Commit 4c41299d authored by Georg Neis's avatar Georg Neis Committed by V8 LUCI CQ

[compiler] Fix serialization for Function#bind

It was not in sync with the optimization, which relies on
inspecting up the length and name fields even for bound
functions.

To make a now meaningful serializer test actually pass, I have
to to make some changes to the test setup.

I'm also moving the function name and length index constants
from JSFunction to JSFunctionOrBoundFunction for clarity.

TBR=marja@chromium.org

Bug: v8:7790
Change-Id: I36dd3c80996ccb53810c7ea9bfceb5c84ffd60ab
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2972919
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarSantiago Aboy Solanes <solanes@chromium.org>
Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75299}
parent 332d6c11
...@@ -16,10 +16,10 @@ extern transitioning builtin ...@@ -16,10 +16,10 @@ extern transitioning builtin
FunctionPrototypeBind(implicit context: Context)( FunctionPrototypeBind(implicit context: Context)(
JSFunction, JSAny, int32): JSAny; JSFunction, JSAny, int32): JSAny;
const kLengthDescriptorIndex: const kLengthDescriptorIndex: constexpr int32
constexpr int32 generates 'JSFunction::kLengthDescriptorIndex'; generates 'JSFunctionOrBoundFunction::kLengthDescriptorIndex';
const kNameDescriptorIndex: const kNameDescriptorIndex: constexpr int32
constexpr int32 generates 'JSFunction::kNameDescriptorIndex'; generates 'JSFunctionOrBoundFunction::kNameDescriptorIndex';
const kMinDescriptorsForFastBind: const kMinDescriptorsForFastBind:
constexpr int31 generates 'JSFunction::kMinDescriptorsForFastBind'; constexpr int31 generates 'JSFunction::kMinDescriptorsForFastBind';
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include "src/objects/feedback-vector-inl.h" #include "src/objects/feedback-vector-inl.h"
#include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-buffer-inl.h"
#include "src/objects/js-array-inl.h" #include "src/objects/js-array-inl.h"
#include "src/objects/js-objects.h" #include "src/objects/js-function.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
#include "src/objects/ordered-hash-table.h" #include "src/objects/ordered-hash-table.h"
...@@ -2633,14 +2633,17 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) { ...@@ -2633,14 +2633,17 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
// recomputed even if the actual value of the object changes. // recomputed even if the actual value of the object changes.
// This mirrors the checks done in builtins-function-gen.cc at // This mirrors the checks done in builtins-function-gen.cc at
// runtime otherwise. // runtime otherwise.
int minimum_nof_descriptors = std::max({JSFunction::kLengthDescriptorIndex, int minimum_nof_descriptors =
JSFunction::kNameDescriptorIndex}) + std::max({JSFunctionOrBoundFunction::kLengthDescriptorIndex,
1; JSFunctionOrBoundFunction::kNameDescriptorIndex}) +
1;
if (receiver_map.NumberOfOwnDescriptors() < minimum_nof_descriptors) { if (receiver_map.NumberOfOwnDescriptors() < minimum_nof_descriptors) {
return inference.NoChange(); return inference.NoChange();
} }
const InternalIndex kLengthIndex(JSFunction::kLengthDescriptorIndex); const InternalIndex kLengthIndex(
const InternalIndex kNameIndex(JSFunction::kNameDescriptorIndex); JSFunctionOrBoundFunction::kLengthDescriptorIndex);
const InternalIndex kNameIndex(
JSFunctionOrBoundFunction::kNameDescriptorIndex);
if (!receiver_map.serialized_own_descriptor(kLengthIndex) || if (!receiver_map.serialized_own_descriptor(kLengthIndex) ||
!receiver_map.serialized_own_descriptor(kNameIndex)) { !receiver_map.serialized_own_descriptor(kNameIndex)) {
TRACE_BROKER_MISSING(broker(), TRACE_BROKER_MISSING(broker(),
......
...@@ -2716,8 +2716,9 @@ void ProcessMapForFunctionBind(MapRef map) { ...@@ -2716,8 +2716,9 @@ void ProcessMapForFunctionBind(MapRef map) {
1; 1;
if (map.NumberOfOwnDescriptors() >= min_nof_descriptors) { if (map.NumberOfOwnDescriptors() >= min_nof_descriptors) {
map.SerializeOwnDescriptor( map.SerializeOwnDescriptor(
InternalIndex(JSFunction::kLengthDescriptorIndex)); InternalIndex(JSFunctionOrBoundFunction::kLengthDescriptorIndex));
map.SerializeOwnDescriptor(InternalIndex(JSFunction::kNameDescriptorIndex)); map.SerializeOwnDescriptor(
InternalIndex(JSFunctionOrBoundFunction::kNameDescriptorIndex));
} }
} }
} // namespace } // namespace
...@@ -2725,17 +2726,22 @@ void ProcessMapForFunctionBind(MapRef map) { ...@@ -2725,17 +2726,22 @@ void ProcessMapForFunctionBind(MapRef map) {
void SerializerForBackgroundCompilation::ProcessHintsForFunctionBind( void SerializerForBackgroundCompilation::ProcessHintsForFunctionBind(
Hints const& receiver_hints) { Hints const& receiver_hints) {
for (auto constant : receiver_hints.constants()) { for (auto constant : receiver_hints.constants()) {
if (!constant->IsJSFunction()) continue; if (constant->IsJSFunction()) {
JSFunctionRef function = JSFunctionRef function =
MakeRef(broker(), Handle<JSFunction>::cast(constant)); MakeRef(broker(), Handle<JSFunction>::cast(constant));
function.Serialize(); function.Serialize();
ProcessMapForFunctionBind(function.map()); ProcessMapForFunctionBind(function.map());
} else if (constant->IsJSBoundFunction()) {
JSBoundFunctionRef function =
MakeRef(broker(), Handle<JSBoundFunction>::cast(constant));
function.Serialize();
ProcessMapForFunctionBind(function.map());
}
} }
for (auto map : receiver_hints.maps()) { for (auto map : receiver_hints.maps()) {
if (!map->IsJSFunctionMap()) continue; if (!map->IsJSFunctionMap() && !map->IsJSBoundFunctionMap()) continue;
MapRef map_ref = MakeRef(broker(), map); ProcessMapForFunctionBind(MakeRef(broker(), map));
ProcessMapForFunctionBind(map_ref);
} }
} }
......
...@@ -3572,14 +3572,14 @@ Handle<Map> Factory::CreateSloppyFunctionMap( ...@@ -3572,14 +3572,14 @@ Handle<Map> Factory::CreateSloppyFunctionMap(
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY); static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
int field_index = 0; int field_index = 0;
STATIC_ASSERT(JSFunction::kLengthDescriptorIndex == 0); STATIC_ASSERT(JSFunctionOrBoundFunction::kLengthDescriptorIndex == 0);
{ // Add length accessor. { // Add length accessor.
Descriptor d = Descriptor::AccessorConstant( Descriptor d = Descriptor::AccessorConstant(
length_string(), function_length_accessor(), roc_attribs); length_string(), function_length_accessor(), roc_attribs);
map->AppendDescriptor(isolate(), &d); map->AppendDescriptor(isolate(), &d);
} }
STATIC_ASSERT(JSFunction::kNameDescriptorIndex == 1); STATIC_ASSERT(JSFunctionOrBoundFunction::kNameDescriptorIndex == 1);
if (IsFunctionModeWithName(function_mode)) { if (IsFunctionModeWithName(function_mode)) {
// Add name field. // Add name field.
Handle<Name> name = isolate()->factory()->name_string(); Handle<Name> name = isolate()->factory()->name_string();
......
...@@ -3871,6 +3871,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -3871,6 +3871,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Map::EnsureDescriptorSlack(isolate_, map, 2); Map::EnsureDescriptorSlack(isolate_, map, 2);
{ // length { // length
STATIC_ASSERT(JSFunctionOrBoundFunction::kLengthDescriptorIndex == 0);
Descriptor d = Descriptor::AccessorConstant( Descriptor d = Descriptor::AccessorConstant(
factory->length_string(), factory->bound_function_length_accessor(), factory->length_string(), factory->bound_function_length_accessor(),
roc_attribs); roc_attribs);
...@@ -3878,6 +3879,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -3878,6 +3879,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
} }
{ // name { // name
STATIC_ASSERT(JSFunctionOrBoundFunction::kNameDescriptorIndex == 1);
Descriptor d = Descriptor::AccessorConstant( Descriptor d = Descriptor::AccessorConstant(
factory->name_string(), factory->bound_function_name_accessor(), factory->name_string(), factory->bound_function_name_accessor(),
roc_attribs); roc_attribs);
......
...@@ -24,6 +24,9 @@ class JSFunctionOrBoundFunction ...@@ -24,6 +24,9 @@ class JSFunctionOrBoundFunction
: public TorqueGeneratedJSFunctionOrBoundFunction<JSFunctionOrBoundFunction, : public TorqueGeneratedJSFunctionOrBoundFunction<JSFunctionOrBoundFunction,
JSObject> { JSObject> {
public: public:
static const int kLengthDescriptorIndex = 0;
static const int kNameDescriptorIndex = 1;
STATIC_ASSERT(kHeaderSize == JSObject::kHeaderSize); STATIC_ASSERT(kHeaderSize == JSObject::kHeaderSize);
TQ_OBJECT_CONSTRUCTORS(JSFunctionOrBoundFunction) TQ_OBJECT_CONSTRUCTORS(JSFunctionOrBoundFunction)
}; };
...@@ -59,9 +62,6 @@ class JSFunction : public JSFunctionOrBoundFunction { ...@@ -59,9 +62,6 @@ class JSFunction : public JSFunctionOrBoundFunction {
// can be shared by instances. // can be shared by instances.
DECL_ACCESSORS(shared, SharedFunctionInfo) DECL_ACCESSORS(shared, SharedFunctionInfo)
static const int kLengthDescriptorIndex = 0;
static const int kNameDescriptorIndex = 1;
// Fast binding requires length and name accessors. // Fast binding requires length and name accessors.
static const int kMinDescriptorsForFastBind = 2; static const int kMinDescriptorsForFastBind = 2;
......
...@@ -272,6 +272,7 @@ i::Handle<i::JSFunction> Optimize( ...@@ -272,6 +272,7 @@ i::Handle<i::JSFunction> Optimize(
i::OptimizedCompilationInfo info(zone, isolate, shared, function, i::OptimizedCompilationInfo info(zone, isolate, shared, function,
i::CodeKind::TURBOFAN); i::CodeKind::TURBOFAN);
if (flags & ~i::OptimizedCompilationInfo::kInlining) UNIMPLEMENTED();
if (flags & i::OptimizedCompilationInfo::kInlining) { if (flags & i::OptimizedCompilationInfo::kInlining) {
info.set_inlining(); info.set_inlining();
} }
......
This diff is collapsed.
...@@ -18,15 +18,16 @@ class ZoneStats; ...@@ -18,15 +18,16 @@ class ZoneStats;
// The purpose of this class is to provide testing facility for the // The purpose of this class is to provide testing facility for the
// SerializerForBackgroundCompilation class. On a high-level, it executes the // SerializerForBackgroundCompilation class. On a high-level, it executes the
// following steps: // code given by {global_source} at global scope and then performs the following
// 1. Wraps the provided source in an IIFE // steps for {local_source}:
// 2. Generates bytecode for the given source // 1. Wraps it in an IIFE.
// 3. Runs the bytecode which *must* return a function // 2. Generates bytecode and runs it, which *must* return a function.
// 4. Takes the returned function and optimizes it // 3. Takes the returned function and optimizes it.
// 5. The optimized function is accessible through `function()` // 4. The optimized function is accessible through `function()`.
class SerializerTester : public HandleAndZoneScope { class SerializerTester : public HandleAndZoneScope {
public: public:
explicit SerializerTester(const char* source); explicit SerializerTester(const char* global_source,
const char* local_source);
JSFunctionRef function() const { return function_.value(); } JSFunctionRef function() const { return function_.value(); }
JSHeapBroker* broker() const { return broker_.get(); } JSHeapBroker* broker() const { return broker_.get(); }
......
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