Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v6.x] deps: backport rehash strings after deserialization #14385

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -296,13 +296,15 @@ test-timers-clean:


ifneq ("","$(wildcard deps/v8/tools/run-tests.py)")
test-v8: v8 test-hash-seed
test-v8: v8
# note: performs full test unless QUICKCHECK is specified
deps/v8/tools/run-tests.py --arch=$(V8_ARCH) \
--mode=$(BUILDTYPE_LOWER) $(V8_TEST_OPTIONS) $(QUICKCHECK_ARG) \
--no-presubmit \
--shell-dir=$(PWD)/deps/v8/out/$(V8_ARCH).$(BUILDTYPE_LOWER) \
$(TAP_V8)
@echo Testing hash seed
$(MAKE) test-hash-seed

test-v8-intl: v8
# note: performs full test unless QUICKCHECK is specified
Expand Down
8 changes: 4 additions & 4 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -419,12 +419,12 @@ parser.add_option('--without-perfctr',
# Dummy option for backwards compatibility
parser.add_option('--with-snapshot',
action='store_true',
dest='with_snapshot',
dest='unused_with_snapshot',
help=optparse.SUPPRESS_HELP)

parser.add_option('--without-snapshot',
action='store_true',
dest='unused_without_snapshot',
dest='without_snapshot',
help=optparse.SUPPRESS_HELP)

parser.add_option('--without-ssl',
Expand Down Expand Up @@ -802,7 +802,7 @@ def configure_node(o):
cross_compiling = (options.cross_compiling
if options.cross_compiling is not None
else target_arch != host_arch)
want_snapshots = 1 if options.with_snapshot else 0
want_snapshots = not options.without_snapshot
o['variables']['want_separate_host_toolset'] = int(
cross_compiling and want_snapshots)

Expand Down Expand Up @@ -946,7 +946,7 @@ def configure_v8(o):
o['variables']['v8_no_strict_aliasing'] = 1 # Work around compiler bugs.
o['variables']['v8_optimized_debug'] = 0 # Compile with -O0 in debug builds.
o['variables']['v8_random_seed'] = 0 # Use a random seed for hash tables.
o['variables']['v8_use_snapshot'] = b(options.with_snapshot)
o['variables']['v8_use_snapshot'] = 'false' if options.without_snapshot else 'true'
o['variables']['node_use_v8_platform'] = b(not options.without_v8_platform)
o['variables']['node_use_bundled_v8'] = b(not options.without_bundled_v8)
o['variables']['force_dynamic_crt'] = 1 if options.shared else 0
Expand Down
2 changes: 1 addition & 1 deletion deps/v8/include/v8-version.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#define V8_MAJOR_VERSION 5
#define V8_MINOR_VERSION 1
#define V8_BUILD_NUMBER 281
#define V8_PATCH_LEVEL 103
#define V8_PATCH_LEVEL 104

// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
Expand Down
6 changes: 6 additions & 0 deletions deps/v8/src/api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,9 @@ StartupData SerializeIsolateAndContext(

i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);

// We might rehash strings and re-sort descriptors. Clear the lookup cache.
internal_isolate->descriptor_lookup_cache()->Clear();

// If we don't do this then we end up with a stray root pointing at the
// context even after we have disposed of the context.
internal_isolate->heap()->CollectAllAvailableGarbage("mksnapshot");
Expand Down Expand Up @@ -428,6 +431,9 @@ StartupData SerializeIsolateAndContext(
context_ser.Serialize(&raw_context);
ser.SerializeWeakReferencesAndDeferred();

metadata.set_can_rehash(ser.can_be_rehashed() &&
context_ser.can_be_rehashed());

return i::Snapshot::CreateSnapshotBlob(ser, context_ser, metadata);
}

Expand Down
4 changes: 4 additions & 0 deletions deps/v8/src/bootstrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,8 @@ Handle<JSFunction> Genesis::GetThrowTypeErrorIntrinsic(
DCHECK(false);
}

JSObject::MigrateSlowToFast(function, 0, "Bootstrapping");

return function;
}

Expand Down Expand Up @@ -1133,6 +1135,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,

sloppy_function_map_writable_prototype_->SetConstructor(*function_fun);
strict_function_map_writable_prototype_->SetConstructor(*function_fun);

JSObject::MigrateSlowToFast(function_fun, 0, "Bootstrapping");
}

