aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/interpreter/bytecode-generator.cc
diff options
context:
space:
mode:
authorMichaƫl Zasso <targos@protonmail.com>2018-01-24 20:16:06 +0100
committerMyles Borins <mylesborins@google.com>2018-01-24 15:02:20 -0800
commit4c4af643e5042d615a60c6bbc05aee9d81b903e5 (patch)
tree3fb0a97988fe4439ae3ae06f26915d1dcf8cab92 /deps/v8/src/interpreter/bytecode-generator.cc
parentfa9f31a4fda5a3782c652e56e394465805ebb50f (diff)
downloadandroid-node-v8-4c4af643e5042d615a60c6bbc05aee9d81b903e5.tar.gz
android-node-v8-4c4af643e5042d615a60c6bbc05aee9d81b903e5.tar.bz2
android-node-v8-4c4af643e5042d615a60c6bbc05aee9d81b903e5.zip
deps: update V8 to 6.4.388.40
PR-URL: https://github.com/nodejs/node/pull/17489 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Myles Borins <myles.borins@gmail.com> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Diffstat (limited to 'deps/v8/src/interpreter/bytecode-generator.cc')
-rw-r--r--deps/v8/src/interpreter/bytecode-generator.cc1070
1 files changed, 748 insertions, 322 deletions
diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc
index ac5367b7e5..45f0d1eca9 100644
--- a/deps/v8/src/interpreter/bytecode-generator.cc
+++ b/deps/v8/src/interpreter/bytecode-generator.cc
@@ -4,6 +4,7 @@
#include "src/interpreter/bytecode-generator.h"
+#include "src/api.h"
#include "src/ast/ast-source-ranges.h"
#include "src/ast/compile-time-value.h"
#include "src/ast/scopes.h"
@@ -18,6 +19,7 @@
#include "src/interpreter/control-flow-builders.h"
#include "src/objects-inl.h"
#include "src/objects/debug-objects.h"
+#include "src/objects/literal-objects-inl.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/token.h"
@@ -494,6 +496,31 @@ class BytecodeGenerator::ControlScopeForTryFinally final
DeferredCommands* commands_;
};
+// Allocate and fetch the coverage indices tracking NaryLogical Expressions.
+class BytecodeGenerator::NaryCodeCoverageSlots {
+ public:
+ NaryCodeCoverageSlots(BytecodeGenerator* generator, NaryOperation* expr)
+ : generator_(generator) {
+ if (generator_->block_coverage_builder_ == nullptr) return;
+ for (size_t i = 0; i < expr->subsequent_length(); i++) {
+ coverage_slots_.push_back(
+ generator_->AllocateNaryBlockCoverageSlotIfEnabled(expr, i));
+ }
+ }
+
+ int GetSlotFor(size_t subsequent_expr_index) const {
+ if (generator_->block_coverage_builder_ == nullptr) {
+ return BlockCoverageBuilder::kNoCoverageArraySlot;
+ }
+ DCHECK(coverage_slots_.size() > subsequent_expr_index);
+ return coverage_slots_[subsequent_expr_index];
+ }
+
+ private:
+ BytecodeGenerator* generator_;
+ std::vector<int> coverage_slots_;
+};
+
void BytecodeGenerator::ControlScope::PerformCommand(Command command,
Statement* statement,
int source_position) {
@@ -562,7 +589,7 @@ class BytecodeGenerator::ExpressionResultScope {
// Specify expression always returns a Boolean result value.
void SetResultIsBoolean() {
- DCHECK(type_hint_ == TypeHint::kAny);
+ DCHECK_EQ(type_hint_, TypeHint::kAny);
type_hint_ = TypeHint::kBoolean;
}
@@ -679,19 +706,19 @@ class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject {
}
Handle<FixedArray> AllocateDeclarations(CompilationInfo* info,
- Handle<Script> script) {
+ Handle<Script> script,
+ Isolate* isolate) {
DCHECK(has_constant_pool_entry_);
int array_index = 0;
- Handle<FixedArray> data = info->isolate()->factory()->NewFixedArray(
+ Handle<FixedArray> data = isolate->factory()->NewFixedArray(
static_cast<int>(declarations_.size() * 4), TENURED);
for (const Declaration& declaration : declarations_) {
FunctionLiteral* func = declaration.func;
Handle<Object> initial_value;
if (func == nullptr) {
- initial_value = info->isolate()->factory()->undefined_value();
+ initial_value = isolate->factory()->undefined_value();
} else {
- initial_value =
- Compiler::GetSharedFunctionInfo(func, script, info->isolate());
+ initial_value = Compiler::GetSharedFunctionInfo(func, script, isolate);
}
// Return a null handle if any initial values can't be created. Caller
@@ -702,7 +729,7 @@ class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject {
data->set(array_index++, Smi::FromInt(declaration.slot.ToInt()));
Object* undefined_or_literal_slot;
if (declaration.literal_slot.IsInvalid()) {
- undefined_or_literal_slot = info->isolate()->heap()->undefined_value();
+ undefined_or_literal_slot = isolate->heap()->undefined_value();
} else {
undefined_or_literal_slot =
Smi::FromInt(declaration.literal_slot.ToInt());
@@ -770,24 +797,64 @@ class BytecodeGenerator::CurrentScope final {
Scope* outer_scope_;
};
-BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
+class BytecodeGenerator::FeedbackSlotCache : public ZoneObject {
+ public:
+ typedef std::pair<TypeofMode, void*> Key;
+
+ explicit FeedbackSlotCache(Zone* zone) : map_(zone) {}
+
+ void Put(TypeofMode typeof_mode, Variable* variable, FeedbackSlot slot) {
+ Key key = std::make_pair(typeof_mode, variable);
+ auto entry = std::make_pair(key, slot);
+ map_.insert(entry);
+ }
+ void Put(AstNode* node, FeedbackSlot slot) {
+ Key key = std::make_pair(NOT_INSIDE_TYPEOF, node);
+ auto entry = std::make_pair(key, slot);
+ map_.insert(entry);
+ }
+
+ FeedbackSlot Get(TypeofMode typeof_mode, Variable* variable) const {
+ Key key = std::make_pair(typeof_mode, variable);
+ auto iter = map_.find(key);
+ if (iter != map_.end()) {
+ return iter->second;
+ }
+ return FeedbackSlot();
+ }
+ FeedbackSlot Get(AstNode* node) const {
+ Key key = std::make_pair(NOT_INSIDE_TYPEOF, node);
+ auto iter = map_.find(key);
+ if (iter != map_.end()) {
+ return iter->second;
+ }
+ return FeedbackSlot();
+ }
+
+ private:
+ ZoneMap<Key, FeedbackSlot> map_;
+};
+
+BytecodeGenerator::BytecodeGenerator(
+ CompilationInfo* info, const AstStringConstants* ast_string_constants)
: zone_(info->zone()),
- builder_(new (zone()) BytecodeArrayBuilder(
- info->isolate(), info->zone(), info->num_parameters_including_this(),
- info->scope()->num_stack_slots(), info->literal(),
- info->SourcePositionRecordingMode())),
+ builder_(zone(), info->num_parameters_including_this(),
+ info->scope()->num_stack_slots(), info->feedback_vector_spec(),
+ info->SourcePositionRecordingMode()),
info_(info),
- ast_string_constants_(info->isolate()->ast_string_constants()),
+ ast_string_constants_(ast_string_constants),
closure_scope_(info->scope()),
current_scope_(info->scope()),
- globals_builder_(new (zone()) GlobalDeclarationsBuilder(info->zone())),
+ feedback_slot_cache_(new (zone()) FeedbackSlotCache(zone())),
+ globals_builder_(new (zone()) GlobalDeclarationsBuilder(zone())),
block_coverage_builder_(nullptr),
- global_declarations_(0, info->zone()),
- function_literals_(0, info->zone()),
- native_function_literals_(0, info->zone()),
- object_literals_(0, info->zone()),
- array_literals_(0, info->zone()),
- template_objects_(0, info->zone()),
+ global_declarations_(0, zone()),
+ function_literals_(0, zone()),
+ native_function_literals_(0, zone()),
+ object_literals_(0, zone()),
+ array_literals_(0, zone()),
+ class_literals_(0, zone()),
+ template_objects_(0, zone()),
execution_control_(nullptr),
execution_context_(nullptr),
execution_result_(nullptr),
@@ -833,7 +900,7 @@ void BytecodeGenerator::AllocateDeferredConstants(Isolate* isolate,
// Build global declaration pair arrays.
for (GlobalDeclarationsBuilder* globals_builder : global_declarations_) {
Handle<FixedArray> declarations =
- globals_builder->AllocateDeclarations(info(), script);
+ globals_builder->AllocateDeclarations(info(), script, isolate);
if (declarations.is_null()) return SetStackOverflow();
builder()->SetDeferredConstantPoolEntry(
globals_builder->constant_pool_entry(), declarations);
@@ -852,10 +919,18 @@ void BytecodeGenerator::AllocateDeferredConstants(Isolate* isolate,
for (std::pair<NativeFunctionLiteral*, size_t> literal :
native_function_literals_) {
NativeFunctionLiteral* expr = literal.first;
+ v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
+
+ // Compute the function template for the native function.
+ v8::Local<v8::FunctionTemplate> info =
+ expr->extension()->GetNativeFunctionTemplate(
+ v8_isolate, Utils::ToLocal(expr->name()));
+ DCHECK(!info.IsEmpty());
+
Handle<SharedFunctionInfo> shared_info =
- Compiler::GetSharedFunctionInfoForNative(expr->extension(),
- expr->name());
- if (shared_info.is_null()) return SetStackOverflow();
+ FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
+ isolate, Utils::OpenHandle(*info), expr->name());
+ DCHECK(!shared_info.is_null());
builder()->SetDeferredConstantPoolEntry(literal.second, shared_info);
}
@@ -881,6 +956,14 @@ void BytecodeGenerator::AllocateDeferredConstants(Isolate* isolate,
builder()->SetDeferredConstantPoolEntry(literal.second, constant_elements);
}
+ // Build class literal boilerplates.
+ for (std::pair<ClassLiteral*, size_t> literal : class_literals_) {
+ ClassLiteral* class_literal = literal.first;
+ Handle<ClassBoilerplate> class_boilerplate =
+ ClassBoilerplate::BuildClassBoilerplate(isolate, class_literal);
+ builder()->SetDeferredConstantPoolEntry(literal.second, class_boilerplate);
+ }
+
// Build template literals.
for (std::pair<GetTemplateObject*, size_t> literal : template_objects_) {
GetTemplateObject* get_template_object = literal.first;
@@ -933,7 +1016,9 @@ void BytecodeGenerator::GenerateBytecodeBody() {
Variable* rest_parameter = closure_scope()->rest_parameter();
VisitRestArgumentsArray(rest_parameter);
- // Build assignment to {.this_function} variable if it is used.
+ // Build assignment to the function name or {.this_function}
+ // variables if used.
+ VisitThisFunctionVariable(closure_scope()->function_var());
VisitThisFunctionVariable(closure_scope()->this_function_var());
// Build assignment to {new.target} variable if it is used.
@@ -949,7 +1034,8 @@ void BytecodeGenerator::GenerateBytecodeBody() {
if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter);
// Emit type profile call.
- if (info()->literal()->feedback_vector_spec()->HasTypeProfileSlot()) {
+ if (info()->collect_type_profile()) {
+ feedback_spec()->AddTypeProfileSlot();
int num_parameters = closure_scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Register parameter(builder()->Parameter(i));
@@ -967,6 +1053,13 @@ void BytecodeGenerator::GenerateBytecodeBody() {
// Perform a stack-check before the body.
builder()->StackCheck(info()->literal()->start_position());
+ // The derived constructor case is handled in VisitCallSuper.
+ if (IsBaseConstructor(function_kind()) &&
+ info()->literal()->requires_instance_fields_initializer()) {
+ BuildInstanceFieldInitialization(Register::function_closure(),
+ builder()->Receiver());
+ }
+
// Visit statements in the function body.
VisitStatements(info()->literal()->body());
@@ -1107,7 +1200,8 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
switch (variable->location()) {
case VariableLocation::UNALLOCATED: {
DCHECK(!variable->binding_needs_init());
- FeedbackSlot slot = decl->proxy()->VariableFeedbackSlot();
+ FeedbackSlot slot =
+ GetCachedLoadGlobalICSlot(NOT_INSIDE_TYPEOF, variable);
globals_builder()->AddUndefinedDeclaration(variable->raw_name(), slot);
break;
}
@@ -1145,8 +1239,7 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
case VariableLocation::MODULE:
if (variable->IsExport() && variable->binding_needs_init()) {
builder()->LoadTheHole();
- BuildVariableAssignment(variable, Token::INIT, FeedbackSlot::Invalid(),
- HoleCheckMode::kElided);
+ BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
}
// Nothing to do for imports.
break;
@@ -1158,17 +1251,17 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
DCHECK(variable->mode() == LET || variable->mode() == VAR);
switch (variable->location()) {
case VariableLocation::UNALLOCATED: {
- FeedbackSlot slot = decl->proxy()->VariableFeedbackSlot();
- globals_builder()->AddFunctionDeclaration(
- variable->raw_name(), slot, decl->fun()->LiteralFeedbackSlot(),
- decl->fun());
+ FeedbackSlot slot =
+ GetCachedLoadGlobalICSlot(NOT_INSIDE_TYPEOF, variable);
+ FeedbackSlot literal_slot = GetCachedCreateClosureSlot(decl->fun());
+ globals_builder()->AddFunctionDeclaration(variable->raw_name(), slot,
+ literal_slot, decl->fun());
break;
}
case VariableLocation::PARAMETER:
case VariableLocation::LOCAL: {
VisitForAccumulatorValue(decl->fun());
- BuildVariableAssignment(variable, Token::INIT, FeedbackSlot::Invalid(),
- HoleCheckMode::kElided);
+ BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
break;
}
case VariableLocation::CONTEXT: {
@@ -1192,8 +1285,7 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
DCHECK_EQ(variable->mode(), LET);
DCHECK(variable->IsExport());
VisitForAccumulatorValue(decl->fun());
- BuildVariableAssignment(variable, Token::INIT, FeedbackSlot::Invalid(),
- HoleCheckMode::kElided);
+ BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
break;
}
}
@@ -1212,8 +1304,7 @@ void BytecodeGenerator::VisitModuleNamespaceImports() {
.CallRuntime(Runtime::kGetModuleNamespace, module_request);
Variable* var = closure_scope()->LookupLocal(entry->local_name);
DCHECK_NOT_NULL(var);
- BuildVariableAssignment(var, Token::INIT, FeedbackSlot::Invalid(),
- HoleCheckMode::kElided);
+ BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kElided);
}
}
@@ -1344,6 +1435,9 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
// Keep the switch value in a register until a case matches.
Register tag = VisitForRegisterValue(stmt->tag());
+ FeedbackSlot slot = clauses->length() > 0
+ ? feedback_spec()->AddCompareICSlot()
+ : FeedbackSlot::Invalid();
// Iterate over all cases and create nodes for label comparison.
for (int i = 0; i < clauses->length(); i++) {
@@ -1357,9 +1451,8 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
// Perform label comparison as if via '===' with tag.
VisitForAccumulatorValue(clause->label());
- builder()->CompareOperation(
- Token::Value::EQ_STRICT, tag,
- feedback_index(clause->CompareOperationFeedbackSlot()));
+ builder()->CompareOperation(Token::Value::EQ_STRICT, tag,
+ feedback_index(slot));
switch_builder.Case(ToBooleanMode::kAlreadyBoolean, i);
}
@@ -1457,8 +1550,7 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
loop_builder.JumpToHeader(loop_depth_);
}
-void BytecodeGenerator::VisitForInAssignment(Expression* expr,
- FeedbackSlot slot) {
+void BytecodeGenerator::VisitForInAssignment(Expression* expr) {
DCHECK(expr->IsValidReferenceExpression());
// Evaluate assignment starting with the value to be stored in the
@@ -1468,7 +1560,7 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr,
switch (assign_type) {
case VARIABLE: {
VariableProxy* proxy = expr->AsVariableProxy();
- BuildVariableAssignment(proxy->var(), Token::ASSIGN, slot,
+ BuildVariableAssignment(proxy->var(), Token::ASSIGN,
proxy->hole_check_mode());
break;
}
@@ -1480,8 +1572,10 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr,
const AstRawString* name =
property->key()->AsLiteral()->AsRawPropertyName();
builder()->LoadAccumulatorWithRegister(value);
+ FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
builder()->StoreNamedProperty(object, name, feedback_index(slot),
language_mode());
+ builder()->LoadAccumulatorWithRegister(value);
break;
}
case KEYED_PROPERTY: {
@@ -1491,8 +1585,10 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr,
Register object = VisitForRegisterValue(property->obj());
Register key = VisitForRegisterValue(property->key());
builder()->LoadAccumulatorWithRegister(value);
+ FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
builder()->StoreKeyedProperty(object, key, feedback_index(slot),
language_mode());
+ builder()->LoadAccumulatorWithRegister(value);
break;
}
case NAMED_SUPER_PROPERTY: {
@@ -1532,7 +1628,7 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
}
BytecodeLabel subject_null_label, subject_undefined_label;
- FeedbackSlot slot = stmt->ForInFeedbackSlot();
+ FeedbackSlot slot = feedback_spec()->AddForInSlot();
// Prepare the state for executing ForIn.
builder()->SetExpressionAsStatementPosition(stmt->subject());
@@ -1563,7 +1659,7 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
builder()->ForInNext(receiver, index, triple.Truncate(2),
feedback_index(slot));
loop_builder.ContinueIfUndefined();
- VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot());
+ VisitForInAssignment(stmt->each());
VisitIterationBody(stmt, &loop_builder);
builder()->ForInStep(index);
builder()->StoreAccumulatorInRegister(index);
@@ -1597,7 +1693,8 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
HandlerTable::CatchPrediction outer_catch_prediction = catch_prediction();
set_catch_prediction(stmt->GetCatchPrediction(outer_catch_prediction));
- TryCatchBuilder try_control_builder(builder(), catch_prediction());
+ TryCatchBuilder try_control_builder(builder(), block_coverage_builder_, stmt,
+ catch_prediction());
// Preserve the context in a dedicated register, so that it can be restored
// when the handler is entered by the stack-unwinding machinery.
@@ -1628,17 +1725,15 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
builder()->LoadAccumulatorWithRegister(context);
// Evaluate the catch-block.
- BuildIncrementBlockCoverageCounterIfEnabled(stmt, SourceRangeKind::kCatch);
VisitInScope(stmt->catch_block(), stmt->scope());
try_control_builder.EndCatch();
- BuildIncrementBlockCoverageCounterIfEnabled(stmt,
- SourceRangeKind::kContinuation);
}
void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
// We can't know whether the finally block will override ("catch") an
// exception thrown in the try block, so we just adopt the outer prediction.
- TryFinallyBuilder try_control_builder(builder(), catch_prediction());
+ TryFinallyBuilder try_control_builder(builder(), block_coverage_builder_,
+ stmt, catch_prediction());
// We keep a record of all paths that enter the finally-block to be able to
// dispatch to the correct continuation point after the statements in the
@@ -1689,7 +1784,6 @@ void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
message);
// Evaluate the finally-block.
- BuildIncrementBlockCoverageCounterIfEnabled(stmt, SourceRangeKind::kFinally);
Visit(stmt->finally_block());
try_control_builder.EndFinally();
@@ -1698,8 +1792,6 @@ void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
// Dynamic dispatch after the finally-block.
commands.ApplyDeferredCommands();
- BuildIncrementBlockCoverageCounterIfEnabled(stmt,
- SourceRangeKind::kContinuation);
}
void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
@@ -1708,50 +1800,133 @@ void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
}
void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
- DCHECK_EQ(expr->scope()->outer_scope(), current_scope());
+ DCHECK(expr->scope()->outer_scope() == current_scope());
uint8_t flags = CreateClosureFlags::Encode(
expr->pretenure(), closure_scope()->is_function_scope());
size_t entry = builder()->AllocateDeferredConstantPoolEntry();
- int slot_index = feedback_index(expr->LiteralFeedbackSlot());
- builder()->CreateClosure(entry, slot_index, flags);
+ FeedbackSlot slot = GetCachedCreateClosureSlot(expr);
+ builder()->CreateClosure(entry, feedback_index(slot), flags);
function_literals_.push_back(std::make_pair(expr, entry));
}
void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr) {
+ size_t class_boilerplate_entry =
+ builder()->AllocateDeferredConstantPoolEntry();
+ class_literals_.push_back(std::make_pair(expr, class_boilerplate_entry));
+
VisitDeclarations(expr->scope()->declarations());
- Register constructor = VisitForRegisterValue(expr->constructor());
+ Register class_constructor = register_allocator()->NewRegister();
+
{
RegisterAllocationScope register_scope(this);
- RegisterList args = register_allocator()->NewRegisterList(4);
+ RegisterList args = register_allocator()->NewGrowableRegisterList();
+
+ Register class_boilerplate = register_allocator()->GrowRegisterList(&args);
+ Register class_constructor_in_args =
+ register_allocator()->GrowRegisterList(&args);
+ Register super_class = register_allocator()->GrowRegisterList(&args);
+ DCHECK_EQ(ClassBoilerplate::kFirstDynamicArgumentIndex,
+ args.register_count());
+
VisitForAccumulatorValueOrTheHole(expr->extends());
+ builder()->StoreAccumulatorInRegister(super_class);
+
+ VisitFunctionLiteral(expr->constructor());
builder()
- ->StoreAccumulatorInRegister(args[0])
- .MoveRegister(constructor, args[1])
- .LoadLiteral(Smi::FromInt(expr->start_position()))
- .StoreAccumulatorInRegister(args[2])
- .LoadLiteral(Smi::FromInt(expr->end_position()))
- .StoreAccumulatorInRegister(args[3])
- .CallRuntime(Runtime::kDefineClass, args);
+ ->StoreAccumulatorInRegister(class_constructor)
+ .MoveRegister(class_constructor, class_constructor_in_args)
+ .LoadConstantPoolEntry(class_boilerplate_entry)
+ .StoreAccumulatorInRegister(class_boilerplate);
+
+ // Create computed names and method values nodes to store into the literal.
+ for (int i = 0; i < expr->properties()->length(); i++) {
+ ClassLiteral::Property* property = expr->properties()->at(i);
+ if (property->is_computed_name()) {
+ Register key = register_allocator()->GrowRegisterList(&args);
+
+ BuildLoadPropertyKey(property, key);
+ if (property->is_static()) {
+ // The static prototype property is read only. We handle the non
+ // computed property name case in the parser. Since this is the only
+ // case where we need to check for an own read only property we
+ // special case this so we do not need to do this for every property.
+ BytecodeLabel done;
+ builder()
+ ->LoadLiteral(ast_string_constants()->prototype_string())
+ .CompareOperation(Token::Value::EQ_STRICT, key)
+ .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done)
+ .CallRuntime(Runtime::kThrowStaticPrototypeError)
+ .Bind(&done);
+ }
+
+ if (property->kind() == ClassLiteral::Property::FIELD) {
+ // Initialize field's name variable with the computed name.
+ DCHECK_NOT_NULL(property->computed_name_var());
+ builder()->LoadAccumulatorWithRegister(key);
+ BuildVariableAssignment(property->computed_name_var(), Token::INIT,
+ HoleCheckMode::kElided);
+ }
+ }
+ if (property->kind() == ClassLiteral::Property::FIELD) {
+ // We don't compute field's value here, but instead do it in the
+ // initializer function.
+ continue;
+ }
+ Register value = register_allocator()->GrowRegisterList(&args);
+ VisitForRegisterValue(property->value(), value);
+ }
+
+ builder()->CallRuntime(Runtime::kDefineClass, args);
}
Register prototype = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(prototype);
- if (FunctionLiteral::NeedsHomeObject(expr->constructor())) {
- // Prototype is already in the accumulator.
- builder()->StoreHomeObjectProperty(
- constructor, feedback_index(expr->HomeObjectSlot()), language_mode());
- }
-
- VisitClassLiteralProperties(expr, constructor, prototype);
- BuildClassLiteralNameProperty(expr, constructor);
- builder()->CallRuntime(Runtime::kToFastProperties, constructor);
// Assign to class variable.
if (expr->class_variable() != nullptr) {
DCHECK(expr->class_variable()->IsStackLocal() ||
expr->class_variable()->IsContextSlot());
+ builder()->LoadAccumulatorWithRegister(class_constructor);
BuildVariableAssignment(expr->class_variable(), Token::INIT,
- FeedbackSlot::Invalid(), HoleCheckMode::kElided);
+ HoleCheckMode::kElided);
+ }
+
+ if (expr->instance_fields_initializer_function() != nullptr) {
+ Register initializer =
+ VisitForRegisterValue(expr->instance_fields_initializer_function());
+
+ if (FunctionLiteral::NeedsHomeObject(
+ expr->instance_fields_initializer_function())) {
+ FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
+ builder()->LoadAccumulatorWithRegister(prototype).StoreHomeObjectProperty(
+ initializer, feedback_index(slot), language_mode());
+ }
+
+ FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
+ builder()
+ ->LoadAccumulatorWithRegister(initializer)
+ .StoreClassFieldsInitializer(class_constructor, feedback_index(slot))
+ .LoadAccumulatorWithRegister(class_constructor);
+ }
+
+ if (expr->static_fields_initializer() != nullptr) {
+ RegisterList args = register_allocator()->NewRegisterList(1);
+ Register initializer =
+ VisitForRegisterValue(expr->static_fields_initializer());
+
+ if (FunctionLiteral::NeedsHomeObject(expr->static_fields_initializer())) {
+ FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
+ builder()
+ ->LoadAccumulatorWithRegister(class_constructor)
+ .StoreHomeObjectProperty(initializer, feedback_index(slot),
+ language_mode());
+ }
+
+ builder()
+ ->MoveRegister(class_constructor, args[0])
+ .CallProperty(initializer, args,
+ feedback_index(feedback_spec()->AddCallICSlot()));
}
+ builder()->LoadAccumulatorWithRegister(class_constructor);
}
void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
@@ -1766,101 +1941,59 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
}
}
-void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr,
- Register constructor,
- Register prototype) {
- RegisterAllocationScope register_scope(this);
- RegisterList args = register_allocator()->NewRegisterList(4);
- Register receiver = args[0], key = args[1], value = args[2], attr = args[3];
-
- bool attr_assigned = false;
- Register old_receiver = Register::invalid_value();
-
- // Create nodes to store method values into the literal.
- for (int i = 0; i < expr->properties()->length(); i++) {
- ClassLiteral::Property* property = expr->properties()->at(i);
-
- // Set-up receiver.
- Register new_receiver = property->is_static() ? constructor : prototype;
- if (new_receiver != old_receiver) {
- builder()->MoveRegister(new_receiver, receiver);
- old_receiver = new_receiver;
- }
-
- BuildLoadPropertyKey(property, key);
- if (property->is_static() && property->is_computed_name()) {
- // The static prototype property is read only. We handle the non computed
- // property name case in the parser. Since this is the only case where we
- // need to check for an own read only property we special case this so we
- // do not need to do this for every property.
- BytecodeLabel done;
- builder()
- ->LoadLiteral(ast_string_constants()->prototype_string())
- .CompareOperation(Token::Value::EQ_STRICT, key)
- .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done)
- .CallRuntime(Runtime::kThrowStaticPrototypeError)
- .Bind(&done);
+void BytecodeGenerator::VisitInitializeClassFieldsStatement(
+ InitializeClassFieldsStatement* expr) {
+ RegisterList args = register_allocator()->NewRegisterList(3);
+ Register constructor = args[0], key = args[1], value = args[2];
+ builder()->MoveRegister(builder()->Receiver(), constructor);
+
+ for (int i = 0; i < expr->fields()->length(); i++) {
+ ClassLiteral::Property* property = expr->fields()->at(i);
+
+ if (property->is_computed_name()) {
+ Variable* var = property->computed_name_var();
+ DCHECK_NOT_NULL(var);
+ // The computed name is already evaluated and stored in a
+ // variable at class definition time.
+ BuildVariableLoad(var, HoleCheckMode::kElided);
+ builder()->StoreAccumulatorInRegister(key);
+ } else {
+ BuildLoadPropertyKey(property, key);
}
VisitForRegisterValue(property->value(), value);
- VisitSetHomeObject(value, receiver, property);
-
- if (!attr_assigned) {
- builder()
- ->LoadLiteral(Smi::FromInt(DONT_ENUM))
- .StoreAccumulatorInRegister(attr);
- attr_assigned = true;
- }
-
- switch (property->kind()) {
- case ClassLiteral::Property::METHOD: {
- DataPropertyInLiteralFlags flags = DataPropertyInLiteralFlag::kDontEnum;
- if (property->NeedsSetFunctionName()) {
- flags |= DataPropertyInLiteralFlag::kSetFunctionName;
- }
+ VisitSetHomeObject(value, constructor, property);
- FeedbackSlot slot = property->GetStoreDataPropertySlot();
- DCHECK(!slot.IsInvalid());
-
- builder()
- ->LoadAccumulatorWithRegister(value)
- .StoreDataPropertyInLiteral(receiver, key, flags,
- feedback_index(slot));
- break;
- }
- case ClassLiteral::Property::GETTER: {
- builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked, args);
- break;
- }
- case ClassLiteral::Property::SETTER: {
- builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked, args);
- break;
- }
- case ClassLiteral::Property::FIELD: {
- UNREACHABLE();
- break;
- }
- }
+ builder()->CallRuntime(Runtime::kCreateDataProperty, args);
}
}
-void BytecodeGenerator::BuildClassLiteralNameProperty(ClassLiteral* expr,
- Register literal) {
- if (!expr->has_name_static_property() &&
- expr->constructor()->has_shared_name()) {
- Runtime::FunctionId runtime_id =
- expr->has_static_computed_names()
- ? Runtime::kInstallClassNameAccessorWithCheck
- : Runtime::kInstallClassNameAccessor;
- builder()->CallRuntime(runtime_id, literal);
- }
+void BytecodeGenerator::BuildInstanceFieldInitialization(Register constructor,
+ Register instance) {
+ RegisterList args = register_allocator()->NewRegisterList(1);
+ Register initializer = register_allocator()->NewRegister();
+
+ FeedbackSlot slot = feedback_spec()->AddLoadICSlot();
+ BytecodeLabel done;
+
+ builder()
+ ->LoadClassFieldsInitializer(constructor, feedback_index(slot))
+ // TODO(gsathya): This jump can be elided for the base
+ // constructor and derived constructor. This is only required
+ // when called from an arrow function.
+ .JumpIfUndefined(&done)
+ .StoreAccumulatorInRegister(initializer)
+ .MoveRegister(instance, args[0])
+ .CallProperty(initializer, args,
+ feedback_index(feedback_spec()->AddCallICSlot()))
+ .Bind(&done);
}
void BytecodeGenerator::VisitNativeFunctionLiteral(
NativeFunctionLiteral* expr) {
size_t entry = builder()->AllocateDeferredConstantPoolEntry();
- int slot_index = feedback_index(expr->LiteralFeedbackSlot());
- builder()->CreateClosure(entry, slot_index, NOT_TENURED);
+ FeedbackSlot slot = feedback_spec()->AddCreateClosureSlot();
+ builder()->CreateClosure(entry, feedback_index(slot), NOT_TENURED);
native_function_literals_.push_back(std::make_pair(expr, entry));
}
@@ -1895,19 +2028,44 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) {
}
void BytecodeGenerator::VisitLiteral(Literal* expr) {
- if (!execution_result()->IsEffect()) {
- const AstValue* raw_value = expr->raw_value();
- builder()->LoadLiteral(raw_value);
- if (raw_value->IsTrue() || raw_value->IsFalse()) {
+ if (execution_result()->IsEffect()) return;
+ switch (expr->type()) {
+ case Literal::kSmi:
+ builder()->LoadLiteral(expr->AsSmiLiteral());
+ break;
+ case Literal::kHeapNumber:
+ builder()->LoadLiteral(expr->AsNumber());
+ break;
+ case Literal::kUndefined:
+ builder()->LoadUndefined();
+ break;
+ case Literal::kBoolean:
+ builder()->LoadBoolean(expr->ToBooleanIsTrue());
execution_result()->SetResultIsBoolean();
- }
+ break;
+ case Literal::kNull:
+ builder()->LoadNull();
+ break;
+ case Literal::kTheHole:
+ builder()->LoadTheHole();
+ break;
+ case Literal::kString:
+ builder()->LoadLiteral(expr->AsRawString());
+ break;
+ case Literal::kSymbol:
+ builder()->LoadLiteral(expr->AsSymbol());
+ break;
+ case Literal::kBigInt:
+ builder()->LoadLiteral(expr->AsBigInt());
+ break;
}
}
void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
// Materialize a regular expression literal.
builder()->CreateRegExpLiteral(
- expr->raw_pattern(), feedback_index(expr->literal_slot()), expr->flags());
+ expr->raw_pattern(), feedback_index(feedback_spec()->AddLiteralSlot()),
+ expr->flags());
}
void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
@@ -1919,7 +2077,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
return;
}
- int literal_index = feedback_index(expr->literal_slot());
+ int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
// Deep-copy the literal boilerplate.
uint8_t flags = CreateObjectLiteralFlags::Encode(
expr->ComputeFlags(), expr->IsFastCloningSupported());
@@ -1963,18 +2121,17 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
DCHECK(key->IsPropertyName());
if (property->emit_store()) {
VisitForAccumulatorValue(property->value());
+ FeedbackSlot slot = feedback_spec()->AddStoreOwnICSlot();
if (FunctionLiteral::NeedsHomeObject(property->value())) {
RegisterAllocationScope register_scope(this);
Register value = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(value);
builder()->StoreNamedOwnProperty(
- literal, key->AsRawPropertyName(),
- feedback_index(property->GetSlot(0)));
- VisitSetHomeObject(value, literal, property, 1);
+ literal, key->AsRawPropertyName(), feedback_index(slot));
+ VisitSetHomeObject(value, literal, property);
} else {
builder()->StoreNamedOwnProperty(
- literal, key->AsRawPropertyName(),
- feedback_index(property->GetSlot(0)));
+ literal, key->AsRawPropertyName(), feedback_index(slot));
}
} else {
VisitForEffect(property->value());
@@ -1987,7 +2144,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
VisitForRegisterValue(property->value(), args[2]);
if (property->emit_store()) {
builder()
- ->LoadLiteral(Smi::FromInt(SLOPPY))
+ ->LoadLiteral(Smi::FromEnum(LanguageMode::kSloppy))
.StoreAccumulatorInRegister(args[3])
.CallRuntime(Runtime::kSetProperty, args);
Register value = args[2];
@@ -2076,9 +2233,8 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
data_property_flags |= DataPropertyInLiteralFlag::kSetFunctionName;
}
- FeedbackSlot slot = property->GetStoreDataPropertySlot();
- DCHECK(!slot.IsInvalid());
-
+ FeedbackSlot slot =
+ feedback_spec()->AddStoreDataPropertyInLiteralICSlot();
builder()
->LoadAccumulatorWithRegister(value)
.StoreDataPropertyInLiteral(literal, key, data_property_flags,
@@ -2120,7 +2276,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
// Deep-copy the literal boilerplate.
- int literal_index = feedback_index(expr->literal_slot());
+ int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
if (expr->is_empty()) {
// Empty array literal fast-path.
DCHECK(expr->IsFastCloningSupported());
@@ -2136,9 +2292,13 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
Register index, literal;
+ // We'll reuse the same literal slot for all of the non-constant
+ // subexpressions that use a keyed store IC.
+
// Evaluate all the non-constant subexpressions and store them into the
// newly cloned array.
bool literal_in_accumulator = true;
+ FeedbackSlot slot;
for (int array_index = 0; array_index < expr->values()->length();
array_index++) {
Expression* subexpr = expr->values()->at(array_index);
@@ -2151,8 +2311,10 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
builder()->StoreAccumulatorInRegister(literal);
literal_in_accumulator = false;
}
+ if (slot.IsInvalid()) {
+ slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
+ }
- FeedbackSlot slot = expr->LiteralFeedbackSlot();
builder()
->LoadLiteral(Smi::FromInt(array_index))
.StoreAccumulatorInRegister(index);
@@ -2169,11 +2331,10 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
builder()->SetExpressionPosition(proxy);
- BuildVariableLoad(proxy->var(), proxy->VariableFeedbackSlot(),
- proxy->hole_check_mode());
+ BuildVariableLoad(proxy->var(), proxy->hole_check_mode());
}
-void BytecodeGenerator::BuildVariableLoad(Variable* variable, FeedbackSlot slot,
+void BytecodeGenerator::BuildVariableLoad(Variable* variable,
HoleCheckMode hole_check_mode,
TypeofMode typeof_mode) {
switch (variable->location()) {
@@ -2211,6 +2372,7 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, FeedbackSlot slot,
if (variable->raw_name() == ast_string_constants()->undefined_string()) {
builder()->LoadUndefined();
} else {
+ FeedbackSlot slot = GetCachedLoadGlobalICSlot(typeof_mode, variable);
builder()->LoadGlobal(variable->raw_name(), feedback_index(slot),
typeof_mode);
}
@@ -2254,7 +2416,8 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, FeedbackSlot slot,
}
case DYNAMIC_GLOBAL: {
int depth =
- closure_scope()->ContextChainLengthUntilOutermostSloppyEval();
+ current_scope()->ContextChainLengthUntilOutermostSloppyEval();
+ FeedbackSlot slot = GetCachedLoadGlobalICSlot(typeof_mode, variable);
builder()->LoadLookupGlobalSlot(variable->raw_name(), typeof_mode,
feedback_index(slot), depth);
break;
@@ -2276,10 +2439,9 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, FeedbackSlot slot,
}
void BytecodeGenerator::BuildVariableLoadForAccumulatorValue(
- Variable* variable, FeedbackSlot slot, HoleCheckMode hole_check_mode,
- TypeofMode typeof_mode) {
+ Variable* variable, HoleCheckMode hole_check_mode, TypeofMode typeof_mode) {
ValueResultScope accumulator_result(this);
- BuildVariableLoad(variable, slot, hole_check_mode, typeof_mode);
+ BuildVariableLoad(variable, hole_check_mode, typeof_mode);
}
void BytecodeGenerator::BuildReturn(int source_position) {
@@ -2290,7 +2452,7 @@ void BytecodeGenerator::BuildReturn(int source_position) {
builder()->StoreAccumulatorInRegister(result).CallRuntime(
Runtime::kTraceExit, result);
}
- if (info()->literal()->feedback_vector_spec()->HasTypeProfileSlot()) {
+ if (info()->collect_type_profile()) {
builder()->CollectTypeProfile(info()->literal()->return_position());
}
builder()->SetReturnPosition(source_position, info()->literal());
@@ -2317,8 +2479,7 @@ void BytecodeGenerator::BuildAsyncReturn(int source_position) {
Variable* var_promise = closure_scope()->promise_var();
DCHECK_NOT_NULL(var_promise);
- BuildVariableLoad(var_promise, FeedbackSlot::Invalid(),
- HoleCheckMode::kElided);
+ BuildVariableLoad(var_promise, HoleCheckMode::kElided);
builder()
->StoreAccumulatorInRegister(promise)
.CallJSRuntime(Context::PROMISE_RESOLVE_INDEX, args)
@@ -2355,8 +2516,8 @@ void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable,
}
void BytecodeGenerator::BuildVariableAssignment(
- Variable* variable, Token::Value op, FeedbackSlot slot,
- HoleCheckMode hole_check_mode, LookupHoistingMode lookup_hoisting_mode) {
+ Variable* variable, Token::Value op, HoleCheckMode hole_check_mode,
+ LookupHoistingMode lookup_hoisting_mode) {
VariableMode mode = variable->mode();
RegisterAllocationScope assignment_register_scope(this);
BytecodeLabel end_label;
@@ -2393,6 +2554,9 @@ void BytecodeGenerator::BuildVariableAssignment(
break;
}
case VariableLocation::UNALLOCATED: {
+ // TODO(ishell): consider using FeedbackSlotCache for variables here.
+ FeedbackSlot slot =
+ feedback_spec()->AddStoreGlobalICSlot(language_mode());
builder()->StoreGlobal(variable->raw_name(), feedback_index(slot),
language_mode());
break;
@@ -2518,19 +2682,18 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
switch (assign_type) {
case VARIABLE: {
VariableProxy* proxy = expr->target()->AsVariableProxy();
- BuildVariableLoad(proxy->var(), proxy->VariableFeedbackSlot(),
- proxy->hole_check_mode());
+ BuildVariableLoad(proxy->var(), proxy->hole_check_mode());
break;
}
case NAMED_PROPERTY: {
- FeedbackSlot slot = property->PropertyFeedbackSlot();
+ FeedbackSlot slot = feedback_spec()->AddLoadICSlot();
builder()->LoadNamedProperty(object, name, feedback_index(slot));
break;
}
case KEYED_PROPERTY: {
// Key is already in accumulator at this point due to evaluating the
// LHS above.
- FeedbackSlot slot = property->PropertyFeedbackSlot();
+ FeedbackSlot slot = feedback_spec()->AddKeyedLoadICSlot();
builder()->LoadKeyedProperty(object, feedback_index(slot));
break;
}
@@ -2546,7 +2709,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
}
}
BinaryOperation* binop = expr->AsCompoundAssignment()->binary_operation();
- FeedbackSlot slot = binop->BinaryOperationFeedbackSlot();
+ FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
if (expr->value()->IsSmiLiteral()) {
builder()->BinaryOperationSmiLiteral(
binop->op(), expr->value()->AsLiteral()->AsSmiLiteral(),
@@ -2563,25 +2726,44 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
// Store the value.
builder()->SetExpressionPosition(expr);
- FeedbackSlot slot = expr->AssignmentSlot();
switch (assign_type) {
case VARIABLE: {
// TODO(oth): The BuildVariableAssignment() call is hard to reason about.
// Is the value in the accumulator safe? Yes, but scary.
VariableProxy* proxy = expr->target()->AsVariableProxy();
- BuildVariableAssignment(proxy->var(), expr->op(), slot,
+ BuildVariableAssignment(proxy->var(), expr->op(),
proxy->hole_check_mode(),
expr->lookup_hoisting_mode());
break;
}
- case NAMED_PROPERTY:
+ case NAMED_PROPERTY: {
+ FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
+ Register value;
+ if (!execution_result()->IsEffect()) {
+ value = register_allocator()->NewRegister();
+ builder()->StoreAccumulatorInRegister(value);
+ }
builder()->StoreNamedProperty(object, name, feedback_index(slot),
language_mode());
+ if (!execution_result()->IsEffect()) {
+ builder()->LoadAccumulatorWithRegister(value);
+ }
break;
- case KEYED_PROPERTY:
+ }
+ case KEYED_PROPERTY: {
+ FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
+ Register value;
+ if (!execution_result()->IsEffect()) {
+ value = register_allocator()->NewRegister();
+ builder()->StoreAccumulatorInRegister(value);
+ }
builder()->StoreKeyedProperty(object, key, feedback_index(slot),
language_mode());
+ if (!execution_result()->IsEffect()) {
+ builder()->LoadAccumulatorWithRegister(value);
+ }
break;
+ }
case NAMED_SUPER_PROPERTY: {
builder()
->StoreAccumulatorInRegister(super_property_args[3])
@@ -2786,11 +2968,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
Register iterator = iterator_and_input[0];
- BuildGetIterator(expr->expression(), iterator_type,
- expr->load_iterable_iterator_slot(),
- expr->call_iterable_iterator_slot(),
- expr->load_iterable_async_iterator_slot(),
- expr->call_iterable_async_iterator_slot());
+ BuildGetIterator(expr->expression(), iterator_type);
builder()->StoreAccumulatorInRegister(iterator);
Register input = iterator_and_input[1];
builder()->LoadUndefined().StoreAccumulatorInRegister(input);
@@ -2825,13 +3003,15 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
RegisterAllocationScope register_scope(this);
// output = iterator.next(input);
Register iterator_next = register_allocator()->NewRegister();
+ FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
+ FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
builder()
- ->LoadNamedProperty(
- iterator, ast_string_constants()->next_string(),
- feedback_index(expr->load_iterator_next_slot()))
+ ->LoadNamedProperty(iterator,
+ ast_string_constants()->next_string(),
+ feedback_index(load_slot))
.StoreAccumulatorInRegister(iterator_next)
.CallProperty(iterator_next, iterator_and_input,
- feedback_index(expr->call_iterator_next_slot()))
+ feedback_index(call_slot))
.Jump(after_switch.New());
}
@@ -2842,15 +3022,17 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
BytecodeLabels return_input(zone());
// Trigger return from within the inner iterator.
Register iterator_return = register_allocator()->NewRegister();
+ FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
+ FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
builder()
- ->LoadNamedProperty(
- iterator, ast_string_constants()->return_string(),
- feedback_index(expr->load_iterator_return_slot()))
+ ->LoadNamedProperty(iterator,
+ ast_string_constants()->return_string(),
+ feedback_index(load_slot))
.JumpIfUndefined(return_input.New())
.JumpIfNull(return_input.New())
.StoreAccumulatorInRegister(iterator_return)
.CallProperty(iterator_return, iterator_and_input,
- feedback_index(expr->call_iterator_return_slot1()))
+ feedback_index(call_slot))
.Jump(after_switch.New());
return_input.Bind(builder());
@@ -2873,16 +3055,18 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
// If the inner iterator has a throw method, use it to trigger an
// exception inside.
Register iterator_throw = register_allocator()->NewRegister();
+ FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
+ FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
builder()
- ->LoadNamedProperty(
- iterator, ast_string_constants()->throw_string(),
- feedback_index(expr->load_iterator_throw_slot()))
+ ->LoadNamedProperty(iterator,
+ ast_string_constants()->throw_string(),
+ feedback_index(load_slot))
.JumpIfUndefined(iterator_throw_is_undefined.New())
.JumpIfNull(iterator_throw_is_undefined.New())
.StoreAccumulatorInRegister(iterator_throw);
builder()
->CallProperty(iterator_throw, iterator_and_input,
- feedback_index(expr->call_iterator_throw_slot()))
+ feedback_index(call_slot))
.Jump(after_switch.New());
}
@@ -2893,17 +3077,18 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
Register iterator_return = register_allocator()->NewRegister();
// If iterator.throw does not exist, try to use iterator.return to
// inform the iterator that it should stop.
+ FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
+ FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
builder()
- ->LoadNamedProperty(
- iterator, ast_string_constants()->return_string(),
- feedback_index(expr->load_iterator_return_slot()))
+ ->LoadNamedProperty(iterator,
+ ast_string_constants()->return_string(),
+ feedback_index(load_slot))
.StoreAccumulatorInRegister(iterator_return);
builder()
->JumpIfUndefined(throw_throw_method_missing.New())
.JumpIfNull(throw_throw_method_missing.New())
- .CallProperty(
- iterator_return, RegisterList(iterator),
- feedback_index(expr->call_iterator_return_slot2()));
+ .CallProperty(iterator_return, RegisterList(iterator),
+ feedback_index(call_slot));
if (iterator_type == IteratorType::kAsync) {
// For async generators, await the result of the .return() call.
@@ -2939,7 +3124,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
// Break once output.done is true.
builder()->LoadNamedProperty(
output, ast_string_constants()->done_string(),
- feedback_index(expr->load_output_done_slot()));
+ feedback_index(feedback_spec()->AddLoadICSlot()));
loop.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
@@ -2948,13 +3133,13 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
builder()->LoadAccumulatorWithRegister(output);
} else {
RegisterAllocationScope register_scope(this);
- DCHECK(iterator_type == IteratorType::kAsync);
+ DCHECK_EQ(iterator_type, IteratorType::kAsync);
// If generatorKind is async, perform AsyncGeneratorYield(output.value),
// which will await `output.value` before resolving the current
// AsyncGeneratorRequest's promise.
builder()->LoadNamedProperty(
output, ast_string_constants()->value_string(),
- feedback_index(expr->load_output_value_slot()));
+ feedback_index(feedback_spec()->AddLoadICSlot()));
RegisterList args = register_allocator()->NewRegisterList(3);
builder()
@@ -2983,7 +3168,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
Register output_value = register_allocator()->NewRegister();
builder()
->LoadNamedProperty(output, ast_string_constants()->value_string(),
- feedback_index(expr->load_output_value_slot()))
+ feedback_index(feedback_spec()->AddLoadICSlot()))
.StoreAccumulatorInRegister(output_value)
.LoadLiteral(Smi::FromInt(JSGeneratorObject::kReturn))
.CompareOperation(Token::EQ_STRICT, resume_mode)
@@ -3038,8 +3223,7 @@ void BytecodeGenerator::BuildAwait(int suspend_id) {
// AsyncFunction Await builtins require a 3rd parameter to hold the outer
// promise.
Variable* var_promise = closure_scope()->promise_var();
- BuildVariableLoadForAccumulatorValue(var_promise, FeedbackSlot::Invalid(),
- HoleCheckMode::kElided);
+ BuildVariableLoadForAccumulatorValue(var_promise, HoleCheckMode::kElided);
builder()->StoreAccumulatorInRegister(args[2]);
}
@@ -3088,7 +3272,6 @@ void BytecodeGenerator::VisitThrow(Throw* expr) {
void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) {
LhsKind property_kind = Property::GetAssignType(property);
- FeedbackSlot slot = property->PropertyFeedbackSlot();
switch (property_kind) {
case VARIABLE:
UNREACHABLE();
@@ -3096,13 +3279,14 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) {
builder()->SetExpressionPosition(property);
builder()->LoadNamedProperty(
obj, property->key()->AsLiteral()->AsRawPropertyName(),
- feedback_index(slot));
+ feedback_index(feedback_spec()->AddLoadICSlot()));
break;
}
case KEYED_PROPERTY: {
VisitForAccumulatorValue(property->key());
builder()->SetExpressionPosition(property);
- builder()->LoadKeyedProperty(obj, feedback_index(slot));
+ builder()->LoadKeyedProperty(
+ obj, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
break;
}
case NAMED_SUPER_PROPERTY:
@@ -3225,7 +3409,6 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// Load callee as a global variable.
VariableProxy* proxy = callee_expr->AsVariableProxy();
BuildVariableLoadForAccumulatorValue(proxy->var(),
- proxy->VariableFeedbackSlot(),
proxy->hole_check_mode());
builder()->StoreAccumulatorInRegister(callee);
break;
@@ -3302,7 +3485,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
->MoveRegister(callee, runtime_call_args[0])
.MoveRegister(first_arg, runtime_call_args[1])
.MoveRegister(Register::function_closure(), runtime_call_args[2])
- .LoadLiteral(Smi::FromInt(language_mode()))
+ .LoadLiteral(Smi::FromEnum(language_mode()))
.StoreAccumulatorInRegister(runtime_call_args[3])
.LoadLiteral(Smi::FromInt(current_scope()->start_position()))
.StoreAccumulatorInRegister(runtime_call_args[4])
@@ -3317,7 +3500,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
builder()->SetExpressionPosition(expr);
- int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
+ int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot());
if (is_spread_call) {
DCHECK(!implicit_undefined_receiver);
@@ -3338,9 +3521,11 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
SuperCallReference* super = expr->expression()->AsSuperCallReference();
// Prepare the constructor to the super call.
- VisitForAccumulatorValue(super->this_function_var());
+ Register this_function = VisitForRegisterValue(super->this_function_var());
Register constructor = register_allocator()->NewRegister();
- builder()->GetSuperConstructor(constructor);
+ builder()
+ ->LoadAccumulatorWithRegister(this_function)
+ .GetSuperConstructor(constructor);
ZoneList<Expression*>* args = expr->arguments();
RegisterList args_regs = register_allocator()->NewGrowableRegisterList();
@@ -3350,9 +3535,10 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
VisitForAccumulatorValue(super->new_target_var());
builder()->SetExpressionPosition(expr);
+ int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot());
+
// When a super call contains a spread, a CallSuper AST node is only created
// if there is exactly one spread, and it is the last argument.
- int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
if (expr->only_last_arg_is_spread()) {
builder()->ConstructWithSpread(constructor, args_regs, feedback_slot_index);
} else {
@@ -3365,6 +3551,24 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
// and come up with a better way.
builder()->Construct(constructor, args_regs, feedback_slot_index);
}
+
+ // The derived constructor has the correct bit set always, so we
+ // don't emit code to load and call the initializer if not
+ // required.
+ //
+ // For the arrow function or eval case, we always emit code to load
+ // and call the initializer.
+ //
+ // TODO(gsathya): In the future, we could tag nested arrow functions
+ // or eval with the correct bit so that we do the load conditionally
+ // if required.
+ if (info()->literal()->requires_instance_fields_initializer() ||
+ !IsDerivedConstructor(info()->literal()->kind())) {
+ Register instance = register_allocator()->NewRegister();
+ builder()->StoreAccumulatorInRegister(instance);
+ BuildInstanceFieldInitialization(this_function, instance);
+ builder()->LoadAccumulatorWithRegister(instance);
+ }
}
void BytecodeGenerator::VisitCallNew(CallNew* expr) {
@@ -3377,7 +3581,7 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) {
builder()->SetExpressionPosition(expr);
builder()->LoadAccumulatorWithRegister(constructor);
- int const feedback_slot_index = feedback_index(expr->CallNewFeedbackSlot());
+ int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot());
if (expr->only_last_arg_is_spread()) {
builder()->ConstructWithSpread(constructor, args, feedback_slot_index);
} else {
@@ -3409,9 +3613,8 @@ void BytecodeGenerator::VisitForTypeOfValue(Expression* 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->AsVariableProxy();
- BuildVariableLoadForAccumulatorValue(
- proxy->var(), proxy->VariableFeedbackSlot(), proxy->hole_check_mode(),
- INSIDE_TYPEOF);
+ BuildVariableLoadForAccumulatorValue(proxy->var(), proxy->hole_check_mode(),
+ INSIDE_TYPEOF);
} else {
VisitForAccumulatorValue(expr);
}
@@ -3460,7 +3663,7 @@ void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
VisitForAccumulatorValue(expr->expression());
builder()->SetExpressionPosition(expr);
builder()->UnaryOperation(
- expr->op(), feedback_index(expr->UnaryOperationFeedbackSlot()));
+ expr->op(), feedback_index(feedback_spec()->AddBinaryOpICSlot()));
break;
default:
UNREACHABLE();
@@ -3538,26 +3741,24 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
case VARIABLE: {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
BuildVariableLoadForAccumulatorValue(proxy->var(),
- proxy->VariableFeedbackSlot(),
proxy->hole_check_mode());
break;
}
case NAMED_PROPERTY: {
- FeedbackSlot slot = property->PropertyFeedbackSlot();
object = VisitForRegisterValue(property->obj());
name = property->key()->AsLiteral()->AsRawPropertyName();
- builder()->LoadNamedProperty(object, name, feedback_index(slot));
+ builder()->LoadNamedProperty(
+ object, name, feedback_index(feedback_spec()->AddLoadICSlot()));
break;
}
case KEYED_PROPERTY: {
- FeedbackSlot slot = property->PropertyFeedbackSlot();
object = VisitForRegisterValue(property->obj());
// Use visit for accumulator here since we need the key in the accumulator
// for the LoadKeyedProperty.
key = register_allocator()->NewRegister();
VisitForAccumulatorValue(property->key());
builder()->StoreAccumulatorInRegister(key).LoadKeyedProperty(
- object, feedback_index(slot));
+ object, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
break;
}
case NAMED_SUPER_PROPERTY: {
@@ -3587,14 +3788,14 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
}
// Save result for postfix expressions.
- FeedbackSlot count_slot = expr->CountBinaryOpFeedbackSlot();
+ FeedbackSlot count_slot = feedback_spec()->AddBinaryOpICSlot();
if (is_postfix) {
old_value = register_allocator()->NewRegister();
// Convert old value into a number before saving it.
// TODO(ignition): Think about adding proper PostInc/PostDec bytecodes
- // instead of this ToNumber + Inc/Dec dance.
+ // instead of this ToNumeric + Inc/Dec dance.
builder()
- ->ToNumber(feedback_index(count_slot))
+ ->ToNumeric(feedback_index(count_slot))
.StoreAccumulatorInRegister(old_value);
}
@@ -3603,22 +3804,39 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
// Store the value.
builder()->SetExpressionPosition(expr);
- FeedbackSlot feedback_slot = expr->CountSlot();
switch (assign_type) {
case VARIABLE: {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
- BuildVariableAssignment(proxy->var(), expr->op(), feedback_slot,
+ BuildVariableAssignment(proxy->var(), expr->op(),
proxy->hole_check_mode());
break;
}
case NAMED_PROPERTY: {
- builder()->StoreNamedProperty(object, name, feedback_index(feedback_slot),
+ FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
+ Register value;
+ if (!execution_result()->IsEffect()) {
+ value = register_allocator()->NewRegister();
+ builder()->StoreAccumulatorInRegister(value);
+ }
+ builder()->StoreNamedProperty(object, name, feedback_index(slot),
language_mode());
+ if (!execution_result()->IsEffect()) {
+ builder()->LoadAccumulatorWithRegister(value);
+ }
break;
}
case KEYED_PROPERTY: {
- builder()->StoreKeyedProperty(object, key, feedback_index(feedback_slot),
+ FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
+ Register value;
+ if (!execution_result()->IsEffect()) {
+ value = register_allocator()->NewRegister();
+ builder()->StoreAccumulatorInRegister(value);
+ }
+ builder()->StoreKeyedProperty(object, key, feedback_index(slot),
language_mode());
+ if (!execution_result()->IsEffect()) {
+ builder()->LoadAccumulatorWithRegister(value);
+ }
break;
}
case NAMED_SUPER_PROPERTY: {
@@ -3658,6 +3876,23 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
}
}
+void BytecodeGenerator::VisitNaryOperation(NaryOperation* expr) {
+ switch (expr->op()) {
+ case Token::COMMA:
+ VisitNaryCommaExpression(expr);
+ break;
+ case Token::OR:
+ VisitNaryLogicalOrExpression(expr);
+ break;
+ case Token::AND:
+ VisitNaryLogicalAndExpression(expr);
+ break;
+ default:
+ VisitNaryArithmeticExpression(expr);
+ break;
+ }
+}
+
void BytecodeGenerator::BuildLiteralCompareNil(Token::Value op, NilValue nil) {
if (execution_result()->IsTest()) {
TestResultScope* test_result = execution_result()->AsTest();
@@ -3706,10 +3941,13 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Register lhs = VisitForRegisterValue(expr->left());
VisitForAccumulatorValue(expr->right());
builder()->SetExpressionPosition(expr);
- FeedbackSlot slot = expr->CompareOperationFeedbackSlot();
- if (slot.IsInvalid()) {
+ if (expr->op() == Token::IN) {
builder()->CompareOperation(expr->op(), lhs);
+ } else if (expr->op() == Token::INSTANCEOF) {
+ FeedbackSlot slot = feedback_spec()->AddInstanceOfSlot();
+ builder()->CompareOperation(expr->op(), lhs, feedback_index(slot));
} else {
+ FeedbackSlot slot = feedback_spec()->AddCompareICSlot();
builder()->CompareOperation(expr->op(), lhs, feedback_index(slot));
}
}
@@ -3718,7 +3956,7 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
}
void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
- FeedbackSlot slot = expr->BinaryOperationFeedbackSlot();
+ FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
Expression* subexpr;
Smi* literal;
if (expr->IsSmiLiteralOperation(&subexpr, &literal)) {
@@ -3734,6 +3972,29 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
}
}
+void BytecodeGenerator::VisitNaryArithmeticExpression(NaryOperation* expr) {
+ // TODO(leszeks): Add support for lhs smi in commutative ops.
+ VisitForAccumulatorValue(expr->first());
+
+ for (size_t i = 0; i < expr->subsequent_length(); ++i) {
+ RegisterAllocationScope register_scope(this);
+ if (expr->subsequent(i)->IsSmiLiteral()) {
+ builder()->SetExpressionPosition(expr->subsequent_op_position(i));
+ builder()->BinaryOperationSmiLiteral(
+ expr->op(), expr->subsequent(i)->AsLiteral()->AsSmiLiteral(),
+ feedback_index(feedback_spec()->AddBinaryOpICSlot()));
+ } else {
+ Register lhs = register_allocator()->NewRegister();
+ builder()->StoreAccumulatorInRegister(lhs);
+ VisitForAccumulatorValue(expr->subsequent(i));
+ builder()->SetExpressionPosition(expr->subsequent_op_position(i));
+ builder()->BinaryOperation(
+ expr->op(), lhs,
+ feedback_index(feedback_spec()->AddBinaryOpICSlot()));
+ }
+ }
+}
+
void BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); }
void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
@@ -3749,11 +4010,7 @@ void BytecodeGenerator::VisitImportCallExpression(ImportCallExpression* expr) {
}
void BytecodeGenerator::BuildGetIterator(Expression* iterable,
- IteratorType hint,
- FeedbackSlot load_slot,
- FeedbackSlot call_slot,
- FeedbackSlot async_load_slot,
- FeedbackSlot async_call_slot) {
+ IteratorType hint) {
RegisterList args = register_allocator()->NewRegisterList(1);
Register method = register_allocator()->NewRegister();
Register obj = args[0];
@@ -3763,7 +4020,7 @@ void BytecodeGenerator::BuildGetIterator(Expression* iterable,
if (hint == IteratorType::kAsync) {
// Set method to GetMethod(obj, @@asyncIterator)
builder()->StoreAccumulatorInRegister(obj).LoadAsyncIteratorProperty(
- obj, feedback_index(async_load_slot));
+ obj, feedback_index(feedback_spec()->AddLoadICSlot()));
BytecodeLabel async_iterator_undefined, async_iterator_null, done;
// TODO(ignition): Add a single opcode for JumpIfNullOrUndefined
@@ -3772,7 +4029,7 @@ void BytecodeGenerator::BuildGetIterator(Expression* iterable,
// Let iterator be Call(method, obj)
builder()->StoreAccumulatorInRegister(method).CallProperty(
- method, args, feedback_index(async_call_slot));
+ method, args, feedback_index(feedback_spec()->AddCallICSlot()));
// If Type(iterator) is not Object, throw a TypeError exception.
builder()->JumpIfJSReceiver(&done);
@@ -3783,11 +4040,13 @@ void BytecodeGenerator::BuildGetIterator(Expression* iterable,
// If method is undefined,
// Let syncMethod be GetMethod(obj, @@iterator)
builder()
- ->LoadIteratorProperty(obj, feedback_index(load_slot))
+ ->LoadIteratorProperty(obj,
+ feedback_index(feedback_spec()->AddLoadICSlot()))
.StoreAccumulatorInRegister(method);
// Let syncIterator be Call(syncMethod, obj)
- builder()->CallProperty(method, args, feedback_index(call_slot));
+ builder()->CallProperty(method, args,
+ feedback_index(feedback_spec()->AddCallICSlot()));
// Return CreateAsyncFromSyncIterator(syncIterator)
// alias `method` register as it's no longer used
@@ -3800,11 +4059,13 @@ void BytecodeGenerator::BuildGetIterator(Expression* iterable,
// Let method be GetMethod(obj, @@iterator).
builder()
->StoreAccumulatorInRegister(obj)
- .LoadIteratorProperty(obj, feedback_index(load_slot))
+ .LoadIteratorProperty(obj,
+ feedback_index(feedback_spec()->AddLoadICSlot()))
.StoreAccumulatorInRegister(method);
// Let iterator be Call(method, obj).
- builder()->CallProperty(method, args, feedback_index(call_slot));
+ builder()->CallProperty(method, args,
+ feedback_index(feedback_spec()->AddCallICSlot()));
// If Type(iterator) is not Object, throw a TypeError exception.
BytecodeLabel no_type_error;
@@ -3816,11 +4077,7 @@ void BytecodeGenerator::BuildGetIterator(Expression* iterable,
void BytecodeGenerator::VisitGetIterator(GetIterator* expr) {
builder()->SetExpressionPosition(expr);
- BuildGetIterator(expr->iterable(), expr->hint(),
- expr->IteratorPropertyFeedbackSlot(),
- expr->IteratorCallFeedbackSlot(),
- expr->AsyncIteratorPropertyFeedbackSlot(),
- expr->AsyncIteratorCallFeedbackSlot());
+ BuildGetIterator(expr->iterable(), expr->hint());
}
void BytecodeGenerator::VisitGetTemplateObject(GetTemplateObject* expr) {
@@ -3849,57 +4106,165 @@ void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) {
Visit(binop->right());
}
-void BytecodeGenerator::BuildLogicalTest(Token::Value token, Expression* left,
- Expression* right) {
+void BytecodeGenerator::VisitNaryCommaExpression(NaryOperation* expr) {
+ DCHECK_GT(expr->subsequent_length(), 0);
+
+ VisitForEffect(expr->first());
+ for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
+ VisitForEffect(expr->subsequent(i));
+ }
+ Visit(expr->subsequent(expr->subsequent_length() - 1));
+}
+
+void BytecodeGenerator::VisitLogicalTestSubExpression(
+ Token::Value token, Expression* expr, BytecodeLabels* then_labels,
+ BytecodeLabels* else_labels, int coverage_slot) {
+ DCHECK(token == Token::OR || token == Token::AND);
+
+ BytecodeLabels test_next(zone());
+ if (token == Token::OR) {
+ VisitForTest(expr, then_labels, &test_next, TestFallthrough::kElse);
+ } else {
+ DCHECK_EQ(Token::AND, token);
+ VisitForTest(expr, &test_next, else_labels, TestFallthrough::kThen);
+ }
+ test_next.Bind(builder());
+
+ BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot);
+}
+
+void BytecodeGenerator::VisitLogicalTest(Token::Value token, Expression* left,
+ Expression* right,
+ int right_coverage_slot) {
DCHECK(token == Token::OR || token == Token::AND);
TestResultScope* test_result = execution_result()->AsTest();
BytecodeLabels* then_labels = test_result->then_labels();
BytecodeLabels* else_labels = test_result->else_labels();
TestFallthrough fallthrough = test_result->fallthrough();
- {
- // Visit the left side using current TestResultScope.
- BytecodeLabels test_right(zone());
- if (token == Token::OR) {
- test_result->set_fallthrough(TestFallthrough::kElse);
- test_result->set_else_labels(&test_right);
- } else {
- DCHECK_EQ(Token::AND, token);
- test_result->set_fallthrough(TestFallthrough::kThen);
- test_result->set_then_labels(&test_right);
- }
- VisitInSameTestExecutionScope(left);
- test_right.Bind(builder());
- }
- // Visit the right side in a new TestResultScope.
+
+ VisitLogicalTestSubExpression(token, left, then_labels, else_labels,
+ right_coverage_slot);
+ // The last test has the same then, else and fallthrough as the parent test.
VisitForTest(right, then_labels, else_labels, fallthrough);
}
+void BytecodeGenerator::VisitNaryLogicalTest(
+ Token::Value token, NaryOperation* expr,
+ const NaryCodeCoverageSlots* coverage_slots) {
+ DCHECK(token == Token::OR || token == Token::AND);
+ DCHECK_GT(expr->subsequent_length(), 0);
+
+ TestResultScope* test_result = execution_result()->AsTest();
+ BytecodeLabels* then_labels = test_result->then_labels();
+ BytecodeLabels* else_labels = test_result->else_labels();
+ TestFallthrough fallthrough = test_result->fallthrough();
+
+ VisitLogicalTestSubExpression(token, expr->first(), then_labels, else_labels,
+ coverage_slots->GetSlotFor(0));
+ for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
+ VisitLogicalTestSubExpression(token, expr->subsequent(i), then_labels,
+ else_labels,
+ coverage_slots->GetSlotFor(i + 1));
+ }
+ // The last test has the same then, else and fallthrough as the parent test.
+ VisitForTest(expr->subsequent(expr->subsequent_length() - 1), then_labels,
+ else_labels, fallthrough);
+}
+
+bool BytecodeGenerator::VisitLogicalOrSubExpression(Expression* expr,
+ BytecodeLabels* end_labels,
+ int coverage_slot) {
+ if (expr->ToBooleanIsTrue()) {
+ VisitForAccumulatorValue(expr);
+ end_labels->Bind(builder());
+ return true;
+ } else if (!expr->ToBooleanIsFalse()) {
+ TypeHint type_hint = VisitForAccumulatorValue(expr);
+ builder()->JumpIfTrue(ToBooleanModeFromTypeHint(type_hint),
+ end_labels->New());
+ }
+
+ BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot);
+
+ return false;
+}
+
+bool BytecodeGenerator::VisitLogicalAndSubExpression(Expression* expr,
+ BytecodeLabels* end_labels,
+ int coverage_slot) {
+ if (expr->ToBooleanIsFalse()) {
+ VisitForAccumulatorValue(expr);
+ end_labels->Bind(builder());
+ return true;
+ } else if (!expr->ToBooleanIsTrue()) {
+ TypeHint type_hint = VisitForAccumulatorValue(expr);
+ builder()->JumpIfFalse(ToBooleanModeFromTypeHint(type_hint),
+ end_labels->New());
+ }
+
+ BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot);
+
+ return false;
+}
+
void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
Expression* left = binop->left();
Expression* right = binop->right();
+ int right_coverage_slot =
+ AllocateBlockCoverageSlotIfEnabled(binop, SourceRangeKind::kRight);
+
if (execution_result()->IsTest()) {
TestResultScope* test_result = execution_result()->AsTest();
if (left->ToBooleanIsTrue()) {
builder()->Jump(test_result->NewThenLabel());
} else if (left->ToBooleanIsFalse() && right->ToBooleanIsFalse()) {
+ BuildIncrementBlockCoverageCounterIfEnabled(right_coverage_slot);
builder()->Jump(test_result->NewElseLabel());
} else {
- BuildLogicalTest(Token::OR, left, right);
+ VisitLogicalTest(Token::OR, left, right, right_coverage_slot);
}
test_result->SetResultConsumedByTest();
} else {
- if (left->ToBooleanIsTrue()) {
- VisitForAccumulatorValue(left);
- } else if (left->ToBooleanIsFalse()) {
- VisitForAccumulatorValue(right);
+ BytecodeLabels end_labels(zone());
+ if (VisitLogicalOrSubExpression(left, &end_labels, right_coverage_slot)) {
+ return;
+ }
+ VisitForAccumulatorValue(right);
+ end_labels.Bind(builder());
+ }
+}
+
+void BytecodeGenerator::VisitNaryLogicalOrExpression(NaryOperation* expr) {
+ Expression* first = expr->first();
+ DCHECK_GT(expr->subsequent_length(), 0);
+
+ NaryCodeCoverageSlots coverage_slots(this, expr);
+
+ if (execution_result()->IsTest()) {
+ TestResultScope* test_result = execution_result()->AsTest();
+ if (first->ToBooleanIsTrue()) {
+ builder()->Jump(test_result->NewThenLabel());
} else {
- BytecodeLabel end_label;
- TypeHint type_hint = VisitForAccumulatorValue(left);
- builder()->JumpIfTrue(ToBooleanModeFromTypeHint(type_hint), &end_label);
- VisitForAccumulatorValue(right);
- builder()->Bind(&end_label);
+ VisitNaryLogicalTest(Token::OR, expr, &coverage_slots);
+ }
+ test_result->SetResultConsumedByTest();
+ } else {
+ BytecodeLabels end_labels(zone());
+ if (VisitLogicalOrSubExpression(first, &end_labels,
+ coverage_slots.GetSlotFor(0))) {
+ return;
+ }
+ for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
+ if (VisitLogicalOrSubExpression(expr->subsequent(i), &end_labels,
+ coverage_slots.GetSlotFor(i + 1))) {
+ return;
+ }
}
+ // We have to visit the last value even if it's true, because we need its
+ // actual value.
+ VisitForAccumulatorValue(expr->subsequent(expr->subsequent_length() - 1));
+ end_labels.Bind(builder());
}
}
@@ -3907,28 +4272,60 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
Expression* left = binop->left();
Expression* right = binop->right();
+ int right_coverage_slot =
+ AllocateBlockCoverageSlotIfEnabled(binop, SourceRangeKind::kRight);
+
if (execution_result()->IsTest()) {
TestResultScope* test_result = execution_result()->AsTest();
if (left->ToBooleanIsFalse()) {
builder()->Jump(test_result->NewElseLabel());
} else if (left->ToBooleanIsTrue() && right->ToBooleanIsTrue()) {
+ BuildIncrementBlockCoverageCounterIfEnabled(right_coverage_slot);
builder()->Jump(test_result->NewThenLabel());
} else {
- BuildLogicalTest(Token::AND, left, right);
+ VisitLogicalTest(Token::AND, left, right, right_coverage_slot);
}
test_result->SetResultConsumedByTest();
} else {
- if (left->ToBooleanIsFalse()) {
- VisitForAccumulatorValue(left);
- } else if (left->ToBooleanIsTrue()) {
- VisitForAccumulatorValue(right);
+ BytecodeLabels end_labels(zone());
+ if (VisitLogicalAndSubExpression(left, &end_labels, right_coverage_slot)) {
+ return;
+ }
+ VisitForAccumulatorValue(right);
+ end_labels.Bind(builder());
+ }
+}
+
+void BytecodeGenerator::VisitNaryLogicalAndExpression(NaryOperation* expr) {
+ Expression* first = expr->first();
+ DCHECK_GT(expr->subsequent_length(), 0);
+
+ NaryCodeCoverageSlots coverage_slots(this, expr);
+
+ if (execution_result()->IsTest()) {
+ TestResultScope* test_result = execution_result()->AsTest();
+ if (first->ToBooleanIsFalse()) {
+ builder()->Jump(test_result->NewElseLabel());
} else {
- BytecodeLabel end_label;
- TypeHint type_hint = VisitForAccumulatorValue(left);
- builder()->JumpIfFalse(ToBooleanModeFromTypeHint(type_hint), &end_label);
- VisitForAccumulatorValue(right);
- builder()->Bind(&end_label);
+ VisitNaryLogicalTest(Token::AND, expr, &coverage_slots);
+ }
+ test_result->SetResultConsumedByTest();
+ } else {
+ BytecodeLabels end_labels(zone());
+ if (VisitLogicalAndSubExpression(first, &end_labels,
+ coverage_slots.GetSlotFor(0))) {
+ return;
}
+ for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
+ if (VisitLogicalAndSubExpression(expr->subsequent(i), &end_labels,
+ coverage_slots.GetSlotFor(i + 1))) {
+ return;
+ }
+ }
+ // We have to visit the last value even if it's false, because we need its
+ // actual value.
+ VisitForAccumulatorValue(expr->subsequent(expr->subsequent_length() - 1));
+ end_labels.Bind(builder());
}
}
@@ -4054,11 +4451,10 @@ void BytecodeGenerator::VisitObjectLiteralAccessor(
}
void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object,
- LiteralProperty* property,
- int slot_number) {
+ LiteralProperty* property) {
Expression* expr = property->value();
if (FunctionLiteral::NeedsHomeObject(expr)) {
- FeedbackSlot slot = property->GetSlot(slot_number);
+ FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
builder()
->LoadAccumulatorWithRegister(home_object)
.StoreHomeObjectProperty(value, feedback_index(slot), language_mode());
@@ -4077,8 +4473,7 @@ void BytecodeGenerator::VisitArgumentsObject(Variable* variable) {
? CreateArgumentsType::kUnmappedArguments
: CreateArgumentsType::kMappedArguments;
builder()->CreateArguments(type);
- BuildVariableAssignment(variable, Token::ASSIGN, FeedbackSlot::Invalid(),
- HoleCheckMode::kElided);
+ BuildVariableAssignment(variable, Token::ASSIGN, HoleCheckMode::kElided);
}
void BytecodeGenerator::VisitRestArgumentsArray(Variable* rest) {
@@ -4088,8 +4483,7 @@ void BytecodeGenerator::VisitRestArgumentsArray(Variable* rest) {
// variable.
builder()->CreateArguments(CreateArgumentsType::kRestParameter);
DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
- BuildVariableAssignment(rest, Token::ASSIGN, FeedbackSlot::Invalid(),
- HoleCheckMode::kElided);
+ BuildVariableAssignment(rest, Token::ASSIGN, HoleCheckMode::kElided);
}
void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) {
@@ -4097,8 +4491,7 @@ void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) {
// Store the closure we were called with in the given variable.
builder()->LoadAccumulatorWithRegister(Register::function_closure());
- BuildVariableAssignment(variable, Token::INIT, FeedbackSlot::Invalid(),
- HoleCheckMode::kElided);
+ BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
}
void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) {
@@ -4119,8 +4512,7 @@ void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) {
// Store the new target we were called with in the given variable.
builder()->LoadAccumulatorWithRegister(incoming_new_target_or_generator_);
- BuildVariableAssignment(variable, Token::INIT, FeedbackSlot::Invalid(),
- HoleCheckMode::kElided);
+ BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
}
void BytecodeGenerator::BuildGeneratorObjectVariableInitialization() {
@@ -4142,7 +4534,7 @@ void BytecodeGenerator::BuildGeneratorObjectVariableInitialization() {
GetRegisterForLocalVariable(generator_object_var).index());
} else {
BuildVariableAssignment(generator_object_var, Token::INIT,
- FeedbackSlot::Invalid(), HoleCheckMode::kElided);
+ HoleCheckMode::kElided);
}
}
@@ -4196,6 +4588,14 @@ int BytecodeGenerator::AllocateBlockCoverageSlotIfEnabled(
: block_coverage_builder_->AllocateBlockCoverageSlot(node, kind);
}
+int BytecodeGenerator::AllocateNaryBlockCoverageSlotIfEnabled(
+ NaryOperation* node, size_t index) {
+ return (block_coverage_builder_ == nullptr)
+ ? BlockCoverageBuilder::kNoCoverageArraySlot
+ : block_coverage_builder_->AllocateNaryBlockCoverageSlot(node,
+ index);
+}
+
void BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled(
AstNode* node, SourceRangeKind kind) {
if (block_coverage_builder_ == nullptr) return;
@@ -4351,11 +4751,37 @@ Register BytecodeGenerator::generator_object() const {
return incoming_new_target_or_generator_;
}
+FeedbackVectorSpec* BytecodeGenerator::feedback_spec() {
+ return info()->feedback_vector_spec();
+}
+
int BytecodeGenerator::feedback_index(FeedbackSlot slot) const {
DCHECK(!slot.IsInvalid());
return FeedbackVector::GetIndex(slot);
}
+FeedbackSlot BytecodeGenerator::GetCachedLoadGlobalICSlot(
+ TypeofMode typeof_mode, Variable* variable) {
+ FeedbackSlot slot = feedback_slot_cache()->Get(typeof_mode, variable);
+ if (!slot.IsInvalid()) {
+ return slot;
+ }
+ slot = feedback_spec()->AddLoadGlobalICSlot(typeof_mode);
+ feedback_slot_cache()->Put(typeof_mode, variable, slot);
+ return slot;
+}
+
+FeedbackSlot BytecodeGenerator::GetCachedCreateClosureSlot(
+ FunctionLiteral* literal) {
+ FeedbackSlot slot = feedback_slot_cache()->Get(literal);
+ if (!slot.IsInvalid()) {
+ return slot;
+ }
+ slot = feedback_spec()->AddCreateClosureSlot();
+ feedback_slot_cache()->Put(literal, slot);
+ return slot;
+}
+
Runtime::FunctionId BytecodeGenerator::StoreToSuperRuntimeId() {
return is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict
: Runtime::kStoreToSuper_Sloppy;