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