Commit 1efe6259 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[snapshot] Clear irregexp code prior to serialization

Compiled irregexp code should be cleared unless
FunctionCodeHandling::kKeep is passed.

Bug: v8:8572
Change-Id: Icb74cc6e0f39a69f8383b05f1638cf0e3be1807c
Reviewed-on: https://chromium-review.googlesource.com/c/1373773
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58272}
parent 35122e51
...@@ -751,19 +751,31 @@ StartupData SnapshotCreator::CreateBlob( ...@@ -751,19 +751,31 @@ StartupData SnapshotCreator::CreateBlob(
// We have to iterate the heap and collect handles to each clearable SFI, // We have to iterate the heap and collect handles to each clearable SFI,
// before we disable allocation, since we have to allocate UncompiledDatas // before we disable allocation, since we have to allocate UncompiledDatas
// to be able to recompile them. // to be able to recompile them.
//
// Compiled irregexp code is also flushed by collecting and clearing any
// seen JSRegExp objects.
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
std::vector<i::Handle<i::SharedFunctionInfo>> sfis_to_clear; std::vector<i::Handle<i::SharedFunctionInfo>> sfis_to_clear;
i::HeapIterator heap_iterator(isolate->heap()); { // Heap allocation is disallowed within this scope.
while (i::HeapObject* current_obj = heap_iterator.next()) { i::HeapIterator heap_iterator(isolate->heap());
if (current_obj->IsSharedFunctionInfo()) { while (i::HeapObject* current_obj = heap_iterator.next()) {
i::SharedFunctionInfo shared = i::SharedFunctionInfo::cast(current_obj); if (current_obj->IsSharedFunctionInfo()) {
if (shared->CanDiscardCompiled()) { i::SharedFunctionInfo shared =
sfis_to_clear.emplace_back(shared, isolate); i::SharedFunctionInfo::cast(current_obj);
if (shared->CanDiscardCompiled()) {
sfis_to_clear.emplace_back(shared, isolate);
}
} else if (current_obj->IsJSRegExp()) {
i::JSRegExp regexp = i::JSRegExp::cast(current_obj);
if (regexp->HasCompiledCode()) {
regexp->DiscardCompiledCodeForSerialization();
}
} }
} }
} }
i::AllowHeapAllocation allocate_for_discard;
// Must happen after heap iteration since SFI::DiscardCompiled may allocate.
for (i::Handle<i::SharedFunctionInfo> shared : sfis_to_clear) { for (i::Handle<i::SharedFunctionInfo> shared : sfis_to_clear) {
i::SharedFunctionInfo::DiscardCompiled(isolate, shared); i::SharedFunctionInfo::DiscardCompiled(isolate, shared);
} }
......
...@@ -26,7 +26,7 @@ ACCESSORS(JSRegExp, flags, Object, kFlagsOffset) ...@@ -26,7 +26,7 @@ ACCESSORS(JSRegExp, flags, Object, kFlagsOffset)
ACCESSORS(JSRegExp, source, Object, kSourceOffset) ACCESSORS(JSRegExp, source, Object, kSourceOffset)
ACCESSORS(JSRegExp, last_index, Object, kLastIndexOffset) ACCESSORS(JSRegExp, last_index, Object, kLastIndexOffset)
JSRegExp::Type JSRegExp::TypeTag() { JSRegExp::Type JSRegExp::TypeTag() const {
Object* data = this->data(); Object* data = this->data();
if (data->IsUndefined()) return JSRegExp::NOT_COMPILED; if (data->IsUndefined()) return JSRegExp::NOT_COMPILED;
Smi smi = Smi::cast(FixedArray::cast(data)->get(kTagIndex)); Smi smi = Smi::cast(FixedArray::cast(data)->get(kTagIndex));
...@@ -66,7 +66,7 @@ Object* JSRegExp::CaptureNameMap() { ...@@ -66,7 +66,7 @@ Object* JSRegExp::CaptureNameMap() {
return value; return value;
} }
Object* JSRegExp::DataAt(int index) { Object* JSRegExp::DataAt(int index) const {
DCHECK(TypeTag() != NOT_COMPILED); DCHECK(TypeTag() != NOT_COMPILED);
return FixedArray::cast(data())->get(index); return FixedArray::cast(data())->get(index);
} }
...@@ -78,6 +78,17 @@ void JSRegExp::SetDataAt(int index, Object* value) { ...@@ -78,6 +78,17 @@ void JSRegExp::SetDataAt(int index, Object* value) {
FixedArray::cast(data())->set(index, value); FixedArray::cast(data())->set(index, value);
} }
bool JSRegExp::HasCompiledCode() const {
return DataAt(kIrregexpLatin1CodeIndex)->IsCode() ||
DataAt(kIrregexpUC16CodeIndex)->IsCode();
}
void JSRegExp::DiscardCompiledCodeForSerialization() {
DCHECK(HasCompiledCode());
SetDataAt(kIrregexpLatin1CodeIndex, Smi::FromInt(kUninitializedValue));
SetDataAt(kIrregexpUC16CodeIndex, Smi::FromInt(kUninitializedValue));
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -95,13 +95,13 @@ class JSRegExp : public JSObject { ...@@ -95,13 +95,13 @@ class JSRegExp : public JSObject {
Handle<String> source, Handle<String> source,
Handle<String> flags_string); Handle<String> flags_string);
inline Type TypeTag(); inline Type TypeTag() const;
// Number of captures (without the match itself). // Number of captures (without the match itself).
inline int CaptureCount(); inline int CaptureCount();
inline Flags GetFlags(); inline Flags GetFlags();
inline String Pattern(); inline String Pattern();
inline Object* CaptureNameMap(); inline Object* CaptureNameMap();
inline Object* DataAt(int index); inline Object* DataAt(int index) const;
// Set implementation data after the object has been prepared. // Set implementation data after the object has been prepared.
inline void SetDataAt(int index, Object* value); inline void SetDataAt(int index, Object* value);
...@@ -113,6 +113,9 @@ class JSRegExp : public JSObject { ...@@ -113,6 +113,9 @@ class JSRegExp : public JSObject {
} }
} }
inline bool HasCompiledCode() const;
inline void DiscardCompiledCodeForSerialization();
DECL_CAST2(JSRegExp) DECL_CAST2(JSRegExp)
// Dispatched behavior. // Dispatched behavior.
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-buffer-inl.h"
#include "src/objects/js-array-inl.h" #include "src/objects/js-array-inl.h"
#include "src/objects/js-regexp-inl.h"
#include "src/runtime/runtime.h" #include "src/runtime/runtime.h"
#include "src/snapshot/code-serializer.h" #include "src/snapshot/code-serializer.h"
#include "src/snapshot/natives.h" #include "src/snapshot/natives.h"
...@@ -163,7 +164,9 @@ bool RunExtraCode(v8::Isolate* isolate, v8::Local<v8::Context> context, ...@@ -163,7 +164,9 @@ bool RunExtraCode(v8::Isolate* isolate, v8::Local<v8::Context> context,
return true; return true;
} }
v8::StartupData CreateSnapshotDataBlob(const char* embedded_source = nullptr) { v8::StartupData CreateSnapshotDataBlob(
v8::SnapshotCreator::FunctionCodeHandling function_code_handling,
const char* embedded_source) {
// Create a new isolate and a new context from scratch, optionally run // Create a new isolate and a new context from scratch, optionally run
// a script to embed, and serialize to create a snapshot blob. // a script to embed, and serialize to create a snapshot blob.
DisableEmbeddedBlobRefcounting(); DisableEmbeddedBlobRefcounting();
...@@ -180,12 +183,16 @@ v8::StartupData CreateSnapshotDataBlob(const char* embedded_source = nullptr) { ...@@ -180,12 +183,16 @@ v8::StartupData CreateSnapshotDataBlob(const char* embedded_source = nullptr) {
} }
snapshot_creator.SetDefaultContext(context); snapshot_creator.SetDefaultContext(context);
} }
result = snapshot_creator.CreateBlob( result = snapshot_creator.CreateBlob(function_code_handling);
v8::SnapshotCreator::FunctionCodeHandling::kClear);
} }
return result; return result;
} }
v8::StartupData CreateSnapshotDataBlob(const char* embedded_source = nullptr) {
return CreateSnapshotDataBlob(
v8::SnapshotCreator::FunctionCodeHandling::kClear, embedded_source);
}
v8::StartupData WarmUpSnapshotDataBlob(v8::StartupData cold_snapshot_blob, v8::StartupData WarmUpSnapshotDataBlob(v8::StartupData cold_snapshot_blob,
const char* warmup_source) { const char* warmup_source) {
CHECK(cold_snapshot_blob.raw_size > 0 && cold_snapshot_blob.data != nullptr); CHECK(cold_snapshot_blob.raw_size > 0 && cold_snapshot_blob.data != nullptr);
...@@ -818,7 +825,10 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobStringNotInternalized) { ...@@ -818,7 +825,10 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobStringNotInternalized) {
FreeCurrentEmbeddedBlob(); FreeCurrentEmbeddedBlob();
} }
UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCode) { namespace {
void TestCustomSnapshotDataBlobWithIrregexpCode(
v8::SnapshotCreator::FunctionCodeHandling function_code_handling) {
DisableAlwaysOpt(); DisableAlwaysOpt();
const char* source = const char* source =
"var re = /\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\//;\n" "var re = /\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\//;\n"
...@@ -827,7 +837,8 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCode) { ...@@ -827,7 +837,8 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCode) {
"function h() { return '// this is a comment'.search(re); }\n" "function h() { return '// this is a comment'.search(re); }\n"
"f(); f(); g(); g();"; "f(); f(); g(); g();";
v8::StartupData data1 = CreateSnapshotDataBlob(source); v8::StartupData data1 =
CreateSnapshotDataBlob(function_code_handling, source);
v8::Isolate::CreateParams params1; v8::Isolate::CreateParams params1;
params1.snapshot_blob = &data1; params1.snapshot_blob = &data1;
...@@ -840,6 +851,15 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCode) { ...@@ -840,6 +851,15 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCode) {
v8::HandleScope h_scope(isolate1); v8::HandleScope h_scope(isolate1);
v8::Local<v8::Context> context = v8::Context::New(isolate1); v8::Local<v8::Context> context = v8::Context::New(isolate1);
v8::Context::Scope c_scope(context); v8::Context::Scope c_scope(context);
{
// Check that compiled irregexp code has not been flushed prior to
// serialization.
i::Handle<i::JSRegExp> re =
Utils::OpenHandle(*CompileRun("re").As<v8::RegExp>());
CHECK_EQ(re->HasCompiledCode(),
function_code_handling ==
v8::SnapshotCreator::FunctionCodeHandling::kKeep);
}
{ {
v8::Maybe<int32_t> result = v8::Maybe<int32_t> result =
CompileRun("f()")->Int32Value(isolate1->GetCurrentContext()); CompileRun("f()")->Int32Value(isolate1->GetCurrentContext());
...@@ -861,6 +881,18 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCode) { ...@@ -861,6 +881,18 @@ UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCode) {
FreeCurrentEmbeddedBlob(); FreeCurrentEmbeddedBlob();
} }
} // namespace
UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCodeKeepCode) {
TestCustomSnapshotDataBlobWithIrregexpCode(
v8::SnapshotCreator::FunctionCodeHandling::kKeep);
}
UNINITIALIZED_TEST(CustomSnapshotDataBlobWithIrregexpCodeClearCode) {
TestCustomSnapshotDataBlobWithIrregexpCode(
v8::SnapshotCreator::FunctionCodeHandling::kClear);
}
UNINITIALIZED_TEST(SnapshotChecksum) { UNINITIALIZED_TEST(SnapshotChecksum) {
DisableAlwaysOpt(); DisableAlwaysOpt();
const char* source1 = "function f() { return 42; }"; const char* source1 = "function f() { return 42; }";
......
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