Revision: 10244
Author:   [email protected]
Date:     Tue Dec 13 09:10:34 2011
Log:      [hydrogen] don't bailout assignments to consts

If constant variable is allocated in CONTEXT

Patch by Fedor Indutny <[email protected]>.

BUG=
TEST=
[email protected]
Review URL: http://codereview.chromium.org/8857001
http://code.google.com/p/v8/source/detail?r=10244

Modified:
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Dec 9 01:50:30 2011 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Dec 13 09:10:34 2011
@@ -2306,7 +2306,11 @@
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
     __ cmp(result, ip);
-    DeoptimizeIf(eq, instr->environment());
+    if (instr->hydrogen()->DeoptimizesOnHole()) {
+      DeoptimizeIf(eq, instr->environment());
+    } else {
+      __ mov(result, Operand(factory()->undefined_value()), LeaveCC, eq);
+    }
   }
 }

@@ -2314,14 +2318,22 @@
 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register value = ToRegister(instr->value());
+  Register scratch = scratch0();
   MemOperand target = ContextOperand(context, instr->slot_index());
+
+  Label skip_assignment;
+
   if (instr->hydrogen()->RequiresHoleCheck()) {
-    Register scratch = scratch0();
     __ ldr(scratch, target);
     __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
     __ cmp(scratch, ip);
-    DeoptimizeIf(eq, instr->environment());
-  }
+    if (instr->hydrogen()->DeoptimizesOnHole()) {
+      DeoptimizeIf(eq, instr->environment());
+    } else {
+      __ b(ne, &skip_assignment);
+    }
+  }
+
   __ str(value, target);
   if (instr->hydrogen()->NeedsWriteBarrier()) {
     HType type = instr->hydrogen()->value()->type();
@@ -2330,12 +2342,14 @@
     __ RecordWriteContextSlot(context,
                               target.offset(),
                               value,
-                              scratch0(),
+                              scratch,
                               kLRHasBeenSaved,
                               kSaveFPRegs,
                               EMIT_REMEMBERED_SET,
                               check_needed);
   }
+
+  __ bind(&skip_assignment);
 }


=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Fri Dec 9 01:50:30 2011 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Tue Dec 13 09:10:34 2011
@@ -3449,28 +3449,45 @@
  public:
   enum Mode {
// Perform a normal load of the context slot without checking its value.
-    kLoad,
+    kNoCheck,
     // Load and check the value of the context slot. Deoptimize if it's the
     // hole value. This is used for checking for loading of uninitialized
// harmony bindings where we deoptimize into full-codegen generated code
     // which will subsequently throw a reference error.
-    kLoadCheck
+    kCheckDeoptimize,
+ // Load and check the value of the context slot. Return undefined if it's
+    // the hole value. This is used for non-harmony const assignments
+    kCheckReturnUndefined
   };

   HLoadContextSlot(HValue* context, Variable* var)
       : HUnaryOperation(context), slot_index_(var->index()) {
     ASSERT(var->IsContextSlot());
-    mode_ = (var->mode() == LET || var->mode() == CONST_HARMONY)
-        ? kLoadCheck : kLoad;
+    switch (var->mode()) {
+      case LET:
+      case CONST_HARMONY:
+        mode_ = kCheckDeoptimize;
+        break;
+      case CONST:
+        mode_ = kCheckReturnUndefined;
+        break;
+      default:
+        mode_ = kNoCheck;
+    }
     set_representation(Representation::Tagged());
     SetFlag(kUseGVN);
     SetFlag(kDependsOnContextSlots);
   }

   int slot_index() const { return slot_index_; }
