Update V8 to r3431 as required by WebKit r51976.

Change-Id: I567392c3f8c0a0d5201a4249611ac4ccf468cd5b
diff --git a/src/compiler.cc b/src/compiler.cc
index e422bf7..48da63d 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -46,11 +46,23 @@
  public:
   enum CodeGenTag { NORMAL, FAST };
 
-  CodeGenSelector() : has_supported_syntax_(true) {}
+  CodeGenSelector()
+      : has_supported_syntax_(true),
+        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);
 
@@ -61,6 +73,9 @@
 
   bool has_supported_syntax_;
 
+  // The desired expression context of the currently visited expression.
+  Expression::Context context_;
+
   DISALLOW_COPY_AND_ASSIGN(CodeGenSelector);
 };
 
@@ -68,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.
@@ -105,12 +121,24 @@
 
   // 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 always_fast_compiler is true, always try the fast compiler.
+    if (shared.is_null() && !literal->scope()->is_global_scope() &&
+        !FLAG_always_fast_compiler) {
+      if (FLAG_trace_bailout) PrintF("Non-global scope\n");
+    } else if (!shared.is_null() && !shared->try_fast_codegen() &&
+               !FLAG_always_fast_compiler) {
+      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);
 }
@@ -151,8 +179,10 @@
     // called.
     if (is_eval) {
       JavaScriptFrameIterator it;
-      script->set_eval_from_function(it.frame()->function());
-      int offset = it.frame()->pc() - it.frame()->code()->instruction_start();
+      script->set_eval_from_shared(
+          JSFunction::cast(it.frame()->function())->shared());
+      int offset = static_cast<int>(
+          it.frame()->pc() - it.frame()->code()->instruction_start());
       script->set_eval_from_instructions_offset(Smi::FromInt(offset));
     }
   }
@@ -195,7 +225,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()) {
@@ -232,7 +263,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
@@ -396,7 +427,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()) {
@@ -438,7 +470,6 @@
   // Set the optimication hints after performing lazy compilation, as these are
   // not set when the function is set up as a lazily compiled function.
   shared->SetThisPropertyAssignmentsInfo(
-      lit->has_only_this_property_assignments(),
       lit->has_only_simple_this_property_assignments(),
       *lit->this_property_assignments());
 
@@ -448,18 +479,132 @@
 }
 
 
+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");
-    return NORMAL;
+  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.\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());
@@ -500,9 +645,20 @@
 
 
 void CodeGenSelector::VisitDeclaration(Declaration* decl) {
-  Variable* var = decl->proxy()->var();
-  if (!var->is_global() || var->mode() == Variable::CONST) {
-    BAILOUT("Non-global declaration");
+  Property* prop = decl->proxy()->AsProperty();
+  if (prop != NULL) {
+    // Property rewrites are shared, ensure we are not changing its
+    // expression context state.
+    ASSERT(prop->obj()->context() == Expression::kUninitialized ||
+           prop->obj()->context() == Expression::kValue);
+    ASSERT(prop->key()->context() == Expression::kUninitialized ||
+           prop->key()->context() == Expression::kValue);
+    ProcessExpression(prop->obj(), Expression::kValue);
+    ProcessExpression(prop->key(), Expression::kValue);
+  }
+
+  if (decl->fun() != NULL) {
+    ProcessExpression(decl->fun(), Expression::kValue);
   }
 }
 
@@ -513,10 +669,7 @@
 
 
 void CodeGenSelector::VisitExpressionStatement(ExpressionStatement* stmt) {
-  Expression* expr = stmt->expression();
-  Visit(expr);
-  CHECK_BAILOUT;
-  expr->set_location(Location::Nowhere());
+  ProcessExpression(stmt->expression(), Expression::kEffect);
 }
 
 
@@ -526,7 +679,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());
 }
 
 
