Commit 162402f9 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[Compile] Move decision of whether an IIFE is oneshot into parser.

The decision as to whether to optimize an IIFE as oneshot depends on
whether it's outer scope is the script scope. During lazy compile, we
might have discarded scopes which don't need a context between the IIFE
and the script scope, which means we might treat an IIFE as oneshot,
even though initial eager compile treated it as non-oneshot. Both
bytecode flushing and lazy source positions rely on us generating the
same bytecode during lazy compile as eager compile, so we move the
decision into the parser where it happens once and is then stored in
the SFI for any future lazy compiles.

BUG=v8:8395,v8:8510

Change-Id: I88f1e74ad95d47a2636c393ceb1318d7d610055d
Reviewed-on: https://chromium-review.googlesource.com/c/1421841Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58996}
parent 7d4ece42
......@@ -2238,8 +2238,10 @@ class FunctionLiteral final : public Expression {
return function_type() == kAnonymousExpression;
}
void mark_as_iife() { bit_field_ = IIFEBit::update(bit_field_, true); }
bool is_iife() const { return IIFEBit::decode(bit_field_); }
void mark_as_oneshot_iife() {
bit_field_ = OneshotIIFEBit::update(bit_field_, true);
}
bool is_oneshot_iife() const { return OneshotIIFEBit::decode(bit_field_); }
bool is_toplevel() const {
return function_literal_id() == FunctionLiteral::kIdTypeTopLevel;
}
......@@ -2370,13 +2372,13 @@ class FunctionLiteral final : public Expression {
body_(0, nullptr),
raw_inferred_name_(ast_value_factory->empty_cons_string()),
produced_preparse_data_(produced_preparse_data) {
bit_field_ |= FunctionTypeBits::encode(function_type) |
Pretenure::encode(false) |
HasDuplicateParameters::encode(has_duplicate_parameters ==
kHasDuplicateParameters) |
DontOptimizeReasonField::encode(BailoutReason::kNoReason) |
RequiresInstanceMembersInitializer::encode(false) |
HasBracesField::encode(has_braces) | IIFEBit::encode(false);
bit_field_ |=
FunctionTypeBits::encode(function_type) | Pretenure::encode(false) |
HasDuplicateParameters::encode(has_duplicate_parameters ==
kHasDuplicateParameters) |
DontOptimizeReasonField::encode(BailoutReason::kNoReason) |
RequiresInstanceMembersInitializer::encode(false) |
HasBracesField::encode(has_braces) | OneshotIIFEBit::encode(false);
if (eager_compile_hint == kShouldEagerCompile) SetShouldEagerCompile();
body.CopyTo(&body_, zone);
}
......@@ -2391,7 +2393,7 @@ class FunctionLiteral final : public Expression {
: public BitField<bool, DontOptimizeReasonField::kNext, 1> {};
class HasBracesField
: public BitField<bool, RequiresInstanceMembersInitializer::kNext, 1> {};
class IIFEBit : public BitField<bool, HasBracesField::kNext, 1> {};
class OneshotIIFEBit : public BitField<bool, HasBracesField::kNext, 1> {};
int expected_property_count_;
int parameter_count_;
......
......@@ -406,7 +406,7 @@ void SetSharedFunctionFlagsFromLiteral(FunctionLiteral* literal,
}
shared_info->set_has_duplicate_parameters(
literal->has_duplicate_parameters());
shared_info->set_is_iife(literal->is_iife());
shared_info->set_is_oneshot_iife(literal->is_oneshot_iife());
shared_info->SetExpectedNofPropertiesFromEstimate(literal);
if (literal->dont_optimize_reason() != BailoutReason::kNoReason) {
shared_info->DisableOptimization(literal->dont_optimize_reason());
......
......@@ -1907,11 +1907,8 @@ bool BytecodeGenerator::ShouldOptimizeAsOneShot() const {
if (loop_depth_ > 0) return false;
// A non-top-level iife is likely to be executed multiple times and so
// shouldn`t be optimized as one-shot.
bool is_toplevel_iife = info()->literal()->is_iife() &&
current_scope()->outer_scope()->is_script_scope();
return info()->literal()->is_toplevel() || is_toplevel_iife;
return info()->literal()->is_toplevel() ||
info()->literal()->is_oneshot_iife();
}
void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
......
......@@ -222,8 +222,8 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_named_expression,
SharedFunctionInfo::IsNamedExpressionBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_toplevel,
SharedFunctionInfo::IsTopLevelBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_iife,
SharedFunctionInfo::IsIIFEBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, flags, is_oneshot_iife,
SharedFunctionInfo::IsOneshotIIFEBit)
bool SharedFunctionInfo::optimization_disabled() const {
return disable_optimization_reason() != BailoutReason::kNoReason;
......
......@@ -489,8 +489,9 @@ class SharedFunctionInfo : public HeapObject {
DECL_BOOLEAN_ACCESSORS(is_anonymous_expression)
// Indicates that the function represented by the shared function info was
// classed as an immediately invoked function execution (IIFE) function.
DECL_BOOLEAN_ACCESSORS(is_iife)
// classed as an immediately invoked function execution (IIFE) function and
// is only executed once.
DECL_BOOLEAN_ACCESSORS(is_oneshot_iife)
// Indicates that the function has been reported for binary code coverage.
DECL_BOOLEAN_ACCESSORS(has_reported_binary_coverage)
......@@ -700,7 +701,7 @@ class SharedFunctionInfo : public HeapObject {
V(HasReportedBinaryCoverageBit, bool, 1, _) \
V(IsNamedExpressionBit, bool, 1, _) \
V(IsTopLevelBit, bool, 1, _) \
V(IsIIFEBit, bool, 1, _)
V(IsOneshotIIFEBit, bool, 1, _)
DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
#undef FLAGS_BIT_FIELDS
......
......@@ -80,7 +80,7 @@ void ParseInfo::SetFunctionInfo(T function) {
set_requires_instance_members_initializer(
function->requires_instance_members_initializer());
set_toplevel(function->is_toplevel());
set_is_iife(function->is_iife());
set_is_oneshot_iife(function->is_oneshot_iife());
set_wrapped_as_function(function->is_wrapped());
}
......
......@@ -114,7 +114,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
set_allow_harmony_private_fields);
FLAG_ACCESSOR(kAllowHarmonyPrivateMethods, allow_harmony_private_methods,
set_allow_harmony_private_methods);
FLAG_ACCESSOR(kIsIIFE, is_iife, set_is_iife);
FLAG_ACCESSOR(kIsOneshotIIFE, is_oneshot_iife, set_is_oneshot_iife);
#undef FLAG_ACCESSOR
void set_parse_restriction(ParseRestriction restriction) {
......@@ -311,7 +311,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
kAllowHarmonyNumericSeparator = 1 << 26,
kAllowHarmonyPrivateFields = 1 << 27,
kAllowHarmonyPrivateMethods = 1 << 28,
kIsIIFE = 1 << 29
kIsOneshotIIFE = 1 << 29
};
//------------- Inputs to parsing and scope analysis -----------------------
......
......@@ -3061,7 +3061,11 @@ ParserBase<Impl>::ParseLeftHandSideContinuation(ExpressionT result) {
// function literal eagerly, we can also compile it eagerly.
if (result->IsFunctionLiteral()) {
result->AsFunctionLiteral()->SetShouldEagerCompile();
result->AsFunctionLiteral()->mark_as_iife();
if (scope()->is_script_scope()) {
// A non-top-level iife is likely to be executed multiple times
// and so shouldn`t be optimized as one-shot.
result->AsFunctionLiteral()->mark_as_oneshot_iife();
}
}
}
bool has_spread;
......
......@@ -859,8 +859,8 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
if (has_error()) return nullptr;
result->set_requires_instance_members_initializer(
info->requires_instance_members_initializer());
if (info->is_iife()) {
result->mark_as_iife();
if (info->is_oneshot_iife()) {
result->mark_as_oneshot_iife();
}
}
......
......@@ -310,7 +310,7 @@ class PreParserExpression {
// More dummy implementations of things PreParser doesn't need to track:
void SetShouldEagerCompile() {}
void mark_as_iife() {}
void mark_as_oneshot_iife() {}
int position() const { return kNoSourcePosition; }
void set_function_token_position(int position) {}
......
......@@ -565,9 +565,9 @@ snippet: "
}
"
frame size: 3
frame size: 2
parameter count: 1
bytecode array length: 46
bytecode array length: 43
bytecodes: [
B(CreateMappedArguments),
B(Star), R(0),
......@@ -577,17 +577,15 @@ bytecodes: [
/* 111 S> */ B(LdaGlobal), U8(0), U8(2),
B(Star), R(1),
B(LdaSmi), I8(3),
/* 115 E> */ B(StaNamedPropertyNoFeedback), R(1), U8(1), U8(0),
/* 115 E> */ B(StaNamedProperty), R(1), U8(1), U8(4),
/* 130 S> */ B(LdaGlobal), U8(0), U8(2),
B(Star), R(1),
B(LdaSmi), I8(4),
/* 134 E> */ B(StaNamedPropertyNoFeedback), R(1), U8(2), U8(0),
/* 149 S> */ B(LdaUndefined),
B(Star), R(2),
B(LdaGlobal), U8(3), U8(4),
/* 134 E> */ B(StaNamedProperty), R(1), U8(2), U8(6),
/* 149 S> */ B(LdaGlobal), U8(3), U8(8),
B(Star), R(1),
/* 149 E> */ B(CallNoFeedback), R(1), R(2), U8(1),
/* 182 S> */ B(LdaNamedPropertyNoFeedback), R(0), U8(4),
/* 149 E> */ B(CallUndefinedReceiver0), R(1), U8(10),
/* 182 S> */ B(LdaNamedProperty), R(0), U8(4), U8(12),
/* 189 S> */ B(Return),
]
constant pool: [
......
......@@ -664,6 +664,7 @@ TEST(IIFEWithOneshotOpt) {
return arguments.callee;
})();
)",
// TODO(rmcilroy): Make this function produce one-shot code.
R"(
var t = 0;
function f2() {};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment