[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/1421841
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58996}
This commit is contained in:
Ross McIlroy 2019-01-21 10:13:52 +00:00 committed by Commit Bot
parent 7d4ece425f
commit 162402f9c5
12 changed files with 40 additions and 37 deletions

View File

@ -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) |
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);
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_;

View File

@ -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());

View File

@ -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) {

View File

@ -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;

View File

@ -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

View File

@ -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());
}

View File

@ -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 -----------------------

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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) {}

View File

@ -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: [

View File

@ -664,6 +664,7 @@ TEST(IIFEWithOneshotOpt) {
return arguments.callee;
})();
)",
// TODO(rmcilroy): Make this function produce one-shot code.
R"(
var t = 0;
function f2() {};