Allow uint32 value on optimized frames if they are consumed by safe operations.
authorvegorov@chromium.org <vegorov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 22 Aug 2012 15:44:17 +0000 (15:44 +0000)
committervegorov@chromium.org <vegorov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 22 Aug 2012 15:44:17 +0000 (15:44 +0000)
Safe operations are those that either do not observe unsignedness or have special support for uint32 values:

- all binary bitwise operations: they perform ToInt32 on inputs;
- >> and << shifts: they perform ToInt32 on left hand side and ToUint32 on right hand side;
- >>> shift: it performs ToUint32 on both inputs;
- stores to integer external arrays (not pixel, float or double ones): these stores are "bitwise";
- HChange: special support added for conversions of uint32 values to double and tagged values;
- HSimulate: special support added for deoptimization with uint32 values in registers and stack slots;
- HPhi: phis that have only safe uses and only uint32 operands are uint32 themselves.

BUG=v8:2097
TEST=test/mjsunit/compiler/uint32.js

Review URL: https://chromiumcodereview.appspot.com/10778029

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12367 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

28 files changed:
src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/arm/lithium-codegen-arm.h
src/arm/simulator-arm.cc
src/deoptimizer.cc
src/deoptimizer.h
src/flag-definitions.h
src/globals.h
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/hydrogen.h
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.h
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/ia32/macro-assembler-ia32.cc
src/ia32/macro-assembler-ia32.h
src/lithium.h
src/objects.cc
src/x64/lithium-codegen-x64.cc
src/x64/lithium-codegen-x64.h
src/x64/lithium-x64.cc
src/x64/lithium-x64.h
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h
test/mjsunit/compiler/uint32.js [new file with mode: 0644]

index 1833f3e..d461ee8 100644 (file)
@@ -713,15 +713,20 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
     right = UseRegisterAtStart(right_value);
   }
 
-  // Shift operations can only deoptimize if we do a logical shift
-  // by 0 and the result cannot be truncated to int32.
-  bool may_deopt = (op == Token::SHR && constant_value == 0);
   bool does_deopt = false;
-  if (may_deopt) {
-    for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
-      if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
-        does_deopt = true;
-        break;
+
+  if (FLAG_opt_safe_uint32_operations) {
+    does_deopt = !instr->CheckFlag(HInstruction::kUint32);
+  } else {
+    // Shift operations can only deoptimize if we do a logical shift
+    // by 0 and the result cannot be truncated to int32.
+    bool may_deopt = (op == Token::SHR && constant_value == 0);
+    if (may_deopt) {
+      for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
+        if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
+          does_deopt = true;
+          break;
+        }
       }
     }
   }
@@ -880,7 +885,9 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
     } else {
       op = UseAny(value);
     }
-    result->AddValue(op, value->representation());
+    result->AddValue(op,
+                     value->representation(),
+                     value->CheckFlag(HInstruction::kUint32));
   }
 
   if (hydrogen_env->frame_type() == JS_FUNCTION) {
@@ -1649,7 +1656,10 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
     if (to.IsTagged()) {
       HValue* val = instr->value();
       LOperand* value = UseRegisterAtStart(val);
-      if (val->HasRange() && val->range()->IsInSmiRange()) {
+      if (val->CheckFlag(HInstruction::kUint32)) {
+        LNumberTagU* result = new(zone()) LNumberTagU(value);
+        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
+      } else if (val->HasRange() && val->range()->IsInSmiRange()) {
         return DefineAsRegister(new(zone()) LSmiTag(value));
       } else {
         LNumberTagI* result = new(zone()) LNumberTagI(value);
@@ -1657,8 +1667,13 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
       }
     } else {
       ASSERT(to.IsDouble());
-      LOperand* value = Use(instr->value());
-      return DefineAsRegister(new(zone()) LInteger32ToDouble(value));
+      if (instr->value()->CheckFlag(HInstruction::kUint32)) {
+        return DefineAsRegister(
+            new(zone()) LUint32ToDouble(UseRegister(instr->value())));
+      } else {
+        return DefineAsRegister(
+            new(zone()) LInteger32ToDouble(Use(instr->value())));
+      }
     }
   }
   UNREACHABLE();
index 9425e96..ada5481 100644 (file)
@@ -108,6 +108,7 @@ class LCodeGen;
   V(InstanceOfKnownGlobal)                      \
   V(InstructionGap)                             \
   V(Integer32ToDouble)                          \
+  V(Uint32ToDouble)                             \
   V(InvokeFunction)                             \
   V(IsConstructCallAndBranch)                   \
   V(IsNilAndBranch)                             \
@@ -137,6 +138,7 @@ class LCodeGen;
   V(MulI)                                       \
   V(NumberTagD)                                 \
   V(NumberTagI)                                 \
+  V(NumberTagU)                                 \
   V(NumberUntagD)                               \
   V(ObjectLiteral)                              \
   V(OsrEntry)                                   \
@@ -1605,6 +1607,16 @@ class LInteger32ToDouble: public LTemplateInstruction<1, 1, 0> {
 };
 
 
+class LUint32ToDouble: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LUint32ToDouble(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(Uint32ToDouble, "uint32-to-double")
+};
+
+
 class LNumberTagI: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LNumberTagI(LOperand* value) {
@@ -1615,6 +1627,16 @@ class LNumberTagI: public LTemplateInstruction<1, 1, 0> {
 };
 
 
+class LNumberTagU: public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LNumberTagU(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(NumberTagU, "number-tag-u")
+};
+
+
 class LNumberTagD: public LTemplateInstruction<1, 1, 2> {
  public:
   LNumberTagD(LOperand* value, LOperand* temp1, LOperand* temp2) {
index ec454f4..0b8f97b 100644 (file)
@@ -512,7 +512,8 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
         translation->MarkDuplicate();
         AddToTranslation(translation,
                          environment->spilled_registers()[value->index()],
-                         environment->HasTaggedValueAt(i));
+                         environment->HasTaggedValueAt(i),
+                         environment->HasUint32ValueAt(i));
       } else if (
           value->IsDoubleRegister() &&
           environment->spilled_double_registers()[value->index()] != NULL) {
@@ -520,18 +521,23 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
         AddToTranslation(
             translation,
             environment->spilled_double_registers()[value->index()],
+            false,
             false);
       }
     }
 
-    AddToTranslation(translation, value, environment->HasTaggedValueAt(i));
+    AddToTranslation(translation,
+                     value,
+                     environment->HasTaggedValueAt(i),
+                     environment->HasUint32ValueAt(i));
   }
 }
 
 
 void LCodeGen::AddToTranslation(Translation* translation,
                                 LOperand* op,
-                                bool is_tagged) {
+                                bool is_tagged,
+                                bool is_uint32) {
   if (op == NULL) {
     // TODO(twuerthinger): Introduce marker operands to indicate that this value
     // is not present and must be reconstructed from the deoptimizer. Currently
@@ -540,6 +546,8 @@ void LCodeGen::AddToTranslation(Translation* translation,
   } else if (op->IsStackSlot()) {
     if (is_tagged) {
       translation->StoreStackSlot(op->index());
+    } else if (is_uint32) {
+      translation->StoreUint32StackSlot(op->index());
     } else {
       translation->StoreInt32StackSlot(op->index());
     }
@@ -553,6 +561,8 @@ void LCodeGen::AddToTranslation(Translation* translation,
     Register reg = ToRegister(op);
     if (is_tagged) {
       translation->StoreRegister(reg);
+    } else if (is_uint32) {
+      translation->StoreUint32Register(reg);
     } else {
       translation->StoreInt32Register(reg);
     }
@@ -3022,11 +3032,10 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
         break;
       case EXTERNAL_UNSIGNED_INT_ELEMENTS:
         __ ldr(result, mem_operand);
-        __ cmp(result, Operand(0x80000000));
-        // TODO(danno): we could be more clever here, perhaps having a special
-        // version of the stub that detects if the overflow case actually
-        // happens, and generate code that returns a double rather than int.
-        DeoptimizeIf(cs, instr->environment());
+        if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
+          __ cmp(result, Operand(0x80000000));
+          DeoptimizeIf(cs, instr->environment());
+        }
         break;
       case EXTERNAL_FLOAT_ELEMENTS:
       case EXTERNAL_DOUBLE_ELEMENTS:
@@ -4285,12 +4294,24 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
 }
 
 
+void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
+  LOperand* input = instr->InputAt(0);
+  LOperand* output = instr->result();
+
+  SwVfpRegister flt_scratch = double_scratch0().low();
+  __ vmov(flt_scratch, ToRegister(input));
+  __ vcvt_f64_u32(ToDoubleRegister(output), flt_scratch);
+}
+
+
 void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
   class DeferredNumberTagI: public LDeferredCode {
    public:
     DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); }
+    virtual void Generate() {
+      codegen()->DoDeferredNumberTagI(instr_, SIGNED_INT32);
+    }
     virtual LInstruction* instr() { return instr_; }
    private:
     LNumberTagI* instr_;
