Push version 2.0.0 to trunk.

Added support for VFP on ARM.

Added TryCatch::ReThrow method to the API.

Reduced the size of snapshots and improved the snapshot load time.

Improved heap profiler support.

64-bit version now supported on Windows.

Fixed a number of debugger issues.

Fixed bugs.


git-svn-id: http://v8.googlecode.com/svn/trunk@3333 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/compiler.cc b/src/compiler.cc
index d85f104..4e80a24 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -48,23 +48,24 @@
 
   CodeGenSelector()
       : has_supported_syntax_(true),
-        location_(Location::Uninitialized()) {
+        context_(Expression::kUninitialized) {
   }
 
   CodeGenTag Select(FunctionLiteral* fun);
 
  private:
+  // Visit an expression in a given expression context.
+  void ProcessExpression(Expression* expr, Expression::Context context) {
+    Expression::Context saved = context_;
+    context_ = context;
+    Visit(expr);
+    expr->set_context(context);
+    context_ = saved;
+  }
+
   void VisitDeclarations(ZoneList<Declaration*>* decls);
   void VisitStatements(ZoneList<Statement*>* stmts);
 
-  // Visit an expression in effect context with a desired location of
-  // nowhere.
-  void VisitAsEffect(Expression* expr);
-
-  // Visit an expression in value context with a desired location of
-  // temporary.
-  void VisitAsValue(Expression* expr);
-
   // AST node visit functions.
 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
   AST_NODE_LIST(DECLARE_VISIT)
@@ -72,8 +73,8 @@
 
   bool has_supported_syntax_;
 
-  // The desired location of the currently visited expression.
-  Location location_;
+  // The desired expression context of the currently visited expression.
+  Expression::Context context_;
 
   DISALLOW_COPY_AND_ASSIGN(CodeGenSelector);
 };
@@ -82,7 +83,8 @@
 static Handle<Code> MakeCode(FunctionLiteral* literal,
                              Handle<Script> script,
                              Handle<Context> context,
-                             bool is_eval) {
+                             bool is_eval,
+                             Handle<SharedFunctionInfo> shared) {
   ASSERT(literal != NULL);
 
   // Rewrite the AST by introducing .result assignments where needed.
@@ -119,12 +121,21 @@
 
   // Generate code and return it.
   if (FLAG_fast_compiler) {
-    CodeGenSelector selector;
-    CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
-    if (code_gen == CodeGenSelector::FAST) {
-      return FastCodeGenerator::MakeCode(literal, script, is_eval);
+    // If there is no shared function info, try the fast code
+    // generator for code in the global scope.  Otherwise obey the
+    // explicit hint in the shared function info.
+    if (shared.is_null() && !literal->scope()->is_global_scope()) {
+      if (FLAG_trace_bailout) PrintF("Non-global scope\n");
+    } else if (!shared.is_null() && !shared->try_fast_codegen()) {
+      if (FLAG_trace_bailout) PrintF("No hint to try fast\n");
+    } else {
+      CodeGenSelector selector;
+      CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
+      if (code_gen == CodeGenSelector::FAST) {
+        return FastCodeGenerator::MakeCode(literal, script, is_eval);
+      }
+      ASSERT(code_gen == CodeGenSelector::NORMAL);
     }
-    ASSERT(code_gen == CodeGenSelector::NORMAL);
   }
   return CodeGenerator::MakeCode(literal, script, is_eval);
 }
@@ -166,7 +177,8 @@
     if (is_eval) {
       JavaScriptFrameIterator it;
       script->set_eval_from_function(it.frame()->function());
-      int offset = it.frame()->pc() - it.frame()->code()->instruction_start();
+      int offset = static_cast<int>(
+          it.frame()->pc() - it.frame()->code()->instruction_start());
       script->set_eval_from_instructions_offset(Smi::FromInt(offset));
     }
   }
@@ -209,7 +221,8 @@
   HistogramTimerScope timer(rate);
 
   // Compile the code.
-  Handle<Code> code = MakeCode(lit, script, context, is_eval);
+  Handle<Code> code = MakeCode(lit, script, context, is_eval,
+                               Handle<SharedFunctionInfo>::null());
 
   // Check for stack-overflow exceptions.
   if (code.is_null()) {
@@ -246,7 +259,7 @@
                                       code);
 
   ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
