Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Unified Diff: src/code-stubs-hydrogen.cc

Issue 2044113002: Turn Function.prototype.bind into a hydrogen stub optimized for the common case (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: arm64 Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/code-stubs.h ('k') | src/crankshaft/hydrogen-instructions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/code-stubs-hydrogen.cc
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index 2192e3fc2b71a4ae4c701631daede0a9945c0aab..683a4c526eab763aaa4b7dca85313f329e915dc4 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -882,6 +882,191 @@ HValue* CodeStubGraphBuilder<FastArrayPushStub>::BuildCodeStub() {
Handle<Code> FastArrayPushStub::GenerateCode() { return DoGenerateCode(this); }
template <>
+HValue* CodeStubGraphBuilder<FastFunctionBindStub>::BuildCodeStub() {
+ // TODO(verwaest): Fix deoptimizer messages.
+ HValue* argc = GetArgumentsLength();
+ HInstruction* argument_elements = Add<HArgumentsElements>(false, false);
+ HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc,
+ graph()->GetConstantMinus1());
+ BuildCheckHeapObject(object);
+ HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap());
+ Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_FUNCTION);
+
+ // Disallow binding of slow-mode functions. We need to figure out whether the
+ // length and name property are in the original state.
+ {
+ HValue* bit_field3 =
+ Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3());
+ HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask));
+ HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask);
+ IfBuilder check(this);
+ check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ);
+ check.ThenDeopt(Deoptimizer::kFastFunctionBindFailed);
+ check.End();
+ }
+
+ // Check whether the length and name properties are still present as
+ // AccessorInfo objects. In that case, their value can be recomputed even if
+ // the actual value on the object changes.
+ {
+ HValue* descriptors =
+ Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors());
+
+ HValue* descriptors_length = Add<HLoadNamedField>(
+ descriptors, nullptr, HObjectAccess::ForFixedArrayLength());
+ IfBuilder range(this);
+ range.If<HCompareNumericAndBranch>(descriptors_length,
+ graph()->GetConstant1(), Token::LTE);
+ range.ThenDeopt(Deoptimizer::kFastFunctionBindFailed);
+ range.End();
+
+ // Verify .length.
+ const int length_index = JSFunction::kLengthDescriptorIndex;
+ HValue* maybe_length = Add<HLoadKeyed>(
+ descriptors, Add<HConstant>(DescriptorArray::ToKeyIndex(length_index)),
+ nullptr, nullptr, FAST_ELEMENTS);
+ Unique<Name> length_string = Unique<Name>::CreateUninitialized(
+ isolate()->factory()->length_string());
+ Add<HCheckValue>(maybe_length, length_string, false);
+
+ HValue* maybe_length_accessor = Add<HLoadKeyed>(
+ descriptors,
+ Add<HConstant>(DescriptorArray::ToValueIndex(length_index)), nullptr,
+ nullptr, FAST_ELEMENTS);
+ BuildCheckHeapObject(maybe_length_accessor);
+ Add<HCheckMaps>(maybe_length_accessor,
+ isolate()->factory()->accessor_info_map());
+
+ // Verify .name.
+ const int name_index = JSFunction::kNameDescriptorIndex;
+ HValue* maybe_name = Add<HLoadKeyed>(
+ descriptors, Add<HConstant>(DescriptorArray::ToKeyIndex(name_index)),
+ nullptr, nullptr, FAST_ELEMENTS);
+ Unique<Name> name_string =
+ Unique<Name>::CreateUninitialized(isolate()->factory()->name_string());
+ Add<HCheckValue>(maybe_name, name_string, false);
+
+ HValue* maybe_name_accessor = Add<HLoadKeyed>(
+ descriptors, Add<HConstant>(DescriptorArray::ToValueIndex(name_index)),
+ nullptr, nullptr, FAST_ELEMENTS);
+ BuildCheckHeapObject(maybe_name_accessor);
+ Add<HCheckMaps>(maybe_name_accessor,
+ isolate()->factory()->accessor_info_map());
+ }
+
+ // Choose the right bound function map based on whether the target is
+ // constructable.
+ {
+ HValue* bit_field =
+ Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField());
+ HValue* mask = Add<HConstant>(static_cast<int>(1 << Map::kIsConstructor));
+ HValue* bits = AddUncasted<HBitwise>(Token::BIT_AND, bit_field, mask);
+
+ HValue* native_context = BuildGetNativeContext();
+ IfBuilder is_constructor(this);
+ is_constructor.If<HCompareNumericAndBranch>(bits, mask, Token::EQ);
+ is_constructor.Then();
+ {
+ HValue* map = Add<HLoadNamedField>(
+ native_context, nullptr,
+ HObjectAccess::ForContextSlot(
+ Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX));
+ environment()->Push(map);
+ }
+ is_constructor.Else();
+ {
+ HValue* map = Add<HLoadNamedField>(
+ native_context, nullptr,
+ HObjectAccess::ForContextSlot(
+ Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX));
+ environment()->Push(map);
+ }
+ is_constructor.End();
+ }
+ HValue* bound_function_map = environment()->Pop();
+
+ // Verify that __proto__ matches that of a the target bound function.
+ {
+ HValue* prototype =
+ Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForPrototype());
+ HValue* expected_prototype = Add<HLoadNamedField>(
+ bound_function_map, nullptr, HObjectAccess::ForPrototype());
+ IfBuilder equal_prototype(this);
+ equal_prototype.IfNot<HCompareObjectEqAndBranch>(prototype,
+ expected_prototype);
+ equal_prototype.ThenDeopt(Deoptimizer::kFastFunctionBindFailed);
+ equal_prototype.End();
+ }
+
+ // Allocate the arguments array.
+ IfBuilder empty_args(this);
+ empty_args.If<HCompareNumericAndBranch>(argc, graph()->GetConstant1(),
+ Token::LTE);
+ empty_args.Then();
+ { environment()->Push(Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex)); }
+ empty_args.Else();
+ {
+ HValue* elements_length = AddUncasted<HSub>(argc, graph()->GetConstant1());
+ HValue* elements =
+ BuildAllocateAndInitializeArray(FAST_ELEMENTS, elements_length);
+
+ LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
+ HValue* start = graph()->GetConstant1();
+ HValue* key = builder.BeginBody(start, argc, Token::LT);
+ {
+ HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key);
+ HValue* index = AddUncasted<HSub>(key, graph()->GetConstant1());
+ AddElementAccess(elements, index, argument, elements, nullptr,
+ FAST_ELEMENTS, STORE);
+ }
+ builder.EndBody();
+ environment()->Push(elements);
+ }
+ empty_args.End();
+ HValue* elements = environment()->Pop();
+
+ // Find the 'this' to bind.
+ IfBuilder no_receiver(this);
+ no_receiver.If<HCompareNumericAndBranch>(argc, graph()->GetConstant0(),
+ Token::EQ);
+ no_receiver.Then();
+ { environment()->Push(Add<HLoadRoot>(Heap::kUndefinedValueRootIndex)); }
+ no_receiver.Else();
+ {
+ environment()->Push(Add<HAccessArgumentsAt>(argument_elements, argc,
+ graph()->GetConstant0()));
+ }
+ no_receiver.End();
+ HValue* receiver = environment()->Pop();
+
+ // Allocate the resulting bound function.
+ HValue* size = Add<HConstant>(JSBoundFunction::kSize);
+ HValue* bound_function =
+ Add<HAllocate>(size, HType::JSObject(), NOT_TENURED,
+ JS_BOUND_FUNCTION_TYPE, graph()->GetConstant0());
+ Add<HStoreNamedField>(bound_function, HObjectAccess::ForMap(),
+ bound_function_map);
+ HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
+ Add<HStoreNamedField>(bound_function, HObjectAccess::ForPropertiesPointer(),
+ empty_fixed_array);
+ Add<HStoreNamedField>(bound_function, HObjectAccess::ForElementsPointer(),
+ empty_fixed_array);
+ Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundTargetFunction(),
+ object);
+
+ Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundThis(),
+ receiver);
+ Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundArguments(),
+ elements);
+
+ return bound_function;
+}
+
+Handle<Code> FastFunctionBindStub::GenerateCode() {
+ return DoGenerateCode(this);
+}
+
+template <>
HValue* CodeStubGraphBuilder<GrowArrayElementsStub>::BuildCodeStub() {
ElementsKind kind = casted_stub()->elements_kind();
if (IsFastDoubleElementsKind(kind)) {
« no previous file with comments | « src/code-stubs.h ('k') | src/crankshaft/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698