{ // --- A r r a y ---
Expand Down
2 changes: 2 additions & 0 deletions deps/v8/src/flag-definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,8 @@ DEFINE_BOOL(abort_on_uncaught_exception, false,
DEFINE_BOOL(randomize_hashes, true,
"randomize hashes to avoid predictable hash collisions "
"(with snapshots this option cannot override the baked-in seed)")
DEFINE_BOOL(rehash_snapshot, true,
"rehash strings from the snapshot to override the baked-in seed")
DEFINE_INT(hash_seed, 0,
"Fixed seed to use to hash property keys (0 means random)"
"(with snapshots this option cannot override the baked-in seed)")
Expand Down
17 changes: 9 additions & 8 deletions deps/v8/src/heap/heap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5348,14 +5348,7 @@ bool Heap::SetUp() {

// Set up the seed that is used to randomize the string hash function.
DCHECK(hash_seed() == 0);
if (FLAG_randomize_hashes) {
if (FLAG_hash_seed == 0) {
int rnd = isolate()->random_number_generator()->NextInt();
set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask));
} else {
set_hash_seed(Smi::FromInt(FLAG_hash_seed));
}
}
if (FLAG_randomize_hashes) InitializeHashSeed();

for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount);
i++) {
Expand Down Expand Up @@ -5393,6 +5386,14 @@ bool Heap::SetUp() {
return true;
}

void Heap::InitializeHashSeed() {
if (FLAG_hash_seed == 0) {
int rnd = isolate()->random_number_generator()->NextInt();
set_hash_seed(Smi::FromInt(rnd & Name::kHashBitMask));
} else {
set_hash_seed(Smi::FromInt(FLAG_hash_seed));
}
}

bool Heap::CreateHeapObjects() {
// Create initial maps.
Expand Down
3 changes: 3 additions & 0 deletions deps/v8/src/heap/heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,9 @@ class Heap {
// without actually creating any objects.
bool SetUp();

// (Re-)Initialize hash seed from flag or RNG.
void InitializeHashSeed();

// Bootstraps the object heap with the core set of objects required to run.
// Returns whether it succeeded.
bool CreateHeapObjects();
Expand Down
2 changes: 2 additions & 0 deletions deps/v8/src/js/array.js
Original file line number Diff line number Diff line change
Expand Up @@ -1831,6 +1831,8 @@ var unscopables = {
keys: true,
};

%ToFastProperties(unscopables);

%AddNamedProperty(GlobalArray.prototype, unscopablesSymbol, unscopables,
DONT_ENUM | READ_ONLY);

Expand Down
12 changes: 12 additions & 0 deletions deps/v8/src/objects.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9469,6 +9469,12 @@ void Map::TraceAllTransitions(Map* map) {

void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
Handle<Name> name, SimpleTransitionFlag flag) {
// Do not track transitions during bootstrap except for element transitions.
Isolate* isolate = parent->GetIsolate();
if (isolate->bootstrapper()->IsActive() &&
!name.is_identical_to(isolate->factory()->elements_transition_symbol())) {
return;
}
if (!parent->GetBackPointer()->IsUndefined()) {
parent->set_owns_descriptors(false);
} else {
Expand Down Expand Up @@ -17520,6 +17526,12 @@ template class Dictionary<UnseededNumberDictionary,
UnseededNumberDictionaryShape,
uint32_t>;

template void
HashTable<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::Rehash(Handle<Name> key);

template void
HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::Rehash(Handle<Name> key);

template Handle<SeededNumberDictionary>
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
Expand Down
75 changes: 75 additions & 0 deletions deps/v8/src/snapshot/deserializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ void Deserializer::Deserialize(Isolate* isolate) {
LOG_CODE_EVENT(isolate_, LogCodeObjects());
LOG_CODE_EVENT(isolate_, LogBytecodeHandlers());
LOG_CODE_EVENT(isolate_, LogCompiledFunctions());

if (FLAG_rehash_snapshot && can_rehash_) Rehash();
}

MaybeHandle<Object> Deserializer::DeserializePartial(
Expand Down Expand Up @@ -138,6 +140,9 @@ MaybeHandle<Object> Deserializer::DeserializePartial(
// changed and logging should be added to notify the profiler et al of the
// new code, which also has to be flushed from instruction cache.
CHECK_EQ(start_address, code_space->top());

if (FLAG_rehash_snapshot && can_rehash_) RehashContext(Context::cast(root));

return Handle<Object>(root, isolate);
}

Expand All @@ -164,6 +169,64 @@ MaybeHandle<SharedFunctionInfo> Deserializer::DeserializeCode(
}
}

// We only really just need HashForObject here.
class StringRehashKey : public HashTableKey {
public:
uint32_t HashForObject(Object* other) override {
return String::cast(other)->Hash();
}

static uint32_t StringHash(Object* obj) {
UNREACHABLE();
return String::cast(obj)->Hash();
}

bool IsMatch(Object* string) override {
UNREACHABLE();
return false;
}

uint32_t Hash() override {
UNREACHABLE();
return 0;
}

Handle<Object> AsHandle(Isolate* isolate) override {
UNREACHABLE();
return isolate->factory()->empty_string();
}
};

void Deserializer::Rehash() {
DCHECK(can_rehash_);
isolate_->heap()->InitializeHashSeed();
if (FLAG_profile_deserialization) {
PrintF("Re-initializing hash seed to %x\n",
isolate_->heap()->hash_seed()->value());
}
StringRehashKey string_rehash_key;
isolate_->heap()->string_table()->Rehash(&string_rehash_key);
isolate_->heap()->intrinsic_function_names()->Rehash(
isolate_->factory()->empty_string());
SortMapDescriptors();
}

void Deserializer::RehashContext(Context* context) {
DCHECK(can_rehash_);
for (const auto& array : transition_arrays_) array->Sort();
Handle<Name> dummy = isolate_->factory()->empty_string();
context->global_object()->global_dictionary()->Rehash(dummy);
SortMapDescriptors();
}

void Deserializer::SortMapDescriptors() {
for (const auto& map : maps_) {
if (map->instance_descriptors()->number_of_descriptors() > 1) {
map->instance_descriptors()->Sort();
}
}
}

Deserializer::~Deserializer() {
// TODO(svenpanne) Re-enable this assertion when v8 initialization is fixed.
// DCHECK(source_.AtEOF());
Expand Down Expand Up @@ -288,6 +351,18 @@ HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
new_code_objects_.Add(Code::cast(obj));
}
}
if (FLAG_rehash_snapshot && can_rehash_ && !deserializing_user_code()) {
if (obj->IsString()) {
// Uninitialize hash field as we are going to reinitialize the hash seed.
String* string = String::cast(obj);
string->set_hash_field(String::kEmptyHashField);
} else if (obj->IsTransitionArray() &&
TransitionArray::cast(obj)->number_of_entries() > 1) {
transition_arrays_.Add(TransitionArray::cast(obj));
} else if (obj->IsMap()) {
maps_.Add(Map::cast(obj));
}
}
// Check alignment.
DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(), obj->RequiredAlignment()));
return obj;
Expand Down
19 changes: 18 additions & 1 deletion deps/v8/src/snapshot/deserializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ class Deserializer : public SerializerDeserializer {
external_reference_table_(NULL),
deserialized_large_objects_(0),
deserializing_user_code_(false),
next_alignment_(kWordAligned) {
next_alignment_(kWordAligned),
can_rehash_(false) {
DecodeReservation(data->Reservations());
}

Expand All @@ -59,6 +60,8 @@ class Deserializer : public SerializerDeserializer {
attached_objects_ = attached_objects;
}

void SetRehashability(bool v) { can_rehash_ = v; }

private:
void VisitPointers(Object** start, Object** end) override;

Expand Down Expand Up @@ -113,6 +116,15 @@ class Deserializer : public SerializerDeserializer {
Object** CopyInNativesSource(Vector<const char> source_vector,
Object** current);

// Rehash after deserializing an isolate.
void Rehash();

// Rehash after deserializing a context.
void RehashContext(Context* context);

// Sort descriptors of deserialized maps using new string hashes.
void SortMapDescriptors();

// Cached current isolate.
Isolate* isolate_;

Expand All @@ -136,11 +148,16 @@ class Deserializer : public SerializerDeserializer {
List<Code*> new_code_objects_;
List<Handle<String> > new_internalized_strings_;
List<Handle<Script> > new_scripts_;
List<Map*> maps_;
List<TransitionArray*> transition_arrays_;

bool deserializing_user_code_;

AllocationAlignment next_alignment_;

// TODO(6593): generalize rehashing, and remove this flag.
bool can_rehash_;

DISALLOW_COPY_AND_ASSIGN(Deserializer);
};

Expand Down
Loading