+  Mode mode() const { return mode_; }
+
+  bool DeoptimizesOnHole() {
+    return mode_ == kCheckDeoptimize;
+  }

   bool RequiresHoleCheck() {
-    return mode_ == kLoadCheck;
+    return mode_ != kNoCheck;
   }

   virtual Representation RequiredInputRepresentation(int index) {
@@ -3498,12 +3515,14 @@
   enum Mode {
// Perform a normal store to the context slot without checking its previous
     // value.
-    kAssign,
+    kNoCheck,
// Check the previous value of the context slot and deoptimize if it's the // hole value. This is used for checking for assignments to uninitialized // harmony bindings where we deoptimize into full-codegen generated code
     // which will subsequently throw a reference error.
-    kAssignCheck
+    kCheckDeoptimize,
+ // Check the previous value and ignore assignment if it isn't a hole value
+    kCheckIgnoreAssignment
   };

HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
@@ -3521,9 +3540,13 @@
   bool NeedsWriteBarrier() {
     return StoringValueNeedsWriteBarrier(value());
   }
+
+  bool DeoptimizesOnHole() {
+    return mode_ == kCheckDeoptimize;
+  }

   bool RequiresHoleCheck() {
-    return mode_ == kAssignCheck;
+    return mode_ != kNoCheck;
   }

   virtual Representation RequiredInputRepresentation(int index) {
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Fri Dec  9 01:50:30 2011
+++ /branches/bleeding_edge/src/hydrogen.cc     Tue Dec 13 09:10:34 2011
@@ -3285,9 +3285,6 @@
     }

     case Variable::CONTEXT: {
-      if (variable->mode() == CONST) {
-        return Bailout("reference to const context slot");
-      }
       HValue* context = BuildContextChainWalk(variable);
HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, variable);
       return ast_context()->ReturnInstruction(instr, expr->id());
@@ -3805,8 +3802,8 @@

   if (proxy != NULL) {
     Variable* var = proxy->var();
-    if (var->mode() == CONST || var->mode() == LET)  {
-      return Bailout("unsupported let or const compound assignment");
+    if (var->mode() == LET)  {
+      return Bailout("unsupported let compound assignment");
     }

     CHECK_ALIVE(VisitForValue(operation));
@@ -3821,6 +3818,9 @@

       case Variable::PARAMETER:
       case Variable::LOCAL:
+        if (var->mode() == CONST)  {
+          return Bailout("unsupported const compound assignment");
+        }
         Bind(var, Top());
         break;

@@ -3840,11 +3840,24 @@
             }
           }
         }
+
+        HStoreContextSlot::Mode mode;
+
+        switch (var->mode()) {
+          case LET:
+            mode = HStoreContextSlot::kCheckDeoptimize;
+            break;
+          case CONST:
+            return ast_context()->ReturnValue(Pop());
+          case CONST_HARMONY:
+            // This case is checked statically so no need to
+            // perform checks here
+            UNREACHABLE();
+          default:
+            mode = HStoreContextSlot::kNoCheck;
+        }

         HValue* context = BuildContextChainWalk(var);
-        HStoreContextSlot::Mode mode =
-            (var->mode() == LET || var->mode() == CONST_HARMONY)
-            ? HStoreContextSlot::kAssignCheck : HStoreContextSlot::kAssign;
         HStoreContextSlot* instr =
new(zone()) HStoreContextSlot(context, var->index(), mode, Top());
         AddInstruction(instr);
