[heap] Forcing external strings to be registered in the external string table.
Bug: chromium:845409 Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng Change-Id: I2ab1ca18a900828e4e116f1b087925319d41bf97 Reviewed-on: https://chromium-review.googlesource.com/1124845 Reviewed-by: Hannes Payer <hpayer@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Commit-Queue: Rodrigo Bruno <rfbpb@google.com> Cr-Commit-Position: refs/heads/master@{#54203}
This commit is contained in:
parent
b19ccf7221
commit
c5c4b588f1
10
include/v8.h
10
include/v8.h
@ -6290,7 +6290,8 @@ class V8_EXPORT AccessorSignature : public Data {
|
||||
|
||||
|
||||
// --- Extensions ---
|
||||
|
||||
V8_DEPRECATE_SOON("Implementation detail",
|
||||
class ExternalOneByteStringResourceImpl);
|
||||
class V8_EXPORT ExternalOneByteStringResourceImpl
|
||||
: public String::ExternalOneByteStringResource {
|
||||
public:
|
||||
@ -6317,7 +6318,7 @@ class V8_EXPORT Extension { // NOLINT
|
||||
int dep_count = 0,
|
||||
const char** deps = 0,
|
||||
int source_length = -1);
|
||||
virtual ~Extension() { }
|
||||
virtual ~Extension() { delete source_; }
|
||||
virtual Local<FunctionTemplate> GetNativeFunctionTemplate(
|
||||
Isolate* isolate, Local<String> name) {
|
||||
return Local<FunctionTemplate>();
|
||||
@ -6326,7 +6327,8 @@ class V8_EXPORT Extension { // NOLINT
|
||||
const char* name() const { return name_; }
|
||||
size_t source_length() const { return source_length_; }
|
||||
const String::ExternalOneByteStringResource* source() const {
|
||||
return &source_; }
|
||||
return source_;
|
||||
}
|
||||
int dependency_count() { return dep_count_; }
|
||||
const char** dependencies() { return deps_; }
|
||||
void set_auto_enable(bool value) { auto_enable_ = value; }
|
||||
@ -6339,7 +6341,7 @@ class V8_EXPORT Extension { // NOLINT
|
||||
private:
|
||||
const char* name_;
|
||||
size_t source_length_; // expected to initialize before source_
|
||||
ExternalOneByteStringResourceImpl source_;
|
||||
String::ExternalOneByteStringResource* source_;
|
||||
int dep_count_;
|
||||
const char** deps_;
|
||||
bool auto_enable_;
|
||||
|
21
src/api.cc
21
src/api.cc
@ -945,6 +945,21 @@ void RegisteredExtension::UnregisterAll() {
|
||||
first_extension_ = nullptr;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class ExtensionResource : public String::ExternalOneByteStringResource {
|
||||
public:
|
||||
ExtensionResource() : data_(0), length_(0) {}
|
||||
ExtensionResource(const char* data, size_t length)
|
||||
: data_(data), length_(length) {}
|
||||
const char* data() const { return data_; }
|
||||
size_t length() const { return length_; }
|
||||
virtual void Dispose() {}
|
||||
|
||||
private:
|
||||
const char* data_;
|
||||
size_t length_;
|
||||
};
|
||||
} // anonymous namespace
|
||||
|
||||
void RegisterExtension(Extension* that) {
|
||||
RegisteredExtension* extension = new RegisteredExtension(that);
|
||||
@ -961,10 +976,10 @@ Extension::Extension(const char* name,
|
||||
source_length_(source_length >= 0 ?
|
||||
source_length :
|
||||
(source ? static_cast<int>(strlen(source)) : 0)),
|
||||
source_(source, source_length_),
|
||||
dep_count_(dep_count),
|
||||
deps_(deps),
|
||||
auto_enable_(false) {
|
||||
source_ = new ExtensionResource(source, source_length_);
|
||||
CHECK(source != nullptr || source_length_ == 0);
|
||||
}
|
||||
|
||||
@ -6719,7 +6734,6 @@ MaybeLocal<String> v8::String::NewExternalTwoByte(
|
||||
i::Handle<i::String> string = i_isolate->factory()
|
||||
->NewExternalStringFromTwoByte(resource)
|
||||
.ToHandleChecked();
|
||||
i_isolate->heap()->RegisterExternalString(*string);
|
||||
return Utils::ToLocal(string);
|
||||
} else {
|
||||
// The resource isn't going to be used, free it immediately.
|
||||
@ -6743,7 +6757,6 @@ MaybeLocal<String> v8::String::NewExternalOneByte(
|
||||
i::Handle<i::String> string = i_isolate->factory()
|
||||
->NewExternalStringFromOneByte(resource)
|
||||
.ToHandleChecked();
|
||||
i_isolate->heap()->RegisterExternalString(*string);
|
||||
return Utils::ToLocal(string);
|
||||
} else {
|
||||
// The resource isn't going to be used, free it immediately.
|
||||
@ -6776,7 +6789,6 @@ bool v8::String::MakeExternal(v8::String::ExternalStringResource* resource) {
|
||||
DCHECK(!CanMakeExternal() || result);
|
||||
if (result) {
|
||||
DCHECK(obj->IsExternalString());
|
||||
isolate->heap()->RegisterExternalString(*obj);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -6800,7 +6812,6 @@ bool v8::String::MakeExternal(
|
||||
DCHECK(!CanMakeExternal() || result);
|
||||
if (result) {
|
||||
DCHECK(obj->IsExternalString());
|
||||
isolate->heap()->RegisterExternalString(*obj);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -81,7 +81,6 @@ Handle<String> Bootstrapper::GetNativeSource(NativeType type, int index) {
|
||||
new NativesExternalStringResource(type, index);
|
||||
Handle<ExternalOneByteString> source_code =
|
||||
isolate_->factory()->NewNativeSourceString(resource);
|
||||
isolate_->heap()->RegisterExternalString(*source_code);
|
||||
DCHECK(source_code->is_short());
|
||||
return source_code;
|
||||
}
|
||||
|
@ -180,14 +180,12 @@ void UnoptimizedCompileJob::PrepareOnMainThread(Isolate* isolate) {
|
||||
if (source->IsOneByteRepresentation()) {
|
||||
ExternalOneByteString::Resource* resource =
|
||||
new OneByteWrapper(data, length);
|
||||
source_wrapper_.reset(resource);
|
||||
wrapper = isolate->factory()
|
||||
->NewExternalStringFromOneByte(resource)
|
||||
.ToHandleChecked();
|
||||
} else {
|
||||
ExternalTwoByteString::Resource* resource =
|
||||
new TwoByteWrapper(data, length);
|
||||
source_wrapper_.reset(resource);
|
||||
wrapper = isolate->factory()
|
||||
->NewExternalStringFromTwoByte(resource)
|
||||
.ToHandleChecked();
|
||||
|
@ -67,7 +67,6 @@ class V8_EXPORT_PRIVATE UnoptimizedCompileJob : public CompilerDispatcherJob {
|
||||
Handle<SharedFunctionInfo> shared_; // Global handle.
|
||||
Handle<String> source_; // Global handle.
|
||||
Handle<String> wrapper_; // Global handle.
|
||||
std::unique_ptr<v8::String::ExternalStringResourceBase> source_wrapper_;
|
||||
size_t max_stack_size_;
|
||||
|
||||
// Members required for parsing.
|
||||
|
@ -98,10 +98,6 @@ void ExternalizeStringExtension::Externalize(
|
||||
SimpleOneByteStringResource* resource = new SimpleOneByteStringResource(
|
||||
reinterpret_cast<char*>(data), string->length());
|
||||
result = string->MakeExternal(resource);
|
||||
if (result) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
|
||||
isolate->heap()->RegisterExternalString(*string);
|
||||
}
|
||||
if (!result) delete resource;
|
||||
} else {
|
||||
uc16* data = new uc16[string->length()];
|
||||
@ -109,10 +105,6 @@ void ExternalizeStringExtension::Externalize(
|
||||
SimpleTwoByteStringResource* resource = new SimpleTwoByteStringResource(
|
||||
data, string->length());
|
||||
result = string->MakeExternal(resource);
|
||||
if (result) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
|
||||
isolate->heap()->RegisterExternalString(*string);
|
||||
}
|
||||
if (!result) delete resource;
|
||||
}
|
||||
if (!result) {
|
||||
|
@ -1271,6 +1271,7 @@ MaybeHandle<String> Factory::NewExternalStringFromOneByte(
|
||||
external_string->set_length(static_cast<int>(length));
|
||||
external_string->set_hash_field(String::kEmptyHashField);
|
||||
external_string->set_resource(resource);
|
||||
isolate()->heap()->RegisterExternalString(*external_string);
|
||||
|
||||
return external_string;
|
||||
}
|
||||
@ -1303,6 +1304,7 @@ MaybeHandle<String> Factory::NewExternalStringFromTwoByte(
|
||||
external_string->set_length(static_cast<int>(length));
|
||||
external_string->set_hash_field(String::kEmptyHashField);
|
||||
external_string->set_resource(resource);
|
||||
isolate()->heap()->RegisterExternalString(*external_string);
|
||||
|
||||
return external_string;
|
||||
}
|
||||
@ -1318,6 +1320,7 @@ Handle<ExternalOneByteString> Factory::NewNativeSourceString(
|
||||
external_string->set_length(static_cast<int>(length));
|
||||
external_string->set_hash_field(String::kEmptyHashField);
|
||||
external_string->set_resource(resource);
|
||||
isolate()->heap()->RegisterExternalString(*external_string);
|
||||
|
||||
return external_string;
|
||||
}
|
||||
|
@ -2626,6 +2626,7 @@ bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
|
||||
|
||||
ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
|
||||
self->set_resource(resource);
|
||||
heap->RegisterExternalString(this);
|
||||
if (is_internalized) self->Hash(); // Force regeneration of the hash value.
|
||||
return true;
|
||||
}
|
||||
@ -2696,6 +2697,7 @@ bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
|
||||
|
||||
ExternalOneByteString* self = ExternalOneByteString::cast(this);
|
||||
self->set_resource(resource);
|
||||
heap->RegisterExternalString(this);
|
||||
if (is_internalized) self->Hash(); // Force regeneration of the hash value.
|
||||
return true;
|
||||
}
|
||||
|
@ -5467,6 +5467,8 @@ TEST(Regress631969) {
|
||||
StaticOneByteResource external_string("12345678901234");
|
||||
s3->MakeExternal(&external_string);
|
||||
CcTest::CollectGarbage(OLD_SPACE);
|
||||
// This avoids the GC from trying to free stack allocated resources.
|
||||
i::Handle<i::ExternalOneByteString>::cast(s3)->set_resource(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,6 +317,11 @@ void TestCharacterStreams(const char* one_byte_source, unsigned length,
|
||||
std::unique_ptr<i::Utf16CharacterStream> uc16_stream(
|
||||
i::ScannerStream::For(uc16_string, start, end));
|
||||
TestCharacterStream(one_byte_source, uc16_stream.get(), length, start, end);
|
||||
|
||||
// This avoids the GC from trying to free a stack allocated resource.
|
||||
if (uc16_string->IsExternalString())
|
||||
i::Handle<i::ExternalTwoByteString>::cast(uc16_string)
|
||||
->set_resource(nullptr);
|
||||
}
|
||||
|
||||
// 1-byte external string
|
||||
@ -333,6 +338,10 @@ void TestCharacterStreams(const char* one_byte_source, unsigned length,
|
||||
i::ScannerStream::For(ext_one_byte_string, start, end));
|
||||
TestCharacterStream(one_byte_source, one_byte_stream.get(), length, start,
|
||||
end);
|
||||
// This avoids the GC from trying to free a stack allocated resource.
|
||||
if (ext_one_byte_string->IsExternalString())
|
||||
i::Handle<i::ExternalOneByteString>::cast(ext_one_byte_string)
|
||||
->set_resource(nullptr);
|
||||
}
|
||||
|
||||
// 1-byte generic i::String
|
||||
|
@ -15621,6 +15621,8 @@ class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
|
||||
virtual ~OneByteVectorResource() {}
|
||||
virtual size_t length() const { return data_.length(); }
|
||||
virtual const char* data() const { return data_.start(); }
|
||||
virtual void Dispose() {}
|
||||
|
||||
private:
|
||||
i::Vector<const char> data_;
|
||||
};
|
||||
@ -15633,6 +15635,8 @@ class UC16VectorResource : public v8::String::ExternalStringResource {
|
||||
virtual ~UC16VectorResource() {}
|
||||
virtual size_t length() const { return data_.length(); }
|
||||
virtual const i::uc16* data() const { return data_.start(); }
|
||||
virtual void Dispose() {}
|
||||
|
||||
private:
|
||||
i::Vector<const i::uc16> data_;
|
||||
};
|
||||
@ -15676,15 +15680,14 @@ THREADED_TEST(MorphCompositeStringTest) {
|
||||
OneByteVectorResource one_byte_resource(
|
||||
i::Vector<const char>(c_string, i::StrLength(c_string)));
|
||||
UC16VectorResource uc16_resource(
|
||||
i::Vector<const uint16_t>(two_byte_string,
|
||||
i::StrLength(c_string)));
|
||||
i::Vector<const uint16_t>(two_byte_string, i::StrLength(c_string)));
|
||||
|
||||
Local<String> lhs(
|
||||
v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
|
||||
&one_byte_resource).ToHandleChecked()));
|
||||
Local<String> rhs(
|
||||
v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
|
||||
&one_byte_resource).ToHandleChecked()));
|
||||
Local<String> lhs(v8::Utils::ToLocal(
|
||||
factory->NewExternalStringFromOneByte(&one_byte_resource)
|
||||
.ToHandleChecked()));
|
||||
Local<String> rhs(v8::Utils::ToLocal(
|
||||
factory->NewExternalStringFromOneByte(&one_byte_resource)
|
||||
.ToHandleChecked()));
|
||||
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("lhs"), lhs).FromJust());
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("rhs"), rhs).FromJust());
|
||||
@ -15697,10 +15700,10 @@ THREADED_TEST(MorphCompositeStringTest) {
|
||||
CHECK(lhs->IsOneByte());
|
||||
CHECK(rhs->IsOneByte());
|
||||
|
||||
MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
|
||||
&uc16_resource);
|
||||
MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
|
||||
&uc16_resource);
|
||||
i::String* ilhs = *v8::Utils::OpenHandle(*lhs);
|
||||
i::String* irhs = *v8::Utils::OpenHandle(*rhs);
|
||||
MorphAString(ilhs, &one_byte_resource, &uc16_resource);
|
||||
MorphAString(irhs, &one_byte_resource, &uc16_resource);
|
||||
|
||||
// This should UTF-8 without flattening, since everything is ASCII.
|
||||
Local<String> cons =
|
||||
@ -15743,6 +15746,16 @@ THREADED_TEST(MorphCompositeStringTest) {
|
||||
->Get(env.local(), v8_str("slice_on_cons"))
|
||||
.ToLocalChecked())
|
||||
.FromJust());
|
||||
|
||||
// This avoids the GC from trying to free a stack allocated resource.
|
||||
if (ilhs->IsExternalOneByteString())
|
||||
i::ExternalOneByteString::cast(ilhs)->set_resource(nullptr);
|
||||
else
|
||||
i::ExternalTwoByteString::cast(ilhs)->set_resource(nullptr);
|
||||
if (irhs->IsExternalOneByteString())
|
||||
i::ExternalOneByteString::cast(irhs)->set_resource(nullptr);
|
||||
else
|
||||
i::ExternalTwoByteString::cast(irhs)->set_resource(nullptr);
|
||||
}
|
||||
i::DeleteArray(two_byte_string);
|
||||
}
|
||||
@ -20307,6 +20320,8 @@ THREADED_TEST(TwoByteStringInOneByteCons) {
|
||||
reresult = CompileRun("str2.charCodeAt(2);");
|
||||
CHECK_EQ(static_cast<int32_t>('e'),
|
||||
reresult->Int32Value(context.local()).FromJust());
|
||||
// This avoids the GC from trying to free stack allocated resources.
|
||||
i::Handle<i::ExternalTwoByteString>::cast(flat_string)->set_resource(nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1877,6 +1877,11 @@ TEST(CodeSerializerExternalString) {
|
||||
|
||||
CHECK_EQ(15.0, copy_result->Number());
|
||||
|
||||
// This avoids the GC from trying to free stack allocated resources.
|
||||
i::Handle<i::ExternalOneByteString>::cast(one_byte_string)
|
||||
->set_resource(nullptr);
|
||||
i::Handle<i::ExternalTwoByteString>::cast(two_byte_string)
|
||||
->set_resource(nullptr);
|
||||
delete cache;
|
||||
}
|
||||
|
||||
@ -1933,6 +1938,8 @@ TEST(CodeSerializerLargeExternalString) {
|
||||
|
||||
CHECK_EQ(42.0, copy_result->Number());
|
||||
|
||||
// This avoids the GC from trying to free stack allocated resources.
|
||||
i::Handle<i::ExternalOneByteString>::cast(name)->set_resource(nullptr);
|
||||
delete cache;
|
||||
string.Dispose();
|
||||
}
|
||||
@ -1982,6 +1989,8 @@ TEST(CodeSerializerExternalScriptName) {
|
||||
|
||||
CHECK_EQ(10.0, copy_result->Number());
|
||||
|
||||
// This avoids the GC from trying to free stack allocated resources.
|
||||
i::Handle<i::ExternalOneByteString>::cast(name)->set_resource(nullptr);
|
||||
delete cache;
|
||||
}
|
||||
|
||||
|
@ -1244,6 +1244,8 @@ TEST(SliceFromExternal) {
|
||||
CHECK_EQ(SlicedString::cast(*slice)->parent(), *string);
|
||||
CHECK(SlicedString::cast(*slice)->parent()->IsExternalString());
|
||||
CHECK(slice->IsFlat());
|
||||
// This avoids the GC from trying to free stack allocated resources.
|
||||
i::Handle<i::ExternalOneByteString>::cast(string)->set_resource(nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -88,9 +88,9 @@ TEST_F(UnoptimizedCompileJobTest, StateTransitions) {
|
||||
}
|
||||
|
||||
TEST_F(UnoptimizedCompileJobTest, SyntaxError) {
|
||||
test::ScriptResource script("^^^", strlen("^^^"));
|
||||
test::ScriptResource* script = new test::ScriptResource("^^^", strlen("^^^"));
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
isolate(), tracer(), test::CreateSharedFunctionInfo(isolate(), &script),
|
||||
isolate(), tracer(), test::CreateSharedFunctionInfo(isolate(), script),
|
||||
FLAG_stack_size));
|
||||
|
||||
job->PrepareOnMainThread(isolate());
|
||||
@ -148,9 +148,10 @@ TEST_F(UnoptimizedCompileJobTest, CompileFailureToAnalyse) {
|
||||
raw_script += "'x' + 'x' - ";
|
||||
}
|
||||
raw_script += " 'x'; }";
|
||||
test::ScriptResource script(raw_script.c_str(), strlen(raw_script.c_str()));
|
||||
test::ScriptResource* script =
|
||||
new test::ScriptResource(raw_script.c_str(), strlen(raw_script.c_str()));
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
isolate(), tracer(), test::CreateSharedFunctionInfo(isolate(), &script),
|
||||
isolate(), tracer(), test::CreateSharedFunctionInfo(isolate(), script),
|
||||
100));
|
||||
|
||||
job->PrepareOnMainThread(isolate());
|
||||
@ -174,9 +175,10 @@ TEST_F(UnoptimizedCompileJobTest, CompileFailureToFinalize) {
|
||||
raw_script += "'x' + 'x' - ";
|
||||
}
|
||||
raw_script += " 'x'; }";
|
||||
test::ScriptResource script(raw_script.c_str(), strlen(raw_script.c_str()));
|
||||
test::ScriptResource* script =
|
||||
new test::ScriptResource(raw_script.c_str(), strlen(raw_script.c_str()));
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
isolate(), tracer(), test::CreateSharedFunctionInfo(isolate(), &script),
|
||||
isolate(), tracer(), test::CreateSharedFunctionInfo(isolate(), script),
|
||||
50));
|
||||
|
||||
job->PrepareOnMainThread(isolate());
|
||||
@ -219,9 +221,10 @@ TEST_F(UnoptimizedCompileJobTest, CompileOnBackgroundThread) {
|
||||
" var d = { foo: 100, bar : bar() }\n"
|
||||
" return bar;"
|
||||
"}";
|
||||
test::ScriptResource script(raw_script, strlen(raw_script));
|
||||
test::ScriptResource* script =
|
||||
new test::ScriptResource(raw_script, strlen(raw_script));
|
||||
std::unique_ptr<UnoptimizedCompileJob> job(new UnoptimizedCompileJob(
|
||||
isolate(), tracer(), test::CreateSharedFunctionInfo(isolate(), &script),
|
||||
isolate(), tracer(), test::CreateSharedFunctionInfo(isolate(), script),
|
||||
100));
|
||||
|
||||
job->PrepareOnMainThread(isolate());
|
||||
|
Loading…
Reference in New Issue
Block a user