-  CodeGenerator::SetFunctionInfo(fun, lit, true, script);
+  Compiler::SetFunctionInfo(fun, lit, true, script);
 
   // Hint to the runtime system used when allocating space for initial
   // property space by setting the expected number of properties for
@@ -410,7 +423,8 @@
   HistogramTimerScope timer(&Counters::compile_lazy);
 
   // Compile the code.
-  Handle<Code> code = MakeCode(lit, script, Handle<Context>::null(), false);
+  Handle<Code> code = MakeCode(lit, script, Handle<Context>::null(), false,
+                               shared);
 
   // Check for stack-overflow exception.
   if (code.is_null()) {
@@ -461,18 +475,137 @@
 }
 
 
+Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal,
+                                              Handle<Script> script,
+                                              AstVisitor* caller) {
+#ifdef DEBUG
+  // We should not try to compile the same function literal more than
+  // once.
+  literal->mark_as_compiled();
+#endif
+
+  // Determine if the function can be lazily compiled. This is
+  // necessary to allow some of our builtin JS files to be lazily
+  // compiled. These builtins cannot be handled lazily by the parser,
+  // since we have to know if a function uses the special natives
+  // syntax, which is something the parser records.
+  bool allow_lazy = literal->AllowsLazyCompilation();
+
+  // Generate code
+  Handle<Code> code;
+  if (FLAG_lazy && allow_lazy) {
+    code = ComputeLazyCompile(literal->num_parameters());
+  } else {
+    // The bodies of function literals have not yet been visited by
+    // the AST optimizer/analyzer.
+    if (!Rewriter::Optimize(literal)) {
+      return Handle<JSFunction>::null();
+    }
+
+    // Generate code and return it.
+    bool is_compiled = false;
+    if (FLAG_fast_compiler && literal->try_fast_codegen()) {
+      CodeGenSelector selector;
+      CodeGenSelector::CodeGenTag code_gen = selector.Select(literal);
+      if (code_gen == CodeGenSelector::FAST) {
+        code = FastCodeGenerator::MakeCode(literal,
+                                           script,
+                                           false);  // Not eval.
+        is_compiled = true;
+      }
+    }
+
+    if (!is_compiled) {
+      // We didn't try the fast compiler, or we failed to select it.
+      code = CodeGenerator::MakeCode(literal,
+                                     script,
+                                     false);  // Not eval.
+    }
+
+    // Check for stack-overflow exception.
+    if (code.is_null()) {
+      caller->SetStackOverflow();
+      return Handle<JSFunction>::null();
+    }
+
+    // Function compilation complete.
+    LOG(CodeCreateEvent(Logger::FUNCTION_TAG, *code, *literal->name()));
+
+#ifdef ENABLE_OPROFILE_AGENT
+    OProfileAgent::CreateNativeCodeRegion(*node->name(),
+                                          code->instruction_start(),
+                                          code->instruction_size());
+#endif
+  }
+
+  // Create a boilerplate function.
+  Handle<JSFunction> function =
+      Factory::NewFunctionBoilerplate(literal->name(),
+                                      literal->materialized_literal_count(),
+                                      code);
+  SetFunctionInfo(function, literal, false, script);
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  // Notify debugger that a new function has been added.
+  Debugger::OnNewFunction(function);
+#endif
+
+  // Set the expected number of properties for instances and return
+  // the resulting function.
+  SetExpectedNofPropertiesFromEstimate(function,
+                                       literal->expected_property_count());
+  return function;
+}
+
+
+// Sets the function info on a function.
+// The start_position points to the first '(' character after the function name
+// in the full script source. When counting characters in the script source the
+// the first character is number 0 (not 1).
+void Compiler::SetFunctionInfo(Handle<JSFunction> fun,
+                               FunctionLiteral* lit,
+                               bool is_toplevel,
+                               Handle<Script> script) {
+  fun->shared()->set_length(lit->num_parameters());
+  fun->shared()->set_formal_parameter_count(lit->num_parameters());
+  fun->shared()->set_script(*script);
+  fun->shared()->set_function_token_position(lit->function_token_position());
+  fun->shared()->set_start_position(lit->start_position());
+  fun->shared()->set_end_position(lit->end_position());
+  fun->shared()->set_is_expression(lit->is_expression());
+  fun->shared()->set_is_toplevel(is_toplevel);
+  fun->shared()->set_inferred_name(*lit->inferred_name());
+  fun->shared()->SetThisPropertyAssignmentsInfo(
+      lit->has_only_simple_this_property_assignments(),
+      *lit->this_property_assignments());
+  fun->shared()->set_try_fast_codegen(lit->try_fast_codegen());
+}
+
+
 CodeGenSelector::CodeGenTag CodeGenSelector::Select(FunctionLiteral* fun) {
   Scope* scope = fun->scope();
 
-  if (!scope->is_global_scope()) {
-    if (FLAG_trace_bailout) PrintF("Non-global scope\n");
+  if (scope->num_heap_slots() > 0) {
+    // We support functions with a local context if they do not have
+    // parameters that need to be copied into the context.
+    for (int i = 0, len = scope->num_parameters(); i < len; i++) {
+      Slot* slot = scope->parameter(i)->slot();
+      if (slot != NULL && slot->type() == Slot::CONTEXT) {
+        if (FLAG_trace_bailout) {
+          PrintF("function has context-allocated parameters");
+        }
+        return NORMAL;
+      }
+    }
+  }
+
+  if (scope->arguments() != NULL) {
+    if (FLAG_trace_bailout) PrintF("function uses 'arguments'\n");
     return NORMAL;
   }
-  ASSERT(scope->num_heap_slots() == 0);
-  ASSERT(scope->arguments() == NULL);
 
   has_supported_syntax_ = true;
-  VisitDeclarations(fun->scope()->declarations());
+  VisitDeclarations(scope->declarations());
   if (!has_supported_syntax_) return NORMAL;
 
   VisitStatements(fun->body());
@@ -512,34 +645,9 @@
 }
 
 
-void CodeGenSelector::VisitAsEffect(Expression* expr) {
-  if (location_.is_effect()) {
-    Visit(expr);
-  } else {
-    Location saved = location_;
-    location_ = Location::Effect();
-    Visit(expr);
-    location_ = saved;
-  }
-}
-
-
-void CodeGenSelector::VisitAsValue(Expression* expr) {
-  if (location_.is_value()) {
-    Visit(expr);
-  } else {
-    Location saved = location_;
-    location_ = Location::Value();
-    Visit(expr);
-    location_ = saved;
-  }
-}
-
-
 void CodeGenSelector::VisitDeclaration(Declaration* decl) {
-  Variable* var = decl->proxy()->var();
-  if (!var->is_global() || var->mode() == Variable::CONST) {
-    BAILOUT("Non-global declaration");
+  if (decl->fun() != NULL) {
+    ProcessExpression(decl->fun(), Expression::kValue);
   }
 }
 
@@ -550,7 +658,7 @@
 
 
 void CodeGenSelector::VisitExpressionStatement(ExpressionStatement* stmt) {
-  VisitAsEffect(stmt->expression());
+  ProcessExpression(stmt->expression(), Expression::kEffect);
 }
 
 
@@ -560,7 +668,11 @@
 
 
 void CodeGenSelector::VisitIfStatement(IfStatement* stmt) {
-  BAILOUT("IfStatement");
+  ProcessExpression(stmt->condition(), Expression::kTest);
+  CHECK_BAILOUT;
+  Visit(stmt->then_statement());
+  CHECK_BAILOUT;
+  Visit(stmt->else_statement());
 }
 
 
@@ -575,7 +687,7 @@
 
 
 void CodeGenSelector::VisitReturnStatement(ReturnStatement* stmt) {
-  VisitAsValue(stmt->expression());
+  ProcessExpression(stmt->expression(), Expression::kValue);
 }
 
 
@@ -595,17 +707,39 @@
 
 
 void CodeGenSelector::VisitDoWhileStatement(DoWhileStatement* stmt) {
-  BAILOUT("DoWhileStatement");
+  // We do not handle loops with breaks or continue statements in their
+  // body.  We will bailout when we hit those statements in the body.
+  ProcessExpression(stmt->cond(), Expression::kTest);
+  CHECK_BAILOUT;
+  Visit(stmt->body());
 }
 
 
 void CodeGenSelector::VisitWhileStatement(WhileStatement* stmt) {
-  BAILOUT("WhileStatement");
+  // We do not handle loops with breaks or continue statements in their
+  // body.  We will bailout when we hit those statements in the body.
+  ProcessExpression(stmt->cond(), Expression::kTest);
+  CHECK_BAILOUT;
+  Visit(stmt->body());
 }
 
 
 void CodeGenSelector::VisitForStatement(ForStatement* stmt) {
-  BAILOUT("ForStatement");
+  // We do not handle loops with breaks or continue statements in their
+  // body.  We will bailout when we hit those statements in the body.
+  if (stmt->init() != NULL) {
+    Visit(stmt->init());
+    CHECK_BAILOUT;
+  }
+  if (stmt->cond() != NULL) {
+    ProcessExpression(stmt->cond(), Expression::kTest);
+    CHECK_BAILOUT;
+  }
+  Visit(stmt->body());
+  if (stmt->next() != NULL) {
+    CHECK_BAILOUT;
+    Visit(stmt->next());
+  }
 }
 
 
@@ -625,15 +759,12 @@
 
 
 void CodeGenSelector::VisitDebuggerStatement(DebuggerStatement* stmt) {
-  BAILOUT("DebuggerStatement");
+  // Debugger statement is supported.
 }
 
 
 void CodeGenSelector::VisitFunctionLiteral(FunctionLiteral* expr) {
-  if (!expr->AllowsLazyCompilation()) {
-    BAILOUT("FunctionLiteral does not allow lazy compilation");
-  }
-  expr->set_location(location_);
+  // Function literal is supported.
 }
 
 
@@ -644,7 +775,11 @@
 
 
 void CodeGenSelector::VisitConditional(Conditional* expr) {
-  BAILOUT("Conditional");
+  ProcessExpression(expr->condition(), Expression::kTest);
+  CHECK_BAILOUT;
+  ProcessExpression(expr->then_expression(), context_);
+  CHECK_BAILOUT;
+  ProcessExpression(expr->else_expression(), context_);
 }
 
 
@@ -659,28 +794,27 @@
   if (rewrite != NULL) {
     // Non-global.
     Slot* slot = rewrite->AsSlot();
-    if (slot == NULL) {
-      // This is a variable rewritten to an explicit property access
-      // on the arguments object.
-      BAILOUT("non-global/non-slot variable reference");
-    }
-
-    Slot::Type type = slot->type();
-    if (type != Slot::PARAMETER && type != Slot::LOCAL) {
-      BAILOUT("non-parameter/non-local slot reference");
+    if (slot != NULL) {
+      Slot::Type type = slot->type();
+      // When LOOKUP slots are enabled, some currently dead code
+      // implementing unary typeof will become live.
+      if (type == Slot::LOOKUP) {
+        BAILOUT("Lookup slot");
+      }
+    } else {
+      BAILOUT("access to arguments object");
     }
   }
-  expr->set_location(location_);
 }
 
 
 void CodeGenSelector::VisitLiteral(Literal* expr) {
-  expr->set_location(location_);
+  /* Nothing to do. */
 }
 
 
 void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) {
-  expr->set_location(location_);
+  /* Nothing to do. */
 }
 
 
@@ -710,14 +844,13 @@
       case ObjectLiteral::Property::GETTER:  // Fall through.
       case ObjectLiteral::Property::SETTER:  // Fall through.
       case ObjectLiteral::Property::PROTOTYPE:
-        VisitAsValue(property->key());
+        ProcessExpression(property->key(), Expression::kValue);
         CHECK_BAILOUT;
         break;
     }