@@ -3955,17 +3968,19 @@
     HandlePropertyAssignment(expr);
   } else if (proxy != NULL) {
     Variable* var = proxy->var();
+
     if (var->mode() == CONST) {
       if (expr->op() != Token::INIT_CONST) {
-        return Bailout("non-initializer assignment to const");
-      }
-      if (!var->IsStackAllocated()) {
-        return Bailout("assignment to const context slot");
-      }
- // We insert a use of the old value to detect unsupported uses of const
-      // variables (e.g. initialization inside a loop).
-      HValue* old_value = environment()->Lookup(var);
-      AddInstruction(new HUseConst(old_value));
+        CHECK_ALIVE(VisitForValue(expr->value()));
+        return ast_context()->ReturnValue(Pop());
+      }
+
+      if (var->IsStackAllocated()) {
+ // We insert a use of the old value to detect unsupported uses of const
+        // variables (e.g. initialization inside a loop).
+        HValue* old_value = environment()->Lookup(var);
+        AddInstruction(new HUseConst(old_value));
+      }
     } else if (var->mode() == CONST_HARMONY) {
       if (expr->op() != Token::INIT_CONST_HARMONY) {
         return Bailout("non-initializer assignment to const");
@@ -4004,7 +4019,6 @@
       }

       case Variable::CONTEXT: {
-        ASSERT(var->mode() != CONST);
// Bail out if we try to mutate a parameter value in a function using
         // the arguments object.  We do not (yet) correctly handle the
         // arguments property of the function.
@@ -4020,17 +4034,32 @@
         }

         CHECK_ALIVE(VisitForValue(expr->value()));
-        HValue* context = BuildContextChainWalk(var);
         HStoreContextSlot::Mode mode;
         if (expr->op() == Token::ASSIGN) {
-          mode = (var->mode() == LET || var->mode() == CONST_HARMONY)
- ? HStoreContextSlot::kAssignCheck : HStoreContextSlot::kAssign;
+          switch (var->mode()) {
+            case LET:
+              mode = HStoreContextSlot::kCheckDeoptimize;
+              break;
+            case CONST:
+              return ast_context()->ReturnValue(Pop());
+            case CONST_HARMONY:
+              // This case is checked statically so no need to
+              // perform checks here
+              UNREACHABLE();
+            default:
+              mode = HStoreContextSlot::kNoCheck;
+          }
+        } else if (expr->op() == Token::INIT_VAR ||
+                   expr->op() == Token::INIT_LET ||
+                   expr->op() == Token::INIT_CONST_HARMONY) {
+          mode = HStoreContextSlot::kNoCheck;
         } else {
-          ASSERT(expr->op() == Token::INIT_VAR ||
-                 expr->op() == Token::INIT_LET ||
-                 expr->op() == Token::INIT_CONST_HARMONY);
-          mode = HStoreContextSlot::kAssign;
-        }
+          ASSERT(expr->op() == Token::INIT_CONST);
+
+          mode = HStoreContextSlot::kCheckIgnoreAssignment;
+        }
+
+        HValue* context = BuildContextChainWalk(var);
         HStoreContextSlot* instr = new(zone()) HStoreContextSlot(
             context, var->index(), mode, Top());
         AddInstruction(instr);
@@ -5643,7 +5672,7 @@
         HValue* context = BuildContextChainWalk(var);
         HStoreContextSlot::Mode mode =
             (var->mode() == LET || var->mode() == CONST_HARMONY)
-            ? HStoreContextSlot::kAssignCheck : HStoreContextSlot::kAssign;
+ ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck;
         HStoreContextSlot* instr =
new(zone()) HStoreContextSlot(context, var->index(), mode, after);
         AddInstruction(instr);
@@ -6251,7 +6280,7 @@
         if (var->IsContextSlot()) {
           HValue* context = environment()->LookupContext();
           HStoreContextSlot* store = new HStoreContextSlot(
-              context, var->index(), HStoreContextSlot::kAssign, value);
+              context, var->index(), HStoreContextSlot::kNoCheck, value);
           AddInstruction(store);
           if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
         } else {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Fri Dec 9 01:50:30 2011 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Dec 13 09:10:34 2011
@@ -2165,9 +2165,17 @@
   Register context = ToRegister(instr->context());
   Register result = ToRegister(instr->result());
   __ mov(result, ContextOperand(context, instr->slot_index()));
+
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ cmp(result, factory()->the_hole_value());
-    DeoptimizeIf(equal, instr->environment());
+    if (instr->hydrogen()->DeoptimizesOnHole()) {
+      DeoptimizeIf(equal, instr->environment());
+    } else {
+      Label is_not_hole;
+      __ j(not_equal, &is_not_hole, Label::kNear);
+      __ mov(result, factory()->undefined_value());
+      __ bind(&is_not_hole);
+    }
   }
 }

@@ -2175,11 +2183,19 @@
 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register value = ToRegister(instr->value());
