Added a simple dead code removal phase.
authorsvenpanne@chromium.org <svenpanne@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 11 Oct 2012 10:52:58 +0000 (10:52 +0000)
committersvenpanne@chromium.org <svenpanne@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 11 Oct 2012 10:52:58 +0000 (10:52 +0000)
We iteratively remove all dead Hydrogen instruction until we reach a fixed point. We consider an instruction dead if it is unused, has no observable side effects and is deletable. The last part of the condition is currently not very nice: We basically have to whitelist "safe" instructions, because we are missing more detailed dependencies and/or more detailed tracking of side effects.

We disable dead code elimination for now in our test runners, because we have tons of poorly written tests which wouldn't test anymore what they are supposed to test with this phase enabled. To get test coverage for dead code elimination itself, we should enable it on a few build bots. This is not really a perfect state, but the best we can do for now.

This patch includes a few const-correctness fixes, most of them were necessary for this CL.

Review URL: https://codereview.chromium.org/11088027

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

src/flag-definitions.h
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/hydrogen.h
src/property-details.h
src/utils.h
tools/run-tests.py
tools/test.py

index 81ec78a..a3e7dfb 100644 (file)
@@ -202,6 +202,8 @@ DEFINE_bool(array_bounds_checks_elimination, true,
             "perform array bounds checks elimination")
 DEFINE_bool(array_index_dehoisting, true,
             "perform array index dehoisting")
+DEFINE_bool(dead_code_elimination, true, "use dead code elimination")
+DEFINE_bool(trace_dead_code_elimination, false, "trace dead code elimination")
 
 DEFINE_bool(trace_osr, false, "trace on-stack replacement")
 DEFINE_int(stress_runs, 0, "number of stress runs")
index 2c3f2da..70a6a05 100644 (file)
@@ -1854,7 +1854,7 @@ void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
 }
 
 