-    VisitAsValue(property->value());
+    ProcessExpression(property->value(), Expression::kValue);
     CHECK_BAILOUT;
   }
-  expr->set_location(location_);
 }
 
 
@@ -727,10 +860,9 @@
     Expression* subexpr = subexprs->at(i);
     if (subexpr->AsLiteral() != NULL) continue;
     if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
-    VisitAsValue(subexpr);
+    ProcessExpression(subexpr, Expression::kValue);
     CHECK_BAILOUT;
   }
-  expr->set_location(location_);
 }
 
 
@@ -740,13 +872,8 @@
 
 
 void CodeGenSelector::VisitAssignment(Assignment* expr) {
-  // We support plain non-compound assignments to parameters and
-  // non-context (stack-allocated) locals.
-  if (expr->starts_initialization_block() ||
-      expr->ends_initialization_block()) {
-    BAILOUT("initialization block start");
-  }
-
+  // We support plain non-compound assignments to properties, parameters and
+  // non-context (stack-allocated) locals, and global variables.
   Token::Value op = expr->op();
   if (op == Token::INIT_CONST) BAILOUT("initialize constant");
   if (op != Token::ASSIGN && op != Token::INIT_VAR) {
@@ -754,18 +881,39 @@
   }
 
   Variable* var = expr->target()->AsVariableProxy()->AsVariable();
-  if (var == NULL) BAILOUT("non-variable assignment");
-
-  if (!var->is_global()) {
-    ASSERT(var->slot() != NULL);
-    Slot::Type type = var->slot()->type();
-    if (type != Slot::PARAMETER && type != Slot::LOCAL) {
-      BAILOUT("non-parameter/non-local slot assignment");
+  Property* prop = expr->target()->AsProperty();
+  if (var != NULL) {
+    // All global variables are supported.
+    if (!var->is_global()) {
+      if (var->slot() == NULL) {
+        // This is a parameter that has rewritten to an arguments access.
+        BAILOUT("non-global/non-slot assignment");
+      }
+      Slot::Type type = var->slot()->type();
+      if (type == Slot::LOOKUP) {
+        BAILOUT("Lookup slot");
+      }
     }
+  } else if (prop != NULL) {
+    ProcessExpression(prop->obj(), Expression::kValue);
+    CHECK_BAILOUT;
+    // We will only visit the key during code generation for keyed property
+    // stores.  Leave its expression context uninitialized for named
+    // property stores.
+    Literal* lit = prop->key()->AsLiteral();
+    uint32_t ignored;
+    if (lit == NULL ||
+        !lit->handle()->IsSymbol() ||
+        String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) {
+      ProcessExpression(prop->key(), Expression::kValue);
+      CHECK_BAILOUT;
+    }
+  } else {
+    // This is a throw reference error.
+    BAILOUT("non-variable/non-property assignment");
   }
 
-  VisitAsValue(expr->value());
-  expr->set_location(location_);
+  ProcessExpression(expr->value(), Expression::kValue);
 }
 
 
@@ -775,10 +923,9 @@
 
 
 void CodeGenSelector::VisitProperty(Property* expr) {
-  VisitAsValue(expr->obj());
+  ProcessExpression(expr->obj(), Expression::kValue);
   CHECK_BAILOUT;
-  VisitAsValue(expr->key());
-  expr->set_location(location_);
+  ProcessExpression(expr->key(), Expression::kValue);
 }
 
 
@@ -789,33 +936,45 @@
 
   // Check for supported calls
   if (var != NULL && var->is_possibly_eval()) {
-    BAILOUT("Call to a function named 'eval'");
+    BAILOUT("call to the identifier 'eval'");
   } else if (var != NULL && !var->is_this() && var->is_global()) {
-    // ----------------------------------
-    // JavaScript example: 'foo(1, 2, 3)'  // foo is global
-    // ----------------------------------
+    // Calls to global variables are supported.
+  } else if (var != NULL && var->slot() != NULL &&
+             var->slot()->type() == Slot::LOOKUP) {
+    BAILOUT("call to a lookup slot");
+  } else if (fun->AsProperty() != NULL) {
+    Property* prop = fun->AsProperty();
+    Literal* literal_key = prop->key()->AsLiteral();
+    if (literal_key != NULL && literal_key->handle()->IsSymbol()) {
+      ProcessExpression(prop->obj(), Expression::kValue);
+      CHECK_BAILOUT;
+    } else {
+      ProcessExpression(prop->obj(), Expression::kValue);
+      CHECK_BAILOUT;
+      ProcessExpression(prop->key(), Expression::kValue);
+      CHECK_BAILOUT;
+    }
   } else {
-    BAILOUT("Call to a non-global function");
+    // Otherwise the call is supported if the function expression is.
+    ProcessExpression(fun, Expression::kValue);
   }
-  // Check all arguments to the call.  (Relies on TEMP meaning STACK.)
+  // Check all arguments to the call.
   for (int i = 0; i < args->length(); i++) {
-    VisitAsValue(args->at(i));
+    ProcessExpression(args->at(i), Expression::kValue);
     CHECK_BAILOUT;
   }
-  expr->set_location(location_);
 }
 
 
 void CodeGenSelector::VisitCallNew(CallNew* expr) {
-  VisitAsValue(expr->expression());
+  ProcessExpression(expr->expression(), Expression::kValue);
   CHECK_BAILOUT;
   ZoneList<Expression*>* args = expr->arguments();
   // Check all arguments to the call
   for (int i = 0; i < args->length(); i++) {
-    VisitAsValue(args->at(i));
+    ProcessExpression(args->at(i), Expression::kValue);
     CHECK_BAILOUT;
   }
-  expr->set_location(location_);
 }
 
 
@@ -829,37 +988,88 @@
   }
   // Check all arguments to the call.  (Relies on TEMP meaning STACK.)
   for (int i = 0; i < expr->arguments()->length(); i++) {
-    VisitAsValue(expr->arguments()->at(i));
+    ProcessExpression(expr->arguments()->at(i), Expression::kValue);
     CHECK_BAILOUT;
   }