@@ -4306,7 +4327,33 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
 }
 
 
-void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
+void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
+  class DeferredNumberTagU: public LDeferredCode {
+   public:
+    DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() {
+      codegen()->DoDeferredNumberTagI(instr_, UNSIGNED_INT32);
+    }
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LNumberTagU* instr_;
+  };
+
+  LOperand* input = instr->InputAt(0);
+  ASSERT(input->IsRegister() && input->Equals(instr->result()));
+  Register reg = ToRegister(input);
+
+  DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
+  __ cmp(reg, Operand(Smi::kMaxValue));
+  __ b(hi, deferred->entry());
+  __ SmiTag(reg, reg);
+  __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
+                                    IntegerSignedness signedness) {
   Label slow;
   Register src = ToRegister(instr->InputAt(0));
   Register dst = ToRegister(instr->result());
@@ -4316,16 +4363,22 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
   // Preserve the value of all registers.
   PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
 
-  // There was overflow, so bits 30 and 31 of the original integer
-  // disagree. Try to allocate a heap number in new space and store
-  // the value in there. If that fails, call the runtime system.
   Label done;
-  if (dst.is(src)) {
-    __ SmiUntag(src, dst);
-    __ eor(src, src, Operand(0x80000000));
+  if (signedness == SIGNED_INT32) {
+    // There was overflow, so bits 30 and 31 of the original integer
+    // disagree. Try to allocate a heap number in new space and store
+    // the value in there. If that fails, call the runtime system.
+    if (dst.is(src)) {
+      __ SmiUntag(src, dst);
+      __ eor(src, src, Operand(0x80000000));
+    }
+    __ vmov(flt_scratch, src);
+    __ vcvt_f64_s32(dbl_scratch, flt_scratch);
+  } else {
+    __ vmov(flt_scratch, src);
+    __ vcvt_f64_u32(dbl_scratch, flt_scratch);
   }
-  __ vmov(flt_scratch, src);
-  __ vcvt_f64_s32(dbl_scratch, flt_scratch);
+
   if (FLAG_inline_new) {
     __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
     __ AllocateHeapNumber(r5, r3, r4, r6, &slow);
index 0db586f..265deb6 100644 (file)
@@ -114,7 +114,10 @@ class LCodeGen BASE_EMBEDDED {
   void DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
                               Token::Value op);
   void DoDeferredNumberTagD(LNumberTagD* instr);
-  void DoDeferredNumberTagI(LNumberTagI* instr);
+
+  enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 };
+  void DoDeferredNumberTagI(LInstruction* instr, IntegerSignedness signedness);
+
   void DoDeferredTaggedToI(LTaggedToI* instr);
   void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
   void DoDeferredStackCheck(LStackCheck* instr);
@@ -252,7 +255,8 @@ class LCodeGen BASE_EMBEDDED {
 
   void AddToTranslation(Translation* translation,
                         LOperand* op,
-                        bool is_tagged);
+                        bool is_tagged,
+                        bool is_uint32);
   void PopulateDeoptimizationData(Handle<Code> code);
   int DefineDeoptimizationLiteral(Handle<Object> literal);
 
index f94c394..a057de5 100644 (file)
@@ -2366,7 +2366,7 @@ void Simulator::DecodeType01(Instruction* instr) {
           // Format(instr, "cmn'cond 'rn, 'imm");
           alu_out = rn_val + shifter_operand;
           SetNZFlags(alu_out);
-          SetCFlag(!CarryFrom(rn_val, shifter_operand));
+          SetCFlag(CarryFrom(rn_val, shifter_operand));
           SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
         } else {
           // Other instructions matching this pattern are handled in the
index 53d3e57..b0a1984 100644 (file)
@@ -595,9 +595,11 @@ void Deoptimizer::DoComputeOutputFrames() {
       case Translation::BEGIN:
       case Translation::REGISTER:
       case Translation::INT32_REGISTER:
+      case Translation::UINT32_REGISTER:
       case Translation::DOUBLE_REGISTER:
       case Translation::STACK_SLOT:
       case Translation::INT32_STACK_SLOT:
+      case Translation::UINT32_STACK_SLOT:
       case Translation::DOUBLE_STACK_SLOT:
       case Translation::LITERAL:
       case Translation::ARGUMENTS_OBJECT:
@@ -769,6 +771,34 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
       return;
     }
 
+    case Translation::UINT32_REGISTER: {
+      int input_reg = iterator->Next();
+      uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
+      bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
+      if (FLAG_trace_deopt) {
+        PrintF(
+            "    0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIuPTR
+            " ; uint %s (%s)\n",
+            output_[frame_index]->GetTop() + output_offset,
+            output_offset,
+            value,
+            converter.NameOfCPURegister(input_reg),
+            is_smi ? "smi" : "heap number");
+      }
+      if (is_smi) {
+        intptr_t tagged_value =
+            reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
+        output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
+      } else {
+        // We save the untagged value on the side and store a GC-safe
+        // temporary placeholder in the frame.
+        AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
+                       static_cast<double>(static_cast<uint32_t>(value)));
+        output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
+      }
+      return;
+    }
+
     case Translation::DOUBLE_REGISTER: {
       int input_reg = iterator->Next();
       double value = input_->GetDoubleRegister(input_reg);
@@ -834,6 +864,36 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
       return;
     }
 
+    case Translation::UINT32_STACK_SLOT: {
+      int input_slot_index = iterator->Next();
+      unsigned input_offset =
+          input_->GetOffsetFromSlotIndex(input_slot_index);
+      uintptr_t value =
+          static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
+      bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
+      if (FLAG_trace_deopt) {
+        PrintF("    0x%08" V8PRIxPTR ": ",
+               output_[frame_index]->GetTop() + output_offset);
+        PrintF("[top + %d] <- %" V8PRIuPTR " ; [sp + %d] (uint32 %s)\n",
+               output_offset,
+               value,
+               input_offset,
+               is_smi ? "smi" : "heap number");
+      }
+      if (is_smi) {
+        intptr_t tagged_value =
+            reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
+        output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
+      } else {
+        // We save the untagged value on the side and store a GC-safe
+        // temporary placeholder in the frame.
+        AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
+                       static_cast<double>(static_cast<uint32_t>(value)));
+        output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
+      }
+      return;
+    }
+
     case Translation::DOUBLE_STACK_SLOT: {
       int input_slot_index = iterator->Next();
       unsigned input_offset =
@@ -886,6 +946,56 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
 }
 
 
+static bool ObjectToInt32(Object* obj, int32_t* value) {
+  if (obj->IsSmi()) {
+    *value = Smi::cast(obj)->value();
+    return true;
+  }
+
+  if (obj->IsHeapNumber()) {
+    double num = HeapNumber::cast(obj)->value();
+    if (FastD2I(FastI2D(num)) != num) {
+      if (FLAG_trace_osr) {
+        PrintF("**** %g could not be converted to int32 ****\n",
+               HeapNumber::cast(obj)->value());
+      }
+      return false;
+    }
+
+    *value = FastD2I(num);
+    return true;
+  }
+
+  return false;
+}
+
+
+static bool ObjectToUint32(Object* obj, uint32_t* value) {
+  if (obj->IsSmi()) {
+    if (Smi::cast(obj)->value() < 0) return false;
+
+    *value = static_cast<uint32_t>(Smi::cast(obj)->value());
+    return true;
+  }
+
+  if (obj->IsHeapNumber()) {
+    double num = HeapNumber::cast(obj)->value();
+    if ((num < 0) || (FastD2UI(FastUI2D(num)) != num)) {
+      if (FLAG_trace_osr) {
+        PrintF("**** %g could not be converted to uint32 ****\n",
+               HeapNumber::cast(obj)->value());
+      }
+      return false;
+    }
+
+    *value = FastD2UI(num);
+    return true;
+  }
+
+  return false;
+}
+
+
 bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
                                         int* input_offset) {
   disasm::NameConverter converter;
@@ -926,22 +1036,10 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
      }
 
     case Translation::INT32_REGISTER: {
-      // Abort OSR if we don't have a number.
-      if (!input_object->IsNumber()) return false;
+      int32_t int32_value = 0;
+      if (!ObjectToInt32(input_object, &int32_value)) return false;
 
       int output_reg = iterator->Next();
-      int int32_value = input_object->IsSmi()
-          ? Smi::cast(input_object)->value()
-          : FastD2I(input_object->Number());
-      // Abort the translation if the conversion lost information.
-      if (!input_object->IsSmi() &&
-          FastI2D(int32_value) != input_object->Number()) {
-        if (FLAG_trace_osr) {
-          PrintF("**** %g could not be converted to int32 ****\n",
-                 input_object->Number());
-        }
-        return false;
-      }
       if (FLAG_trace_osr) {
         PrintF("    %s <- %d (int32) ; [sp + %d]\n",
                converter.NameOfCPURegister(output_reg),
@@ -952,6 +1050,21 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
       break;
     }
 
+    case Translation::UINT32_REGISTER: {
+      uint32_t uint32_value = 0;
+      if (!ObjectToUint32(input_object, &uint32_value)) return false;
+
+      int output_reg = iterator->Next();
+      if (FLAG_trace_osr) {
+        PrintF("    %s <- %u (uint32) ; [sp + %d]\n",
+               converter.NameOfCPURegister(output_reg),
+               uint32_value,
+               *input_offset);
+      }
+      output->SetRegister(output_reg, static_cast<int32_t>(uint32_value));
+    }
+
+
     case Translation::DOUBLE_REGISTER: {
       // Abort OSR if we don't have a number.
       if (!input_object->IsNumber()) return false;
@@ -985,24 +1098,12 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
     }
 
     case Translation::INT32_STACK_SLOT: {
-      // Abort OSR if we don't have a number.
-      if (!input_object->IsNumber()) return false;
+      int32_t int32_value = 0;
+      if (!ObjectToInt32(input_object, &int32_value)) return false;
 
       int output_index = iterator->Next();
       unsigned output_offset =
           output->GetOffsetFromSlotIndex(output_index);
-      int int32_value = input_object->IsSmi()
-          ? Smi::cast(input_object)->value()
-          : DoubleToInt32(input_object->Number());
-      // Abort the translation if the conversion lost information.
-      if (!input_object->IsSmi() &&
-          FastI2D(int32_value) != input_object->Number()) {
-        if (FLAG_trace_osr) {
-          PrintF("**** %g could not be converted to int32 ****\n",
-                 input_object->Number());
-        }
-        return false;
-      }
       if (FLAG_trace_osr) {
         PrintF("    [sp + %d] <- %d (int32) ; [sp + %d]\n",
                output_offset,
@@ -1013,6 +1114,23 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
       break;
     }
 
+    case Translation::UINT32_STACK_SLOT: {
+      uint32_t uint32_value = 0;
+      if (!ObjectToUint32(input_object, &uint32_value)) return false;
+
+      int output_index = iterator->Next();
+      unsigned output_offset =
+          output->GetOffsetFromSlotIndex(output_index);
+      if (FLAG_trace_osr) {
+        PrintF("    [sp + %d] <- %u (uint32) ; [sp + %d]\n",
+               output_offset,
+               uint32_value,
+               *input_offset);
+      }
+      output->SetFrameSlot(output_offset, static_cast<int32_t>(uint32_value));
+      break;
+    }
+
     case Translation::DOUBLE_STACK_SLOT: {
       static const int kLowerOffset = 0 * kPointerSize;
       static const int kUpperOffset = 1 * kPointerSize;
@@ -1399,6 +1517,12 @@ void Translation::StoreInt32Register(Register reg) {
 }
 
 
+void Translation::StoreUint32Register(Register reg) {
+  buffer_->Add(UINT32_REGISTER, zone());
+  buffer_->Add(reg.code(), zone());
+}
+
+
 void Translation::StoreDoubleRegister(DoubleRegister reg) {
   buffer_->Add(DOUBLE_REGISTER, zone());
   buffer_->Add(DoubleRegister::ToAllocationIndex(reg), zone());
@@ -1417,6 +1541,12 @@ void Translation::StoreInt32StackSlot(int index) {
 }
 
 
+void Translation::StoreUint32StackSlot(int index) {
+  buffer_->Add(UINT32_STACK_SLOT, zone());
+  buffer_->Add(index, zone());
+}
+
+
 void Translation::StoreDoubleStackSlot(int index) {
   buffer_->Add(DOUBLE_STACK_SLOT, zone());
   buffer_->Add(index, zone());
@@ -1447,9 +1577,11 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
     case SETTER_STUB_FRAME:
     case REGISTER:
     case INT32_REGISTER:
+    case UINT32_REGISTER:
     case DOUBLE_REGISTER:
     case STACK_SLOT:
     case INT32_STACK_SLOT:
+    case UINT32_STACK_SLOT:
     case DOUBLE_STACK_SLOT:
     case LITERAL:
       return 1;
@@ -1483,12 +1615,16 @@ const char* Translation::StringFor(Opcode opcode) {
       return "REGISTER";
     case INT32_REGISTER:
       return "INT32_REGISTER";
+    case UINT32_REGISTER:
+      return "UINT32_REGISTER";
     case DOUBLE_REGISTER:
       return "DOUBLE_REGISTER";
     case STACK_SLOT:
       return "STACK_SLOT";
     case INT32_STACK_SLOT:
       return "INT32_STACK_SLOT";
+    case UINT32_STACK_SLOT:
+      return "UINT32_STACK_SLOT";
     case DOUBLE_STACK_SLOT:
       return "DOUBLE_STACK_SLOT";
     case LITERAL:
@@ -1545,6 +1681,7 @@ SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
 
     case Translation::REGISTER:
     case Translation::INT32_REGISTER:
+    case Translation::UINT32_REGISTER:
     case Translation::DOUBLE_REGISTER:
     case Translation::DUPLICATE:
       // We are at safepoint which corresponds to call.  All registers are
@@ -1564,6 +1701,12 @@ SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
       return SlotRef(slot_addr, SlotRef::INT32);
     }
 
+    case Translation::UINT32_STACK_SLOT: {
+      int slot_index = iterator->Next();
+      Address slot_addr = SlotAddress(frame, slot_index);
+      return SlotRef(slot_addr, SlotRef::UINT32);
+    }
+
     case Translation::DOUBLE_STACK_SLOT: {
       int slot_index = iterator->Next();
       Address slot_addr = SlotAddress(frame, slot_index);
index cd8c9ea..c49ae86 100644 (file)
@@ -565,9 +565,11 @@ class Translation BASE_EMBEDDED {
     ARGUMENTS_ADAPTOR_FRAME,
     REGISTER,
     INT32_REGISTER,
+    UINT32_REGISTER,
     DOUBLE_REGISTER,
     STACK_SLOT,
     INT32_STACK_SLOT,
+    UINT32_STACK_SLOT,
     DOUBLE_STACK_SLOT,
     LITERAL,
     ARGUMENTS_OBJECT,
@@ -596,9 +598,11 @@ class Translation BASE_EMBEDDED {
   void BeginSetterStubFrame(int literal_id);
   void StoreRegister(Register reg);
   void StoreInt32Register(Register reg);
+  void StoreUint32Register(Register reg);
   void StoreDoubleRegister(DoubleRegister reg);
   void StoreStackSlot(int index);
   void StoreInt32StackSlot(int index);
+  void StoreUint32StackSlot(int index);
   void StoreDoubleStackSlot(int index);
   void StoreLiteral(int literal_id);
   void StoreArgumentsObject();
@@ -648,6 +652,7 @@ class SlotRef BASE_EMBEDDED {
     UNKNOWN,
     TAGGED,
     INT32,
+    UINT32,
     DOUBLE,
     LITERAL
   };
@@ -675,6 +680,16 @@ class SlotRef BASE_EMBEDDED {
         }
       }
 
+      case UINT32: {
+        uint32_t value = Memory::uint32_at(addr_);
+        if (value <= static_cast<uint32_t>(Smi::kMaxValue)) {
+          return Handle<Object>(Smi::FromInt(static_cast<int>(value)));
+        } else {
+          return Isolate::Current()->factory()->NewNumber(
+            static_cast<double>(value));
+        }
+      }
+
       case DOUBLE: {
         double value = Memory::double_at(addr_);
         return Isolate::Current()->factory()->NewNumber(value);
index 42a09bd..b44246a 100644 (file)
@@ -218,6 +218,9 @@ DEFINE_int(loop_weight, 1, "loop weight for representation inference")
 
 DEFINE_bool(optimize_for_in, true,
             "optimize functions containing for-in loops")
+DEFINE_bool(opt_safe_uint32_operations, true,
+            "allow uint32 values on optimize frames if they are used only in"
+            "safe operations")
 
 DEFINE_bool(parallel_recompilation, false,
             "optimizing hot functions asynchronously on a separate thread")
index b5ca769..00ecd63 100644 (file)
@@ -203,6 +203,7 @@ typedef byte* Address;
 
 #define V8PRIxPTR V8_PTR_PREFIX "x"
 #define V8PRIdPTR V8_PTR_PREFIX "d"
+#define V8PRIuPTR V8_PTR_PREFIX "u"
 
 // Fix for Mac OS X defining uintptr_t as "unsigned long":
 #if defined(__APPLE__) && defined(__MACH__)
index 67ee5bd..e989cc6 100644 (file)
@@ -875,12 +875,14 @@ HValue* HBitwise::Canonicalize() {
   int32_t nop_constant = (op() == Token::BIT_AND) ? -1 : 0;
   if (left()->IsConstant() &&
       HConstant::cast(left())->HasInteger32Value() &&
-      HConstant::cast(left())->Integer32Value() == nop_constant) {
+      HConstant::cast(left())->Integer32Value() == nop_constant &&
+      !right()->CheckFlag(kUint32)) {
     return right();
   }
   if (right()->IsConstant() &&
       HConstant::cast(right())->HasInteger32Value() &&
-      HConstant::cast(right())->Integer32Value() == nop_constant) {
+      HConstant::cast(right())->Integer32Value() == nop_constant &&
+      !left()->CheckFlag(kUint32)) {
     return left();
   }
   return this;
@@ -892,7 +894,9 @@ HValue* HBitNot::Canonicalize() {
   if (value()->IsBitNot()) {
     HValue* result = HBitNot::cast(value())->value();
     ASSERT(result->representation().IsInteger32());
-    return result;
+    if (!result->CheckFlag(kUint32)) {
+      return result;
+    }
   }
   return this;
 }
index b822a78..4a16288 100644 (file)
@@ -562,7 +562,14 @@ class HValue: public ZoneObject {
     kIsArguments,
     kTruncatingToInt32,
     kIsDead,
-    kLastFlag = kIsDead
+    // Instructions that are allowed to produce full range unsigned integer
+    // values are marked with kUint32 flag. If arithmetic shift or a load from
+    // EXTERNAL_UNSIGNED_INT_ELEMENTS array is not marked with this flag
+    // it will deoptimize if result does not fit into signed integer range.
+    // HGraph::ComputeSafeUint32Operations is responsible for setting this
+    // flag.
+    kUint32,
+    kLastFlag = kUint32
   };
 
   STATIC_ASSERT(kLastFlag < kBitsPerInt);
@@ -2556,6 +2563,10 @@ class HConstant: public HTemplateInstruction<0> {
 
   bool ToBoolean();
 
+  bool IsUint32() {
+    return HasInteger32Value() && (Integer32Value() >= 0);
+  }
+
   virtual intptr_t Hashcode() {
     ASSERT_ALLOCATION_DISABLED;
     intptr_t hash;
index 50025f5..f37902e 100644 (file)
@@ -694,6 +694,7 @@ HGraph::HGraph(CompilationInfo* info)
       blocks_(8, info->zone()),
       values_(16, info->zone()),
       phi_list_(NULL),
+      uint32_instructions_(NULL),
       info_(info),
       zone_(info->zone()),
       is_recursive_(false) {
@@ -2723,6 +2724,226 @@ void HGraph::MarkDeoptimizeOnUndefined() {
 }
 
 
+// Discover instructions that can be marked with kUint32 flag allowing
+// them to produce full range uint32 values.
+class Uint32Analysis BASE_EMBEDDED {
+ public:
+  explicit Uint32Analysis(Zone* zone) : zone_(zone), phis_(4, zone) { }
+
+  void Analyze(HInstruction* current);
+
+  void UnmarkUnsafePhis();
+
+ private:
+  bool IsSafeUint32Use(HValue* val, HValue* use);
+  bool Uint32UsesAreSafe(HValue* uint32val);
+  bool CheckPhiOperands(HPhi* phi);
+  void UnmarkPhi(HPhi* phi, ZoneList<HPhi*>* worklist);
+
+  Zone* zone_;
+  ZoneList<HPhi*> phis_;
+};
+
+
+bool Uint32Analysis::IsSafeUint32Use(HValue* val, HValue* use) {
+  // Operations that operatate on bits are safe.
+  if (use->IsBitwise() ||
+      use->IsShl() ||
+      use->IsSar() ||
+      use->IsShr() ||
+      use->IsBitNot()) {
+    return true;
+  } else if (use->IsChange() || use->IsSimulate()) {
+    // Conversions and deoptimization have special support for unt32.
+    return true;
+  } else if (use->IsStoreKeyedSpecializedArrayElement()) {
+    // Storing a value into an external integer array is a bit level operation.
+    HStoreKeyedSpecializedArrayElement* store =
+        HStoreKeyedSpecializedArrayElement::cast(use);
+
+    if (store->value() == val) {
+      // Clamping or a conversion to double should have beed inserted.
+      ASSERT(store->elements_kind() != EXTERNAL_PIXEL_ELEMENTS);
+      ASSERT(store->elements_kind() != EXTERNAL_FLOAT_ELEMENTS);
+      ASSERT(store->elements_kind() != EXTERNAL_DOUBLE_ELEMENTS);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+// Iterate over all uses and verify that they are uint32 safe: either don't
+// distinguish between int32 and uint32 due to their bitwise nature or
+// have special support for uint32 values.
+// Encountered phis are optimisitically treated as safe uint32 uses,
+// marked with kUint32 flag and collected in the phis_ list. A separate
+// path will be performed later by UnmarkUnsafePhis to clear kUint32 from
+// phis that are not actually uint32-safe (it requries fix point iteration).
+bool Uint32Analysis::Uint32UsesAreSafe(HValue* uint32val) {
+  bool collect_phi_uses = false;
+  for (HUseIterator it(uint32val->uses()); !it.Done(); it.Advance()) {
+    HValue* use = it.value();
+
+    if (use->IsPhi()) {
+      if (!use->CheckFlag(HInstruction::kUint32)) {
+        // There is a phi use of this value from a phis that is not yet
+        // collected in phis_ array. Separate pass is required.
+        collect_phi_uses = true;
+      }
+
+      // Optimistically treat phis as uint32 safe.
+      continue;
+    }
+
+    if (!IsSafeUint32Use(uint32val, use)) {
+      return false;
+    }
+  }
+
+  if (collect_phi_uses) {
+    for (HUseIterator it(uint32val->uses()); !it.Done(); it.Advance()) {
+      HValue* use = it.value();
+
+      // There is a phi use of this value from a phis that is not yet
+      // collected in phis_ array. Separate pass is required.
+      if (use->IsPhi() && !use->CheckFlag(HInstruction::kUint32)) {
+        use->SetFlag(HInstruction::kUint32);
+        phis_.Add(HPhi::cast(use), zone_);
+      }
+    }
+  }
+
+  return true;
+}
+
+
+// Analyze instruction and mark it with kUint32 if all its uses are uint32
+// safe.
+void Uint32Analysis::Analyze(HInstruction* current) {
+  if (Uint32UsesAreSafe(current)) current->SetFlag(HInstruction::kUint32);
+}
+
+
+// Check if all operands to the given phi are marked with kUint32 flag.
+bool Uint32Analysis::CheckPhiOperands(HPhi* phi) {
+  if (!phi->CheckFlag(HInstruction::kUint32)) {
+    // This phi is not uint32 safe. No need to check operands.
+    return false;
+  }
+
+  for (int j = 0; j < phi->OperandCount(); j++) {
+    HValue* operand = phi->OperandAt(j);
+    if (!operand->CheckFlag(HInstruction::kUint32)) {
+      // Lazyly mark constants that fit into uint32 range with kUint32 flag.
+      if (operand->IsConstant() &&
+          HConstant::cast(operand)->IsUint32()) {
+        operand->SetFlag(HInstruction::kUint32);
+        continue;
+      }
+
+      // This phi is not safe, some operands are not uint32 values.
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+// Remove kUint32 flag from the phi itself and its operands. If any operand
+// was a phi marked with kUint32 place it into a worklist for
+// transitive clearing of kUint32 flag.
+void Uint32Analysis::UnmarkPhi(HPhi* phi, ZoneList<HPhi*>* worklist) {
+  phi->ClearFlag(HInstruction::kUint32);
+  for (int j = 0; j < phi->OperandCount(); j++) {
+    HValue* operand = phi->OperandAt(j);
+    if (operand->CheckFlag(HInstruction::kUint32)) {
+      operand->ClearFlag(HInstruction::kUint32);
+      if (operand->IsPhi()) {
+        worklist->Add(HPhi::cast(operand), zone_);
+      }
+    }
+  }
+}
+
+
+void Uint32Analysis::UnmarkUnsafePhis() {
+  // No phis were collected. Nothing to do.
+  if (phis_.length() == 0) return;
+
+  // Worklist used to transitively clear kUint32 from phis that
+  // are used as arguments to other phis.
+  ZoneList<HPhi*> worklist(phis_.length(), zone_);
+
+  // Phi can be used as a uint32 value if and only if
+  // all its operands are uint32 values and all its
+  // uses are uint32 safe.
+
+  // Iterate over collected phis and unmark those that
+  // are unsafe. When unmarking phi unmark its operands
+  // and add it to the worklist if it is a phi as well.
+  // Phis that are still marked as safe are shifted down
+  // so that all safe phis form a prefix of the phis_ array.
+  int phi_count = 0;
+  for (int i = 0; i < phis_.length(); i++) {
+    HPhi* phi = phis_[i];
+
+    if (CheckPhiOperands(phi) && Uint32UsesAreSafe(phi)) {
+      phis_[phi_count++] = phi;
+    } else {
+      UnmarkPhi(phi, &worklist);
+    }
+  }
+
+  // Now phis array contains only those phis that have safe
+  // non-phi uses. Start transitively clearing kUint32 flag
+  // from phi operands of discovered non-safe phies until
+  // only safe phies are left.
+  while (!worklist.is_empty())  {
+    while (!worklist.is_empty()) {
+      HPhi* phi = worklist.RemoveLast();
+      UnmarkPhi(phi, &worklist);
+    }
+
+    // Check if any operands to safe phies were unmarked
+    // turning a safe phi into unsafe. The same value
+    // can flow into several phis.
+    int new_phi_count = 0;
+    for (int i = 0; i < phi_count; i++) {
+      HPhi* phi = phis_[i];
+
+      if (CheckPhiOperands(phi)) {
+        phis_[new_phi_count++] = phi;
+      } else {
+        UnmarkPhi(phi, &worklist);
+      }
+    }
+    phi_count = new_phi_count;
+  }
+}
+
+
+void HGraph::ComputeSafeUint32Operations() {
+  if (!FLAG_opt_safe_uint32_operations || uint32_instructions_ == NULL) {
+    return;
+  }
+
+  Uint32Analysis analysis(zone());
+  for (int i = 0; i < uint32_instructions_->length(); ++i) {
+    HInstruction* current = uint32_instructions_->at(i);
+    if (current->IsLinked()) analysis.Analyze(current);
+  }
+
+  // Some phis might have been optimistically marked with kUint32 flag.
+  // Remove this flag from those phis that are unsafe and propagate
+  // this information transitively potentially clearing kUint32 flag
+  // from some non-phi operations that are used as operands to unsafe phis.
+  analysis.UnmarkUnsafePhis();
+}
+
+
 void HGraph::ComputeMinusZeroChecks() {
   BitVector visited(GetMaximumValueID(), zone());
   for (int i = 0; i < blocks_.length(); ++i) {
@@ -3131,6 +3352,12 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) {
   InsertRepresentationChanges();
 
   InitializeInferredTypes();
+
+  // Must be performed before canonicalization to ensure that Canonicalize
+  // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with
+  // zero.
+  ComputeSafeUint32Operations();
+
   Canonicalize();
 
   // Perform common subexpression elimination and loop-invariant code motion.
@@ -5851,8 +6078,14 @@ HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
         external_elements, checked_key, val, elements_kind);
   } else {
     ASSERT(val == NULL);
-    return new(zone()) HLoadKeyedSpecializedArrayElement(
-        external_elements, checked_key, dependency, elements_kind);
+    HLoadKeyedSpecializedArrayElement* load =
+       new(zone()) HLoadKeyedSpecializedArrayElement(
+          external_elements, checked_key, dependency, elements_kind);
+    if (FLAG_opt_safe_uint32_operations &&
+        elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+      graph()->RecordUint32Instruction(load);
+    }
+    return load;
   }
 }
 
@@ -8034,6 +8267,9 @@ HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr,
       break;
     case Token::SHR:
       instr = HShr::NewHShr(zone(), context, left, right);
+      if (FLAG_opt_safe_uint32_operations && instr->IsShr()) {
+        graph()->RecordUint32Instruction(instr);
+      }
       break;
     case Token::SHL:
       instr = HShl::NewHShl(zone(), context, left, right);
index b4e04f3..dca25b2 100644 (file)
@@ -258,6 +258,7 @@ class HGraph: public ZoneObject {
   void InsertRepresentationChanges();
   void MarkDeoptimizeOnUndefined();
   void ComputeMinusZeroChecks();
+  void ComputeSafeUint32Operations();
   bool ProcessArgumentsObject();
   void EliminateRedundantPhis();
   void EliminateUnreachablePhis();
@@ -343,6 +344,13 @@ class HGraph: public ZoneObject {
     return is_recursive_;
   }
 
+  void RecordUint32Instruction(HInstruction* instr) {
+    if (uint32_instructions_ == NULL) {
+      uint32_instructions_ = new(zone()) ZoneList<HInstruction*>(4, zone());
+    }
+    uint32_instructions_->Add(instr, zone());
+  }
+
  private:
   HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
                          Handle<Object> value);
@@ -370,6 +378,7 @@ class HGraph: public ZoneObject {
   ZoneList<HBasicBlock*> blocks_;
   ZoneList<HValue*> values_;
   ZoneList<HPhi*>* phi_list_;
+  ZoneList<HInstruction*>* uint32_instructions_;
   SetOncePointer<HConstant> undefined_constant_;
   SetOncePointer<HConstant> constant_1_;
   SetOncePointer<HConstant> constant_minus1_;
index 161a82c..edf1582 100644 (file)
@@ -451,7 +451,8 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
         translation->MarkDuplicate();
         AddToTranslation(translation,
                          environment->spilled_registers()[value->index()],
-                         environment->HasTaggedValueAt(i));
+                         environment->HasTaggedValueAt(i),
+                         environment->HasUint32ValueAt(i));
       } else if (
           value->IsDoubleRegister() &&
           environment->spilled_double_registers()[value->index()] != NULL) {
@@ -459,18 +460,23 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
         AddToTranslation(
             translation,
             environment->spilled_double_registers()[value->index()],
+            false,
             false);
       }
     }
 
-    AddToTranslation(translation, value, environment->HasTaggedValueAt(i));
+    AddToTranslation(translation,
+                     value,
+                     environment->HasTaggedValueAt(i),
+                     environment->HasUint32ValueAt(i));
   }
 }
 
 
 void LCodeGen::AddToTranslation(Translation* translation,
                                 LOperand* op,
-                                bool is_tagged) {
+                                bool is_tagged,
+                                bool is_uint32) {
   if (op == NULL) {
     // TODO(twuerthinger): Introduce marker operands to indicate that this value
     // is not present and must be reconstructed from the deoptimizer. Currently
@@ -479,6 +485,8 @@ void LCodeGen::AddToTranslation(Translation* translation,
   } else if (op->IsStackSlot()) {
     if (is_tagged) {
       translation->StoreStackSlot(op->index());
+    } else if (is_uint32) {
+      translation->StoreUint32StackSlot(op->index());
     } else {
       translation->StoreInt32StackSlot(op->index());
     }
@@ -492,6 +500,8 @@ void LCodeGen::AddToTranslation(Translation* translation,
     Register reg = ToRegister(op);
     if (is_tagged) {
       translation->StoreRegister(reg);
+    } else if (is_uint32) {
+      translation->StoreUint32Register(reg);
     } else {
       translation->StoreInt32Register(reg);
     }
@@ -2837,11 +2847,10 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
         break;
       case EXTERNAL_UNSIGNED_INT_ELEMENTS:
         __ mov(result, operand);
-        __ test(result, Operand(result));
-        // TODO(danno): we could be more clever here, perhaps having a special
-        // version of the stub that detects if the overflow case actually
-        // happens, and generate code that returns a double rather than int.
-        DeoptimizeIf(negative, instr->environment());
+        if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
+          __ test(result, Operand(result));
+          DeoptimizeIf(negative, instr->environment());
+        }
         break;
       case EXTERNAL_FLOAT_ELEMENTS:
       case EXTERNAL_DOUBLE_ELEMENTS:
@@ -4081,12 +4090,25 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
 }
 
 
+void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
+  LOperand* input = instr->InputAt(0);
+  LOperand* output = instr->result();
+  LOperand* temp = instr->TempAt(0);
+
+  __ LoadUint32(ToDoubleRegister(output),
+                ToRegister(input),
+                ToDoubleRegister(temp));
+}
+
+
 void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
   class DeferredNumberTagI: public LDeferredCode {
    public:
     DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
         : LDeferredCode(codegen), instr_(instr) { }
-    virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); }
+    virtual void Generate() {
+      codegen()->DoDeferredNumberTagI(instr_, SIGNED_INT32);
+    }
     virtual LInstruction* instr() { return instr_; }
    private:
     LNumberTagI* instr_;
@@ -4103,7 +4125,33 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
 }
 
 
-void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
+void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
+  class DeferredNumberTagU: public LDeferredCode {
+   public:
+    DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() {
+      codegen()->DoDeferredNumberTagI(instr_, UNSIGNED_INT32);
+    }
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LNumberTagU* instr_;
+  };
+
+  LOperand* input = instr->InputAt(0);
+  ASSERT(input->IsRegister() && input->Equals(instr->result()));
+  Register reg = ToRegister(input);
+
+  DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
+  __ cmp(reg, Immediate(Smi::kMaxValue));
+  __ j(above, deferred->entry());
+  __ SmiTag(reg);
+  __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
+                                    IntegerSignedness signedness) {
   Label slow;
   Register reg = ToRegister(instr->InputAt(0));
   Register tmp = reg.is(eax) ? ecx : eax;
@@ -4111,13 +4159,19 @@ void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
   // Preserve the value of all registers.
   PushSafepointRegistersScope scope(this);
 
-  // There was overflow, so bits 30 and 31 of the original integer
-  // disagree. Try to allocate a heap number in new space and store
-  // the value in there. If that fails, call the runtime system.
   Label done;
-  __ SmiUntag(reg);
-  __ xor_(reg, 0x80000000);
-  __ cvtsi2sd(xmm0, Operand(reg));
+
+  if (signedness == SIGNED_INT32) {
+    // There was overflow, so bits 30 and 31 of the original integer
+    // disagree. Try to allocate a heap number in new space and store
+    // the value in there. If that fails, call the runtime system.
+    __ SmiUntag(reg);
+    __ xor_(reg, 0x80000000);
+    __ cvtsi2sd(xmm0, Operand(reg));
+  } else {
+    __ LoadUint32(xmm0, reg, xmm1);
+  }
+
   if (FLAG_inline_new) {
     __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
     __ jmp(&done, Label::kNear);
index 1d77a07..4683f17 100644 (file)
@@ -105,7 +105,10 @@ class LCodeGen BASE_EMBEDDED {
 
   // Deferred code support.
   void DoDeferredNumberTagD(LNumberTagD* instr);
-  void DoDeferredNumberTagI(LNumberTagI* instr);
+
+  enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 };
+  void DoDeferredNumberTagI(LInstruction* instr, IntegerSignedness signedness);
+
   void DoDeferredTaggedToI(LTaggedToI* instr);
   void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
   void DoDeferredStackCheck(LStackCheck* instr);
@@ -233,7 +236,8 @@ class LCodeGen BASE_EMBEDDED {
 
   void AddToTranslation(Translation* translation,
                         LOperand* op,
-                        bool is_tagged);
+                        bool is_tagged,
+                        bool is_uint32);
   void PopulateDeoptimizationData(Handle<Code> code);
   int DefineDeoptimizationLiteral(Handle<Object> literal);
 
index 8613048..f41a18e 100644 (file)
@@ -738,15 +738,20 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
     right = UseFixed(right_value, ecx);
   }
 
-  // Shift operations can only deoptimize if we do a logical shift by 0 and
-  // the result cannot be truncated to int32.
-  bool may_deopt = (op == Token::SHR && constant_value == 0);
   bool does_deopt = false;
-  if (may_deopt) {
-    for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
-      if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
-        does_deopt = true;
-        break;
+  if (FLAG_opt_safe_uint32_operations) {
+    does_deopt = !instr->CheckFlag(HInstruction::kUint32);
+  } else {
+    // Shift operations can only deoptimize if we do a logical shift by 0 and
+    // the result cannot be truncated to int32.
+    bool may_deopt = (op == Token::SHR && constant_value == 0 &&
+      !instr->CheckFlag(HInstruction::kUint32));
+    if (may_deopt) {
+      for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
+        if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
+          does_deopt = true;
+          break;
+        }
       }
     }
   }
@@ -906,7 +911,9 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
     } else {
       op = UseAny(value);
     }
-    result->AddValue(op, value->representation());
+    result->AddValue(op,
+                     value->representation(),
+                     value->CheckFlag(HInstruction::kUint32));
   }
 
   if (hydrogen_env->frame_type() == JS_FUNCTION) {
@@ -1698,14 +1705,24 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
       LOperand* value = UseRegister(val);
       if (val->HasRange() && val->range()->IsInSmiRange()) {
         return DefineSameAsFirst(new(zone()) LSmiTag(value));
+      } else if (val->CheckFlag(HInstruction::kUint32)) {
+        LOperand* temp = FixedTemp(xmm1);
+        LNumberTagU* result = new(zone()) LNumberTagU(value, temp);
+        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
       } else {
         LNumberTagI* result = new(zone()) LNumberTagI(value);
         return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
       }
     } else {
       ASSERT(to.IsDouble());
-      return DefineAsRegister(
-          new(zone()) LInteger32ToDouble(Use(instr->value())));
+      if (instr->value()->CheckFlag(HInstruction::kUint32)) {
+        LOperand* temp = FixedTemp(xmm1);
+        return DefineAsRegister(
+            new(zone()) LUint32ToDouble(UseRegister(instr->value()), temp));
+      } else {
+        return DefineAsRegister(
+            new(zone()) LInteger32ToDouble(Use(instr->value())));
+      }
     }
   }
   UNREACHABLE();
index ee41ef7..8a31f80 100644 (file)
@@ -102,6 +102,7 @@ class LCodeGen;
   V(InstanceOfKnownGlobal)                      \
   V(InstructionGap)                             \
   V(Integer32ToDouble)                          \
+  V(Uint32ToDouble)                             \
   V(InvokeFunction)                             \
   V(IsConstructCallAndBranch)                   \
   V(IsNilAndBranch)                             \
@@ -132,6 +133,7 @@ class LCodeGen;
   V(MulI)                                       \
   V(NumberTagD)                                 \
   V(NumberTagI)                                 \
+  V(NumberTagU)                                 \
   V(NumberUntagD)                               \
   V(ObjectLiteral)                              \
   V(OsrEntry)                                   \
@@ -1671,6 +1673,17 @@ class LInteger32ToDouble: public LTemplateInstruction<1, 1, 0> {
 };
 
 
+class LUint32ToDouble: public LTemplateInstruction<1, 1, 1> {
+ public:
+  explicit LUint32ToDouble(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(Uint32ToDouble, "uint32-to-double")
+};
+
+
 class LNumberTagI: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LNumberTagI(LOperand* value) {
@@ -1681,6 +1694,17 @@ class LNumberTagI: public LTemplateInstruction<1, 1, 0> {
 };
 
 
+class LNumberTagU: public LTemplateInstruction<1, 1, 1> {
+ public:
+  explicit LNumberTagU(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(NumberTagU, "number-tag-u")
+};
+
+
 class LNumberTagD: public LTemplateInstruction<1, 1, 1> {
  public:
   LNumberTagD(LOperand* value, LOperand* temp) {
index e81144a..85dcf1f 100644 (file)
@@ -152,6 +152,24 @@ void MacroAssembler::ClampUint8(Register reg) {
 }
 
 
+static double kUint32Bias =
+    static_cast<double>(static_cast<uint32_t>(0xFFFFFFFF)) + 1;
+
+
+void MacroAssembler::LoadUint32(XMMRegister dst,
+                                Register src,
+                                XMMRegister scratch) {
+  Label done;
+  cmp(src, Immediate(0));
+  movdbl(scratch,
+         Operand(reinterpret_cast<int32_t>(&kUint32Bias), RelocInfo::NONE));
+  cvtsi2sd(dst, src);
+  j(not_sign, &done, Label::kNear);
+  addsd(dst, scratch);
+  bind(&done);
+}
+
+
 void MacroAssembler::RecordWriteArray(Register object,
                                       Register value,
                                       Register index,
index c525d3f..8ec3652 100644 (file)
@@ -467,6 +467,8 @@ class MacroAssembler: public Assembler {
     j(not_carry, is_smi);
   }
 
+  void LoadUint32(XMMRegister dst, Register src, XMMRegister scratch);
+
   // Jump the register contains a smi.
   inline void JumpIfSmi(Register value,
                         Label* smi_label,
index d0d1b23..923a159 100644 (file)
@@ -471,6 +471,7 @@ class LEnvironment: public ZoneObject {
         pc_offset_(-1),
         values_(value_count, zone),
         is_tagged_(value_count, zone),
+        is_uint32_(value_count, zone),
         spilled_registers_(NULL),
         spilled_double_registers_(NULL),
         outer_(outer),
@@ -491,17 +492,28 @@ class LEnvironment: public ZoneObject {
   const ZoneList<LOperand*>* values() const { return &values_; }
   LEnvironment* outer() const { return outer_; }
 
-  void AddValue(LOperand* operand, Representation representation) {
+  void AddValue(LOperand* operand,
+                Representation representation,
+                bool is_uint32) {
     values_.Add(operand, zone());
     if (representation.IsTagged()) {
+      ASSERT(!is_uint32);
       is_tagged_.Add(values_.length() - 1);
     }
+
+    if (is_uint32) {
+      is_uint32_.Add(values_.length() - 1);
+    }
   }
 
   bool HasTaggedValueAt(int index) const {
     return is_tagged_.Contains(index);
   }
 
+  bool HasUint32ValueAt(int index) const {
+    return is_uint32_.Contains(index);
+  }
+
   void Register(int deoptimization_index,
                 int translation_index,
                 int pc_offset) {
@@ -535,6 +547,7 @@ class LEnvironment: public ZoneObject {
   int pc_offset_;
   ZoneList<LOperand*> values_;
   BitVector is_tagged_;
+  BitVector is_uint32_;
 
   // Allocation index indexed arrays of spill slot operands for registers
   // that are also in spill slots at an OSR entry.  NULL for environments
index 9306eb9..82cefdc 100644 (file)
@@ -8340,6 +8340,14 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
           break;
         }
 
+        case Translation::UINT32_REGISTER: {
+          int reg_code = iterator.Next();
+          PrintF(out,
+                 "{input=%s (unsigned)}",
+                 converter.NameOfCPURegister(reg_code));
+          break;
+        }
+
         case Translation::DOUBLE_REGISTER: {
           int reg_code = iterator.Next();
           PrintF(out, "{input=%s}",
@@ -8359,6 +8367,12 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
           break;
         }
 
+        case Translation::UINT32_STACK_SLOT: {
+          int input_slot_index = iterator.Next();
+          PrintF(out, "{input=%d (unsigned)}", input_slot_index);
+          break;
+        }
+
         case Translation::DOUBLE_STACK_SLOT: {
           int input_slot_index = iterator.Next();
           PrintF(out, "{input=%d}", input_slot_index);
index 54e3cac..d549054 100644 (file)
@@ -399,7 +399,8 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
         translation->MarkDuplicate();
         AddToTranslation(translation,
                          environment->spilled_registers()[value->index()],
-                         environment->HasTaggedValueAt(i));
+                         environment->HasTaggedValueAt(i),
+                         environment->HasUint32ValueAt(i));
       } else if (
           value->IsDoubleRegister() &&
           environment->spilled_double_registers()[value->index()] != NULL) {
@@ -407,18 +408,23 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
         AddToTranslation(
             translation,
             environment->spilled_double_registers()[value->index()],
+            false,
             false);
       }
     }
 
-    AddToTranslation(translation, value, environment->HasTaggedValueAt(i));
+    AddToTranslation(translation,
+                     value,
+                     environment->HasTaggedValueAt(i),
+                     environment->HasUint32ValueAt(i));
   }
 }
 
 
 void LCodeGen::AddToTranslation(Translation* translation,
                                 LOperand* op,
-                                bool is_tagged) {
+                                bool is_tagged,
+                                bool is_uint32) {
   if (op == NULL) {
     // TODO(twuerthinger): Introduce marker operands to indicate that this value
     // is not present and must be reconstructed from the deoptimizer. Currently
@@ -427,6 +433,8 @@ void LCodeGen::AddToTranslation(Translation* translation,
   } else if (op->IsStackSlot()) {
     if (is_tagged) {
       translation->StoreStackSlot(op->index());
+    } else if (is_uint32) {
+      translation->StoreUint32StackSlot(op->index());
     } else {
       translation->StoreInt32StackSlot(op->index());
     }
@@ -440,6 +448,8 @@ void LCodeGen::AddToTranslation(Translation* translation,
     Register reg = ToRegister(op);
     if (is_tagged) {
       translation->StoreRegister(reg);
+    } else if (is_uint32) {
+      translation->StoreUint32Register(reg);
     } else {
       translation->StoreInt32Register(reg);
     }
@@ -2724,11 +2734,10 @@ void LCodeGen::DoLoadKeyedSpecializedArrayElement(
         break;
       case EXTERNAL_UNSIGNED_INT_ELEMENTS:
         __ movl(result, operand);
-        __ testl(result, result);
-        // TODO(danno): we could be more clever here, perhaps having a special
-        // version of the stub that detects if the overflow case actually
-        // happens, and generate code that returns a double rather than int.
-        DeoptimizeIf(negative, instr->environment());
+        if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
+          __ testl(result, result);
+          DeoptimizeIf(negative, instr->environment());
+        }
         break;
       case EXTERNAL_FLOAT_ELEMENTS:
       case EXTERNAL_DOUBLE_ELEMENTS:
@@ -4012,6 +4021,17 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
 }
 
 
+void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
+  LOperand* input = instr->InputAt(0);
+  LOperand* output = instr->result();
+  LOperand* temp = instr->TempAt(0);
+
+  __ LoadUint32(ToDoubleRegister(output),
+                ToRegister(input),
+                ToDoubleRegister(temp));
+}
+
+
 void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
   LOperand* input = instr->InputAt(0);
   ASSERT(input->IsRegister() && input->Equals(instr->result()));
@@ -4021,6 +4041,66 @@ void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
 }
 
 
+void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
+  class DeferredNumberTagU: public LDeferredCode {
+   public:
+    DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() {
+      codegen()->DoDeferredNumberTagU(instr_);
+    }
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LNumberTagU* instr_;
+  };
+
+  LOperand* input = instr->InputAt(0);
+  ASSERT(input->IsRegister() && input->Equals(instr->result()));
+  Register reg = ToRegister(input);
+
+  DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
+  __ cmpl(reg, Immediate(Smi::kMaxValue));
+  __ j(above, deferred->entry());
+  __ Integer32ToSmi(reg, reg);
+  __ bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredNumberTagU(LNumberTagU* instr) {
+  Label slow;
+  Register reg = ToRegister(instr->InputAt(0));
+  Register tmp = reg.is(rax) ? rcx : rax;
+
+  // Preserve the value of all registers.
+  PushSafepointRegistersScope scope(this);
+
+  Label done;
+  __ LoadUint32(xmm0, reg, xmm1);
+
+  if (FLAG_inline_new) {
+    __ AllocateHeapNumber(reg, tmp, &slow);
+    __ jmp(&done, Label::kNear);
+  }
+
+  // Slow case: Call the runtime system to do the number allocation.
+  __ bind(&slow);
+
+  // Put a valid pointer value in the stack slot where the result
+  // register is stored, as this register is in the pointer map, but contains an
+  // integer value.
+  __ StoreToSafepointRegisterSlot(reg, Immediate(0));
+
+  CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
+  if (!reg.is(rax)) __ movq(reg, rax);
+
+  // Done. Put the value in xmm0 into the value of the allocated heap
+  // number.
+  __ bind(&done);
+  __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
+  __ StoreToSafepointRegisterSlot(reg, reg);
+}
+
+
 void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
   class DeferredNumberTagD: public LDeferredCode {
    public:
index 21486ef..bfa721a 100644 (file)
@@ -98,6 +98,7 @@ class LCodeGen BASE_EMBEDDED {
 
   // Deferred code support.
   void DoDeferredNumberTagD(LNumberTagD* instr);
+  void DoDeferredNumberTagU(LNumberTagU* instr);
   void DoDeferredTaggedToI(LTaggedToI* instr);
   void DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr);
   void DoDeferredStackCheck(LStackCheck* instr);
@@ -223,7 +224,8 @@ class LCodeGen BASE_EMBEDDED {
 
   void AddToTranslation(Translation* translation,
                         LOperand* op,
-                        bool is_tagged);
+                        bool is_tagged,
+                        bool is_uint32);
   void PopulateDeoptimizationData(Handle<Code> code);
   int DefineDeoptimizationLiteral(Handle<Object> literal);
 
index 824c1a6..87fa907 100644 (file)
@@ -720,13 +720,17 @@ LInstruction* LChunkBuilder::DoShift(Token::Value op,
 
   // Shift operations can only deoptimize if we do a logical shift by 0 and
   // the result cannot be truncated to int32.
-  bool may_deopt = (op == Token::SHR && constant_value == 0);
   bool does_deopt = false;
-  if (may_deopt) {
-    for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
-      if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
-        does_deopt = true;
-        break;
+  if (FLAG_opt_safe_uint32_operations) {
+    does_deopt = !instr->CheckFlag(HInstruction::kUint32);
+  } else {
+    bool may_deopt = (op == Token::SHR && constant_value == 0);
+    if (may_deopt) {
+      for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
+        if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) {
+          does_deopt = true;
+          break;
+        }
       }
     }
   }
@@ -885,7 +889,9 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
     } else {
       op = UseAny(value);
     }
-    result->AddValue(op, value->representation());
+    result->AddValue(op,
+                     value->representation(),
+                     value->CheckFlag(HInstruction::kUint32));
   }
 
   if (hydrogen_env->frame_type() == JS_FUNCTION) {
@@ -1623,16 +1629,26 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
     if (to.IsTagged()) {
       HValue* val = instr->value();
       LOperand* value = UseRegister(val);
-      if (val->HasRange() && val->range()->IsInSmiRange()) {
+      if (val->CheckFlag(HInstruction::kUint32)) {
+        LOperand* temp = FixedTemp(xmm1);
+        LNumberTagU* result = new(zone()) LNumberTagU(value, temp);
+        return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
+      } else if (val->HasRange() && val->range()->IsInSmiRange()) {
         return DefineSameAsFirst(new(zone()) LSmiTag(value));
       } else {
         LNumberTagI* result = new(zone()) LNumberTagI(value);
         return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result)));
       }
     } else {
-      ASSERT(to.IsDouble());
-      LOperand* value = Use(instr->value());
-      return DefineAsRegister(new(zone()) LInteger32ToDouble(value));
+      if (instr->value()->CheckFlag(HInstruction::kUint32)) {
+        LOperand* temp = FixedTemp(xmm1);
+        return DefineAsRegister(
+            new(zone()) LUint32ToDouble(UseRegister(instr->value()), temp));
+      } else {
+        ASSERT(to.IsDouble());
+        LOperand* value = Use(instr->value());
+        return DefineAsRegister(new(zone()) LInteger32ToDouble(value));
+      }
     }
   }
   UNREACHABLE();
index 7d9cb6c..b30dd97 100644 (file)
@@ -108,6 +108,7 @@ class LCodeGen;
   V(InstanceOfKnownGlobal)                      \
   V(InstructionGap)                             \
   V(Integer32ToDouble)                          \
+  V(Uint32ToDouble)                             \
   V(InvokeFunction)                             \
   V(IsConstructCallAndBranch)                   \
   V(IsNilAndBranch)                             \
@@ -137,6 +138,7 @@ class LCodeGen;
   V(MulI)                                       \
   V(NumberTagD)                                 \
   V(NumberTagI)                                 \
+  V(NumberTagU)                                 \
   V(NumberUntagD)                               \
   V(ObjectLiteral)                              \
   V(OsrEntry)                                   \
@@ -1581,6 +1583,17 @@ class LInteger32ToDouble: public LTemplateInstruction<1, 1, 0> {
 };
 
 
+class LUint32ToDouble: public LTemplateInstruction<1, 1, 1> {
+ public:
+  explicit LUint32ToDouble(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(Uint32ToDouble, "uint32-to-double")
+};
+
+
 class LNumberTagI: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LNumberTagI(LOperand* value) {
@@ -1591,6 +1604,17 @@ class LNumberTagI: public LTemplateInstruction<1, 1, 0> {
 };
 
 
+class LNumberTagU: public LTemplateInstruction<1, 1, 1> {
+ public:
+  explicit LNumberTagU(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(NumberTagU, "number-tag-u")
+};
+
+
 class LNumberTagD: public LTemplateInstruction<1, 1, 1> {
  public:
   explicit LNumberTagD(LOperand* value, LOperand* temp) {
index 87ac078..d49048f 100644 (file)
@@ -2500,6 +2500,12 @@ MacroAssembler::kSafepointPushRegisterIndices[Register::kNumRegisters] = {
 };
 
 
+void MacroAssembler::StoreToSafepointRegisterSlot(Register dst,
+                                                  const Immediate& imm) {
+  movq(SafepointRegisterSlot(dst), imm);
+}
+
+
 void MacroAssembler::StoreToSafepointRegisterSlot(Register dst, Register src) {
   movq(SafepointRegisterSlot(dst), src);
 }
@@ -2854,6 +2860,26 @@ void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg,
 }
 
 
+static double kUint32Bias =
+    static_cast<double>(static_cast<uint32_t>(0xFFFFFFFF)) + 1;
+
+
+void MacroAssembler::LoadUint32(XMMRegister dst,
+                                Register src,
+                                XMMRegister scratch) {
+  Label done;
+  cmpl(src, Immediate(0));
+  movq(kScratchRegister,
+       reinterpret_cast<int64_t>(&kUint32Bias),
+       RelocInfo::NONE);
+  movsd(scratch, Operand(kScratchRegister, 0));
+  cvtlsi2sd(dst, src);
+  j(not_sign, &done, Label::kNear);
+  addsd(dst, scratch);
+  bind(&done);
+}
+
+
 void MacroAssembler::LoadInstanceDescriptors(Register map,
                                              Register descriptors) {
   Register temp = descriptors;
index 61e140e..9c8f550 100644 (file)
@@ -317,6 +317,7 @@ class MacroAssembler: public Assembler {
   void PopSafepointRegisters() { Popad(); }
   // Store the value in register src in the safepoint register stack
   // slot for register dst.
+  void StoreToSafepointRegisterSlot(Register dst, const Immediate& imm);
   void StoreToSafepointRegisterSlot(Register dst, Register src);
   void LoadFromSafepointRegisterSlot(Register dst, Register src);
 
@@ -944,6 +945,8 @@ class MacroAssembler: public Assembler {
                           Register result_reg,
                           Register temp_reg);
 
+  void LoadUint32(XMMRegister dst, Register src, XMMRegister scratch);
+
   void LoadInstanceDescriptors(Register map, Register descriptors);
 
   // Abort execution if argument is not a number. Used in debug code.
diff --git a/test/mjsunit/compiler/uint32.js b/test/mjsunit/compiler/uint32.js
new file mode 100644 (file)
index 0000000..4237207
--- /dev/null
@@ -0,0 +1,150 @@
+// Copyright 2012 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: --allow-natives-syntax
+
+// Test uint32 handing in optimized frames.
+
+var K1 = 0x7fffffff;
+var K2 = 0xffffffff;
+
+var uint32_array = new Uint32Array(2);
+uint32_array[0] = K1;
+uint32_array[1] = K2;
+
+function ChangeI2T(arr, i) {
+  return uint32_array[i];
+}
+
+assertEquals(K1, ChangeI2T(uint32_array, 0));
+assertEquals(K2, ChangeI2T(uint32_array, 1));
+%OptimizeFunctionOnNextCall(ChangeI2T);
+assertEquals(K1, ChangeI2T(uint32_array, 0));
+assertEquals(K2, ChangeI2T(uint32_array, 1));
+
+function SideEffect() {
+  with ({}) { }  // not inlinable
+}
+
+function Deopt(obj, arr, i) {
+  var x = arr[i];
+  SideEffect();  // x will be used by HSimulate.
+  obj.x;
+  return x;
+}
+
+assertEquals(K1, Deopt({x: 0}, uint32_array, 0));
+assertEquals(K2, Deopt({x: 0}, uint32_array, 1));
+%OptimizeFunctionOnNextCall(Deopt);
+assertEquals(K2, Deopt({}, uint32_array, 1));
+
+function ChangeI2D(arr) {
+  // This addition will have a double type feedback so ChangeI2D will
+  // be generated for its operands.
+  return arr[0] + arr[1];
+}
+
+assertEquals(K1 + K2, ChangeI2D(uint32_array));
+assertEquals(K1 + K2, ChangeI2D(uint32_array));
+%OptimizeFunctionOnNextCall(ChangeI2D);
+assertEquals(K1 + K2, ChangeI2D(uint32_array));
+
+function ShrShr(val) {
+  return (val >>> 0) >>> 1;
+}
+
+assertEquals(K1, ShrShr(K2 | 0));
+assertEquals(K1, ShrShr(K2 | 0));
+%OptimizeFunctionOnNextCall(ShrShr);
+assertEquals(K1, ShrShr(K2 | 0));
+
+function SarShr(val) {
+  return val >> (-2 >>> 0);
+}
+
+var K3 = 0x80000000;
+assertEquals(-2, SarShr(K3 | 0));
+assertEquals(-2, SarShr(K3 | 0));
+%OptimizeFunctionOnNextCall(SarShr);
+assertEquals(-2, SarShr(K3 | 0));
+
+function Uint32Phi(a, b, c) {
+  var i = a ? (b >>> 0) : (c >>> 0);
+  return (i | 0);
+}
+
+var K4 = 0x80000001;
+assertEquals(K3 | 0, Uint32Phi(true, K3, K4));
+assertEquals(K4 | 0, Uint32Phi(false, K3, K4));
+assertEquals(K3 | 0, Uint32Phi(true, K3, K4));
+assertEquals(K4 | 0, Uint32Phi(false, K3, K4));
+%OptimizeFunctionOnNextCall(Uint32Phi);
+assertEquals(K3 | 0, Uint32Phi(true, K3, K4));
+assertEquals(K4 | 0, Uint32Phi(false, K3, K4));
+
+function NonUint32Phi(a, b, c) {
+  var i = a ? (b >>> 0) : c;
+  return (i | 0);
+}
+
+assertEquals(K3 | 0, NonUint32Phi(true, K3, K4));
+assertEquals(K4 | 0, NonUint32Phi(false, K3, K4));
+assertEquals(K3 | 0, NonUint32Phi(true, K3, K4));
+assertEquals(K4 | 0, NonUint32Phi(false, K3, K4));
+%OptimizeFunctionOnNextCall(NonUint32Phi);
+assertEquals(K3 | 0, NonUint32Phi(true, K3, K4));
+assertEquals(K4 | 0, NonUint32Phi(false, K3, K4));
+
+function PhiOfPhi(x) {
+  var a = (x >>> 0);
+  for (var i = 0; i < 2; i++) {
+    for (var j = 0; j < 2; j++) {
+      a = (a >>> 0);
+    }
+  }
+  return (a | 0);
+}
+
+assertEquals(1, PhiOfPhi(1));
+assertEquals(1, PhiOfPhi(1));
+%OptimizeFunctionOnNextCall(PhiOfPhi);
+assertEquals(K3 | 0, PhiOfPhi(K3));
+
+function PhiOfPhiUnsafe(x) {
+  var a = x >>> 0;
+  for (var i = 0; i < 2; i++) {
+    for (var j = 0; j < 2; j++) {
+      a = (a >>> 0);
+    }
+  }
+  return a + a;
+}
+
+assertEquals(2, PhiOfPhiUnsafe(1));
+assertEquals(2, PhiOfPhiUnsafe(1));
+%OptimizeFunctionOnNextCall(PhiOfPhiUnsafe);
+assertEquals(2 * K3, PhiOfPhiUnsafe(K3));