Commit 7b69507c authored by Maya Lekova's avatar Maya Lekova Committed by Commit Bot

[turbofan] Add handling of jumps to the serializer

Implemented branching and merging of Environments to facilitate handling of
conditional and unconditional jumps in the SerializerForBackgroundCompilation.
Added tests and printing helpers for the Environment. The internal structure
of the hints was changed to ZoneSet to support avoiding of duplicates.
Alternative implementation considerations were documented here:
https://docs.google.com/document/d/1vCQYhtFPqXafSMweSnGD8l0TKEIB6cPV5UGMHJtpy8k/edit?ts=5bf7d341#heading=h.jx4br0df5qzm

R=neis@chromium.org

Bug: v8:7790
Change-Id: Ib929c75ddb7f7fb290a5ca28d4422680a1514a4f
Reviewed-on: https://chromium-review.googlesource.com/c/1451847Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59534}
parent 0a78f454
...@@ -36,27 +36,6 @@ namespace compiler { ...@@ -36,27 +36,6 @@ namespace compiler {
V(CreateFunctionContext) \ V(CreateFunctionContext) \
V(CreateEvalContext) \ V(CreateEvalContext) \
V(Debugger) \ V(Debugger) \
V(Jump) \
V(JumpConstant) \
V(JumpIfFalse) \
V(JumpIfFalseConstant) \
V(JumpIfJSReceiver) \
V(JumpIfJSReceiverConstant) \
V(JumpIfNotNull) \
V(JumpIfNotNullConstant) \
V(JumpIfNotUndefined) \
V(JumpIfNotUndefinedConstant) \
V(JumpIfNull) \
V(JumpIfNullConstant) \
V(JumpIfToBooleanTrueConstant) \
V(JumpIfToBooleanFalseConstant) \
V(JumpIfToBooleanTrue) \
V(JumpIfToBooleanFalse) \
V(JumpIfTrue) \
V(JumpIfTrueConstant) \
V(JumpIfUndefined) \
V(JumpIfUndefinedConstant) \
V(JumpLoop) \
V(PushContext) \ V(PushContext) \
V(PopContext) \ V(PopContext) \
V(ResumeGenerator) \ V(ResumeGenerator) \
...@@ -65,10 +44,7 @@ namespace compiler { ...@@ -65,10 +44,7 @@ namespace compiler {
V(StaCurrentContextSlot) \ V(StaCurrentContextSlot) \
V(SuspendGenerator) \ V(SuspendGenerator) \
V(SwitchOnGeneratorState) \ V(SwitchOnGeneratorState) \
V(Throw) \ V(Throw)
V(ThrowReferenceErrorIfHole) \
V(ThrowSuperNotCalledIfHole) \
V(ThrowSuperAlreadyCalledIfNotHole)
#define CLEAR_ACCUMULATOR_LIST(V) \ #define CLEAR_ACCUMULATOR_LIST(V) \
V(CreateEmptyObjectLiteral) \ V(CreateEmptyObjectLiteral) \
...@@ -85,6 +61,49 @@ namespace compiler { ...@@ -85,6 +61,49 @@ namespace compiler {
V(LdaNamedProperty) \ V(LdaNamedProperty) \
V(LdaNamedPropertyNoFeedback) V(LdaNamedPropertyNoFeedback)
#define UNCONDITIONAL_JUMPS_LIST(V) \
V(Jump) \
V(JumpConstant) \
V(JumpLoop)
#define CONDITIONAL_JUMPS_LIST(V) \
V(JumpIfFalse) \
V(JumpIfFalseConstant) \
V(JumpIfJSReceiver) \
V(JumpIfJSReceiverConstant) \
V(JumpIfNotNull) \
V(JumpIfNotNullConstant) \
V(JumpIfNotUndefined) \
V(JumpIfNotUndefinedConstant) \
V(JumpIfNull) \
V(JumpIfNullConstant) \
V(JumpIfToBooleanTrueConstant) \
V(JumpIfToBooleanFalseConstant) \
V(JumpIfToBooleanTrue) \
V(JumpIfToBooleanFalse) \
V(JumpIfTrue) \
V(JumpIfTrueConstant) \
V(JumpIfUndefined) \
V(JumpIfUndefinedConstant)
#define INGORED_BYTECODE_LIST(V) \
V(TestEqual) \
V(TestEqualStrict) \
V(TestLessThan) \
V(TestGreaterThan) \
V(TestLessThanOrEqual) \
V(TestGreaterThanOrEqual) \
V(TestReferenceEqual) \
V(TestInstanceOf) \
V(TestIn) \
V(TestUndetectable) \
V(TestNull) \
V(TestUndefined) \
V(TestTypeOf) \
V(ThrowReferenceErrorIfHole) \
V(ThrowSuperNotCalledIfHole) \
V(ThrowSuperAlreadyCalledIfNotHole)
#define SUPPORTED_BYTECODE_LIST(V) \ #define SUPPORTED_BYTECODE_LIST(V) \
V(CallAnyReceiver) \ V(CallAnyReceiver) \
V(CallNoFeedback) \ V(CallNoFeedback) \
...@@ -114,13 +133,30 @@ namespace compiler { ...@@ -114,13 +133,30 @@ namespace compiler {
V(Star) \ V(Star) \
V(Wide) \ V(Wide) \
CLEAR_ENVIRONMENT_LIST(V) \ CLEAR_ENVIRONMENT_LIST(V) \
CLEAR_ACCUMULATOR_LIST(V) CLEAR_ACCUMULATOR_LIST(V) \
CONDITIONAL_JUMPS_LIST(V) \
UNCONDITIONAL_JUMPS_LIST(V) \
INGORED_BYTECODE_LIST(V)
class JSHeapBroker; class JSHeapBroker;
template <typename T>
struct HandleComparator {
bool operator()(const Handle<T>& lhs, const Handle<T>& rhs) const {
return lhs.address() < rhs.address();
}
};
struct FunctionBlueprint { struct FunctionBlueprint {
Handle<SharedFunctionInfo> shared; Handle<SharedFunctionInfo> shared;
Handle<FeedbackVector> feedback_vector; Handle<FeedbackVector> feedback_vector;
bool operator<(const FunctionBlueprint& other) const {
// A feedback vector is never used for more than one SFI, so it could
// be used for strict ordering of blueprints.
return HandleComparator<FeedbackVector>()(feedback_vector,
other.feedback_vector);
}
}; };
class CompilationSubject { class CompilationSubject {
...@@ -137,13 +173,17 @@ class CompilationSubject { ...@@ -137,13 +173,17 @@ class CompilationSubject {
MaybeHandle<JSFunction> closure_; MaybeHandle<JSFunction> closure_;
}; };
typedef ZoneSet<Handle<Object>, HandleComparator<Object>> ConstantsSet;
typedef ZoneSet<Handle<Map>, HandleComparator<Map>> MapsSet;
typedef ZoneSet<FunctionBlueprint> BlueprintsSet;
class Hints { class Hints {
public: public:
explicit Hints(Zone* zone); explicit Hints(Zone* zone);
const ZoneVector<Handle<Object>>& constants() const; const ConstantsSet& constants() const;
const ZoneVector<Handle<Map>>& maps() const; const MapsSet& maps() const;
const ZoneVector<FunctionBlueprint>& function_blueprints() const; const BlueprintsSet& function_blueprints() const;
void AddConstant(Handle<Object> constant); void AddConstant(Handle<Object> constant);
void AddMap(Handle<Map> map); void AddMap(Handle<Map> map);
...@@ -155,9 +195,9 @@ class Hints { ...@@ -155,9 +195,9 @@ class Hints {
bool IsEmpty() const; bool IsEmpty() const;
private: private:
ZoneVector<Handle<Object>> constants_; ConstantsSet constants_;
ZoneVector<Handle<Map>> maps_; MapsSet maps_;
ZoneVector<FunctionBlueprint> function_blueprints_; BlueprintsSet function_blueprints_;
}; };
typedef ZoneVector<Hints> HintsVector; typedef ZoneVector<Hints> HintsVector;
...@@ -171,6 +211,8 @@ class SerializerForBackgroundCompilation { ...@@ -171,6 +211,8 @@ class SerializerForBackgroundCompilation {
Handle<JSFunction> closure); Handle<JSFunction> closure);
Hints Run(); // NOTE: Returns empty for an already-serialized function. Hints Run(); // NOTE: Returns empty for an already-serialized function.
class Environment;
private: private:
SerializerForBackgroundCompilation(JSHeapBroker* broker, Zone* zone, SerializerForBackgroundCompilation(JSHeapBroker* broker, Zone* zone,
CompilationSubject function, CompilationSubject function,
...@@ -184,14 +226,14 @@ class SerializerForBackgroundCompilation { ...@@ -184,14 +226,14 @@ class SerializerForBackgroundCompilation {
SUPPORTED_BYTECODE_LIST(DECLARE_VISIT_BYTECODE) SUPPORTED_BYTECODE_LIST(DECLARE_VISIT_BYTECODE)
#undef DECLARE_VISIT_BYTECODE #undef DECLARE_VISIT_BYTECODE
class Environment;
void ProcessCallOrConstruct(Hints callee, base::Optional<Hints> new_target, void ProcessCallOrConstruct(Hints callee, base::Optional<Hints> new_target,
const HintsVector& arguments, FeedbackSlot slot, const HintsVector& arguments, FeedbackSlot slot,
bool with_spread = false); bool with_spread = false);
void ProcessCallVarArgs(interpreter::BytecodeArrayIterator* iterator, void ProcessCallVarArgs(interpreter::BytecodeArrayIterator* iterator,
ConvertReceiverMode receiver_mode, ConvertReceiverMode receiver_mode,
bool with_spread = false); bool with_spread = false);
void ProcessJump(interpreter::BytecodeArrayIterator* iterator);
void MergeAfterJump(interpreter::BytecodeArrayIterator* iterator);
Hints RunChildSerializer(CompilationSubject function, Hints RunChildSerializer(CompilationSubject function,
base::Optional<Hints> new_target, base::Optional<Hints> new_target,
...@@ -204,6 +246,7 @@ class SerializerForBackgroundCompilation { ...@@ -204,6 +246,7 @@ class SerializerForBackgroundCompilation {
JSHeapBroker* const broker_; JSHeapBroker* const broker_;
Zone* const zone_; Zone* const zone_;
Environment* const environment_; Environment* const environment_;
ZoneUnorderedMap<int, Environment*> stashed_environments_;
}; };
} // namespace compiler } // namespace compiler
......
...@@ -28,6 +28,8 @@ SerializerTester::SerializerTester(const char* source) ...@@ -28,6 +28,8 @@ SerializerTester::SerializerTester(const char* source)
FLAG_use_ic = true; FLAG_use_ic = true;
// We need manual control over when a given function is optimized. // We need manual control over when a given function is optimized.
FLAG_always_opt = false; FLAG_always_opt = false;
// We need allocation of executable memory for the compilation.
FLAG_jitless = false;
std::string function_string = "(function() { "; std::string function_string = "(function() { ";
function_string += source; function_string += source;
...@@ -180,6 +182,36 @@ TEST(SerializeConstructWithSpread) { ...@@ -180,6 +182,36 @@ TEST(SerializeConstructWithSpread) {
"}; f(); return f;"); "}; f(); return f;");
} }
TEST(SerializeConditionalJump) {
CheckForSerializedInlinee(
"function g(callee) { callee(); };"
"function h() {};"
"function i() {};"
"let a = true;"
"g(h); g(i);"
"function f() {"
" function q() {};"
" if (a) g(q);"
" return q;"
"}; f(); return f;");
}
TEST(SerializeUnconditionalJump) {
CheckForSerializedInlinee(
"function g(callee) { callee(); };"
"function h() {};"
"function i() {};"
"let a = false;"
"g(h); g(i);"
"function f() {"
" function p() {};"
" function q() {};"
" if (a) g(q);"
" else g(p);"
" return p;"
"}; f(); return f;");
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
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