-  expr->set_location(location_);
 }
 
 
 void CodeGenSelector::VisitUnaryOperation(UnaryOperation* expr) {
-  BAILOUT("UnaryOperation");
+  switch (expr->op()) {
+    case Token::VOID:
+      ProcessExpression(expr->expression(), Expression::kEffect);
+      break;
+    case Token::NOT:
+      ProcessExpression(expr->expression(), Expression::kTest);
+      break;
+    case Token::TYPEOF:
+      ProcessExpression(expr->expression(), Expression::kValue);
+      break;
+    default:
+      BAILOUT("UnaryOperation");
+  }
 }
 
 
 void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
-  BAILOUT("CountOperation");
+  // We support postfix count operations on global variables.
+  if (expr->is_prefix()) BAILOUT("Prefix CountOperation");
+  Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
+  if (var == NULL || !var->is_global()) BAILOUT("non-global postincrement");
+  ProcessExpression(expr->expression(), Expression::kValue);
 }
 
 
 void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
   switch (expr->op()) {
     case Token::COMMA:
-      VisitAsEffect(expr->left());
+      ProcessExpression(expr->left(), Expression::kEffect);
       CHECK_BAILOUT;
-      Visit(expr->right());  // Location is the same as the parent location.
+      ProcessExpression(expr->right(), context_);
       break;
 
     case Token::OR:
-      VisitAsValue(expr->left());
+      switch (context_) {
+        case Expression::kUninitialized:
+          UNREACHABLE();
+        case Expression::kEffect:  // Fall through.
+        case Expression::kTest:  // Fall through.
+        case Expression::kTestValue:
+          // The left subexpression's value is not needed, it is in a pure
+          // test context.
+          ProcessExpression(expr->left(), Expression::kTest);
+          break;
+        case Expression::kValue:  // Fall through.
+        case Expression::kValueTest:
+          // The left subexpression's value is needed, it is in a hybrid
+          // value/test context.
+          ProcessExpression(expr->left(), Expression::kValueTest);
+          break;
+      }
       CHECK_BAILOUT;
-      // The location for the right subexpression is the same as for the
-      // whole expression so we call Visit directly.
-      Visit(expr->right());
+      ProcessExpression(expr->right(), context_);
+      break;
+
+    case Token::AND:
+      switch (context_) {
+        case Expression::kUninitialized:
+          UNREACHABLE();
+        case Expression::kEffect:  // Fall through.
+        case Expression::kTest:  // Fall through.
+        case Expression::kValueTest:
+          // The left subexpression's value is not needed, it is in a pure
+          // test context.
+          ProcessExpression(expr->left(), Expression::kTest);
+          break;
+        case Expression::kValue:  // Fall through.
+        case Expression::kTestValue:
+          // The left subexpression's value is needed, it is in a hybrid
+          // test/value context.
+          ProcessExpression(expr->left(), Expression::kTestValue);
+          break;
+      }
+      CHECK_BAILOUT;
+      ProcessExpression(expr->right(), context_);
       break;
 
     case Token::ADD:
@@ -873,20 +1083,21 @@
     case Token::SHL:
     case Token::SHR:
     case Token::SAR:
-      VisitAsValue(expr->left());
+      ProcessExpression(expr->left(), Expression::kValue);
       CHECK_BAILOUT;
-      VisitAsValue(expr->right());
+      ProcessExpression(expr->right(), Expression::kValue);
       break;
 
     default:
       BAILOUT("Unsupported binary operation");
   }
-  expr->set_location(location_);
 }
 
 
 void CodeGenSelector::VisitCompareOperation(CompareOperation* expr) {
-  BAILOUT("CompareOperation");
+      ProcessExpression(expr->left(), Expression::kValue);
+      CHECK_BAILOUT;
+      ProcessExpression(expr->right(), Expression::kValue);
 }