@@ -541,7 +698,7 @@
 
 
 void CodeGenSelector::VisitReturnStatement(ReturnStatement* stmt) {
-  Visit(stmt->expression());
+  ProcessExpression(stmt->expression(), Expression::kValue);
 }
 
 
@@ -561,17 +718,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());
+  }
 }
 
 
@@ -591,14 +770,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");
-  }
+  // Function literal is supported.
 }
 
 
@@ -609,37 +786,92 @@
 
 
 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_);
 }
 
 
 void CodeGenSelector::VisitSlot(Slot* expr) {
-  Slot::Type type = expr->type();
-  if (type != Slot::PARAMETER && type != Slot::LOCAL) {
-    BAILOUT("non-parameter/non-local slot reference");
-  }
+  UNREACHABLE();
 }
 
 
 void CodeGenSelector::VisitVariableProxy(VariableProxy* expr) {
   Expression* rewrite = expr->var()->rewrite();
-  if (rewrite != NULL) Visit(rewrite);
+  // A rewrite of NULL indicates a global variable.
+  if (rewrite != NULL) {
+    // Non-global.
+    Slot* slot = rewrite->AsSlot();
+    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 {
+#ifdef DEBUG
+      // Only remaining possibility is a property where the object is
+      // a slotted variable and the key is a smi.
+      Property* property = rewrite->AsProperty();
+      ASSERT_NOT_NULL(property);
+      Variable* object = property->obj()->AsVariableProxy()->AsVariable();
+      ASSERT_NOT_NULL(object);
+      ASSERT_NOT_NULL(object->slot());
+      ASSERT_NOT_NULL(property->key()->AsLiteral());
+      ASSERT(property->key()->AsLiteral()->handle()->IsSmi());
+#endif
+    }
+  }
 }
 
 
 void CodeGenSelector::VisitLiteral(Literal* expr) {
-  // All literals are supported.
-  expr->set_location(Location::Constant());
+  /* Nothing to do. */
 }
 
 
 void CodeGenSelector::VisitRegExpLiteral(RegExpLiteral* expr) {
-  // RegexpLiterals are supported.
+  /* Nothing to do. */
 }
 
 
 void CodeGenSelector::VisitObjectLiteral(ObjectLiteral* expr) {
-  BAILOUT("ObjectLiteral");
+  ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
+
+  for (int i = 0, len = properties->length(); i < len; i++) {
+    ObjectLiteral::Property* property = properties->at(i);
+    if (property->IsCompileTimeValue()) continue;
+
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+        UNREACHABLE();
+
+      // For (non-compile-time) materialized literals and computed
+      // properties with symbolic keys we will use an IC and therefore not
+      // generate code for the key.
+      case ObjectLiteral::Property::COMPUTED:  // Fall through.
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+        if (property->key()->handle()->IsSymbol()) {
+          break;
+        }
+        // Fall through.
+
+      // In all other cases we need the key's value on the stack
+      // for a runtime call.  (Relies on TEMP meaning STACK.)
+      case ObjectLiteral::Property::GETTER:  // Fall through.
+      case ObjectLiteral::Property::SETTER:  // Fall through.
+      case ObjectLiteral::Property::PROTOTYPE:
+        ProcessExpression(property->key(), Expression::kValue);
+        CHECK_BAILOUT;
+        break;
+    }
+    ProcessExpression(property->value(), Expression::kValue);
+    CHECK_BAILOUT;
+  }
 }
 
 
@@ -649,7 +881,7 @@
     Expression* subexpr = subexprs->at(i);
     if (subexpr->AsLiteral() != NULL) continue;
     if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
-    Visit(subexpr);
+    ProcessExpression(subexpr, Expression::kValue);
     CHECK_BAILOUT;
   }
 }
@@ -661,10 +893,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()) BAILOUT("initialization block");
-
+  // 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) {
@@ -672,17 +902,41 @@
   }
 
   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();