+
+  Label skip_assignment;
+
   Operand target = ContextOperand(context, instr->slot_index());
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ cmp(target, factory()->the_hole_value());
-    DeoptimizeIf(equal, instr->environment());
-  }
+    if (instr->hydrogen()->DeoptimizesOnHole()) {
+      DeoptimizeIf(equal, instr->environment());
+    } else {
+      __ j(not_equal, &skip_assignment, Label::kNear);
+    }
+  }
+
   __ mov(target, value);
   if (instr->hydrogen()->NeedsWriteBarrier()) {
     HType type = instr->hydrogen()->value()->type();
@@ -2195,6 +2211,8 @@
                               EMIT_REMEMBERED_SET,
                               check_needed);
   }
+
+  __ bind(&skip_assignment);
 }


=======================================
--- /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Mon Dec 12 00:48:39 2011 +++ /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Tue Dec 13 09:10:34 2011
@@ -2180,10 +2180,19 @@
 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register result = ToRegister(instr->result());
+
   __ lw(result, ContextOperand(context, instr->slot_index()));
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(eq, instr->environment(), result, Operand(at));
+
+    if (instr->hydrogen()->DeoptimizesOnHole()) {
+      DeoptimizeIf(eq, instr->environment(), result, Operand(at));
+    } else {
+      Label is_not_hole;
+      __ Branch(&is_not_hole, ne, result, Operand(at));
+      __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
+      __ bind(&is_not_hole);
+    }
   }
 }

@@ -2191,13 +2200,22 @@
 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register value = ToRegister(instr->value());
+  Register scratch = scratch0();
   MemOperand target = ContextOperand(context, instr->slot_index());
+
+  Label skip_assignment;
+
   if (instr->hydrogen()->RequiresHoleCheck()) {
-    Register scratch = scratch0();
     __ lw(scratch, target);
     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(eq, instr->environment(), scratch, Operand(at));
-  }
+
+    if (instr->hydrogen()->DeoptimizesOnHole()) {
+      DeoptimizeIf(eq, instr->environment(), scratch, Operand(at));
+    } else {
+      __ Branch(&skip_assignment, ne, scratch, Operand(at));
+    }
+  }
+
   __ sw(value, target);
   if (instr->hydrogen()->NeedsWriteBarrier()) {
     HType type = instr->hydrogen()->value()->type();
@@ -2212,6 +2230,8 @@
                               EMIT_REMEMBERED_SET,
                               check_needed);
   }
+
+  __ bind(&skip_assignment);
 }


=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Fri Dec 9 01:50:30 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Dec 13 09:10:34 2011
@@ -2069,7 +2069,14 @@
   __ movq(result, ContextOperand(context, instr->slot_index()));
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(equal, instr->environment());
+    if (instr->hydrogen()->DeoptimizesOnHole()) {
+      DeoptimizeIf(equal, instr->environment());
+    } else {
+      Label is_not_hole;
+      __ j(not_equal, &is_not_hole, Label::kNear);
+      __ movq(result, factory()->undefined_value(), RelocInfo::NONE);
+      __ bind(&is_not_hole);
+    }
   }
 }

@@ -2077,12 +2084,20 @@
 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register value = ToRegister(instr->value());
+
   Operand target = ContextOperand(context, instr->slot_index());
+
+  Label skip_assignment;
   if (instr->hydrogen()->RequiresHoleCheck()) {
     __ CompareRoot(target, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(equal, instr->environment());
+    if (instr->hydrogen()->DeoptimizesOnHole()) {
+      DeoptimizeIf(equal, instr->environment());
+    } else {
+      __ j(not_equal, &skip_assignment, Label::kNear);
+    }
   }
   __ movq(target, value);
+
   if (instr->hydrogen()->NeedsWriteBarrier()) {
     HType type = instr->hydrogen()->value()->type();
     SmiCheck check_needed =
@@ -2097,6 +2112,8 @@
                               EMIT_REMEMBERED_SET,
                               check_needed);
   }
+
+  __ bind(&skip_assignment);
 }


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

Reply via email to