Commit 585e3d16 authored by Creddy's avatar Creddy Committed by Commit Bot

[runtime] Fix the bug that caused performance regression with prototype lookup

Word32Not was used instead of Word32BinaryNot which caused unecssary runtime lookup.
This CL fixed the performance regression https://crrev.com/c/1145438.

Bug: chromium:868799
Change-Id: I9e070de6155797e52dd9b461a9660cb003509a57
Reviewed-on: https://chromium-review.googlesource.com/1169808
Commit-Queue: Chandan Reddy <chandanreddy@google.com>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55100}
parent c46915b9
...@@ -2454,7 +2454,7 @@ TNode<Map> CodeStubAssembler::LoadJSArrayElementsMap( ...@@ -2454,7 +2454,7 @@ TNode<Map> CodeStubAssembler::LoadJSArrayElementsMap(
LoadContextElement(native_context, Context::ArrayMapIndex(kind))); LoadContextElement(native_context, Context::ArrayMapIndex(kind)));
} }
TNode<Word32T> CodeStubAssembler::IsGeneratorFunction( TNode<BoolT> CodeStubAssembler::IsGeneratorFunction(
TNode<JSFunction> function) { TNode<JSFunction> function) {
TNode<SharedFunctionInfo> const shared_function_info = TNode<SharedFunctionInfo> const shared_function_info =
CAST(LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset)); CAST(LoadObjectField(function, JSFunction::kSharedFunctionInfoOffset));
...@@ -2464,7 +2464,7 @@ TNode<Word32T> CodeStubAssembler::IsGeneratorFunction( ...@@ -2464,7 +2464,7 @@ TNode<Word32T> CodeStubAssembler::IsGeneratorFunction(
shared_function_info, SharedFunctionInfo::kFlagsOffset, shared_function_info, SharedFunctionInfo::kFlagsOffset,
MachineType::Uint32())); MachineType::Uint32()));
return Word32Or( return TNode<BoolT>::UncheckedCast(Word32Or(
Word32Or( Word32Or(
Word32Or( Word32Or(
Word32Equal(function_kind, Word32Equal(function_kind,
...@@ -2475,25 +2475,26 @@ TNode<Word32T> CodeStubAssembler::IsGeneratorFunction( ...@@ -2475,25 +2475,26 @@ TNode<Word32T> CodeStubAssembler::IsGeneratorFunction(
Word32Equal(function_kind, Word32Equal(function_kind,
Int32Constant(FunctionKind::kGeneratorFunction))), Int32Constant(FunctionKind::kGeneratorFunction))),
Word32Equal(function_kind, Word32Equal(function_kind,
Int32Constant(FunctionKind::kConciseGeneratorMethod))); Int32Constant(FunctionKind::kConciseGeneratorMethod))));
} }
TNode<Word32T> CodeStubAssembler::HasPrototypeProperty( TNode<BoolT> CodeStubAssembler::HasPrototypeProperty(TNode<JSFunction> function,
TNode<JSFunction> function) { TNode<Map> map) {
TNode<Int32T> mask = Int32Constant(Map::HasPrototypeSlotBit::kMask | // (has_prototype_slot() && IsConstructor()) ||
Map::IsConstructorBit::kMask); // IsGeneratorFunction(shared()->kind())
return Word32Or( uint32_t mask =
Word32Equal(Word32And(LoadMapBitField(LoadMap(function)), mask), mask), Map::HasPrototypeSlotBit::kMask | Map::IsConstructorBit::kMask;
IsGeneratorFunction(function)); return TNode<BoolT>::UncheckedCast(
Word32Or(IsAllSetWord32(LoadMapBitField(map), mask),
IsGeneratorFunction(function)));
} }
TNode<Word32T> CodeStubAssembler::PrototypeRequiresRuntimeLookup( void CodeStubAssembler::GotoIfPrototypeRequiresRuntimeLookup(
TNode<JSFunction> function) { TNode<JSFunction> function, TNode<Map> map, Label* runtime) {
TNode<Map> map = LoadMap(function); // !has_prototype_property() || has_non_instance_prototype()
GotoIfNot(HasPrototypeProperty(function, map), runtime);
return Word32Or( GotoIf(IsSetWord32<Map::HasNonInstancePrototypeBit>(LoadMapBitField(map)),
Word32BinaryNot(HasPrototypeProperty(function)), runtime);
IsSetWord32<Map::HasNonInstancePrototypeBit>(LoadMapBitField(map)));
} }
Node* CodeStubAssembler::LoadJSFunctionPrototype(Node* function, Node* CodeStubAssembler::LoadJSFunctionPrototype(Node* function,
...@@ -8385,7 +8386,8 @@ TNode<Object> CodeStubAssembler::CallGetterIfAccessor( ...@@ -8385,7 +8386,8 @@ TNode<Object> CodeStubAssembler::CallGetterIfAccessor(
LoadObjectField(accessor_info, AccessorInfo::kNameOffset)), LoadObjectField(accessor_info, AccessorInfo::kNameOffset)),
if_bailout); if_bailout);
GotoIf(PrototypeRequiresRuntimeLookup(CAST(receiver)), if_bailout); GotoIfPrototypeRequiresRuntimeLookup(CAST(receiver), CAST(receiver_map),
if_bailout);
var_value.Bind(LoadJSFunctionPrototype(receiver, if_bailout)); var_value.Bind(LoadJSFunctionPrototype(receiver, if_bailout));
Goto(&done); Goto(&done);
} }
...@@ -8839,7 +8841,8 @@ Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable, ...@@ -8839,7 +8841,8 @@ Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable,
GotoIfNot(InstanceTypeEqual(callable_instance_type, JS_FUNCTION_TYPE), GotoIfNot(InstanceTypeEqual(callable_instance_type, JS_FUNCTION_TYPE),
&return_runtime); &return_runtime);
GotoIf(PrototypeRequiresRuntimeLookup(CAST(callable)), &return_runtime); GotoIfPrototypeRequiresRuntimeLookup(CAST(callable), CAST(callable_map),
&return_runtime);
// Get the "prototype" (or initial map) of the {callable}. // Get the "prototype" (or initial map) of the {callable}.
Node* callable_prototype = Node* callable_prototype =
......
...@@ -1116,9 +1116,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -1116,9 +1116,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
TNode<Map> LoadJSArrayElementsMap(SloppyTNode<Int32T> kind, TNode<Map> LoadJSArrayElementsMap(SloppyTNode<Int32T> kind,
SloppyTNode<Context> native_context); SloppyTNode<Context> native_context);
TNode<Word32T> IsGeneratorFunction(TNode<JSFunction> function); TNode<BoolT> IsGeneratorFunction(TNode<JSFunction> function);
TNode<Word32T> HasPrototypeProperty(TNode<JSFunction> function); TNode<BoolT> HasPrototypeProperty(TNode<JSFunction> function, TNode<Map> map);
TNode<Word32T> PrototypeRequiresRuntimeLookup(TNode<JSFunction> function); void GotoIfPrototypeRequiresRuntimeLookup(TNode<JSFunction> function,
TNode<Map> map, Label* runtime);
// Load the "prototype" property of a JSFunction. // Load the "prototype" property of a JSFunction.
Node* LoadJSFunctionPrototype(Node* function, Label* if_bailout); Node* LoadJSFunctionPrototype(Node* function, Label* if_bailout);
...@@ -2053,6 +2054,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -2053,6 +2054,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Int32Constant(0)); Int32Constant(0));
} }
// Returns true if all of the mask's bits in a given |word32| are set.
TNode<BoolT> IsAllSetWord32(SloppyTNode<Word32T> word32, uint32_t mask) {
TNode<Int32T> const_mask = Int32Constant(mask);
return Word32Equal(Word32And(word32, const_mask), const_mask);
}
// Returns true if any of the |T|'s bits in given |word| are set. // Returns true if any of the |T|'s bits in given |word| are set.
template <typename T> template <typename T>
TNode<BoolT> IsSetWord(SloppyTNode<WordT> word) { TNode<BoolT> IsSetWord(SloppyTNode<WordT> word) {
......
...@@ -2494,8 +2494,8 @@ void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) { ...@@ -2494,8 +2494,8 @@ void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
&not_function_prototype); &not_function_prototype);
GotoIfNot(IsPrototypeString(p->name), &not_function_prototype); GotoIfNot(IsPrototypeString(p->name), &not_function_prototype);
GotoIf(PrototypeRequiresRuntimeLookup(CAST(receiver)), GotoIfPrototypeRequiresRuntimeLookup(CAST(receiver), CAST(receiver_map),
&not_function_prototype); &not_function_prototype);
Return(LoadJSFunctionPrototype(receiver, &miss)); Return(LoadJSFunctionPrototype(receiver, &miss));
BIND(&not_function_prototype); BIND(&not_function_prototype);
} }
......
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