| // 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/execution/isolate.h" |
| #include "src/heap/heap-inl.h" |
| #include "src/objects/oddball-inl.h" |
| #include "src/roots/roots-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(ReadOnlyRoots(isolate_).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(RootsTable::IsImmortalImmovable(RootIndex::kEmptyFixedArray)); |
| } |
| |
| 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. |
| RootIndex root_list_index; |
| DCHECK(!isolate_->roots_table().IsRootHandle(object, &root_list_index)); |
| |
| // Not yet finalized. |
| DCHECK_EQ(ReadOnlyRoots(isolate_).empty_fixed_array(), |
| isolate_->heap()->builtins_constants_table()); |
| |
| // Must be on the main thread. |
| DCHECK_EQ(ThreadId::Current(), isolate_->thread_id()); |
| |
| // Must be generating embedded builtin code. |
| DCHECK(isolate_->IsGeneratingEmbeddedBuiltins()); |
| |
| // All code objects should be loaded through the root register or use |
| // pc-relative addressing. |
| DCHECK(!object->IsCode()); |
| #endif |
| |
| auto find_result = map_.FindOrInsert(object); |
| if (!find_result.already_exists) { |
| DCHECK(object->IsHeapObject()); |
| *find_result.entry = map_.size() - 1; |
| } |
| return *find_result.entry; |
| } |
| |
| namespace { |
| void CheckPreconditionsForPatching(Isolate* isolate, |
| Handle<Object> replacement_object) { |
| // Roots must not be inserted into the constants table as they are already |
| // accessible from the root list. |
| RootIndex root_list_index; |
| DCHECK(!isolate->roots_table().IsRootHandle(replacement_object, |
| &root_list_index)); |
| USE(root_list_index); |
| |
| // Not yet finalized. |
| DCHECK_EQ(ReadOnlyRoots(isolate).empty_fixed_array(), |
| isolate->heap()->builtins_constants_table()); |
| |
| DCHECK(isolate->IsGeneratingEmbeddedBuiltins()); |
| } |
| } // namespace |
| |
| void BuiltinsConstantsTableBuilder::PatchSelfReference( |
| Handle<Object> self_reference, Handle<Code> code_object) { |
| CheckPreconditionsForPatching(isolate_, code_object); |
| DCHECK(self_reference->IsOddball()); |
| DCHECK(Oddball::cast(*self_reference).kind() == |
| Oddball::kSelfReferenceMarker); |
| |
| uint32_t key; |
| if (map_.Delete(self_reference, &key)) { |
| DCHECK(code_object->IsCode()); |
| map_.Insert(code_object, key); |
| } |
| } |
| |
| void BuiltinsConstantsTableBuilder::PatchBasicBlockCountersReference( |
| Handle<ByteArray> counters) { |
| CheckPreconditionsForPatching(isolate_, counters); |
| |
| uint32_t key; |
| if (map_.Delete(ReadOnlyRoots(isolate_).basic_block_counters_marker(), |
| &key)) { |
| map_.Insert(counters, key); |
| } |
| } |
| |
| void BuiltinsConstantsTableBuilder::Finalize() { |
| HandleScope handle_scope(isolate_); |
| |
| DCHECK_EQ(ReadOnlyRoots(isolate_).empty_fixed_array(), |
| isolate_->heap()->builtins_constants_table()); |
| DCHECK(isolate_->IsGeneratingEmbeddedBuiltins()); |
| |
| // An empty map means there's nothing to do. |
| if (map_.size() == 0) return; |
| |
| Handle<FixedArray> table = |
| isolate_->factory()->NewFixedArray(map_.size(), AllocationType::kOld); |
| |
| Builtins* builtins = isolate_->builtins(); |
| ConstantsMap::IteratableScope it_scope(&map_); |
| for (auto it = it_scope.begin(); it != it_scope.end(); ++it) { |
| uint32_t index = *it.entry(); |
| Object value = it.key(); |
| if (value.IsCode() && Code::cast(value).kind() == CodeKind::BUILTIN) { |
| // Replace placeholder code objects with the real builtin. |
| // See also: SetupIsolateDelegate::PopulateWithPlaceholders. |
| // TODO(jgruber): Deduplicate placeholders and their corresponding |
| // builtin. |
| value = builtins->builtin(Code::cast(value).builtin_index()); |
| } |
| DCHECK(value.IsHeapObject()); |
| table->set(index, value); |
| } |
| |
| #ifdef DEBUG |
| for (int i = 0; i < map_.size(); i++) { |
| DCHECK(table->get(i).IsHeapObject()); |
| DCHECK_NE(ReadOnlyRoots(isolate_).undefined_value(), table->get(i)); |
| DCHECK_NE(ReadOnlyRoots(isolate_).self_reference_marker(), table->get(i)); |
| DCHECK_NE(ReadOnlyRoots(isolate_).basic_block_counters_marker(), |
| table->get(i)); |
| } |
| #endif |
| |
| isolate_->heap()->SetBuiltinsConstantsTable(*table); |
| } |
| |
| } // namespace internal |
| } // namespace v8 |