+  ASSERT(var == NULL || prop == NULL);
+  if (var != NULL) {
+    // All global variables are supported.
+    if (!var->is_global()) {
+      ASSERT(var->slot() != NULL);
+      Slot::Type type = var->slot()->type();
+      if (type == Slot::LOOKUP) {
+        BAILOUT("Lookup slot");
+      }
     }
+  } else if (prop != NULL) {
+    ASSERT(prop->obj()->context() == Expression::kUninitialized ||
+           prop->obj()->context() == Expression::kValue);
+    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)) {
+      ASSERT(prop->key()->context() == Expression::kUninitialized ||
+             prop->key()->context() == Expression::kValue);
+      ProcessExpression(prop->key(), Expression::kValue);
+      CHECK_BAILOUT;
+    }
+  } else {
+    // This is a throw reference error.
+    BAILOUT("non-variable/non-property assignment");
   }
 
-  Visit(expr->value());
+  ProcessExpression(expr->value(), Expression::kValue);
 }
 
 
@@ -692,7 +946,9 @@
 
 
 void CodeGenSelector::VisitProperty(Property* expr) {
-  BAILOUT("Property");
+  ProcessExpression(expr->obj(), Expression::kValue);
+  CHECK_BAILOUT;
+  ProcessExpression(expr->key(), Expression::kValue);
 }
 
 
@@ -703,58 +959,154 @@
 
   // 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
+  // Check all arguments to the call.
   for (int i = 0; i < args->length(); i++) {
-    Visit(args->at(i));
+    ProcessExpression(args->at(i), Expression::kValue);
     CHECK_BAILOUT;
   }
 }
 
 
 void CodeGenSelector::VisitCallNew(CallNew* expr) {
-  BAILOUT("CallNew");
+  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++) {
+    ProcessExpression(args->at(i), Expression::kValue);
+    CHECK_BAILOUT;
+  }
 }
 
 
 void CodeGenSelector::VisitCallRuntime(CallRuntime* expr) {
-  // In case of JS runtime function bail out.
-  if (expr->function() == NULL) BAILOUT("CallRuntime");
   // Check for inline runtime call
   if (expr->name()->Get(0) == '_' &&
       CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {
-    BAILOUT("InlineRuntimeCall");
+    BAILOUT("inlined runtime call");
   }
+  // Check all arguments to the call.  (Relies on TEMP meaning STACK.)
   for (int i = 0; i < expr->arguments()->length(); i++) {
-    Visit(expr->arguments()->at(i));
+    ProcessExpression(expr->arguments()->at(i), Expression::kValue);
     CHECK_BAILOUT;
   }
 }
 
 
 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::OR:
-      Visit(expr->left());
+    case Token::COMMA:
+      ProcessExpression(expr->left(), Expression::kEffect);
       CHECK_BAILOUT;
-      Visit(expr->right());
+      ProcessExpression(expr->right(), context_);
+      break;
+
+    case Token::OR:
+      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;
+      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:
+    case Token::SUB:
+    case Token::DIV:
+    case Token::MOD:
+    case Token::MUL:
+    case Token::BIT_OR:
+    case Token::BIT_AND:
+    case Token::BIT_XOR:
+    case Token::SHL:
+    case Token::SHR:
+    case Token::SAR:
+      ProcessExpression(expr->left(), Expression::kValue);
+      CHECK_BAILOUT;
+      ProcessExpression(expr->right(), Expression::kValue);
       break;
 
     default:
@@ -764,12 +1116,14 @@
 
 
 void CodeGenSelector::VisitCompareOperation(CompareOperation* expr) {
-  BAILOUT("CompareOperation");
+      ProcessExpression(expr->left(), Expression::kValue);
+      CHECK_BAILOUT;
+      ProcessExpression(expr->right(), Expression::kValue);
 }
 
 
 void CodeGenSelector::VisitThisFunction(ThisFunction* expr) {
-  BAILOUT("ThisFunction");
+  // ThisFunction is supported.
 }
 
 #undef BAILOUT