[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:
parent
7d4ece425f
commit
162402f9c5
@ -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() {};
|
||||
|
Loading…
Reference in New Issue
Block a user