76c6282de6
This is a Dart-tailored implementation of the "row-displacement dispatch table" technique for closed-world instance calls: All interface targets in the program are grouped into selectors such that all targets that could potentially be called from the same call site have the same selector (currently just grouped by name). Each selector is assigned a selector offset such that offset + classid is unique for all selector/classid combinations where the class implements the selector. At every instance call site that has an interface target (i.e. where the static type of the receiver is not dynamic), the selector offset + receiver classid is computed and used as index into a global table of entry points. If the receiver can be null (as determined by the front-end TFA and the VM type propagation), a null check is inserted before the call. An arguments descriptor is provided (only) for selectors that need it (those which have type parameters or optional/named parameters). The dispatch table calls don't need the monomorphic entry code, so for functions that are only called via dispatch table calls (i.e. never called dynamically), the monomorphic entry code is left out. Some future improvements to the table dispatch implementation are mentioned in https://github.com/dart-lang/sdk/issues/40188 The table dispatch flag is disabled by default in this commit. A separate commit enables the flag. Change-Id: Ic2911742b4a2c9a8d3bc7df60605454cbe4c0714 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/126648 Commit-Queue: Aske Simon Christensen <askesc@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
80 lines
2.0 KiB
C++
80 lines
2.0 KiB
C++
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#ifndef RUNTIME_VM_DISPATCH_TABLE_H_
|
|
#define RUNTIME_VM_DISPATCH_TABLE_H_
|
|
|
|
#include <memory>
|
|
|
|
#include "vm/globals.h"
|
|
#include "vm/growable_array.h"
|
|
|
|
namespace dart {
|
|
|
|
class Array;
|
|
class Code;
|
|
class Deserializer;
|
|
class RawCode;
|
|
class Serializer;
|
|
|
|
namespace compiler {
|
|
class DispatchTableGenerator;
|
|
}
|
|
|
|
class DispatchTable {
|
|
public:
|
|
explicit DispatchTable(intptr_t length)
|
|
: length_(length), array_(new uword[length]()) {}
|
|
|
|
intptr_t length() const { return length_; }
|
|
uword* array() const { return array_.get(); }
|
|
|
|
// The element of the dispatch table array to which the dispatch table
|
|
// register points.
|
|
static intptr_t OriginElement() {
|
|
#if defined(TARGET_ARCH_X64)
|
|
// Max negative byte offset / 8
|
|
return 16;
|
|
#elif defined(TARGET_ARCH_ARM)
|
|
// Max negative load offset / 4
|
|
return 1023;
|
|
#elif defined(TARGET_ARCH_ARM64)
|
|
// Max consecutive sub immediate value
|
|
return 4096;
|
|
#else
|
|
// No AOT on IA32
|
|
UNREACHABLE();
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
// Dispatch table array pointer to put into the dispatch table register.
|
|
uword* ArrayOrigin() const { return &array()[OriginElement()]; }
|
|
|
|
void SetCodeAt(intptr_t index, const Code& code);
|
|
|
|
static intptr_t Serialize(Serializer* serializer,
|
|
const DispatchTable* table,
|
|
const GrowableArray<RawCode*>& code_objects);
|
|
static DispatchTable* Deserialize(Deserializer* deserializer,
|
|
const Array& code_array);
|
|
|
|
private:
|
|
friend class compiler::DispatchTableGenerator;
|
|
|
|
void Serialize(Serializer* serializer,
|
|
const GrowableArray<RawCode*>& code_objects) const;
|
|
|
|
static uword EntryPointFor(const Code& code);
|
|
|
|
intptr_t length_;
|
|
std::unique_ptr<uword[]> array_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(DispatchTable);
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_DISPATCH_TABLE_H_
|