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