[builtins] Add builtins constants list to roots
This is a step towards off-heap (and eventually isolate-independent) builtins. Off-heap code cannot use the standard CallStub/CallRuntime mechanisms, since they directly embed the callee code object pointer within the caller. There are two main issues with that: 1. the callee may be moved by GC, and 2. the pc-relative addressing we currently use breaks (i.e. ends up pointing to a random spot on the heap) when moving the caller off-heap. This CL addresses that by introducing a constants list stored on the roots array. Instead of embedding code targets, we now have the option of loading them from constants list. The code sequence is: REX.W movq rax,[r13+0x4a0] // Load the constants cache. REX.W movq rdx,[rax+0xf] // From there, load the code target. ... REX.W addq rdx,0x5f // Add instruction_start. call rdx There's no visible performance impact on the web tooling benchmark. This list will later be extended to also contain other constants such as Strings. Bug: v8:6666 Change-Id: Ifcf67d1f682804ba0b6d3d0383216e16575b6bf5 Reviewed-on: https://chromium-review.googlesource.com/923729 Commit-Queue: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Cr-Commit-Position: refs/heads/master@{#51434}
This commit is contained in:
parent
46c4979e86
commit
ad74be52fa
3
BUILD.gn
3
BUILD.gn
@ -65,6 +65,7 @@ declare_args() {
|
||||
v8_enable_fast_mksnapshot = false
|
||||
|
||||
# Enable embedded builtins.
|
||||
# TODO(jgruber,v8:6666): Support ia32.
|
||||
v8_enable_embedded_builtins = false
|
||||
|
||||
# Enable code-generation-time checking of types in the CodeStubAssembler.
|
||||
@ -1326,6 +1327,8 @@ v8_source_set("v8_base") {
|
||||
"src/builtins/builtins-utils.h",
|
||||
"src/builtins/builtins.cc",
|
||||
"src/builtins/builtins.h",
|
||||
"src/builtins/constants-table-builder.cc",
|
||||
"src/builtins/constants-table-builder.h",
|
||||
"src/cached-powers.cc",
|
||||
"src/cached-powers.h",
|
||||
"src/callable.h",
|
||||
|
@ -283,14 +283,28 @@ bool Builtins::IsIsolateIndependent(int index) {
|
||||
case kContinueToJavaScriptBuiltin:
|
||||
case kContinueToJavaScriptBuiltinWithResult:
|
||||
#ifndef DEBUG
|
||||
#if !V8_TARGET_ARCH_IA32
|
||||
case kAsyncFunctionAwaitFulfill:
|
||||
case kAsyncFunctionAwaitReject:
|
||||
case kAsyncGeneratorAwaitFulfill:
|
||||
case kAsyncGeneratorAwaitReject:
|
||||
case kAsyncGeneratorReturnClosedFulfill:
|
||||
case kAsyncGeneratorReturnClosedReject:
|
||||
case kAsyncGeneratorReturnFulfill:
|
||||
case kAsyncGeneratorYieldFulfill:
|
||||
case kConstructFunction:
|
||||
case kTypeof:
|
||||
case kWeakMapLookupHashIndex:
|
||||
#endif
|
||||
case kKeyedLoadICTrampoline:
|
||||
case kKeyedStoreICTrampoline:
|
||||
case kLoadGlobalICInsideTypeofTrampoline:
|
||||
case kLoadGlobalICTrampoline:
|
||||
case kLoadIC_StringLength:
|
||||
case kLoadIC_StringWrapperLength:
|
||||
case kLoadICTrampoline:
|
||||
case kOrderedHashTableHealIndex:
|
||||
case kStoreGlobalICTrampoline:
|
||||
case kStoreICTrampoline:
|
||||
case kStringRepeat:
|
||||
case kTypeof:
|
||||
case kWeakMapLookupHashIndex:
|
||||
#endif
|
||||
return true;
|
||||
default:
|
||||
|
74
src/builtins/constants-table-builder.cc
Normal file
74
src/builtins/constants-table-builder.cc
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/builtins/constants-table-builder.h"
|
||||
|
||||
#include "src/heap/heap-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
BuiltinsConstantsTableBuilder::BuiltinsConstantsTableBuilder(Isolate* isolate)
|
||||
: isolate_(isolate), map_(isolate->heap()) {
|
||||
// Ensure this is only called once per Isolate.
|
||||
DCHECK_EQ(isolate_->heap()->empty_fixed_array(),
|
||||
isolate_->heap()->builtins_constants_table());
|
||||
|
||||
// And that the initial value of the builtins constants table can be treated
|
||||
// as a constant, which means that codegen will load it using the root
|
||||
// register.
|
||||
DCHECK(isolate_->heap()->RootCanBeTreatedAsConstant(
|
||||
Heap::kEmptyFixedArrayRootIndex));
|
||||
}
|
||||
|
||||
uint32_t BuiltinsConstantsTableBuilder::AddObject(Handle<Object> object) {
|
||||
#ifdef DEBUG
|
||||
// Roots must not be inserted into the constants table as they are already
|
||||
// accessibly from the root list.
|
||||
Heap::RootListIndex root_list_index;
|
||||
DCHECK(!isolate_->heap()->IsRootHandle(object, &root_list_index));
|
||||
|
||||
// Not yet finalized.
|
||||
DCHECK_EQ(isolate_->heap()->empty_fixed_array(),
|
||||
isolate_->heap()->builtins_constants_table());
|
||||
#endif
|
||||
|
||||
uint32_t* maybe_key = map_.Find(object);
|
||||
if (maybe_key == nullptr) {
|
||||
uint32_t index = map_.size();
|
||||
map_.Set(object, index);
|
||||
return index;
|
||||
} else {
|
||||
return *maybe_key;
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltinsConstantsTableBuilder::Finalize() {
|
||||
HandleScope handle_scope(isolate_);
|
||||
|
||||
DCHECK_EQ(isolate_->heap()->empty_fixed_array(),
|
||||
isolate_->heap()->builtins_constants_table());
|
||||
|
||||
DCHECK_LT(0, map_.size());
|
||||
Handle<FixedArray> table =
|
||||
isolate_->factory()->NewFixedArray(map_.size(), TENURED);
|
||||
|
||||
ConstantsMap::IteratableScope it_scope(&map_);
|
||||
for (auto it = it_scope.begin(); it != it_scope.end(); ++it) {
|
||||
uint32_t index = *it.entry();
|
||||
table->set(index, it.key());
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
for (int i = 0; i < map_.size(); i++) {
|
||||
DCHECK(table->get(i)->IsHeapObject());
|
||||
DCHECK_NE(isolate_->heap()->undefined_value(), table->get(i));
|
||||
}
|
||||
#endif
|
||||
|
||||
isolate_->heap()->SetBuiltinsConstantsTable(*table);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
48
src/builtins/constants-table-builder.h
Normal file
48
src/builtins/constants-table-builder.h
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_BUILTINS_CONSTANTS_TABLE_BUILDER_H_
|
||||
#define V8_BUILTINS_CONSTANTS_TABLE_BUILDER_H_
|
||||
|
||||
#include "src/allocation.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/handles.h"
|
||||
#include "src/identity-map.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class Isolate;
|
||||
class Object;
|
||||
|
||||
// Utility class to build the builtins constants table and store it on the root
|
||||
// list. The constants table contains constants used by builtins, and is there
|
||||
// to avoid directly embedding them into code objects, which would not be
|
||||
// possible for off-heap (and thus immutable) code objects.
|
||||
class BuiltinsConstantsTableBuilder final {
|
||||
public:
|
||||
explicit BuiltinsConstantsTableBuilder(Isolate* isolate);
|
||||
|
||||
// Returns the index within the builtins constants list for the given object,
|
||||
// possibly adding the object to the cache. Objects are deduplicated.
|
||||
uint32_t AddObject(Handle<Object> object);
|
||||
|
||||
// Should be called after all affected code (e.g. builtins and bytecode
|
||||
// handlers) has been generated.
|
||||
void Finalize();
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
|
||||
// Maps objects to corresponding indices within the constants list.
|
||||
typedef IdentityMap<uint32_t, FreeStoreAllocationPolicy> ConstantsMap;
|
||||
ConstantsMap map_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BuiltinsConstantsTableBuilder)
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_BUILTINS_CONSTANTS_TABLE_BUILDER_H_
|
@ -1,7 +1,10 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/code-stub-assembler.h"
|
||||
|
||||
#include "src/builtins/constants-table-builder.h"
|
||||
#include "src/code-factory.h"
|
||||
#include "src/frames-inl.h"
|
||||
#include "src/frames.h"
|
||||
@ -7302,6 +7305,23 @@ void CodeStubAssembler::TryGetOwnProperty(
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
TNode<Code> CodeStubAssembler::LookupConstantCodeTarget(Handle<Code> code) {
|
||||
DCHECK(isolate()->serializer_enabled());
|
||||
// The builtins constants table is loaded through the root register on all
|
||||
// supported platforms. This is checked by the
|
||||
// VerifyBuiltinsIsolateIndependence cctest, which disallows embedded objects
|
||||
// in isolate-independent builtins.
|
||||
BuiltinsConstantsTableBuilder* builder =
|
||||
isolate()->builtins_constants_table_builder();
|
||||
uint32_t index = builder->AddObject(code);
|
||||
DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(
|
||||
Heap::kBuiltinsConstantsTableRootIndex));
|
||||
TNode<FixedArray> cache = BuiltinsConstantsTableConstant();
|
||||
return CAST(LoadFixedArrayElement(cache, index));
|
||||
}
|
||||
#endif // V8_EMBEDDED_BUILTINS
|
||||
|
||||
void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
|
||||
Node* instance_type,
|
||||
Node* intptr_index, Label* if_found,
|
||||
|
@ -22,48 +22,49 @@ class StubCache;
|
||||
|
||||
enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
||||
|
||||
#define HEAP_CONSTANT_LIST(V) \
|
||||
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
|
||||
V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \
|
||||
V(AllocationSiteMap, allocation_site_map, AllocationSiteMap) \
|
||||
V(BooleanMap, boolean_map, BooleanMap) \
|
||||
V(CodeMap, code_map, CodeMap) \
|
||||
V(EmptyPropertyDictionary, empty_property_dictionary, \
|
||||
EmptyPropertyDictionary) \
|
||||
V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \
|
||||
V(EmptySlowElementDictionary, empty_slow_element_dictionary, \
|
||||
EmptySlowElementDictionary) \
|
||||
V(empty_string, empty_string, EmptyString) \
|
||||
V(EmptyWeakCell, empty_weak_cell, EmptyWeakCell) \
|
||||
V(FalseValue, false_value, False) \
|
||||
V(FeedbackVectorMap, feedback_vector_map, FeedbackVectorMap) \
|
||||
V(FixedArrayMap, fixed_array_map, FixedArrayMap) \
|
||||
V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap) \
|
||||
V(FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArrayMap) \
|
||||
V(FunctionTemplateInfoMap, function_template_info_map, \
|
||||
FunctionTemplateInfoMap) \
|
||||
V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \
|
||||
V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \
|
||||
V(HeapNumberMap, heap_number_map, HeapNumberMap) \
|
||||
V(length_string, length_string, LengthString) \
|
||||
V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \
|
||||
V(MetaMap, meta_map, MetaMap) \
|
||||
V(MinusZeroValue, minus_zero_value, MinusZero) \
|
||||
V(MutableHeapNumberMap, mutable_heap_number_map, MutableHeapNumberMap) \
|
||||
V(NanValue, nan_value, Nan) \
|
||||
V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \
|
||||
V(NullValue, null_value, Null) \
|
||||
V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap) \
|
||||
V(prototype_string, prototype_string, PrototypeString) \
|
||||
V(SpeciesProtector, species_protector, SpeciesProtector) \
|
||||
V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \
|
||||
V(SymbolMap, symbol_map, SymbolMap) \
|
||||
V(TheHoleValue, the_hole_value, TheHole) \
|
||||
V(TrueValue, true_value, True) \
|
||||
V(Tuple2Map, tuple2_map, Tuple2Map) \
|
||||
V(Tuple3Map, tuple3_map, Tuple3Map) \
|
||||
V(UndefinedValue, undefined_value, Undefined) \
|
||||
V(WeakCellMap, weak_cell_map, WeakCellMap) \
|
||||
#define HEAP_CONSTANT_LIST(V) \
|
||||
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
|
||||
V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \
|
||||
V(AllocationSiteMap, allocation_site_map, AllocationSiteMap) \
|
||||
V(BooleanMap, boolean_map, BooleanMap) \
|
||||
V(BuiltinsConstantsTable, builtins_constants_table, BuiltinsConstantsTable) \
|
||||
V(CodeMap, code_map, CodeMap) \
|
||||
V(EmptyPropertyDictionary, empty_property_dictionary, \
|
||||
EmptyPropertyDictionary) \
|
||||
V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \
|
||||
V(EmptySlowElementDictionary, empty_slow_element_dictionary, \
|
||||
EmptySlowElementDictionary) \
|
||||
V(empty_string, empty_string, EmptyString) \
|
||||
V(EmptyWeakCell, empty_weak_cell, EmptyWeakCell) \
|
||||
V(FalseValue, false_value, False) \
|
||||
V(FeedbackVectorMap, feedback_vector_map, FeedbackVectorMap) \
|
||||
V(FixedArrayMap, fixed_array_map, FixedArrayMap) \
|
||||
V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap) \
|
||||
V(FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArrayMap) \
|
||||
V(FunctionTemplateInfoMap, function_template_info_map, \
|
||||
FunctionTemplateInfoMap) \
|
||||
V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \
|
||||
V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \
|
||||
V(HeapNumberMap, heap_number_map, HeapNumberMap) \
|
||||
V(length_string, length_string, LengthString) \
|
||||
V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \
|
||||
V(MetaMap, meta_map, MetaMap) \
|
||||
V(MinusZeroValue, minus_zero_value, MinusZero) \
|
||||
V(MutableHeapNumberMap, mutable_heap_number_map, MutableHeapNumberMap) \
|
||||
V(NanValue, nan_value, Nan) \
|
||||
V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \
|
||||
V(NullValue, null_value, Null) \
|
||||
V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap) \
|
||||
V(prototype_string, prototype_string, PrototypeString) \
|
||||
V(SpeciesProtector, species_protector, SpeciesProtector) \
|
||||
V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \
|
||||
V(SymbolMap, symbol_map, SymbolMap) \
|
||||
V(TheHoleValue, the_hole_value, TheHole) \
|
||||
V(TrueValue, true_value, True) \
|
||||
V(Tuple2Map, tuple2_map, Tuple2Map) \
|
||||
V(Tuple3Map, tuple3_map, Tuple3Map) \
|
||||
V(UndefinedValue, undefined_value, Undefined) \
|
||||
V(WeakCellMap, weak_cell_map, WeakCellMap) \
|
||||
V(SharedFunctionInfoMap, shared_function_info_map, SharedFunctionInfoMap)
|
||||
|
||||
// Returned from IteratorBuiltinsAssembler::GetIterator(). Struct is declared
|
||||
@ -1597,6 +1598,90 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
Label* if_not_found, Label* if_bailout,
|
||||
GetOwnPropertyMode mode);
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
#error "ia32 does not yet support embedded builtins"
|
||||
#endif
|
||||
|
||||
// Off-heap builtins cannot embed constants within the code object itself,
|
||||
// and thus need to load them from the root list.
|
||||
bool ShouldLoadConstantsFromRootList() const {
|
||||
return (isolate()->serializer_enabled() &&
|
||||
isolate()->builtins_constants_table_builder() != nullptr);
|
||||
}
|
||||
|
||||
TNode<Code> LookupConstantCodeTarget(Handle<Code> code);
|
||||
|
||||
template <class... TArgs>
|
||||
Node* CallStub(Callable const& callable, Node* context, TArgs... args) {
|
||||
if (ShouldLoadConstantsFromRootList()) {
|
||||
TNode<Code> target = LookupConstantCodeTarget(callable.code());
|
||||
return compiler::CodeAssembler::CallStub(callable.descriptor(), target,
|
||||
context, args...);
|
||||
} else {
|
||||
return compiler::CodeAssembler::CallStub(callable, context, args...);
|
||||
}
|
||||
}
|
||||
|
||||
template <class... TArgs>
|
||||
Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target,
|
||||
Node* context, TArgs... args) {
|
||||
// Just a forwarding definition, required due to the other overload above.
|
||||
return compiler::CodeAssembler::CallStub(descriptor, target, context,
|
||||
args...);
|
||||
}
|
||||
|
||||
template <class... TArgs>
|
||||
Node* TailCallStub(Callable const& callable, Node* context, TArgs... args) {
|
||||
if (ShouldLoadConstantsFromRootList()) {
|
||||
TNode<Code> target = LookupConstantCodeTarget(callable.code());
|
||||
return compiler::CodeAssembler::TailCallStub(callable.descriptor(),
|
||||
target, context, args...);
|
||||
} else {
|
||||
return compiler::CodeAssembler::TailCallStub(callable, context, args...);
|
||||
}
|
||||
}
|
||||
|
||||
template <class... TArgs>
|
||||
Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
|
||||
Node* context, TArgs... args) {
|
||||
// Just a forwarding definition, required due to the other overload above.
|
||||
return compiler::CodeAssembler::TailCallStub(descriptor, target, context,
|
||||
args...);
|
||||
}
|
||||
|
||||
template <class... TArgs>
|
||||
TNode<Object> CallRuntime(Runtime::FunctionId function,
|
||||
SloppyTNode<Object> context, TArgs... args) {
|
||||
if (ShouldLoadConstantsFromRootList()) {
|
||||
auto function_info = Runtime::FunctionForId(function);
|
||||
Handle<Code> code =
|
||||
CodeFactory::RuntimeCEntry(isolate(), function_info->result_size);
|
||||
TNode<Code> target = LookupConstantCodeTarget(code);
|
||||
return compiler::CodeAssembler::CallRuntime(function, target, context,
|
||||
args...);
|
||||
} else {
|
||||
return compiler::CodeAssembler::CallRuntime(function, context, args...);
|
||||
}
|
||||
}
|
||||
|
||||
template <class... TArgs>
|
||||
TNode<Object> TailCallRuntime(Runtime::FunctionId function,
|
||||
SloppyTNode<Object> context, TArgs... args) {
|
||||
if (ShouldLoadConstantsFromRootList()) {
|
||||
auto function_info = Runtime::FunctionForId(function);
|
||||
Handle<Code> code =
|
||||
CodeFactory::RuntimeCEntry(isolate(), function_info->result_size);
|
||||
TNode<Code> target = LookupConstantCodeTarget(code);
|
||||
return compiler::CodeAssembler::TailCallRuntime(function, target, context,
|
||||
args...);
|
||||
} else {
|
||||
return compiler::CodeAssembler::TailCallRuntime(function, context,
|
||||
args...);
|
||||
}
|
||||
}
|
||||
#endif // V8_EMBEDDED_BUILTINS
|
||||
|
||||
Node* GetProperty(Node* context, Node* receiver, Handle<Name> name) {
|
||||
return GetProperty(context, receiver, HeapConstant(name));
|
||||
}
|
||||
|
@ -1011,6 +1011,37 @@ TNode<Object> CodeAssembler::CallRuntimeImpl(Runtime::FunctionId function,
|
||||
REPEAT_1_TO_7(INSTANTIATE, SloppyTNode<Object>)
|
||||
#undef INSTANTIATE
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
template <class... TArgs>
|
||||
TNode<Object> CodeAssembler::CallRuntimeImpl(Runtime::FunctionId function,
|
||||
TNode<Code> target,
|
||||
SloppyTNode<Object> context,
|
||||
TArgs... args) {
|
||||
int argc = static_cast<int>(sizeof...(args));
|
||||
auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
|
||||
zone(), function, argc, Operator::kNoProperties,
|
||||
CallDescriptor::kNoFlags);
|
||||
|
||||
Node* ref = ExternalConstant(ExternalReference(function, isolate()));
|
||||
Node* arity = Int32Constant(argc);
|
||||
|
||||
Node* nodes[] = {target, args..., ref, arity, context};
|
||||
|
||||
CallPrologue();
|
||||
Node* return_value =
|
||||
raw_assembler()->CallN(call_descriptor, arraysize(nodes), nodes);
|
||||
CallEpilogue();
|
||||
return UncheckedCast<Object>(return_value);
|
||||
}
|
||||
|
||||
// Instantiate CallRuntime() for argument counts used by CSA-generated code
|
||||
#define INSTANTIATE(...) \
|
||||
template V8_EXPORT_PRIVATE TNode<Object> CodeAssembler::CallRuntimeImpl( \
|
||||
Runtime::FunctionId, TNode<Code>, __VA_ARGS__);
|
||||
REPEAT_1_TO_7(INSTANTIATE, SloppyTNode<Object>)
|
||||
#undef INSTANTIATE
|
||||
#endif // V8_EMBEDDED_BUILTINS
|
||||
|
||||
template <class... TArgs>
|
||||
TNode<Object> CodeAssembler::TailCallRuntimeImpl(Runtime::FunctionId function,
|
||||
SloppyTNode<Object> context,
|
||||
@ -1039,6 +1070,34 @@ TNode<Object> CodeAssembler::TailCallRuntimeImpl(Runtime::FunctionId function,
|
||||
REPEAT_1_TO_7(INSTANTIATE, SloppyTNode<Object>)
|
||||
#undef INSTANTIATE
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
template <class... TArgs>
|
||||
TNode<Object> CodeAssembler::TailCallRuntimeImpl(Runtime::FunctionId function,
|
||||
TNode<Code> target,
|
||||
SloppyTNode<Object> context,
|
||||
TArgs... args) {
|
||||
int argc = static_cast<int>(sizeof...(args));
|
||||
auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
|
||||
zone(), function, argc, Operator::kNoProperties,
|
||||
CallDescriptor::kNoFlags);
|
||||
|
||||
Node* ref = ExternalConstant(ExternalReference(function, isolate()));
|
||||
Node* arity = Int32Constant(argc);
|
||||
|
||||
Node* nodes[] = {target, args..., ref, arity, context};
|
||||
|
||||
return UncheckedCast<Object>(
|
||||
raw_assembler()->TailCallN(call_descriptor, arraysize(nodes), nodes));
|
||||
}
|
||||
|
||||
// Instantiate TailCallRuntime() for argument counts used by CSA-generated code
|
||||
#define INSTANTIATE(...) \
|
||||
template V8_EXPORT_PRIVATE TNode<Object> CodeAssembler::TailCallRuntimeImpl( \
|
||||
Runtime::FunctionId, TNode<Code>, __VA_ARGS__);
|
||||
REPEAT_1_TO_7(INSTANTIATE, SloppyTNode<Object>)
|
||||
#undef INSTANTIATE
|
||||
#endif // V8_EMBEDDED_BUILTINS
|
||||
|
||||
template <class... TArgs>
|
||||
Node* CodeAssembler::CallStubR(const CallInterfaceDescriptor& descriptor,
|
||||
size_t result_size, Node* target, Node* context,
|
||||
|
@ -913,6 +913,18 @@ class V8_EXPORT_PRIVATE CodeAssembler {
|
||||
return CallRuntimeImpl(function, context,
|
||||
base::implicit_cast<SloppyTNode<Object>>(args)...);
|
||||
}
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
template <class... TArgs>
|
||||
TNode<Object> CallRuntimeImpl(Runtime::FunctionId function,
|
||||
TNode<Code> target, SloppyTNode<Object> context,
|
||||
TArgs... args);
|
||||
template <class... TArgs>
|
||||
TNode<Object> CallRuntime(Runtime::FunctionId function, TNode<Code> target,
|
||||
SloppyTNode<Object> context, TArgs... args) {
|
||||
return CallRuntimeImpl(function, target, context,
|
||||
base::implicit_cast<SloppyTNode<Object>>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class... TArgs>
|
||||
TNode<Object> TailCallRuntimeImpl(Runtime::FunctionId function,
|
||||
@ -923,6 +935,20 @@ class V8_EXPORT_PRIVATE CodeAssembler {
|
||||
return TailCallRuntimeImpl(
|
||||
function, context, base::implicit_cast<SloppyTNode<Object>>(args)...);
|
||||
}
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
template <class... TArgs>
|
||||
TNode<Object> TailCallRuntimeImpl(Runtime::FunctionId function,
|
||||
TNode<Code> target,
|
||||
SloppyTNode<Object> context, TArgs... args);
|
||||
template <class... TArgs>
|
||||
TNode<Object> TailCallRuntime(Runtime::FunctionId function,
|
||||
TNode<Code> target, SloppyTNode<Object> context,
|
||||
TArgs... args) {
|
||||
return TailCallRuntimeImpl(
|
||||
function, target, context,
|
||||
base::implicit_cast<SloppyTNode<Object>>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// If context passed to CallStub is nullptr, it won't be passed to the stub.
|
||||
|
@ -766,12 +766,22 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
|
||||
bool call_use_fixed_target_reg = (flags & kCallFixedTargetRegister) != 0;
|
||||
switch (buffer->descriptor->kind()) {
|
||||
case CallDescriptor::kCallCodeObject:
|
||||
// TODO(jgruber, v8:7449): The below is a hack to support tail-calls from
|
||||
// JS-linkage callers with a register code target. The problem is that the
|
||||
// code target register may be clobbered before the final jmp by
|
||||
// AssemblePopArgumentsAdaptorFrame. As a more permanent fix we could
|
||||
// entirely remove support for tail-calls from JS-linkage callers.
|
||||
buffer->instruction_args.push_back(
|
||||
(call_code_immediate && callee->opcode() == IrOpcode::kHeapConstant)
|
||||
? g.UseImmediate(callee)
|
||||
: call_use_fixed_target_reg
|
||||
? g.UseFixed(callee, kJavaScriptCallCodeStartRegister)
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
: is_tail_call ? g.UseUniqueRegister(callee)
|
||||
: g.UseRegister(callee));
|
||||
#else
|
||||
: g.UseRegister(callee));
|
||||
#endif
|
||||
break;
|
||||
case CallDescriptor::kCallAddress:
|
||||
buffer->instruction_args.push_back(
|
||||
|
@ -6518,6 +6518,10 @@ void Heap::SetDeserializeLazyHandlerExtraWide(Code* code) {
|
||||
set_deserialize_lazy_handler_extra_wide(code);
|
||||
}
|
||||
|
||||
void Heap::SetBuiltinsConstantsTable(FixedArray* cache) {
|
||||
set_builtins_constants_table(cache);
|
||||
}
|
||||
|
||||
size_t Heap::NumberOfTrackedHeapObjectTypes() {
|
||||
return ObjectStats::OBJECT_STATS_COUNT;
|
||||
}
|
||||
|
@ -250,6 +250,8 @@ using v8::MemoryPressureLevel;
|
||||
/* slots refer to the code with the reference to the weak object. */ \
|
||||
V(ArrayList, weak_new_space_object_to_code_list, \
|
||||
WeakNewSpaceObjectToCodeList) \
|
||||
/* Indirection lists for isolate-independent builtins */ \
|
||||
V(FixedArray, builtins_constants_table, BuiltinsConstantsTable) \
|
||||
/* Feedback vectors that we need for code coverage or type profile */ \
|
||||
V(Object, feedback_vectors_for_profiling_tools, \
|
||||
FeedbackVectorsForProfilingTools) \
|
||||
@ -1121,6 +1123,8 @@ class Heap {
|
||||
void SetDeserializeLazyHandlerWide(Code* code);
|
||||
void SetDeserializeLazyHandlerExtraWide(Code* code);
|
||||
|
||||
void SetBuiltinsConstantsTable(FixedArray* cache);
|
||||
|
||||
// ===========================================================================
|
||||
// Inline allocation. ========================================================
|
||||
// ===========================================================================
|
||||
|
@ -659,6 +659,9 @@ void Heap::CreateInitialObjects() {
|
||||
set_deserialize_lazy_handler_wide(Smi::kZero);
|
||||
set_deserialize_lazy_handler_extra_wide(Smi::kZero);
|
||||
|
||||
// Initialize builtins constants table.
|
||||
set_builtins_constants_table(empty_fixed_array());
|
||||
|
||||
// Initialize context slot cache.
|
||||
isolate_->context_slot_cache()->Clear();
|
||||
|
||||
|
@ -194,6 +194,14 @@ void* IdentityMapBase::DeleteEntry(Object* key) {
|
||||
return DeleteIndex(index);
|
||||
}
|
||||
|
||||
Object* IdentityMapBase::KeyAtIndex(int index) const {
|
||||
DCHECK_LE(0, index);
|
||||
DCHECK_LT(index, capacity_);
|
||||
DCHECK_NE(keys_[index], heap_->not_mapped_symbol());
|
||||
CHECK(is_iterable()); // Must be iterable to access by index;
|
||||
return keys_[index];
|
||||
}
|
||||
|
||||
IdentityMapBase::RawEntry IdentityMapBase::EntryAtIndex(int index) const {
|
||||
DCHECK_LE(0, index);
|
||||
DCHECK_LT(index, capacity_);
|
||||
|
@ -46,6 +46,8 @@ class IdentityMapBase {
|
||||
void* DeleteEntry(Object* key);
|
||||
void Clear();
|
||||
|
||||
Object* KeyAtIndex(int index) const;
|
||||
|
||||
V8_EXPORT_PRIVATE RawEntry EntryAtIndex(int index) const;
|
||||
V8_EXPORT_PRIVATE int NextIndex(int index) const;
|
||||
|
||||
@ -126,8 +128,13 @@ class IdentityMap : public IdentityMapBase {
|
||||
return *this;
|
||||
}
|
||||
|
||||
V* operator*() { return reinterpret_cast<V*>(map_->EntryAtIndex(index_)); }
|
||||
V* operator->() { return reinterpret_cast<V*>(map_->EntryAtIndex(index_)); }
|
||||
Object* key() const { return map_->KeyAtIndex(index_); }
|
||||
V* entry() const {
|
||||
return reinterpret_cast<V*>(map_->EntryAtIndex(index_));
|
||||
}
|
||||
|
||||
V* operator*() { return entry(); }
|
||||
V* operator->() { return entry(); }
|
||||
bool operator!=(const Iterator& other) { return index_ != other.index_; }
|
||||
|
||||
private:
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "src/base/utils/random-number-generator.h"
|
||||
#include "src/basic-block-profiler.h"
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/builtins/constants-table-builder.h"
|
||||
#include "src/callable.h"
|
||||
#include "src/cancelable-task.h"
|
||||
#include "src/code-stubs.h"
|
||||
@ -3041,6 +3042,9 @@ bool Isolate::Init(StartupDeserializer* des) {
|
||||
if (create_heap_objects) {
|
||||
// Terminate the partial snapshot cache so we can iterate.
|
||||
partial_snapshot_cache_.push_back(heap_.undefined_value());
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
builtins_constants_table_builder_ = new BuiltinsConstantsTableBuilder(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
InitializeThreadLocal();
|
||||
@ -3073,6 +3077,14 @@ bool Isolate::Init(StartupDeserializer* des) {
|
||||
store_stub_cache_->Initialize();
|
||||
setup_delegate_->SetupInterpreter(interpreter_);
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
if (create_heap_objects) {
|
||||
builtins_constants_table_builder_->Finalize();
|
||||
delete builtins_constants_table_builder_;
|
||||
builtins_constants_table_builder_ = nullptr;
|
||||
}
|
||||
#endif // V8_EMBEDDED_BUILTINS
|
||||
|
||||
heap_.NotifyDeserializationComplete();
|
||||
}
|
||||
delete setup_delegate_;
|
||||
|
@ -48,6 +48,7 @@ class AddressToIndexHashMap;
|
||||
class AstStringConstants;
|
||||
class BasicBlockProfiler;
|
||||
class Bootstrapper;
|
||||
class BuiltinsConstantsTableBuilder;
|
||||
class CallInterfaceDescriptorData;
|
||||
class CancelableTaskManager;
|
||||
class CodeEventDispatcher;
|
||||
@ -1244,6 +1245,12 @@ class Isolate {
|
||||
off_heap_code_.emplace_back(stream);
|
||||
}
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
BuiltinsConstantsTableBuilder* builtins_constants_table_builder() const {
|
||||
return builtins_constants_table_builder_;
|
||||
}
|
||||
#endif
|
||||
|
||||
void set_array_buffer_allocator(v8::ArrayBuffer::Allocator* allocator) {
|
||||
array_buffer_allocator_ = allocator;
|
||||
}
|
||||
@ -1617,6 +1624,12 @@ class Isolate {
|
||||
// implemented.
|
||||
std::vector<InstructionStream*> off_heap_code_;
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
// Used during builtins compilation to build the builtins constants table,
|
||||
// which is stored on the root list prior to serialization.
|
||||
BuiltinsConstantsTableBuilder* builtins_constants_table_builder_ = nullptr;
|
||||
#endif
|
||||
|
||||
v8::ArrayBuffer::Allocator* array_buffer_allocator_;
|
||||
|
||||
FutexWaitListNode futex_wait_list_node_;
|
||||
|
@ -19,6 +19,7 @@ namespace v8 {
|
||||
namespace internal {
|
||||
namespace test_isolate_independent_builtins {
|
||||
|
||||
#ifdef V8_EMBEDDED_BUILTINS
|
||||
TEST(VerifyBuiltinsIsolateIndependence) {
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope handle_scope(isolate);
|
||||
@ -81,6 +82,7 @@ TEST(VerifyBuiltinsIsolateIndependence) {
|
||||
|
||||
CHECK(!found_mismatch);
|
||||
}
|
||||
#endif // V8_EMBEDDED_BUILTINS
|
||||
|
||||
// V8_CC_MSVC is true for both MSVC and clang on windows. clang can handle
|
||||
// __asm__-style inline assembly but MSVC cannot, and thus we need a more
|
||||
|
Loading…
Reference in New Issue
Block a user