-bool HLoadKeyedFastElement::RequiresHoleCheck() {
+bool HLoadKeyedFastElement::RequiresHoleCheck() const {
   if (IsFastPackedElementsKind(elements_kind())) {
     return false;
   }
@@ -2090,7 +2090,7 @@ void HLoadGlobalCell::PrintDataTo(StringStream* stream) {
 }
 
 
-bool HLoadGlobalCell::RequiresHoleCheck() {
+bool HLoadGlobalCell::RequiresHoleCheck() const {
   if (details_.IsDontDelete() && !details_.IsReadOnly()) return false;
   for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
     HValue* use = it.value();
index a4e9ed7..ae769fe 100644 (file)
@@ -667,7 +667,7 @@ class HValue: public ZoneObject {
 
   // Operands.
   virtual int OperandCount() = 0;
-  virtual HValue* OperandAt(int index) = 0;
+  virtual HValue* OperandAt(int index) const = 0;
   void SetOperandAt(int index, HValue* value);
 
   void DeleteAndReplaceWith(HValue* other);
@@ -778,6 +778,10 @@ class HValue: public ZoneObject {
     UNREACHABLE();
   }
 
+  bool IsDead() const {
+    return HasNoUses() && !HasObservableSideEffects() && IsDeletable();
+  }
+
 #ifdef DEBUG
   virtual void Verify() = 0;
 #endif
@@ -862,6 +866,8 @@ class HValue: public ZoneObject {
   GVNFlagSet gvn_flags_;
 
  private:
+  virtual bool IsDeletable() const { return false; }
+
   DISALLOW_COPY_AND_ASSIGN(HValue);
 };
 
@@ -930,7 +936,7 @@ template<int V>
 class HTemplateInstruction : public HInstruction {
  public:
   int OperandCount() { return V; }
-  HValue* OperandAt(int i) { return inputs_[i]; }
+  HValue* OperandAt(int i) const { return inputs_[i]; }
 
  protected:
   void InternalSetOperandAt(int i, HValue* value) { inputs_[i] = value; }
@@ -982,7 +988,7 @@ class HTemplateControlInstruction: public HControlInstruction {
   void SetSuccessorAt(int i, HBasicBlock* block) { successors_[i] = block; }
 
   int OperandCount() { return V; }
-  HValue* OperandAt(int i) { return inputs_[i]; }
+  HValue* OperandAt(int i) const { return inputs_[i]; }
 
 
  protected:
@@ -1027,7 +1033,7 @@ class HDeoptimize: public HControlInstruction {
   }
 
   virtual int OperandCount() { return values_.length(); }
-  virtual HValue* OperandAt(int index) { return values_[index]; }
+  virtual HValue* OperandAt(int index) const { return values_[index]; }
   virtual void PrintDataTo(StringStream* stream);
 
   virtual int SuccessorCount() { return 0; }
@@ -1284,6 +1290,9 @@ class HChange: public HUnaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -1303,6 +1312,9 @@ class HClampToUint8: public HUnaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -1341,7 +1353,7 @@ class HSimulate: public HInstruction {
     AddValue(kNoIndex, value);
   }
   virtual int OperandCount() { return values_.length(); }
-  virtual HValue* OperandAt(int index) { return values_[index]; }
+  virtual HValue* OperandAt(int index) const { return values_[index]; }
 
   virtual Representation RequiredInputRepresentation(int index) {
     return Representation::None();
@@ -1514,6 +1526,9 @@ class HThisFunction: public HTemplateInstruction<0> {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -1532,6 +1547,9 @@ class HContext: public HTemplateInstruction<0> {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -1550,6 +1568,9 @@ class HOuterContext: public HUnaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -1595,6 +1616,9 @@ class HGlobalObject: public HUnaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -1614,6 +1638,9 @@ class HGlobalReceiver: public HUnaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -1899,6 +1926,9 @@ class HJSArrayLength: public HTemplateInstruction<2> {
 
  protected:
   virtual bool DataEquals(HValue* other_raw) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -1919,6 +1949,9 @@ class HFixedArrayBaseLength: public HUnaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -1939,6 +1972,9 @@ class HMapEnumLength: public HUnaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -1958,6 +1994,9 @@ class HElementsKind: public HUnaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -1980,6 +2019,9 @@ class HBitNot: public HUnaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -2062,6 +2104,8 @@ class HUnaryMathOperation: public HTemplateInstruction<2> {
   }
 
  private:
+  virtual bool IsDeletable() const { return true; }
+
   BuiltinFunctionId op_;
 };
 
@@ -2086,6 +2130,9 @@ class HLoadElements: public HTemplateInstruction<2> {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -2109,6 +2156,9 @@ class HLoadExternalArrayPointer: public HUnaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -2408,7 +2458,7 @@ class HPhi: public HValue {
   }
   virtual HType CalculateInferredType();
   virtual int OperandCount() { return inputs_.length(); }
-  virtual HValue* OperandAt(int index) { return inputs_[index]; }
+  virtual HValue* OperandAt(int index) const { return inputs_[index]; }
   HValue* GetRedundantReplacement();
   void AddInput(HValue* value);
   bool HasRealUses();
@@ -2504,6 +2554,9 @@ class HArgumentsObject: public HTemplateInstruction<0> {
   }
 
   DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -2632,6 +2685,8 @@ class HConstant: public HTemplateInstruction<0> {
   }
 
  private:
+  virtual bool IsDeletable() const { return true; }
+
   // If this is a numerical constant, handle_ either points to to the
   // HeapObject the constant originated from or is null.  If the
   // constant is non-numeric, handle_ always points to a valid
@@ -2754,6 +2809,9 @@ class HArgumentsElements: public HTemplateInstruction<0> {
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
 
+ private:
+  virtual bool IsDeletable() const { return true; }
+
   bool from_inlined_;
 };
 
@@ -2773,6 +2831,9 @@ class HArgumentsLength: public HUnaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -2898,6 +2959,8 @@ class HBitwiseBinaryOperation: public HBinaryOperation {
   DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
 
  private:
+  virtual bool IsDeletable() const { return true; }
+
   Representation observed_input_representation_[3];
 };
 
@@ -2921,6 +2984,9 @@ class HMathFloorOfDiv: public HBinaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -2953,6 +3019,9 @@ class HArithmeticBinaryOperation: public HBinaryOperation {
     }
     return HValue::InferredRepresentation();
   }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -3238,6 +3307,9 @@ class HGetCachedArrayIndex: public HUnaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -3342,7 +3414,7 @@ class HPower: public HTemplateInstruction<2> {
   }
 
   HValue* left() { return OperandAt(0); }
-  HValue* right() { return OperandAt(1); }
+  HValue* right() const { return OperandAt(1); }
 
   virtual Representation RequiredInputRepresentation(int index) {
     return index == 0
@@ -3354,6 +3426,11 @@ class HPower: public HTemplateInstruction<2> {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+ private:
+  virtual bool IsDeletable() const {
+    return !right()->representation().IsTagged();
+  }
 };
 
 
@@ -3371,6 +3448,9 @@ class HRandom: public HTemplateInstruction<1> {
   }
 
   DECLARE_CONCRETE_INSTRUCTION(Random)
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -3761,7 +3841,7 @@ class HLoadGlobalCell: public HTemplateInstruction<0> {
   }
 
   Handle<JSGlobalPropertyCell>  cell() const { return cell_; }
-  bool RequiresHoleCheck();
+  bool RequiresHoleCheck() const;
 
   virtual void PrintDataTo(StringStream* stream);
 
@@ -3783,6 +3863,8 @@ class HLoadGlobalCell: public HTemplateInstruction<0> {
   }
 
  private:
+  virtual bool IsDeletable() const { return !RequiresHoleCheck(); }
+
   Handle<JSGlobalPropertyCell> cell_;
   PropertyDetails details_;
 };
@@ -3943,7 +4025,7 @@ class HLoadContextSlot: public HUnaryOperation {
     return mode_ == kCheckDeoptimize;
   }
 
-  bool RequiresHoleCheck() {
+  bool RequiresHoleCheck() const {
     return mode_ != kNoCheck;
   }
 
@@ -3962,6 +4044,8 @@ class HLoadContextSlot: public HUnaryOperation {
   }
 
  private:
+  virtual bool IsDeletable() const { return !RequiresHoleCheck(); }
+
   int slot_index_;
   Mode mode_;
 };
@@ -4054,6 +4138,8 @@ class HLoadNamedField: public HUnaryOperation {
   }
 
  private:
+  virtual bool IsDeletable() const { return true; }
+
   bool is_in_object_;
   int offset_;
 };
@@ -4200,7 +4286,7 @@ class HLoadKeyedFastElement
 
   virtual void PrintDataTo(StringStream* stream);
 
-  bool RequiresHoleCheck();
+  bool RequiresHoleCheck() const;
 
   DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastElement)
 
@@ -4214,6 +4300,8 @@ class HLoadKeyedFastElement
   }
 
  private:
+  virtual bool IsDeletable() const { return !RequiresHoleCheck(); }
+
   class ElementsKindField:  public BitField<ElementsKind, 0, 4> {};
   class IndexOffsetField:   public BitField<uint32_t, 4, 27> {};
   class IsDehoistedField:   public BitField<bool, 31, 1> {};
@@ -4260,7 +4348,7 @@ class HLoadKeyedFastDoubleElement
     return Representation::None();
   }
 
-  bool RequiresHoleCheck() {
+  bool RequiresHoleCheck() const {
     return hole_check_mode_ == PERFORM_HOLE_CHECK;
   }
 
@@ -4277,6 +4365,8 @@ class HLoadKeyedFastDoubleElement
   }
 
  private:
+  virtual bool IsDeletable() const { return !RequiresHoleCheck(); }
+
   uint32_t index_offset_;
   bool is_dehoisted_;
   HoleCheckMode hole_check_mode_;
@@ -4341,6 +4431,8 @@ class HLoadKeyedSpecializedArrayElement
   }
 
  private:
+  virtual bool IsDeletable() const { return true; }
+
   ElementsKind elements_kind_;
   uint32_t index_offset_;
   bool is_dehoisted_;
@@ -4722,6 +4814,10 @@ class HStringAdd: public HBinaryOperation {
 
  protected:
   virtual bool DataEquals(HValue* other) { return true; }
+
+  // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
+  // private:
+  //  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -4756,6 +4852,10 @@ class HStringCharCodeAt: public HTemplateInstruction<3> {
   virtual Range* InferRange(Zone* zone) {
     return new(zone) Range(0, String::kMaxUtf16CodeUnit);
   }
+
+  // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
+  // private:
+  //  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -4782,6 +4882,10 @@ class HStringCharFromCode: public HTemplateInstruction<2> {
   virtual bool DataEquals(HValue* other) { return true; }
 
   DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode)
+
+  // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
+  // private:
+  //  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -4810,6 +4914,9 @@ class HStringLength: public HUnaryOperation {
   virtual Range* InferRange(Zone* zone) {
     return new(zone) Range(0, String::kMaxLength);
   }
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -4836,6 +4943,9 @@ class HAllocateObject: public HTemplateInstruction<1> {
   DECLARE_CONCRETE_INSTRUCTION(AllocateObject)
 
  private:
+  // TODO(svenpanne) Might be safe, but leave it out until we know for sure.
+  //  virtual bool IsDeletable() const { return true; }
+
   Handle<JSFunction> constructor_;
 };
 
@@ -4852,6 +4962,8 @@ class HMaterializedLiteral: public HTemplateInstruction<V> {
   int depth() const { return depth_; }
 
  private:
+  virtual bool IsDeletable() const { return true; }
+
   int literal_index_;
   int depth_;
 };
@@ -5027,6 +5139,8 @@ class HFunctionLiteral: public HTemplateInstruction<1> {
   bool pretenure() const { return pretenure_; }
 
  private:
+  virtual bool IsDeletable() const { return true; }
+
   Handle<SharedFunctionInfo> shared_info_;
   bool pretenure_;
 };
@@ -5051,6 +5165,9 @@ class HTypeof: public HTemplateInstruction<2> {
   }
 
   DECLARE_CONCRETE_INSTRUCTION(Typeof)
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -5069,6 +5186,9 @@ class HToFastProperties: public HUnaryOperation {
   }
 
   DECLARE_CONCRETE_INSTRUCTION(ToFastProperties)
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -5083,6 +5203,9 @@ class HValueOf: public HUnaryOperation {
   }
 
   DECLARE_CONCRETE_INSTRUCTION(ValueOf)
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
@@ -5279,6 +5402,9 @@ class HLoadFieldByIndex : public HTemplateInstruction<2> {
   }
 
   DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex);
+
+ private:
+  virtual bool IsDeletable() const { return true; }
 };
 
 
index 1afa660..628d987 100644 (file)
@@ -3358,6 +3358,7 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) {
 
   EliminateRedundantBoundsChecks();
   DehoistSimpleArrayIndexComputations();
+  if (FLAG_dead_code_elimination) DeadCodeElimination();
 
   return true;
 }
@@ -3787,6 +3788,36 @@ void HGraph::DehoistSimpleArrayIndexComputations() {
 }
 
 
+void HGraph::DeadCodeElimination() {
+  HPhase phase("H_Dead code elimination", this);
+  ZoneList<HInstruction*> worklist(blocks_.length(), zone());
+  for (int i = 0; i < blocks()->length(); ++i) {
+    for (HInstruction* instr = blocks()->at(i)->first();
+         instr != NULL;
+         instr = instr->next()) {
+      if (instr->IsDead()) worklist.Add(instr, zone());
+    }
+  }
+
+  while (!worklist.is_empty()) {
+    HInstruction* instr = worklist.RemoveLast();
+    if (FLAG_trace_dead_code_elimination) {
+      HeapStringAllocator allocator;
+      StringStream stream(&allocator);
+      instr->PrintNameTo(&stream);
+      stream.Add(" = ");
+      instr->PrintTo(&stream);
+      PrintF("[removing dead instruction %s]\n", *stream.ToCString());
+    }
+    instr->DeleteAndReplaceWith(NULL);
+    for (int i = 0; i < instr->OperandCount(); ++i) {
+      HValue* operand = instr->OperandAt(i);
+      if (operand->IsDead()) worklist.Add(HInstruction::cast(operand), zone());
+    }
+  }
+}
+
+
 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
   ASSERT(current_block() != NULL);
   current_block()->AddInstruction(instr);
index 837fc7a..a0d8149 100644 (file)
@@ -268,6 +268,7 @@ class HGraph: public ZoneObject {
   void ReplaceCheckedValues();
   void EliminateRedundantBoundsChecks();
   void DehoistSimpleArrayIndexComputations();
+  void DeadCodeElimination();
   void PropagateDeoptimizingMark();
 
   // Returns false if there are phi-uses of the arguments-object
index b8fbb3c..64e3205 100644 (file)
@@ -96,7 +96,9 @@ class PropertyDetails BASE_EMBEDDED {
 
   PropertyType type() { return TypeField::decode(value_); }
 
-  PropertyAttributes attributes() { return AttributesField::decode(value_); }
+  PropertyAttributes attributes() const {
+    return AttributesField::decode(value_);
+  }
 
   int dictionary_index() {
     return DictionaryStorageField::decode(value_);
@@ -112,10 +114,10 @@ class PropertyDetails BASE_EMBEDDED {
     return DictionaryStorageField::is_valid(index);
   }
 
-  bool IsReadOnly() { return (attributes() & READ_ONLY) != 0; }
-  bool IsDontDelete() { return (attributes() & DONT_DELETE) != 0; }
-  bool IsDontEnum() { return (attributes() & DONT_ENUM) != 0; }
-  bool IsDeleted() { return DeletedField::decode(value_) != 0;}
+  bool IsReadOnly() const { return (attributes() & READ_ONLY) != 0; }
+  bool IsDontDelete() const { return (attributes() & DONT_DELETE) != 0; }
+  bool IsDontEnum() const { return (attributes() & DONT_ENUM) != 0; }
+  bool IsDeleted() const { return DeletedField::decode(value_) != 0;}
 
   // Bit fields in value_ (type, shift, size). Must be public so the
   // constants can be embedded in generated code.
index e659de2..e03f96f 100644 (file)
@@ -862,7 +862,11 @@ class EmbeddedContainer {
  public:
   EmbeddedContainer() : elems_() { }
 
-  int length() { return NumElements; }
+  int length() const { return NumElements; }
+  const ElementType& operator[](int i) const {
+    ASSERT(i < length());
+    return elems_[i];
+  }
   ElementType& operator[](int i) {
     ASSERT(i < length());
     return elems_[i];
@@ -876,7 +880,12 @@ class EmbeddedContainer {
 template<typename ElementType>
 class EmbeddedContainer<ElementType, 0> {
  public:
-  int length() { return 0; }
+  int length() const { return 0; }
+  const ElementType& operator[](int i) const {
+    UNREACHABLE();
+    static ElementType t = 0;
+    return t;
+  }
   ElementType& operator[](int i) {
     UNREACHABLE();
     static ElementType t = 0;
index ed01abe..cab93fb 100755 (executable)
@@ -56,9 +56,9 @@ VARIANT_FLAGS = [[],
                  ["--stress-opt", "--always-opt"],
                  ["--nocrankshaft"]]
 MODE_FLAGS = {
-    "debug"   : ["--nobreak-on-abort", "--enable-slow-asserts",
-                 "--debug-code", "--verify-heap"],
-    "release" : ["--nobreak-on-abort"]}
+    "debug"   : ["--nobreak-on-abort", "--nodead-code-elimination",
+                 "--enable-slow-asserts", "--debug-code", "--verify-heap"],
+    "release" : ["--nobreak-on-abort", "--nodead-code-elimination"]}
 
 
 def BuildOptions():
index c361f93..8c62136 100755 (executable)
@@ -684,8 +684,9 @@ SUFFIX = {
     'debug'   : '_g',
     'release' : '' }
 FLAGS = {
-    'debug'   : ['--nobreak-on-abort', '--enable-slow-asserts', '--debug-code', '--verify-heap'],
-    'release' : ['--nobreak-on-abort']}
+    'debug'   : ['--nobreak-on-abort', '--nodead-code-elimination',
+                 '--enable-slow-asserts', '--debug-code', '--verify-heap'],
+    'release' : ['--nobreak-on-abort', '--nodead-code-elimination']}
 TIMEOUT_SCALEFACTOR = {
     'debug'   : 4,
     'release' : 1 }