[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:
jgruber 2018-02-21 15:16:10 +01:00 committed by Commit Bot
parent 46c4979e86
commit ad74be52fa
17 changed files with 440 additions and 48 deletions

View File

@ -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",

View File

@ -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:

View 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

View 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_

View File

@ -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,

View File

@ -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));
}

View File

@ -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,

View File

@ -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.

View File

@ -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(

View File

@ -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;
}

View File

@ -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. ========================================================
// ===========================================================================

View File

@ -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();

View File

@ -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_);

View File

@ -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:

View File

@ -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_;

View File

@ -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_;

View File

@ -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