diff options
author | Michaël Zasso <targos@protonmail.com> | 2017-02-14 11:27:26 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2017-02-22 15:55:42 +0100 |
commit | 7a77daf24344db7942e34c962b0f1ee729ab7af5 (patch) | |
tree | e7cbe7bf4e2f4b802a8f5bc18336c546cd6a0d7f /deps/v8/src/interpreter/bytecode-generator.cc | |
parent | 5f08871ee93ea739148cc49e0f7679e33c70295a (diff) | |
download | android-node-v8-7a77daf24344db7942e34c962b0f1ee729ab7af5.tar.gz android-node-v8-7a77daf24344db7942e34c962b0f1ee729ab7af5.tar.bz2 android-node-v8-7a77daf24344db7942e34c962b0f1ee729ab7af5.zip |
deps: update V8 to 5.6.326.55
PR-URL: https://github.com/nodejs/node/pull/10992
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'deps/v8/src/interpreter/bytecode-generator.cc')
-rw-r--r-- | deps/v8/src/interpreter/bytecode-generator.cc | 360 |
1 files changed, 200 insertions, 160 deletions
diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index db5a596b85..99e76725d5 100644 --- a/deps/v8/src/interpreter/bytecode-generator.cc +++ b/deps/v8/src/interpreter/bytecode-generator.cc @@ -14,6 +14,7 @@ #include "src/interpreter/bytecode-register-allocator.h" #include "src/interpreter/control-flow-builders.h" #include "src/objects.h" +#include "src/parsing/parse-info.h" #include "src/parsing/token.h" namespace v8 { @@ -361,7 +362,7 @@ void BytecodeGenerator::ControlScope::PerformCommand(Command command, return; } current = current->outer(); - if (current->context() != context) { + if (current->context() != context && context->ShouldPopContext()) { // Pop context to the expected depth. // TODO(rmcilroy): Only emit a single context pop. generator()->builder()->PopContext(current->context()->reg()); @@ -571,7 +572,11 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) generator_state_(), loop_depth_(0), home_object_symbol_(info->isolate()->factory()->home_object_symbol()), - prototype_string_(info->isolate()->factory()->prototype_string()) { + empty_fixed_array_(info->isolate()->factory()->empty_fixed_array()) { + AstValueFactory* ast_value_factory = info->parse_info()->ast_value_factory(); + const AstRawString* prototype_string = ast_value_factory->prototype_string(); + ast_value_factory->Internalize(info->isolate()); + prototype_string_ = prototype_string->string(); } Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(Isolate* isolate) { @@ -678,6 +683,9 @@ void BytecodeGenerator::GenerateBytecodeBody() { // Visit declarations within the function scope. VisitDeclarations(scope()->declarations()); + // Emit initializing assignments for module namespace imports (if any). + VisitModuleNamespaceImports(); + // Perform a stack-check before the body. builder()->StackCheck(info()->literal()->start_position()); @@ -826,8 +834,9 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { case VariableLocation::MODULE: if (variable->IsExport() && variable->binding_needs_init()) { builder()->LoadTheHole(); - VisitVariableAssignment(variable, Token::INIT, - FeedbackVectorSlot::Invalid()); + BuildVariableAssignment(variable, Token::INIT, + FeedbackVectorSlot::Invalid(), + HoleCheckMode::kElided); } // Nothing to do for imports. break; @@ -846,8 +855,9 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { case VariableLocation::PARAMETER: case VariableLocation::LOCAL: { VisitForAccumulatorValue(decl->fun()); - VisitVariableAssignment(variable, Token::INIT, - FeedbackVectorSlot::Invalid()); + BuildVariableAssignment(variable, Token::INIT, + FeedbackVectorSlot::Invalid(), + HoleCheckMode::kElided); break; } case VariableLocation::CONTEXT: { @@ -871,19 +881,38 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { DCHECK_EQ(variable->mode(), LET); DCHECK(variable->IsExport()); VisitForAccumulatorValue(decl->fun()); - VisitVariableAssignment(variable, Token::INIT, - FeedbackVectorSlot::Invalid()); + BuildVariableAssignment(variable, Token::INIT, + FeedbackVectorSlot::Invalid(), + HoleCheckMode::kElided); break; } } -void BytecodeGenerator::VisitDeclarations( - ZoneList<Declaration*>* declarations) { +void BytecodeGenerator::VisitModuleNamespaceImports() { + if (!scope()->is_module_scope()) return; + + RegisterAllocationScope register_scope(this); + Register module_request = register_allocator()->NewRegister(); + + ModuleDescriptor* descriptor = scope()->AsModuleScope()->module(); + for (auto entry : descriptor->namespace_imports()) { + builder() + ->LoadLiteral(Smi::FromInt(entry->module_request)) + .StoreAccumulatorInRegister(module_request) + .CallRuntime(Runtime::kGetModuleNamespace, module_request); + Variable* var = scope()->LookupLocal(entry->local_name); + DCHECK_NOT_NULL(var); + BuildVariableAssignment(var, Token::INIT, FeedbackVectorSlot::Invalid(), + HoleCheckMode::kElided); + } +} + +void BytecodeGenerator::VisitDeclarations(Declaration::List* declarations) { RegisterAllocationScope register_scope(this); DCHECK(globals_builder()->empty()); - for (int i = 0; i < declarations->length(); i++) { + for (Declaration* decl : *declarations) { RegisterAllocationScope register_scope(this); - Visit(declarations->at(i)); + Visit(decl); } if (globals_builder()->empty()) return; @@ -1126,8 +1155,9 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr, LhsKind assign_type = Property::GetAssignType(property); switch (assign_type) { case VARIABLE: { - Variable* variable = expr->AsVariableProxy()->var(); - VisitVariableAssignment(variable, Token::ASSIGN, slot); + VariableProxy* proxy = expr->AsVariableProxy(); + BuildVariableAssignment(proxy->var(), Token::ASSIGN, slot, + proxy->hole_check_mode()); break; } case NAMED_PROPERTY: { @@ -1206,7 +1236,7 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Set up loop counter Register index = register_allocator()->NewRegister(); - builder()->LoadLiteral(Smi::FromInt(0)); + builder()->LoadLiteral(Smi::kZero); builder()->StoreAccumulatorInRegister(index); // The loop @@ -1374,11 +1404,12 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) { builder()->CallRuntime(Runtime::kToFastProperties, literal); // Assign to class variable. if (expr->class_variable_proxy() != nullptr) { - Variable* var = expr->class_variable_proxy()->var(); + VariableProxy* proxy = expr->class_variable_proxy(); FeedbackVectorSlot slot = expr->NeedsProxySlot() ? expr->ProxySlot() : FeedbackVectorSlot::Invalid(); - VisitVariableAssignment(var, Token::INIT, slot); + BuildVariableAssignment(proxy->var(), Token::INIT, slot, + HoleCheckMode::kElided); } } @@ -1541,11 +1572,14 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { FastCloneShallowObjectStub::IsSupported(expr), FastCloneShallowObjectStub::PropertiesCount(expr->properties_count()), expr->ComputeFlags()); - // Allocate in the outer scope since this register is used to return the - // expression's results to the caller. + // If constant properties is an empty fixed array, use our cached + // empty_fixed_array to ensure it's only added to the constant pool once. + Handle<FixedArray> constant_properties = expr->properties_count() == 0 + ? empty_fixed_array() + : expr->constant_properties(); Register literal = register_allocator()->NewRegister(); - builder()->CreateObjectLiteral(expr->constant_properties(), - expr->literal_index(), flags, literal); + builder()->CreateObjectLiteral(constant_properties, expr->literal_index(), + flags, literal); // Store computed values into the literal. int property_index = 0; @@ -1752,17 +1786,13 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { builder()->SetExpressionPosition(proxy); - VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); + BuildVariableLoad(proxy->var(), proxy->VariableFeedbackSlot(), + proxy->hole_check_mode()); } -void BytecodeGenerator::BuildHoleCheckForVariableLoad(Variable* variable) { - if (variable->binding_needs_init()) { - BuildThrowIfHole(variable->name()); - } -} - -void BytecodeGenerator::VisitVariableLoad(Variable* variable, +void BytecodeGenerator::BuildVariableLoad(Variable* variable, FeedbackVectorSlot slot, + HoleCheckMode hole_check_mode, TypeofMode typeof_mode) { switch (variable->location()) { case VariableLocation::LOCAL: { @@ -1771,7 +1801,9 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, // VisitForRegisterScope, in order to avoid register aliasing if // subsequent expressions assign to the same variable. builder()->LoadAccumulatorWithRegister(source); - BuildHoleCheckForVariableLoad(variable); + if (hole_check_mode == HoleCheckMode::kRequired) { + BuildThrowIfHole(variable->name()); + } break; } case VariableLocation::PARAMETER: { @@ -1782,7 +1814,9 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, // VisitForRegisterScope, in order to avoid register aliasing if // subsequent expressions assign to the same variable. builder()->LoadAccumulatorWithRegister(source); - BuildHoleCheckForVariableLoad(variable); + if (hole_check_mode == HoleCheckMode::kRequired) { + BuildThrowIfHole(variable->name()); + } break; } case VariableLocation::UNALLOCATED: { @@ -1801,7 +1835,9 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, } builder()->LoadContextSlot(context_reg, variable->index(), depth); - BuildHoleCheckForVariableLoad(variable); + if (hole_check_mode == HoleCheckMode::kRequired) { + BuildThrowIfHole(variable->name()); + } break; } case VariableLocation::LOOKUP: { @@ -1812,7 +1848,9 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, execution_context()->ContextChainDepth(local_variable->scope()); builder()->LoadLookupContextSlot(variable->name(), typeof_mode, local_variable->index(), depth); - BuildHoleCheckForVariableLoad(variable); + if (hole_check_mode == HoleCheckMode::kRequired) { + BuildThrowIfHole(variable->name()); + } break; } case DYNAMIC_GLOBAL: { @@ -1827,36 +1865,21 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, break; } case VariableLocation::MODULE: { - ModuleDescriptor* descriptor = scope()->GetModuleScope()->module(); - if (variable->IsExport()) { - auto it = descriptor->regular_exports().find(variable->raw_name()); - DCHECK(it != descriptor->regular_exports().end()); - Register export_name = register_allocator()->NewRegister(); - builder() - ->LoadLiteral(it->second->export_name->string()) - .StoreAccumulatorInRegister(export_name) - .CallRuntime(Runtime::kLoadModuleExport, export_name); - } else { - auto it = descriptor->regular_imports().find(variable->raw_name()); - DCHECK(it != descriptor->regular_imports().end()); - RegisterList args = register_allocator()->NewRegisterList(2); - builder() - ->LoadLiteral(it->second->import_name->string()) - .StoreAccumulatorInRegister(args[0]) - .LoadLiteral(Smi::FromInt(it->second->module_request)) - .StoreAccumulatorInRegister(args[1]) - .CallRuntime(Runtime::kLoadModuleImport, args); + int depth = execution_context()->ContextChainDepth(variable->scope()); + builder()->LoadModuleVariable(variable->index(), depth); + if (hole_check_mode == HoleCheckMode::kRequired) { + BuildThrowIfHole(variable->name()); } - BuildHoleCheckForVariableLoad(variable); break; } } } -void BytecodeGenerator::VisitVariableLoadForAccumulatorValue( - Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) { +void BytecodeGenerator::BuildVariableLoadForAccumulatorValue( + Variable* variable, FeedbackVectorSlot slot, HoleCheckMode hole_check_mode, + TypeofMode typeof_mode) { ValueResultScope accumulator_result(this); - VisitVariableLoad(variable, slot, typeof_mode); + BuildVariableLoad(variable, slot, hole_check_mode, typeof_mode); } void BytecodeGenerator::BuildReturn() { @@ -1911,29 +1934,26 @@ void BytecodeGenerator::BuildThrowIfNotHole(Handle<String> name) { void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable, Token::Value op) { - if (op != Token::INIT) { - // Perform an initialization check for let/const declared variables. - // E.g. let x = (x = 20); is not allowed. - BuildThrowIfHole(variable->name()); - } else { - DCHECK(variable->is_this() && variable->mode() == CONST && - op == Token::INIT); + if (variable->is_this() && variable->mode() == CONST && op == Token::INIT) { // Perform an initialization check for 'this'. 'this' variable is the // only variable able to trigger bind operations outside the TDZ // via 'super' calls. BuildThrowIfNotHole(variable->name()); + } else { + // Perform an initialization check for let/const declared variables. + // E.g. let x = (x = 20); is not allowed. + DCHECK(IsLexicalVariableMode(variable->mode())); + BuildThrowIfHole(variable->name()); } } -void BytecodeGenerator::VisitVariableAssignment(Variable* variable, +void BytecodeGenerator::BuildVariableAssignment(Variable* variable, Token::Value op, - FeedbackVectorSlot slot) { + FeedbackVectorSlot slot, + HoleCheckMode hole_check_mode) { VariableMode mode = variable->mode(); RegisterAllocationScope assignment_register_scope(this); BytecodeLabel end_label; - bool hole_check_required = - variable->binding_needs_init() && - (op != Token::INIT || (mode == CONST && variable->is_this())); switch (variable->location()) { case VariableLocation::PARAMETER: case VariableLocation::LOCAL: { @@ -1944,7 +1964,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, destination = Register(variable->index()); } - if (hole_check_required) { + if (hole_check_mode == HoleCheckMode::kRequired) { // Load destination to check for hole. Register value_temp = register_allocator()->NewRegister(); builder() @@ -1979,7 +1999,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, context_reg = execution_context()->reg(); } - if (hole_check_required) { + if (hole_check_mode == HoleCheckMode::kRequired) { // Load destination to check for hole. Register value_temp = register_allocator()->NewRegister(); builder() @@ -2014,18 +2034,16 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, // assignments for them. DCHECK(variable->IsExport()); - ModuleDescriptor* mod = scope()->GetModuleScope()->module(); - // There may be several export names for this local name, but it doesn't - // matter which one we pick, as they all map to the same cell. - auto it = mod->regular_exports().find(variable->raw_name()); - DCHECK(it != mod->regular_exports().end()); - - RegisterList args = register_allocator()->NewRegisterList(2); - builder() - ->StoreAccumulatorInRegister(args[1]) - .LoadLiteral(it->second->export_name->string()) - .StoreAccumulatorInRegister(args[0]) - .CallRuntime(Runtime::kStoreModuleExport, args); + int depth = execution_context()->ContextChainDepth(variable->scope()); + if (hole_check_mode == HoleCheckMode::kRequired) { + Register value_temp = register_allocator()->NewRegister(); + builder() + ->StoreAccumulatorInRegister(value_temp) + .LoadModuleVariable(variable->index(), depth); + BuildHoleCheckForVariableAssignment(variable, op); + builder()->LoadAccumulatorWithRegister(value_temp); + } + builder()->StoreModuleVariable(variable->index(), depth); break; } } @@ -2087,7 +2105,8 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { switch (assign_type) { case VARIABLE: { VariableProxy* proxy = expr->target()->AsVariableProxy(); - VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); + BuildVariableLoad(proxy->var(), proxy->VariableFeedbackSlot(), + proxy->hole_check_mode()); builder()->StoreAccumulatorInRegister(old_value); break; } @@ -2136,10 +2155,11 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { FeedbackVectorSlot slot = expr->AssignmentSlot(); switch (assign_type) { case VARIABLE: { - // TODO(oth): The VisitVariableAssignment() call is hard to reason about. + // TODO(oth): The BuildVariableAssignment() call is hard to reason about. // Is the value in the accumulator safe? Yes, but scary. - Variable* variable = expr->target()->AsVariableProxy()->var(); - VisitVariableAssignment(variable, expr->op(), slot); + VariableProxy* proxy = expr->target()->AsVariableProxy(); + BuildVariableAssignment(proxy->var(), expr->op(), slot, + proxy->hole_check_mode()); break; } case NAMED_PROPERTY: @@ -2273,10 +2293,12 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { } } -void BytecodeGenerator::VisitPropertyLoadForAccumulator(Register obj, - Property* expr) { +void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj, + Property* expr, + Register destination) { ValueResultScope result_scope(this); VisitPropertyLoad(obj, expr); + builder()->StoreAccumulatorInRegister(destination); } void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property, @@ -2325,11 +2347,10 @@ void BytecodeGenerator::VisitProperty(Property* expr) { } void BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args, - RegisterList arg_regs, - size_t first_argument_register) { + RegisterList* arg_regs) { // Visit arguments. for (int i = 0; i < static_cast<int>(args->length()); i++) { - VisitForRegisterValue(args->at(i), arg_regs[first_argument_register + i]); + VisitAndPushIntoRegisterList(args->at(i), arg_regs); } } @@ -2342,11 +2363,11 @@ void BytecodeGenerator::VisitCall(Call* expr) { } Register callee = register_allocator()->NewRegister(); - - // Add an argument register for the receiver. - RegisterList args = - register_allocator()->NewRegisterList(expr->arguments()->length() + 1); - Register receiver = args[0]; + // Grow the args list as we visit receiver / arguments to avoid allocating all + // the registers up-front. Otherwise these registers are unavailable during + // receiver / argument visiting and we can end up with memory leaks due to + // registers keeping objects alive. + RegisterList args = register_allocator()->NewGrowableRegisterList(); // Prepare the callee and the receiver to the function call. This depends on // the semantics of the underlying call type. @@ -2354,54 +2375,55 @@ void BytecodeGenerator::VisitCall(Call* expr) { case Call::NAMED_PROPERTY_CALL: case Call::KEYED_PROPERTY_CALL: { Property* property = callee_expr->AsProperty(); - VisitForAccumulatorValue(property->obj()); - builder()->StoreAccumulatorInRegister(receiver); - VisitPropertyLoadForAccumulator(receiver, property); - builder()->StoreAccumulatorInRegister(callee); + VisitAndPushIntoRegisterList(property->obj(), &args); + VisitPropertyLoadForRegister(args[0], property, callee); break; } case Call::GLOBAL_CALL: { // Receiver is undefined for global calls. - builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); + BuildPushUndefinedIntoRegisterList(&args); // Load callee as a global variable. VariableProxy* proxy = callee_expr->AsVariableProxy(); - VisitVariableLoadForAccumulatorValue(proxy->var(), - proxy->VariableFeedbackSlot()); + BuildVariableLoadForAccumulatorValue(proxy->var(), + proxy->VariableFeedbackSlot(), + proxy->hole_check_mode()); builder()->StoreAccumulatorInRegister(callee); break; } - case Call::LOOKUP_SLOT_CALL: - case Call::POSSIBLY_EVAL_CALL: { - if (callee_expr->AsVariableProxy()->var()->IsLookupSlot()) { + case Call::WITH_CALL: { + Register receiver = register_allocator()->GrowRegisterList(&args); + DCHECK(callee_expr->AsVariableProxy()->var()->IsLookupSlot()); + { RegisterAllocationScope inner_register_scope(this); Register name = register_allocator()->NewRegister(); // Call %LoadLookupSlotForCall to get the callee and receiver. DCHECK(Register::AreContiguous(callee, receiver)); RegisterList result_pair(callee.index(), 2); + USE(receiver); Variable* variable = callee_expr->AsVariableProxy()->var(); builder() ->LoadLiteral(variable->name()) .StoreAccumulatorInRegister(name) .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name, result_pair); - break; } - // Fall through. - DCHECK_EQ(call_type, Call::POSSIBLY_EVAL_CALL); + break; } case Call::OTHER_CALL: { - builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); + BuildPushUndefinedIntoRegisterList(&args); VisitForRegisterValue(callee_expr, callee); break; } case Call::NAMED_SUPER_PROPERTY_CALL: { + Register receiver = register_allocator()->GrowRegisterList(&args); Property* property = callee_expr->AsProperty(); VisitNamedSuperPropertyLoad(property, receiver); builder()->StoreAccumulatorInRegister(callee); break; } case Call::KEYED_SUPER_PROPERTY_CALL: { + Register receiver = register_allocator()->GrowRegisterList(&args); Property* property = callee_expr->AsProperty(); VisitKeyedSuperPropertyLoad(property, receiver); builder()->StoreAccumulatorInRegister(callee); @@ -2414,12 +2436,12 @@ void BytecodeGenerator::VisitCall(Call* expr) { // Evaluate all arguments to the function call and store in sequential args // registers. - VisitArguments(expr->arguments(), args, 1); + VisitArguments(expr->arguments(), &args); + CHECK_EQ(expr->arguments()->length() + 1, args.register_count()); // Resolve callee for a potential direct eval call. This block will mutate the // callee value. - if (call_type == Call::POSSIBLY_EVAL_CALL && - expr->arguments()->length() > 0) { + if (expr->is_possibly_eval() && expr->arguments()->length() > 0) { RegisterAllocationScope inner_register_scope(this); // Set up arguments for ResolvePossiblyDirectEval by copying callee, source // strings and function closure, and loading language and @@ -2445,18 +2467,9 @@ void BytecodeGenerator::VisitCall(Call* expr) { builder()->SetExpressionPosition(expr); - int feedback_slot_index; - if (expr->CallFeedbackICSlot().IsInvalid()) { - DCHECK(call_type == Call::POSSIBLY_EVAL_CALL); - // Valid type feedback slots can only be greater than kReservedIndexCount. - // We use 0 to indicate an invalid slot id. Statically assert that 0 cannot - // be a valid slot id. - STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0); - feedback_slot_index = 0; - } else { - feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); - } - builder()->Call(callee, args, feedback_slot_index, expr->tail_call_mode()); + int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); + builder()->Call(callee, args, feedback_slot_index, call_type, + expr->tail_call_mode()); } void BytecodeGenerator::VisitCallSuper(Call* expr) { @@ -2470,9 +2483,8 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) { Register constructor = this_function; // Re-use dead this_function register. builder()->StoreAccumulatorInRegister(constructor); - RegisterList args = - register_allocator()->NewRegisterList(expr->arguments()->length()); - VisitArguments(expr->arguments(), args); + RegisterList args = register_allocator()->NewGrowableRegisterList(); + VisitArguments(expr->arguments(), &args); // The new target is loaded into the accumulator from the // {new.target} variable. @@ -2480,20 +2492,20 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) { // Call construct. builder()->SetExpressionPosition(expr); - // Valid type feedback slots can only be greater than kReservedIndexCount. - // Assert that 0 cannot be valid a valid slot id. - STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0); - // Type feedback is not necessary for super constructor calls. The type - // information can be inferred in most cases. Slot id 0 indicates type - // feedback is not required. - builder()->New(constructor, args, 0); + // TODO(turbofan): For now we do gather feedback on super constructor + // calls, utilizing the existing machinery to inline the actual call + // target and the JSCreate for the implicit receiver allocation. This + // is not an ideal solution for super constructor calls, but it gets + // the job done for now. In the long run we might want to revisit this + // and come up with a better way. + int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); + builder()->New(constructor, args, feedback_slot_index); } void BytecodeGenerator::VisitCallNew(CallNew* expr) { Register constructor = VisitForRegisterValue(expr->expression()); - RegisterList args = - register_allocator()->NewRegisterList(expr->arguments()->length()); - VisitArguments(expr->arguments(), args); + RegisterList args = register_allocator()->NewGrowableRegisterList(); + VisitArguments(expr->arguments(), &args); builder()->SetExpressionPosition(expr); // The accumulator holds new target which is the same as the @@ -2505,18 +2517,15 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) { void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { if (expr->is_jsruntime()) { + RegisterList args = register_allocator()->NewGrowableRegisterList(); // Allocate a register for the receiver and load it with undefined. - RegisterList args = - register_allocator()->NewRegisterList(expr->arguments()->length() + 1); - Register receiver = args[0]; - builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); - VisitArguments(expr->arguments(), args, 1); + BuildPushUndefinedIntoRegisterList(&args); + VisitArguments(expr->arguments(), &args); builder()->CallJSRuntime(expr->context_index(), args); } else { // Evaluate all arguments to the runtime call. - RegisterList args = - register_allocator()->NewRegisterList(expr->arguments()->length()); - VisitArguments(expr->arguments(), args); + RegisterList args = register_allocator()->NewGrowableRegisterList(); + VisitArguments(expr->arguments(), &args); Runtime::FunctionId function_id = expr->function()->function_id; builder()->CallRuntime(function_id, args); } @@ -2532,8 +2541,9 @@ void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) { // Typeof does not throw a reference error on global variables, hence we // perform a non-contextual load in case the operand is a variable proxy. VariableProxy* proxy = expr->expression()->AsVariableProxy(); - VisitVariableLoadForAccumulatorValue( - proxy->var(), proxy->VariableFeedbackSlot(), INSIDE_TYPEOF); + BuildVariableLoadForAccumulatorValue( + proxy->var(), proxy->VariableFeedbackSlot(), proxy->hole_check_mode(), + INSIDE_TYPEOF); } else { VisitForAccumulatorValue(expr->expression()); } @@ -2657,8 +2667,9 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { switch (assign_type) { case VARIABLE: { VariableProxy* proxy = expr->expression()->AsVariableProxy(); - VisitVariableLoadForAccumulatorValue(proxy->var(), - proxy->VariableFeedbackSlot()); + BuildVariableLoadForAccumulatorValue(proxy->var(), + proxy->VariableFeedbackSlot(), + proxy->hole_check_mode()); break; } case NAMED_PROPERTY: { @@ -2709,7 +2720,9 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { if (is_postfix) { // Convert old value into a number before saving it. old_value = register_allocator()->NewRegister(); - builder()->ConvertAccumulatorToNumber(old_value); + builder() + ->ConvertAccumulatorToNumber(old_value) + .LoadAccumulatorWithRegister(old_value); } // Perform +1/-1 operation. @@ -2721,8 +2734,9 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { FeedbackVectorSlot feedback_slot = expr->CountSlot(); switch (assign_type) { case VARIABLE: { - Variable* variable = expr->expression()->AsVariableProxy()->var(); - VisitVariableAssignment(variable, expr->op(), feedback_slot); + VariableProxy* proxy = expr->expression()->AsVariableProxy(); + BuildVariableAssignment(proxy->var(), expr->op(), feedback_slot, + proxy->hole_check_mode()); break; } case NAMED_PROPERTY: { @@ -2821,7 +2835,7 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { if (execution_result()->IsTest()) { TestResultScope* test_result = execution_result()->AsTest(); - if (left->ToBooleanIsTrue() || right->ToBooleanIsTrue()) { + if (left->ToBooleanIsTrue()) { builder()->Jump(test_result->NewThenLabel()); } else if (left->ToBooleanIsFalse() && right->ToBooleanIsFalse()) { builder()->Jump(test_result->NewElseLabel()); @@ -2856,7 +2870,7 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { if (execution_result()->IsTest()) { TestResultScope* test_result = execution_result()->AsTest(); - if (left->ToBooleanIsFalse() || right->ToBooleanIsFalse()) { + if (left->ToBooleanIsFalse()) { builder()->Jump(test_result->NewElseLabel()); } else if (left->ToBooleanIsTrue() && right->ToBooleanIsTrue()) { builder()->Jump(test_result->NewThenLabel()); @@ -3019,8 +3033,9 @@ void BytecodeGenerator::VisitArgumentsObject(Variable* variable) { ? CreateArgumentsType::kUnmappedArguments : CreateArgumentsType::kMappedArguments; builder()->CreateArguments(type); - VisitVariableAssignment(variable, Token::ASSIGN, - FeedbackVectorSlot::Invalid()); + BuildVariableAssignment(variable, Token::ASSIGN, + FeedbackVectorSlot::Invalid(), + HoleCheckMode::kElided); } void BytecodeGenerator::VisitRestArgumentsArray(Variable* rest) { @@ -3030,7 +3045,8 @@ void BytecodeGenerator::VisitRestArgumentsArray(Variable* rest) { // variable. builder()->CreateArguments(CreateArgumentsType::kRestParameter); DCHECK(rest->IsContextSlot() || rest->IsStackAllocated()); - VisitVariableAssignment(rest, Token::ASSIGN, FeedbackVectorSlot::Invalid()); + BuildVariableAssignment(rest, Token::ASSIGN, FeedbackVectorSlot::Invalid(), + HoleCheckMode::kElided); } void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) { @@ -3038,7 +3054,8 @@ void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) { // Store the closure we were called with in the given variable. builder()->LoadAccumulatorWithRegister(Register::function_closure()); - VisitVariableAssignment(variable, Token::INIT, FeedbackVectorSlot::Invalid()); + BuildVariableAssignment(variable, Token::INIT, FeedbackVectorSlot::Invalid(), + HoleCheckMode::kElided); } void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) { @@ -3046,7 +3063,8 @@ void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) { // Store the new target we were called with in the given variable. builder()->LoadAccumulatorWithRegister(Register::new_target()); - VisitVariableAssignment(variable, Token::INIT, FeedbackVectorSlot::Invalid()); + BuildVariableAssignment(variable, Token::INIT, FeedbackVectorSlot::Invalid(), + HoleCheckMode::kElided); // TODO(mstarzinger): The <new.target> register is not set by the deoptimizer // and we need to make sure {BytecodeRegisterOptimizer} flushes its state @@ -3120,6 +3138,28 @@ void BytecodeGenerator::VisitForRegisterValue(Expression* expr, builder()->StoreAccumulatorInRegister(destination); } +// Visits the expression |expr| and pushes the result into a new register +// added to the end of |reg_list|. +void BytecodeGenerator::VisitAndPushIntoRegisterList(Expression* expr, + RegisterList* reg_list) { + { + ValueResultScope register_scope(this); + Visit(expr); + } + // Grow the register list after visiting the expression to avoid reserving + // the register across the expression evaluation, which could cause memory + // leaks for deep expressions due to dead objects being kept alive by pointers + // in registers. + Register destination = register_allocator()->GrowRegisterList(reg_list); + builder()->StoreAccumulatorInRegister(destination); +} + +void BytecodeGenerator::BuildPushUndefinedIntoRegisterList( + RegisterList* reg_list) { + Register reg = register_allocator()->GrowRegisterList(reg_list); + builder()->LoadUndefined().StoreAccumulatorInRegister(reg); +} + // Visits the expression |expr| for testing its boolean value and jumping to the // |then| or |other| label depending on value and short-circuit semantics void BytecodeGenerator::VisitForTest(Expression* expr, |