Commit ad74be52 authored by jgruber's avatar jgruber Committed by Commit Bot

[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: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51434}
parent 46c4979e
...@@ -65,6 +65,7 @@ declare_args() { ...@@ -65,6 +65,7 @@ declare_args() {
v8_enable_fast_mksnapshot = false v8_enable_fast_mksnapshot = false
# Enable embedded builtins. # Enable embedded builtins.
# TODO(jgruber,v8:6666): Support ia32.
v8_enable_embedded_builtins = false v8_enable_embedded_builtins = false
# Enable code-generation-time checking of types in the CodeStubAssembler. # Enable code-generation-time checking of types in the CodeStubAssembler.
...@@ -1326,6 +1327,8 @@ v8_source_set("v8_base") { ...@@ -1326,6 +1327,8 @@ v8_source_set("v8_base") {
"src/builtins/builtins-utils.h", "src/builtins/builtins-utils.h",
"src/builtins/builtins.cc", "src/builtins/builtins.cc",
"src/builtins/builtins.h", "src/builtins/builtins.h",
"src/builtins/constants-table-builder.cc",
"src/builtins/constants-table-builder.h",
"src/cached-powers.cc", "src/cached-powers.cc",
"src/cached-powers.h", "src/cached-powers.h",
"src/callable.h", "src/callable.h",
......
...@@ -283,14 +283,28 @@ bool Builtins::IsIsolateIndependent(int index) { ...@@ -283,14 +283,28 @@ bool Builtins::IsIsolateIndependent(int index) {
case kContinueToJavaScriptBuiltin: case kContinueToJavaScriptBuiltin:
case kContinueToJavaScriptBuiltinWithResult: case kContinueToJavaScriptBuiltinWithResult:
#ifndef DEBUG #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 kConstructFunction:
case kTypeof: case kKeyedLoadICTrampoline:
case kWeakMapLookupHashIndex: case kKeyedStoreICTrampoline:
#endif case kLoadGlobalICInsideTypeofTrampoline:
case kLoadGlobalICTrampoline:
case kLoadIC_StringLength: case kLoadIC_StringLength:
case kLoadIC_StringWrapperLength: case kLoadIC_StringWrapperLength:
case kLoadICTrampoline:
case kOrderedHashTableHealIndex: case kOrderedHashTableHealIndex:
case kStoreGlobalICTrampoline:
case kStoreICTrampoline:
case kStringRepeat:
case kTypeof:
case kWeakMapLookupHashIndex:
#endif #endif
return true; return true;
default: default:
......
// 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
// 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_
// Copyright 2016 the V8 project authors. All rights reserved. // Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "src/code-stub-assembler.h" #include "src/code-stub-assembler.h"
#include "src/builtins/constants-table-builder.h"
#include "src/code-factory.h" #include "src/code-factory.h"
#include "src/frames-inl.h" #include "src/frames-inl.h"
#include "src/frames.h" #include "src/frames.h"
...@@ -7302,6 +7305,23 @@ void CodeStubAssembler::TryGetOwnProperty( ...@@ -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, void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Node* instance_type, Node* instance_type,
Node* intptr_index, Label* if_found, Node* intptr_index, Label* if_found,
......
...@@ -22,48 +22,49 @@ class StubCache; ...@@ -22,48 +22,49 @@ class StubCache;
enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol }; enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
#define HEAP_CONSTANT_LIST(V) \ #define HEAP_CONSTANT_LIST(V) \
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \ V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \ V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \
V(AllocationSiteMap, allocation_site_map, AllocationSiteMap) \ V(AllocationSiteMap, allocation_site_map, AllocationSiteMap) \
V(BooleanMap, boolean_map, BooleanMap) \ V(BooleanMap, boolean_map, BooleanMap) \
V(CodeMap, code_map, CodeMap) \ V(BuiltinsConstantsTable, builtins_constants_table, BuiltinsConstantsTable) \
V(EmptyPropertyDictionary, empty_property_dictionary, \ V(CodeMap, code_map, CodeMap) \
EmptyPropertyDictionary) \ V(EmptyPropertyDictionary, empty_property_dictionary, \
V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \ EmptyPropertyDictionary) \
V(EmptySlowElementDictionary, empty_slow_element_dictionary, \ V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \
EmptySlowElementDictionary) \ V(EmptySlowElementDictionary, empty_slow_element_dictionary, \
V(empty_string, empty_string, EmptyString) \ EmptySlowElementDictionary) \
V(EmptyWeakCell, empty_weak_cell, EmptyWeakCell) \ V(empty_string, empty_string, EmptyString) \
V(FalseValue, false_value, False) \ V(EmptyWeakCell, empty_weak_cell, EmptyWeakCell) \
V(FeedbackVectorMap, feedback_vector_map, FeedbackVectorMap) \ V(FalseValue, false_value, False) \
V(FixedArrayMap, fixed_array_map, FixedArrayMap) \ V(FeedbackVectorMap, feedback_vector_map, FeedbackVectorMap) \
V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap) \ V(FixedArrayMap, fixed_array_map, FixedArrayMap) \
V(FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArrayMap) \ V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap) \
V(FunctionTemplateInfoMap, function_template_info_map, \ V(FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArrayMap) \
FunctionTemplateInfoMap) \ V(FunctionTemplateInfoMap, function_template_info_map, \
V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \ FunctionTemplateInfoMap) \
V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \ V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \
V(HeapNumberMap, heap_number_map, HeapNumberMap) \ V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \
V(length_string, length_string, LengthString) \ V(HeapNumberMap, heap_number_map, HeapNumberMap) \
V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \ V(length_string, length_string, LengthString) \
V(MetaMap, meta_map, MetaMap) \ V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \
V(MinusZeroValue, minus_zero_value, MinusZero) \ V(MetaMap, meta_map, MetaMap) \
V(MutableHeapNumberMap, mutable_heap_number_map, MutableHeapNumberMap) \ V(MinusZeroValue, minus_zero_value, MinusZero) \
V(NanValue, nan_value, Nan) \ V(MutableHeapNumberMap, mutable_heap_number_map, MutableHeapNumberMap) \
V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \ V(NanValue, nan_value, Nan) \
V(NullValue, null_value, Null) \ V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \
V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap) \ V(NullValue, null_value, Null) \
V(prototype_string, prototype_string, PrototypeString) \ V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap) \
V(SpeciesProtector, species_protector, SpeciesProtector) \ V(prototype_string, prototype_string, PrototypeString) \
V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \ V(SpeciesProtector, species_protector, SpeciesProtector) \
V(SymbolMap, symbol_map, SymbolMap) \ V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \
V(TheHoleValue, the_hole_value, TheHole) \ V(SymbolMap, symbol_map, SymbolMap) \
V(TrueValue, true_value, True) \ V(TheHoleValue, the_hole_value, TheHole) \
V(Tuple2Map, tuple2_map, Tuple2Map) \ V(TrueValue, true_value, True) \
V(Tuple3Map, tuple3_map, Tuple3Map) \ V(Tuple2Map, tuple2_map, Tuple2Map) \
V(UndefinedValue, undefined_value, Undefined) \ V(Tuple3Map, tuple3_map, Tuple3Map) \
V(WeakCellMap, weak_cell_map, WeakCellMap) \ V(UndefinedValue, undefined_value, Undefined) \
V(WeakCellMap, weak_cell_map, WeakCellMap) \
V(SharedFunctionInfoMap, shared_function_info_map, SharedFunctionInfoMap) V(SharedFunctionInfoMap, shared_function_info_map, SharedFunctionInfoMap)
// Returned from IteratorBuiltinsAssembler::GetIterator(). Struct is declared // Returned from IteratorBuiltinsAssembler::GetIterator(). Struct is declared
...@@ -1597,6 +1598,90 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -1597,6 +1598,90 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Label* if_not_found, Label* if_bailout, Label* if_not_found, Label* if_bailout,
GetOwnPropertyMode mode); 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) { Node* GetProperty(Node* context, Node* receiver, Handle<Name> name) {
return GetProperty(context, receiver, HeapConstant(name)); return GetProperty(context, receiver, HeapConstant(name));
} }
......
...@@ -1011,6 +1011,37 @@ TNode<Object> CodeAssembler::CallRuntimeImpl(Runtime::FunctionId function, ...@@ -1011,6 +1011,37 @@ TNode<Object> CodeAssembler::CallRuntimeImpl(Runtime::FunctionId function,
REPEAT_1_TO_7(INSTANTIATE, SloppyTNode<Object>) REPEAT_1_TO_7(INSTANTIATE, SloppyTNode<Object>)
#undef INSTANTIATE #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> template <class... TArgs>
TNode<Object> CodeAssembler::TailCallRuntimeImpl(Runtime::FunctionId function, TNode<Object> CodeAssembler::TailCallRuntimeImpl(Runtime::FunctionId function,
SloppyTNode<Object> context, SloppyTNode<Object> context,
...@@ -1039,6 +1070,34 @@ TNode<Object> CodeAssembler::TailCallRuntimeImpl(Runtime::FunctionId function, ...@@ -1039,6 +1070,34 @@ TNode<Object> CodeAssembler::TailCallRuntimeImpl(Runtime::FunctionId function,
REPEAT_1_TO_7(INSTANTIATE, SloppyTNode<Object>) REPEAT_1_TO_7(INSTANTIATE, SloppyTNode<Object>)
#undef INSTANTIATE #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> template <class... TArgs>
Node* CodeAssembler::CallStubR(const CallInterfaceDescriptor& descriptor, Node* CodeAssembler::CallStubR(const CallInterfaceDescriptor& descriptor,
size_t result_size, Node* target, Node* context, size_t result_size, Node* target, Node* context,
......
...@@ -913,6 +913,18 @@ class V8_EXPORT_PRIVATE CodeAssembler { ...@@ -913,6 +913,18 @@ class V8_EXPORT_PRIVATE CodeAssembler {
return CallRuntimeImpl(function, context, return CallRuntimeImpl(function, context,
base::implicit_cast<SloppyTNode<Object>>(args)...); 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> template <class... TArgs>
TNode<Object> TailCallRuntimeImpl(Runtime::FunctionId function, TNode<Object> TailCallRuntimeImpl(Runtime::FunctionId function,
...@@ -923,6 +935,20 @@ class V8_EXPORT_PRIVATE CodeAssembler { ...@@ -923,6 +935,20 @@ class V8_EXPORT_PRIVATE CodeAssembler {
return TailCallRuntimeImpl( return TailCallRuntimeImpl(
function, context, base::implicit_cast<SloppyTNode<Object>>(args)...); 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. // 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, ...@@ -766,12 +766,22 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
bool call_use_fixed_target_reg = (flags & kCallFixedTargetRegister) != 0; bool call_use_fixed_target_reg = (flags & kCallFixedTargetRegister) != 0;
switch (buffer->descriptor->kind()) { switch (buffer->descriptor->kind()) {
case CallDescriptor::kCallCodeObject: 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( buffer->instruction_args.push_back(
(call_code_immediate && callee->opcode() == IrOpcode::kHeapConstant) (call_code_immediate && callee->opcode() == IrOpcode::kHeapConstant)
? g.UseImmediate(callee) ? g.UseImmediate(callee)
: call_use_fixed_target_reg : call_use_fixed_target_reg
? g.UseFixed(callee, kJavaScriptCallCodeStartRegister) ? g.UseFixed(callee, kJavaScriptCallCodeStartRegister)
#ifdef V8_EMBEDDED_BUILTINS
: is_tail_call ? g.UseUniqueRegister(callee)
: g.UseRegister(callee));
#else
: g.UseRegister(callee)); : g.UseRegister(callee));
#endif
break; break;
case CallDescriptor::kCallAddress: case CallDescriptor::kCallAddress:
buffer->instruction_args.push_back( buffer->instruction_args.push_back(
......
...@@ -6518,6 +6518,10 @@ void Heap::SetDeserializeLazyHandlerExtraWide(Code* code) { ...@@ -6518,6 +6518,10 @@ void Heap::SetDeserializeLazyHandlerExtraWide(Code* code) {
set_deserialize_lazy_handler_extra_wide(code); set_deserialize_lazy_handler_extra_wide(code);
} }
void Heap::SetBuiltinsConstantsTable(FixedArray* cache) {
set_builtins_constants_table(cache);
}
size_t Heap::NumberOfTrackedHeapObjectTypes() { size_t Heap::NumberOfTrackedHeapObjectTypes() {
return ObjectStats::OBJECT_STATS_COUNT; return ObjectStats::OBJECT_STATS_COUNT;
} }
......
...@@ -250,6 +250,8 @@ using v8::MemoryPressureLevel; ...@@ -250,6 +250,8 @@ using v8::MemoryPressureLevel;
/* slots refer to the code with the reference to the weak object. */ \ /* slots refer to the code with the reference to the weak object. */ \
V(ArrayList, weak_new_space_object_to_code_list, \ V(ArrayList, weak_new_space_object_to_code_list, \
WeakNewSpaceObjectToCodeList) \ WeakNewSpaceObjectToCodeList) \
/* Indirection lists for isolate-independent builtins */ \
V(FixedArray, builtins_constants_table, BuiltinsConstantsTable) \
/* Feedback vectors that we need for code coverage or type profile */ \ /* Feedback vectors that we need for code coverage or type profile */ \
V(Object, feedback_vectors_for_profiling_tools, \ V(Object, feedback_vectors_for_profiling_tools, \
FeedbackVectorsForProfilingTools) \ FeedbackVectorsForProfilingTools) \
...@@ -1121,6 +1123,8 @@ class Heap { ...@@ -1121,6 +1123,8 @@ class Heap {
void SetDeserializeLazyHandlerWide(Code* code); void SetDeserializeLazyHandlerWide(Code* code);
void SetDeserializeLazyHandlerExtraWide(Code* code); void SetDeserializeLazyHandlerExtraWide(Code* code);
void SetBuiltinsConstantsTable(FixedArray* cache);
// =========================================================================== // ===========================================================================
// Inline allocation. ======================================================== // Inline allocation. ========================================================
// =========================================================================== // ===========================================================================
......
...@@ -659,6 +659,9 @@ void Heap::CreateInitialObjects() { ...@@ -659,6 +659,9 @@ void Heap::CreateInitialObjects() {
set_deserialize_lazy_handler_wide(Smi::kZero); set_deserialize_lazy_handler_wide(Smi::kZero);
set_deserialize_lazy_handler_extra_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. // Initialize context slot cache.
isolate_->context_slot_cache()->Clear(); isolate_->context_slot_cache()->Clear();
......
...@@ -194,6 +194,14 @@ void* IdentityMapBase::DeleteEntry(Object* key) { ...@@ -194,6 +194,14 @@ void* IdentityMapBase::DeleteEntry(Object* key) {
return DeleteIndex(index); 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 { IdentityMapBase::RawEntry IdentityMapBase::EntryAtIndex(int index) const {
DCHECK_LE(0, index); DCHECK_LE(0, index);
DCHECK_LT(index, capacity_); DCHECK_LT(index, capacity_);
......
...@@ -46,6 +46,8 @@ class IdentityMapBase { ...@@ -46,6 +46,8 @@ class IdentityMapBase {
void* DeleteEntry(Object* key); void* DeleteEntry(Object* key);
void Clear(); void Clear();
Object* KeyAtIndex(int index) const;
V8_EXPORT_PRIVATE RawEntry EntryAtIndex(int index) const; V8_EXPORT_PRIVATE RawEntry EntryAtIndex(int index) const;
V8_EXPORT_PRIVATE int NextIndex(int index) const; V8_EXPORT_PRIVATE int NextIndex(int index) const;
...@@ -126,8 +128,13 @@ class IdentityMap : public IdentityMapBase { ...@@ -126,8 +128,13 @@ class IdentityMap : public IdentityMapBase {
return *this; return *this;
} }
V* operator*() { return reinterpret_cast<V*>(map_->EntryAtIndex(index_)); } Object* key() const { return map_->KeyAtIndex(index_); }
V* operator->() { return reinterpret_cast<V*>(map_->EntryAtIndex(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_; } bool operator!=(const Iterator& other) { return index_ != other.index_; }
private: private:
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "src/base/utils/random-number-generator.h" #include "src/base/utils/random-number-generator.h"
#include "src/basic-block-profiler.h" #include "src/basic-block-profiler.h"
#include "src/bootstrapper.h" #include "src/bootstrapper.h"
#include "src/builtins/constants-table-builder.h"
#include "src/callable.h" #include "src/callable.h"
#include "src/cancelable-task.h" #include "src/cancelable-task.h"
#include "src/code-stubs.h" #include "src/code-stubs.h"
...@@ -3041,6 +3042,9 @@ bool Isolate::Init(StartupDeserializer* des) { ...@@ -3041,6 +3042,9 @@ bool Isolate::Init(StartupDeserializer* des) {
if (create_heap_objects) { if (create_heap_objects) {
// Terminate the partial snapshot cache so we can iterate. // Terminate the partial snapshot cache so we can iterate.
partial_snapshot_cache_.push_back(heap_.undefined_value()); partial_snapshot_cache_.push_back(heap_.undefined_value());
#ifdef V8_EMBEDDED_BUILTINS
builtins_constants_table_builder_ = new BuiltinsConstantsTableBuilder(this);
#endif
} }
InitializeThreadLocal(); InitializeThreadLocal();
...@@ -3073,6 +3077,14 @@ bool Isolate::Init(StartupDeserializer* des) { ...@@ -3073,6 +3077,14 @@ bool Isolate::Init(StartupDeserializer* des) {
store_stub_cache_->Initialize(); store_stub_cache_->Initialize();
setup_delegate_->SetupInterpreter(interpreter_); 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(); heap_.NotifyDeserializationComplete();
} }
delete setup_delegate_; delete setup_delegate_;
......
...@@ -48,6 +48,7 @@ class AddressToIndexHashMap; ...@@ -48,6 +48,7 @@ class AddressToIndexHashMap;
class AstStringConstants; class AstStringConstants;
class BasicBlockProfiler; class BasicBlockProfiler;
class Bootstrapper; class Bootstrapper;
class BuiltinsConstantsTableBuilder;
class CallInterfaceDescriptorData; class CallInterfaceDescriptorData;
class CancelableTaskManager; class CancelableTaskManager;
class CodeEventDispatcher; class CodeEventDispatcher;
...@@ -1244,6 +1245,12 @@ class Isolate { ...@@ -1244,6 +1245,12 @@ class Isolate {
off_heap_code_.emplace_back(stream); 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) { void set_array_buffer_allocator(v8::ArrayBuffer::Allocator* allocator) {
array_buffer_allocator_ = allocator; array_buffer_allocator_ = allocator;
} }
...@@ -1617,6 +1624,12 @@ class Isolate { ...@@ -1617,6 +1624,12 @@ class Isolate {
// implemented. // implemented.
std::vector<InstructionStream*> off_heap_code_; 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_; v8::ArrayBuffer::Allocator* array_buffer_allocator_;
FutexWaitListNode futex_wait_list_node_; FutexWaitListNode futex_wait_list_node_;
......
...@@ -19,6 +19,7 @@ namespace v8 { ...@@ -19,6 +19,7 @@ namespace v8 {
namespace internal { namespace internal {
namespace test_isolate_independent_builtins { namespace test_isolate_independent_builtins {
#ifdef V8_EMBEDDED_BUILTINS
TEST(VerifyBuiltinsIsolateIndependence) { TEST(VerifyBuiltinsIsolateIndependence) {
Isolate* isolate = CcTest::i_isolate(); Isolate* isolate = CcTest::i_isolate();
HandleScope handle_scope(isolate); HandleScope handle_scope(isolate);
...@@ -81,6 +82,7 @@ TEST(VerifyBuiltinsIsolateIndependence) { ...@@ -81,6 +82,7 @@ TEST(VerifyBuiltinsIsolateIndependence) {
CHECK(!found_mismatch); CHECK(!found_mismatch);
} }
#endif // V8_EMBEDDED_BUILTINS
// V8_CC_MSVC is true for both MSVC and clang on windows. clang can handle // 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 // __asm__-style inline assembly but MSVC cannot, and thus we need a more
......
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