Remove support for unused compile options.

We don't use parser caches anymore and request code caches
explicitly using ScriptCompiler::CreateCodeCache. Hence
removing the support for both parser cache and code cache options.
They are still retained in CompileOptions for backwards
compatibility. Apart from the api.cc, no other part should see
this option.

Bug: chromium:779254, chromium:783124
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: Ic8ad9afe3fa44bbb5adc71bdde59c0b4057a523d
Reviewed-on: https://chromium-review.googlesource.com/916261
Commit-Queue: Mythri Alle <mythria@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51416}
This commit is contained in:
Mythri 2018-02-20 14:14:54 +00:00 committed by Commit Bot
parent dea41745ee
commit 5a68df2ab5
22 changed files with 159 additions and 1002 deletions

View File

@ -2327,17 +2327,21 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal(
ENTER_V8_NO_SCRIPT(isolate, v8_isolate->GetCurrentContext(), ScriptCompiler,
CompileUnbound, MaybeLocal<UnboundScript>(),
InternalEscapableScope);
bool produce_cache = options == kProduceParserCache ||
options == kProduceCodeCache ||
options == kProduceFullCodeCache;
// Don't try to produce any kind of cache when the debugger is loaded.
if (isolate->debug()->is_loaded() && produce_cache) {
// ProduceParserCache, ProduceCodeCache, ProduceFullCodeCache and
// ConsumeParserCache are not supported. They are present only for
// backward compatability. All these options behave as kNoCompileOptions.
if (options == kConsumeParserCache) {
// We do not support parser caches anymore. Just set cached_data to
// rejected to signal an error.
options = kNoCompileOptions;
source->cached_data->rejected = true;
} else if (options == kProduceParserCache || options == kProduceCodeCache ||
options == kProduceFullCodeCache) {
options = kNoCompileOptions;
}
i::ScriptData* script_data = nullptr;
if (options == kConsumeParserCache || options == kConsumeCodeCache) {
if (options == kConsumeCodeCache) {
DCHECK(source->cached_data);
// ScriptData takes care of pointer-aligning the data.
script_data = new i::ScriptData(source->cached_data->data,
@ -2383,13 +2387,7 @@ MaybeLocal<UnboundScript> ScriptCompiler::CompileUnboundInternal(
}
RETURN_ON_FAILED_EXECUTION(UnboundScript);
if (produce_cache && script_data != nullptr) {
// script_data now contains the data that was generated. source will
// take the ownership.
source->cached_data = new CachedData(
script_data->data(), script_data->length(), CachedData::BufferOwned);
script_data->ReleaseDataOwnership();
} else if (options == kConsumeParserCache || options == kConsumeCodeCache) {
if (options == kConsumeCodeCache) {
source->cached_data->rejected = script_data->rejected();
}
delete script_data;

View File

@ -1235,15 +1235,6 @@ MaybeHandle<JSFunction> Compiler::GetWrappedFunction(
return Handle<JSFunction>::cast(result);
}
namespace {
bool ShouldProduceCodeCache(ScriptCompiler::CompileOptions options) {
return options == ScriptCompiler::kProduceCodeCache ||
options == ScriptCompiler::kProduceFullCodeCache;
}
} // namespace
bool Compiler::CodeGenerationFromStringsAllowed(Isolate* isolate,
Handle<Context> context,
Handle<String> source) {
@ -1500,14 +1491,8 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
if (compile_options == ScriptCompiler::kNoCompileOptions ||
compile_options == ScriptCompiler::kEagerCompile) {
cached_data = nullptr;
} else if (compile_options == ScriptCompiler::kProduceParserCache ||
ShouldProduceCodeCache(compile_options)) {
DCHECK(cached_data && !*cached_data);
DCHECK_NULL(extension);
DCHECK(!isolate->debug()->is_loaded());
} else {
DCHECK(compile_options == ScriptCompiler::kConsumeParserCache ||
compile_options == ScriptCompiler::kConsumeCodeCache);
DCHECK(compile_options == ScriptCompiler::kConsumeCodeCache);
DCHECK(cached_data && *cached_data);
DCHECK_NULL(extension);
}
@ -1571,13 +1556,8 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
}
}
base::ElapsedTimer timer;
if (FLAG_profile_deserialization && ShouldProduceCodeCache(compile_options)) {
timer.Start();
}
if (maybe_result.is_null() || ShouldProduceCodeCache(compile_options)) {
// No cache entry found, or embedder wants a code cache. Compile the script.
if (maybe_result.is_null()) {
// No cache entry found compile the script.
// Create a script object describing the script to be compiled.
Handle<Script> script = isolate->factory()->NewScript(source);
@ -1607,21 +1587,15 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
script->set_host_defined_options(*host_defined_options);
}
// Compile the function and add it to the cache.
// Compile the function and add it to the isolate cache.
ParseInfo parse_info(script);
Zone compile_zone(isolate->allocator(), ZONE_NAME);
if (resource_options.IsModule()) parse_info.set_module();
if (compile_options != ScriptCompiler::kNoCompileOptions) {
parse_info.set_cached_data(cached_data);
}
parse_info.set_compile_options(compile_options);
parse_info.set_extension(extension);
if (!context->IsNativeContext()) {
parse_info.set_outer_scope_info(handle(context->scope_info()));
}
parse_info.set_eager(
(compile_options == ScriptCompiler::kProduceFullCodeCache) ||
(compile_options == ScriptCompiler::kEagerCompile));
parse_info.set_eager(compile_options == ScriptCompiler::kEagerCompile);
parse_info.set_language_mode(
stricter_language_mode(parse_info.language_mode(), language_mode));
@ -1635,22 +1609,6 @@ MaybeHandle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript(
vector = isolate->factory()->NewCell(feedback_vector);
compilation_cache->PutScript(source, context, language_mode, result,
vector);
if (ShouldProduceCodeCache(compile_options) &&
!script->ContainsAsmModule()) {
compile_timer.set_producing_code_cache();
HistogramTimerScope histogram_timer(
isolate->counters()->compile_serialize());
RuntimeCallTimerScope runtimeTimer(
isolate, RuntimeCallCounterId::kCompileSerialize);
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.CompileSerialize");
*cached_data = CodeSerializer::Serialize(isolate, result, source);
if (FLAG_profile_deserialization) {
PrintF("[Compiling and serializing took %0.3f ms]\n",
timer.Elapsed().InMillisecondsF());
}
}
}
if (maybe_result.is_null()) {

View File

@ -604,8 +604,9 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
Local<Context> context(isolate->GetCurrentContext());
ScriptOrigin origin(name);
if (options.compile_options == ScriptCompiler::kConsumeCodeCache ||
options.compile_options == ScriptCompiler::kConsumeParserCache) {
DCHECK(options.compile_options != ScriptCompiler::kProduceParserCache);
DCHECK(options.compile_options != ScriptCompiler::kConsumeParserCache);
if (options.compile_options == ScriptCompiler::kConsumeCodeCache) {
ScriptCompiler::CachedData* cached_code =
LookupCodeCache(isolate, source);
if (cached_code != nullptr) {
@ -639,9 +640,6 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
ScriptCompiler::Source script_source(source, origin);
maybe_script = ScriptCompiler::Compile(context, &script_source,
options.compile_options);
if (options.compile_options == ScriptCompiler::kProduceParserCache) {
StoreInCodeCache(isolate, source, script_source.GetCachedData());
}
}
Local<Script> script;
@ -2837,8 +2835,6 @@ bool Shell::SetOptions(int argc, char* argv[]) {
options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
options.code_cache_options =
ShellOptions::CodeCacheOptions::kProduceCache;
} else if (strncmp(value, "=parse", 7) == 0) {
options.compile_options = v8::ScriptCompiler::kProduceParserCache;
} else if (strncmp(value, "=none", 6) == 0) {
options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
options.code_cache_options =
@ -3420,14 +3416,9 @@ int Shell::Main(int argc, char* argv[]) {
result = RunMain(isolate, argc, argv, false);
// Change the options to consume cache
if (options.compile_options == v8::ScriptCompiler::kProduceParserCache) {
options.compile_options = v8::ScriptCompiler::kConsumeParserCache;
} else {
DCHECK(options.compile_options == v8::ScriptCompiler::kEagerCompile ||
options.compile_options ==
v8::ScriptCompiler::kNoCompileOptions);
options.compile_options = v8::ScriptCompiler::kConsumeCodeCache;
}
DCHECK(options.compile_options == v8::ScriptCompiler::kEagerCompile ||
options.compile_options == v8::ScriptCompiler::kNoCompileOptions);
options.compile_options = v8::ScriptCompiler::kConsumeCodeCache;
printf("============ Run: Consume code cache ============\n");
// Second run to consume the cache in new isolate

View File

@ -23,15 +23,11 @@ BackgroundParsingTask::BackgroundParsingTask(
int stack_size, Isolate* isolate)
: source_(source),
stack_size_(stack_size),
script_data_(nullptr),
timer_(isolate->counters()->compile_script_on_background()) {
// We don't set the context to the CompilationInfo yet, because the background
// thread cannot do anything with it anyway. We set it just before compilation
// on the foreground thread.
DCHECK(options == ScriptCompiler::kProduceParserCache ||
options == ScriptCompiler::kProduceCodeCache ||
options == ScriptCompiler::kProduceFullCodeCache ||
options == ScriptCompiler::kNoCompileOptions ||
DCHECK(options == ScriptCompiler::kNoCompileOptions ||
options == ScriptCompiler::kEagerCompile);
VMState<PARSER> state(isolate);
@ -51,12 +47,10 @@ BackgroundParsingTask::BackgroundParsingTask(
info->runtime_call_stats()));
info->set_character_stream(std::move(stream));
info->set_unicode_cache(&source_->unicode_cache);
info->set_compile_options(options);
info->set_allow_lazy_parsing();
if (V8_UNLIKELY(info->block_coverage_enabled())) {
info->AllocateSourceRangeMap();
}
info->set_cached_data(&script_data_);
LanguageMode language_mode = construct_language_mode(FLAG_use_strict);
info->set_language_mode(
stricter_language_mode(info->language_mode(), language_mode));
@ -93,15 +87,6 @@ void BackgroundParsingTask::Run() {
source_->info.get(), allocator_, &source_->inner_function_jobs);
}
if (script_data_ != nullptr) {
source_->cached_data.reset(new ScriptCompiler::CachedData(
script_data_->data(), script_data_->length(),
ScriptCompiler::CachedData::BufferOwned));
script_data_->ReleaseDataOwnership();
delete script_data_;
script_data_ = nullptr;
}
source_->info->EmitBackgroundParseStatisticsOnBackgroundThread();
source_->info->set_on_background_thread(false);

View File

@ -63,7 +63,6 @@ class BackgroundParsingTask : public ScriptCompiler::ScriptStreamingTask {
private:
StreamedSource* source_; // Not owned.
int stack_size_;
ScriptData* script_data_;
AccountingAllocator* allocator_;
TimedHistogram* timer_;
};

View File

@ -20,7 +20,6 @@ ParseInfo::ParseInfo(AccountingAllocator* zone_allocator)
: zone_(std::make_shared<Zone>(zone_allocator, ZONE_NAME)),
flags_(0),
extension_(nullptr),
compile_options_(ScriptCompiler::kNoCompileOptions),
script_scope_(nullptr),
unicode_cache_(nullptr),
stack_limit_(0),
@ -32,7 +31,6 @@ ParseInfo::ParseInfo(AccountingAllocator* zone_allocator)
function_literal_id_(FunctionLiteral::kIdTypeInvalid),
max_function_literal_id_(FunctionLiteral::kIdTypeInvalid),
character_stream_(nullptr),
cached_data_(nullptr),
ast_value_factory_(nullptr),
ast_string_constants_(nullptr),
function_name_(nullptr),

View File

@ -29,7 +29,6 @@ class DeclarationScope;
class FunctionLiteral;
class RuntimeCallStats;
class Logger;
class ScriptData;
class SourceRangeMap;
class UnicodeCache;
class Utf16CharacterStream;
@ -107,20 +106,11 @@ class V8_EXPORT_PRIVATE ParseInfo {
v8::Extension* extension() const { return extension_; }
void set_extension(v8::Extension* extension) { extension_ = extension; }
ScriptData** cached_data() const { return cached_data_; }
void set_cached_data(ScriptData** cached_data) { cached_data_ = cached_data; }
ConsumedPreParsedScopeData* consumed_preparsed_scope_data() {
return &consumed_preparsed_scope_data_;
}
ScriptCompiler::CompileOptions compile_options() const {
return compile_options_;
}
void set_compile_options(ScriptCompiler::CompileOptions compile_options) {
compile_options_ = compile_options;
}
DeclarationScope* script_scope() const { return script_scope_; }
void set_script_scope(DeclarationScope* script_scope) {
script_scope_ = script_scope;
@ -271,7 +261,6 @@ class V8_EXPORT_PRIVATE ParseInfo {
std::shared_ptr<Zone> zone_;
unsigned flags_;
v8::Extension* extension_;
ScriptCompiler::CompileOptions compile_options_;
DeclarationScope* script_scope_;
UnicodeCache* unicode_cache_;
uintptr_t stack_limit_;
@ -289,7 +278,6 @@ class V8_EXPORT_PRIVATE ParseInfo {
//----------- Inputs+Outputs of parsing and scope analysis -----------------
std::unique_ptr<Utf16CharacterStream> character_stream_;
ScriptData** cached_data_; // used if available, populated if requested.
ConsumedPreParsedScopeData consumed_preparsed_scope_data_;
std::shared_ptr<AstValueFactory> ast_value_factory_;
const class AstStringConstants* ast_string_constants_;

View File

@ -29,81 +29,7 @@
namespace v8 {
namespace internal {
ScriptData::ScriptData(const byte* data, int length)
: owns_data_(false), rejected_(false), data_(data), length_(length) {
if (!IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment)) {
byte* copy = NewArray<byte>(length);
DCHECK(IsAligned(reinterpret_cast<intptr_t>(copy), kPointerAlignment));
CopyBytes(copy, data, length);
data_ = copy;
AcquireDataOwnership();
}
}
FunctionEntry ParseData::GetFunctionEntry(int start) {
// The current pre-data entry must be a FunctionEntry with the given
// start position.
if ((function_index_ + FunctionEntry::kSize <= Length()) &&
(static_cast<int>(Data()[function_index_]) == start)) {
int index = function_index_;
function_index_ += FunctionEntry::kSize;
Vector<unsigned> subvector(&(Data()[index]), FunctionEntry::kSize);
return FunctionEntry(subvector);
}
return FunctionEntry();
}
int ParseData::FunctionCount() {
int functions_size = FunctionsSize();
if (functions_size < 0) return 0;
if (functions_size % FunctionEntry::kSize != 0) return 0;
return functions_size / FunctionEntry::kSize;
}
bool ParseData::IsSane() {
if (!IsAligned(script_data_->length(), sizeof(unsigned))) return false;
// Check that the header data is valid and doesn't specify
// point to positions outside the store.
int data_length = Length();
if (data_length < PreparseDataConstants::kHeaderSize) return false;
if (Magic() != PreparseDataConstants::kMagicNumber) return false;
if (Version() != PreparseDataConstants::kCurrentVersion) return false;
// Check that the space allocated for function entries is sane.
int functions_size = FunctionsSize();
if (functions_size < 0) return false;
if (functions_size % FunctionEntry::kSize != 0) return false;
// Check that the total size has room for header and function entries.
int minimum_size =
PreparseDataConstants::kHeaderSize + functions_size;
if (data_length < minimum_size) return false;
return true;
}
void ParseData::Initialize() {
// Prepares state for use.
int data_length = Length();
if (data_length >= PreparseDataConstants::kHeaderSize) {
function_index_ = PreparseDataConstants::kHeaderSize;
}
}
unsigned ParseData::Magic() {
return Data()[PreparseDataConstants::kMagicOffset];
}
unsigned ParseData::Version() {
return Data()[PreparseDataConstants::kVersionOffset];
}
int ParseData::FunctionsSize() {
return static_cast<int>(Data()[PreparseDataConstants::kFunctionsSizeOffset]);
}
// Helper for putting parts of the parse results into a temporary zone when
// parsing inner function bodies.
@ -153,17 +79,6 @@ class DiscardableZoneScope {
DISALLOW_COPY_AND_ASSIGN(DiscardableZoneScope);
};
void Parser::SetCachedData(ParseInfo* info) {
DCHECK_NULL(cached_parse_data_);
if (consume_cached_parse_data()) {
if (allow_lazy_) {
cached_parse_data_ = ParseData::FromCachedData(*info->cached_data());
if (cached_parse_data_ != nullptr) return;
}
compile_options_ = ScriptCompiler::kNoCompileOptions;
}
}
FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
bool call_super, int pos,
int end_pos) {
@ -511,11 +426,8 @@ Parser::Parser(ParseInfo* info)
mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly.
source_range_map_(info->source_range_map()),
target_stack_(nullptr),
compile_options_(info->compile_options()),
cached_parse_data_(nullptr),
total_preparse_skipped_(0),
temp_zoned_(false),
log_(nullptr),
consumed_preparsed_scope_data_(info->consumed_preparsed_scope_data()),
parameters_end_pos_(info->parameters_end_pos()) {
// Even though we were passed ParseInfo, we should not store it in
@ -603,18 +515,6 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
// Initialize parser state.
ParserLogger logger;
if (produce_cached_parse_data()) {
if (allow_lazy_) {
log_ = &logger;
} else {
compile_options_ = ScriptCompiler::kNoCompileOptions;
}
} else if (consume_cached_parse_data()) {
cached_parse_data_->Initialize();
}
DeserializeScopeChain(info, info->maybe_outer_scope_info());
scanner_.Initialize(info->character_stream(), info->is_module());
@ -623,11 +523,6 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
HandleSourceURLComments(isolate, info->script());
if (produce_cached_parse_data() && result != nullptr) {
*info->cached_data() = logger.GetScriptData();
}
log_ = nullptr;
if (V8_UNLIKELY(FLAG_log_function_events) && result != nullptr) {
double ms = timer.Elapsed().InMillisecondsF();
const char* event_name = "parse-eval";
@ -2832,38 +2727,11 @@ Parser::LazyParsingResult Parser::SkipFunction(
DCHECK_NE(kNoSourcePosition, function_scope->start_position());
DCHECK_EQ(kNoSourcePosition, parameters_end_pos_);
if (produce_cached_parse_data()) CHECK(log_);
DCHECK_IMPLIES(IsArrowFunction(kind),
scanner()->current_token() == Token::ARROW);
// Inner functions are not part of the cached data.
if (!is_inner_function && consume_cached_parse_data() &&
!cached_parse_data_->rejected()) {
// If we have cached data, we use it to skip parsing the function. The data
// contains the information we need to construct the lazy function.
FunctionEntry entry =
cached_parse_data_->GetFunctionEntry(function_scope->start_position());
// Check that cached data is valid. If not, mark it as invalid (the embedder
// handles it). Note that end position greater than end of stream is safe,
// and hard to check.
if (entry.is_valid() &&
entry.end_pos() > function_scope->start_position()) {
total_preparse_skipped_ += entry.end_pos() - position();
function_scope->set_end_position(entry.end_pos());
scanner()->SeekForward(entry.end_pos() - 1);
Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete));
*num_parameters = entry.num_parameters();
SetLanguageMode(function_scope, entry.language_mode());
if (entry.uses_super_property())
function_scope->RecordSuperPropertyUsage();
SkipFunctionLiterals(entry.num_inner_functions());
return kLazyParsingComplete;
}
cached_parse_data_->Reject();
}
// FIXME(marja): There are 3 ways to skip functions now. Unify them.
// FIXME(marja): There are 2 ways to skip functions now. Unify them.
DCHECK_NOT_NULL(consumed_preparsed_scope_data_);
if (consumed_preparsed_scope_data_->HasData()) {
DCHECK(FLAG_preparser_scope_analysis);
@ -2924,13 +2792,6 @@ Parser::LazyParsingResult Parser::SkipFunction(
function_scope->end_position() - function_scope->start_position();
*num_parameters = logger->num_parameters();
SkipFunctionLiterals(logger->num_inner_functions());
if (!is_inner_function && produce_cached_parse_data()) {
DCHECK(log_);
log_->LogFunction(function_scope->start_position(),
function_scope->end_position(), *num_parameters,
language_mode(), function_scope->NeedsHomeObject(),
logger->num_inner_functions());
}
return kLazyParsingComplete;
}
@ -3573,15 +3434,6 @@ void Parser::ParseOnBackground(ParseInfo* info) {
DCHECK_NULL(info->literal());
FunctionLiteral* result = nullptr;
ParserLogger logger;
if (produce_cached_parse_data()) {
if (allow_lazy_) {
log_ = &logger;
} else {
compile_options_ = ScriptCompiler::kNoCompileOptions;
}
}
scanner_.Initialize(info->character_stream(), info->is_module());
DCHECK(info->maybe_outer_scope_info().is_null());
@ -3605,11 +3457,6 @@ void Parser::ParseOnBackground(ParseInfo* info) {
// We cannot internalize on a background thread; a foreground task will take
// care of calling AstValueFactory::Internalize just before compilation.
if (produce_cached_parse_data()) {
if (result != nullptr) *info->cached_data() = logger.GetScriptData();
log_ = nullptr;
}
}
Parser::TemplateLiteralState Parser::OpenTemplateLiteral(int pos) {

View File

@ -14,7 +14,6 @@
#include "src/globals.h"
#include "src/parsing/parser-base.h"
#include "src/parsing/parsing.h"
#include "src/parsing/preparse-data-format.h"
#include "src/parsing/preparse-data.h"
#include "src/parsing/preparser.h"
#include "src/utils.h"
@ -27,7 +26,6 @@ namespace internal {
class ConsumedPreParsedScopeData;
class ParseInfo;
class ScriptData;
class ParserTarget;
class ParserTargetScope;
class PendingCompilationErrorHandler;
@ -77,47 +75,6 @@ class FunctionEntry BASE_EMBEDDED {
};
// Wrapper around ScriptData to provide parser-specific functionality.
class ParseData {
public:
static ParseData* FromCachedData(ScriptData* cached_data) {
ParseData* pd = new ParseData(cached_data);
if (pd->IsSane()) return pd;
cached_data->Reject();
delete pd;
return nullptr;
}
void Initialize();
FunctionEntry GetFunctionEntry(int start);
int FunctionCount();
unsigned* Data() { // Writable data as unsigned int array.
return reinterpret_cast<unsigned*>(const_cast<byte*>(script_data_->data()));
}
void Reject() { script_data_->Reject(); }
bool rejected() const { return script_data_->rejected(); }
private:
explicit ParseData(ScriptData* script_data) : script_data_(script_data) {}
bool IsSane();
unsigned Magic();
unsigned Version();
int FunctionsSize();
int Length() const {
// Script data length is already checked to be a multiple of unsigned size.
return script_data_->length() / sizeof(unsigned);
}
ScriptData* script_data_;
int function_index_;
DISALLOW_COPY_AND_ASSIGN(ParseData);
};
// ----------------------------------------------------------------------------
// JAVASCRIPT PARSING
@ -192,8 +149,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
~Parser() {
delete reusable_preparser_;
reusable_preparser_ = nullptr;
delete cached_parse_data_;
cached_parse_data_ = nullptr;
}
static bool IsPreParser() { return false; }
@ -276,20 +231,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
ZoneList<const AstRawString*>* PrepareWrappedArguments(ParseInfo* info,
Zone* zone);
void SetCachedData(ParseInfo* info);
void StitchAst(ParseInfo* top_level_parse_info, Isolate* isolate);
ScriptCompiler::CompileOptions compile_options() const {
return compile_options_;
}
bool consume_cached_parse_data() const {
return compile_options_ == ScriptCompiler::kConsumeParserCache;
}
bool produce_cached_parse_data() const {
return compile_options_ == ScriptCompiler::kProduceParserCache;
}
PreParser* reusable_preparser() {
if (reusable_preparser_ == nullptr) {
reusable_preparser_ =
@ -1145,7 +1088,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
ParserTarget* target_stack_; // for break, continue statements
ScriptCompiler::CompileOptions compile_options_;
ParseData* cached_parse_data_;
// Other information which will be stored in Parser and moved to Isolate after
// parsing.
@ -1153,7 +1095,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
int total_preparse_skipped_;
bool allow_lazy_;
bool temp_zoned_;
ParserLogger* log_;
ConsumedPreParsedScopeData* consumed_preparsed_scope_data_;
// If not kNoSourcePosition, indicates that the first function literal

View File

@ -36,7 +36,6 @@ bool ParseProgram(ParseInfo* info, Isolate* isolate) {
// Ok to use Isolate here; this function is only called in the main thread.
DCHECK(parser.parsing_on_main_thread_);
parser.SetCachedData(info);
result = parser.ParseProgram(isolate, info);
info->set_literal(result);
if (result == nullptr) {

View File

@ -1,32 +0,0 @@
// Copyright 2011 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_PARSING_PREPARSE_DATA_FORMAT_H_
#define V8_PARSING_PREPARSE_DATA_FORMAT_H_
namespace v8 {
namespace internal {
// Generic and general data used by preparse data recorders and readers.
struct PreparseDataConstants {
public:
// Layout and constants of the preparse data exchange format.
static const unsigned kMagicNumber = 0xBadDead;
static const unsigned kCurrentVersion = 18;
static const int kMagicOffset = 0;
static const int kVersionOffset = 1;
static const int kFunctionsSizeOffset = 2;
static const int kSizeOffset = 3;
static const int kHeaderSize = 4;
static const unsigned char kNumberTerminator = 0x80u;
};
} // namespace internal
} // namespace v8.
#endif // V8_PARSING_PREPARSE_DATA_FORMAT_H_

View File

@ -8,53 +8,10 @@
#include "src/globals.h"
#include "src/objects-inl.h"
#include "src/parsing/parser.h"
#include "src/parsing/preparse-data-format.h"
namespace v8 {
namespace internal {
void ParserLogger::LogFunction(int start, int end, int num_parameters,
LanguageMode language_mode,
bool uses_super_property,
int num_inner_functions) {
function_store_.Add(start);
function_store_.Add(end);
function_store_.Add(num_parameters);
function_store_.Add(
FunctionEntry::EncodeFlags(language_mode, uses_super_property));
function_store_.Add(num_inner_functions);
}
ParserLogger::ParserLogger() {
preamble_[PreparseDataConstants::kMagicOffset] =
PreparseDataConstants::kMagicNumber;
preamble_[PreparseDataConstants::kVersionOffset] =
PreparseDataConstants::kCurrentVersion;
preamble_[PreparseDataConstants::kFunctionsSizeOffset] = 0;
preamble_[PreparseDataConstants::kSizeOffset] = 0;
DCHECK_EQ(4, PreparseDataConstants::kHeaderSize);
#ifdef DEBUG
prev_start_ = -1;
#endif
}
ScriptData* ParserLogger::GetScriptData() {
int function_size = function_store_.size();
int total_size = PreparseDataConstants::kHeaderSize + function_size;
unsigned* data = NewArray<unsigned>(total_size);
preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
MemCopy(data, preamble_, sizeof(preamble_));
if (function_size > 0) {
function_store_.WriteTo(Vector<unsigned>(
data + PreparseDataConstants::kHeaderSize, function_size));
}
DCHECK(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
ScriptData* result = new ScriptData(reinterpret_cast<byte*>(data),
total_size * sizeof(unsigned));
result->AcquireDataOwnership();
return result;
}
PreParseData::FunctionData PreParseData::GetFunctionData(int start) const {
auto it = functions_.find(start);
if (it != functions_.end()) {

View File

@ -11,43 +11,9 @@
#include "src/base/hashmap.h"
#include "src/collector.h"
#include "src/messages.h"
#include "src/parsing/preparse-data-format.h"
namespace v8 {
namespace internal {
class ScriptData {
public:
ScriptData(const byte* data, int length);
~ScriptData() {
if (owns_data_) DeleteArray(data_);
}
const byte* data() const { return data_; }
int length() const { return length_; }
bool rejected() const { return rejected_; }
void Reject() { rejected_ = true; }
void AcquireDataOwnership() {
DCHECK(!owns_data_);
owns_data_ = true;
}
void ReleaseDataOwnership() {
DCHECK(owns_data_);
owns_data_ = false;
}
private:
bool owns_data_ : 1;
bool rejected_ : 1;
const byte* data_;
int length_;
DISALLOW_COPY_AND_ASSIGN(ScriptData);
};
class PreParserLogger final {
public:
PreParserLogger()
@ -74,25 +40,6 @@ class PreParserLogger final {
int num_inner_functions_;
};
class ParserLogger final {
public:
ParserLogger();
void LogFunction(int start, int end, int num_parameters,
LanguageMode language_mode, bool uses_super_property,
int num_inner_functions);
ScriptData* GetScriptData();
private:
Collector<unsigned> function_store_;
unsigned preamble_[PreparseDataConstants::kHeaderSize];
#ifdef DEBUG
int prev_start_;
#endif
};
class PreParseData final {
public:
struct FunctionData {

View File

@ -11,7 +11,6 @@
#include "src/globals.h"
#include "src/parsing/duplicate-finder.h"
#include "src/parsing/parser-base.h"
#include "src/parsing/preparse-data-format.h"
#include "src/parsing/preparse-data.h"
#include "src/parsing/preparsed-scope-data.h"
#include "src/parsing/preparser.h"

View File

@ -22,6 +22,17 @@
namespace v8 {
namespace internal {
ScriptData::ScriptData(const byte* data, int length)
: owns_data_(false), rejected_(false), data_(data), length_(length) {
if (!IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment)) {
byte* copy = NewArray<byte>(length);
DCHECK(IsAligned(reinterpret_cast<intptr_t>(copy), kPointerAlignment));
CopyBytes(copy, data, length);
data_ = copy;
AcquireDataOwnership();
}
}
ScriptData* CodeSerializer::Serialize(Isolate* isolate,
Handle<SharedFunctionInfo> info,
Handle<String> source) {

View File

@ -11,6 +11,38 @@
namespace v8 {
namespace internal {
class ScriptData {
public:
ScriptData(const byte* data, int length);
~ScriptData() {
if (owns_data_) DeleteArray(data_);
}
const byte* data() const { return data_; }
int length() const { return length_; }
bool rejected() const { return rejected_; }
void Reject() { rejected_ = true; }
void AcquireDataOwnership() {
DCHECK(!owns_data_);
owns_data_ = true;
}
void ReleaseDataOwnership() {
DCHECK(owns_data_);
owns_data_ = false;
}
private:
bool owns_data_ : 1;
bool rejected_ : 1;
const byte* data_;
int length_;
DISALLOW_COPY_AND_ASSIGN(ScriptData);
};
class CodeSerializer : public Serializer<> {
public:
static ScriptData* Serialize(Isolate* isolate,

View File

@ -454,25 +454,6 @@ static inline v8::Local<v8::Value> CompileRun(
}
static inline v8::Local<v8::Value> ParserCacheCompileRun(const char* source) {
// Compile once just to get the preparse data, then compile the second time
// using the data.
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::ScriptCompiler::Source script_source(v8_str(source));
v8::ScriptCompiler::Compile(context, &script_source,
v8::ScriptCompiler::kProduceParserCache)
.ToLocalChecked();
// Check whether we received cached data, and if so use it.
v8::ScriptCompiler::CompileOptions options =
script_source.GetCachedData() ? v8::ScriptCompiler::kConsumeParserCache
: v8::ScriptCompiler::kNoCompileOptions;
return CompileRun(context, &script_source, options);
}
// Helper functions that compile and run the source with given origin.
static inline v8::Local<v8::Value> CompileRunWithOrigin(const char* source,
const char* origin_url,

View File

@ -14896,38 +14896,6 @@ THREADED_TEST(AccessChecksReenabledCorrectly) {
}
// Tests that ScriptData can be serialized and deserialized.
TEST(PreCompileSerialization) {
// Producing cached parser data while parsing eagerly is not supported.
if (!i::FLAG_lazy) return;
v8::V8::Initialize();
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
HandleScope handle_scope(isolate);
const char* script = "function foo(a) { return a+1; }";
v8::ScriptCompiler::Source source(v8_str(script));
v8::ScriptCompiler::Compile(env.local(), &source,
v8::ScriptCompiler::kProduceParserCache)
.ToLocalChecked();
// Serialize.
const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
i::MemCopy(serialized_data, cd->data, cd->length);
// Deserialize.
i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
// Verify that the original is the same as the deserialized.
CHECK_EQ(cd->length, deserialized->length());
CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
delete deserialized;
i::DeleteArray(serialized_data);
}
// This tests that we do not allow dictionary load/call inline caches
// to use functions that have not yet been compiled. The potential
// problem of loading a function that has not yet been compiled can
@ -24906,33 +24874,6 @@ TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
}
TEST(StreamingProducesParserCache) {
const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
nullptr};
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
v8::ScriptCompiler::StreamedSource source(
new TestSourceStream(chunks),
v8::ScriptCompiler::StreamedSource::ONE_BYTE);
v8::ScriptCompiler::ScriptStreamingTask* task =
v8::ScriptCompiler::StartStreamingScript(
isolate, &source, v8::ScriptCompiler::kProduceParserCache);
// TestSourceStream::GetMoreData won't block, so it's OK to just run the
// task here in the main thread.
task->Run();
delete task;
const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
CHECK_NOT_NULL(cached_data);
CHECK_NOT_NULL(cached_data->data);
CHECK(!cached_data->rejected);
CHECK_GT(cached_data->length, 0);
}
TEST(StreamingWithDebuggingEnabledLate) {
// The streaming parser can only parse lazily, i.e. inner functions are not
@ -25106,13 +25047,11 @@ TEST(CodeCache) {
v8::ScriptOrigin script_origin(v8_str(origin));
v8::ScriptCompiler::Source source(source_string, script_origin);
v8::ScriptCompiler::CompileOptions option =
v8::ScriptCompiler::kProduceCodeCache;
v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
int length = source.GetCachedData()->length;
uint8_t* cache_data = new uint8_t[length];
memcpy(cache_data, source.GetCachedData()->data, length);
cache = new v8::ScriptCompiler::CachedData(
cache_data, length, v8::ScriptCompiler::CachedData::BufferOwned);
v8::ScriptCompiler::kNoCompileOptions;
v8::Local<v8::Script> script =
v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
cache = v8::ScriptCompiler::CreateCodeCache(script->GetUnboundScript(),
source_string);
}
isolate1->Dispose();
@ -25163,15 +25102,6 @@ void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
script->Run(context).ToLocalChecked()->Int32Value(context).FromJust());
}
TEST(InvalidParserCacheData) {
v8::V8::Initialize();
v8::HandleScope scope(CcTest::isolate());
LocalContext context;
if (i::FLAG_lazy) {
// Cached parser data is not consumed while parsing eagerly.
TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
}
}
TEST(InvalidCodeCacheData) {
v8::V8::Initialize();
@ -25181,67 +25111,6 @@ TEST(InvalidCodeCacheData) {
}
TEST(ParserCacheRejectedGracefully) {
// Producing cached parser data while parsing eagerly is not supported.
if (!i::FLAG_lazy) return;
v8::V8::Initialize();
v8::HandleScope scope(CcTest::isolate());
LocalContext context;
// Produce valid cached data.
v8::ScriptOrigin origin(v8_str("origin"));
v8::Local<v8::String> source_str = v8_str("function foo() {}");
v8::ScriptCompiler::Source source(source_str, origin);
v8::Local<v8::Script> script =
v8::ScriptCompiler::Compile(context.local(), &source,
v8::ScriptCompiler::kProduceParserCache)
.ToLocalChecked();
USE(script);
const v8::ScriptCompiler::CachedData* original_cached_data =
source.GetCachedData();
CHECK_NOT_NULL(original_cached_data);
CHECK_NOT_NULL(original_cached_data->data);
CHECK(!original_cached_data->rejected);
CHECK_GT(original_cached_data->length, 0);
// Recompiling the same script with it won't reject the data.
{
v8::ScriptCompiler::Source source_with_cached_data(
source_str, origin,
new v8::ScriptCompiler::CachedData(original_cached_data->data,
original_cached_data->length));
v8::Local<v8::Script> script =
v8::ScriptCompiler::Compile(context.local(), &source_with_cached_data,
v8::ScriptCompiler::kConsumeParserCache)
.ToLocalChecked();
USE(script);
const v8::ScriptCompiler::CachedData* new_cached_data =
source_with_cached_data.GetCachedData();
CHECK_NOT_NULL(new_cached_data);
CHECK(!new_cached_data->rejected);
}
// Compile an incompatible script with the cached data. The new script doesn't
// have the same starting position for the function as the old one, so the old
// cached data will be incompatible with it and will be rejected.
{
v8::Local<v8::String> incompatible_source_str =
v8_str(" function foo() {}");
v8::ScriptCompiler::Source source_with_cached_data(
incompatible_source_str, origin,
new v8::ScriptCompiler::CachedData(original_cached_data->data,
original_cached_data->length));
v8::Local<v8::Script> script =
v8::ScriptCompiler::Compile(context.local(), &source_with_cached_data,
v8::ScriptCompiler::kConsumeParserCache)
.ToLocalChecked();
USE(script);
const v8::ScriptCompiler::CachedData* new_cached_data =
source_with_cached_data.GetCachedData();
CHECK_NOT_NULL(new_cached_data);
CHECK(new_cached_data->rejected);
}
}
TEST(StringConcatOverflow) {
v8::V8::Initialize();
v8::HandleScope scope(CcTest::isolate());

View File

@ -6268,41 +6268,6 @@ TEST(LiveEditDisabled) {
}
TEST(PrecompiledFunction) {
// Regression test for crbug.com/346207. If we have preparse data, parsing the
// function in the presence of the debugger (and breakpoints) should still
// succeed. The bug was that preparsing was done lazily and parsing was done
// eagerly, so, the symbol streams didn't match.
DebugLocalContext env;
v8::HandleScope scope(env->GetIsolate());
env.ExposeDebug();
SetDebugEventListener(env->GetIsolate(), DebugBreakInlineListener);
v8::Local<v8::Function> break_here =
CompileFunction(&env, "function break_here(){}", "break_here");
SetBreakPoint(break_here, 0);
const char* source =
"var a = b = c = 1; \n"
"function this_is_lazy() { \n"
// This symbol won't appear in the preparse data.
" var a; \n"
"} \n"
"function bar() { \n"
" return \"bar\"; \n"
"}; \n"
"a = b = c = 2; \n"
"bar(); \n";
v8::Local<v8::Value> result = ParserCacheCompileRun(source);
CHECK(result->IsString());
v8::String::Utf8Value utf8(env->GetIsolate(), result);
CHECK_EQ(0, strcmp("bar", *utf8));
SetDebugEventListener(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded();
}
static void DebugBreakStackTraceListener(
const v8::Debug::EventDetails& event_details) {
v8::StackTrace::CurrentStackTrace(CcTest::isolate(), 10);

View File

@ -262,125 +262,6 @@ class ScriptResource : public v8::String::ExternalOneByteStringResource {
};
TEST(UsingCachedData) {
// Producing cached parser data while parsing eagerly is not supported.
if (!i::FLAG_lazy) return;
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handles(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
CcTest::i_isolate()->stack_guard()->SetStackLimit(
i::GetCurrentStackPosition() - 128 * 1024);
// Source containing functions that might be lazily compiled and all types
// of symbols (string, propertyName, regexp).
const char* source =
"var x = 42;"
"function foo(a) { return function nolazy(b) { return a + b; } }"
"function bar(a) { if (a) return function lazy(b) { return b; } }"
"var z = {'string': 'string literal', bareword: 'propertyName', "
" 42: 'number literal', for: 'keyword as propertyName', "
" f\\u006fr: 'keyword propertyname with escape'};"
"var v = /RegExp Literal/;"
"var w = /RegExp Literal\\u0020With Escape/gi;"
"var y = { get getter() { return 42; }, "
" set setter(v) { this.value = v; }};"
"var f = a => function (b) { return a + b; };"
"var g = a => b => a + b;";
int source_length = i::StrLength(source);
// ScriptResource will be deleted when the corresponding String is GCd.
v8::ScriptCompiler::Source script_source(
v8::String::NewExternalOneByte(isolate,
new ScriptResource(source, source_length))
.ToLocalChecked());
v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &script_source,
v8::ScriptCompiler::kProduceParserCache)
.ToLocalChecked();
CHECK(script_source.GetCachedData());
// Compile the script again, using the cached data.
bool lazy_flag = i::FLAG_lazy;
i::FLAG_lazy = true;
v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &script_source,
v8::ScriptCompiler::kConsumeParserCache)
.ToLocalChecked();
i::FLAG_lazy = false;
v8::ScriptCompiler::CompileUnboundScript(
isolate, &script_source, v8::ScriptCompiler::kConsumeParserCache)
.ToLocalChecked();
i::FLAG_lazy = lazy_flag;
}
TEST(PreparseFunctionDataIsUsed) {
// Producing cached parser data while parsing eagerly is not supported.
if (!i::FLAG_lazy) return;
// This tests that we actually do use the function data generated by the
// preparser.
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handles(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
CcTest::i_isolate()->stack_guard()->SetStackLimit(
i::GetCurrentStackPosition() - 128 * 1024);
const char* good_code[] = {
"function z() { var a; } function f() { return 25; } f();",
"var z = function () { var a; }; function f() { return 25; } f();",
"function *z() { var a; } function f() { return 25; } f();",
"var z = function *() { var a; }; function f() { return 25; } f();",
"function z(p1, p2) { var a; } function f() { return 25; } f();",
"var z = function (p1, p2) { var a; }; function f() { return 25; } f();",
"function *z(p1, p2) { var a; } function f() { return 25; } f();",
"var z = function *(p1, p2) { var a; }; function f() { return 25; } f();",
"var z = () => { var a; }; function f() { return 25; } f();",
"var z = (p1, p2) => { var a; }; function f() { return 25; } f();",
};
// Insert a syntax error inside the lazy function.
const char* bad_code[] = {
"function z() { if ( } function f() { return 25; } f();",
"var z = function () { if ( }; function f() { return 25; } f();",
"function *z() { if ( } function f() { return 25; } f();",
"var z = function *() { if ( }; function f() { return 25; } f();",
"function z(p1, p2) { if ( } function f() { return 25; } f();",
"var z = function (p1, p2) { if ( }; function f() { return 25; } f();",
"function *z(p1, p2) { if ( } function f() { return 25; } f();",
"var z = function *(p1, p2) { if ( }; function f() { return 25; } f();",
"var z = () => { if ( }; function f() { return 25; } f();",
"var z = (p1, p2) => { if ( }; function f() { return 25; } f();",
};
for (unsigned i = 0; i < arraysize(good_code); i++) {
v8::ScriptCompiler::Source good_source(v8_str(good_code[i]));
v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &good_source,
v8::ScriptCompiler::kProduceParserCache)
.ToLocalChecked();
const v8::ScriptCompiler::CachedData* cached_data =
good_source.GetCachedData();
CHECK_NOT_NULL(cached_data->data);
CHECK_GT(cached_data->length, 0);
// Now compile the erroneous code with the good preparse data. If the
// preparse data is used, the lazy function is skipped and it should
// compile fine.
v8::ScriptCompiler::Source bad_source(
v8_str(bad_code[i]), new v8::ScriptCompiler::CachedData(
cached_data->data, cached_data->length));
v8::Local<v8::Value> result =
CompileRun(isolate->GetCurrentContext(), &bad_source,
v8::ScriptCompiler::kConsumeParserCache);
CHECK(result->IsInt32());
CHECK_EQ(25, result->Int32Value(isolate->GetCurrentContext()).FromJust());
}
}
TEST(StandAlonePreParser) {
v8::V8::Initialize();
i::Isolate* i_isolate = CcTest::i_isolate();
@ -452,42 +333,6 @@ TEST(StandAlonePreParserNoNatives) {
}
TEST(PreparsingObjectLiterals) {
// Regression test for a bug where the symbol stream produced by PreParser
// didn't match what Parser wanted to consume.
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handles(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
CcTest::i_isolate()->stack_guard()->SetStackLimit(
i::GetCurrentStackPosition() - 128 * 1024);
{
const char* source = "var myo = {if: \"foo\"}; myo.if;";
v8::Local<v8::Value> result = ParserCacheCompileRun(source);
CHECK(result->IsString());
v8::String::Utf8Value utf8(isolate, result);
CHECK_EQ(0, strcmp("foo", *utf8));
}
{
const char* source = "var myo = {\"bar\": \"foo\"}; myo[\"bar\"];";
v8::Local<v8::Value> result = ParserCacheCompileRun(source);
CHECK(result->IsString());
v8::String::Utf8Value utf8(isolate, result);
CHECK_EQ(0, strcmp("foo", *utf8));
}
{
const char* source = "var myo = {1: \"foo\"}; myo[1];";
v8::Local<v8::Value> result = ParserCacheCompileRun(source);
CHECK(result->IsString());
v8::String::Utf8Value utf8(isolate, result);
CHECK_EQ(0, strcmp("foo", *utf8));
}
}
TEST(RegressChromium62639) {
v8::V8::Initialize();
i::Isolate* isolate = CcTest::i_isolate();
@ -521,48 +366,6 @@ TEST(RegressChromium62639) {
}
TEST(Regress928) {
// Test only applies when lazy parsing.
if (!i::FLAG_lazy) return;
// Tests that the first non-toplevel function is not included in the preparse
// data.
const char* program =
"try { } catch (e) { var foo = function () { /* first */ } }"
"var bar = function () { /* second */ }";
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handles(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
v8::ScriptCompiler::Source script_source(v8_str(program));
v8::ScriptCompiler::Compile(context, &script_source,
v8::ScriptCompiler::kProduceParserCache)
.ToLocalChecked();
const v8::ScriptCompiler::CachedData* cached_data =
script_source.GetCachedData();
i::ScriptData script_data(cached_data->data, cached_data->length);
std::unique_ptr<i::ParseData> pd(i::ParseData::FromCachedData(&script_data));
pd->Initialize();
int first_function =
static_cast<int>(strstr(program, "function") - program);
int first_lparen = first_function + i::StrLength("function ");
CHECK_EQ('(', program[first_lparen]);
i::FunctionEntry entry1 = pd->GetFunctionEntry(first_lparen);
CHECK(!entry1.is_valid());
int second_function =
static_cast<int>(strstr(program + first_lparen, "function") - program);
int second_lparen = second_function + i::StrLength("function ");
CHECK_EQ('(', program[second_lparen]);
i::FunctionEntry entry2 = pd->GetFunctionEntry(second_lparen);
CHECK(entry2.is_valid());
CHECK_EQ('}', program[entry2.end_pos() - 1]);
}
TEST(PreParseOverflow) {
v8::V8::Initialize();
i::Isolate* isolate = CcTest::i_isolate();
@ -2352,63 +2155,6 @@ TEST(NoErrorsIdentifierNames) {
RunParserSyncTest(context_data, statement_data, kSuccess);
}
TEST(DontRegressPreParserDataSizes) {
// These tests make sure that Parser doesn't start producing less "preparse
// data" (data which the embedder can cache).
v8::V8::Initialize();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handles(isolate);
CcTest::i_isolate()->stack_guard()->SetStackLimit(
i::GetCurrentStackPosition() - 128 * 1024);
struct TestCase {
const char* program;
int functions;
} test_cases[] = {
// No functions.
{"var x = 42;", 0},
// Functions.
{"function foo() {}", 1},
{"function foo() {} function bar() {}", 2},
// Getter / setter functions are recorded as functions if they're on the
// top
// level.
{"var x = {get foo(){} };", 1},
// Functions insize lazy functions are not recorded.
{"function lazy() { function a() {} function b() {} function c() {} }",
1},
{"function lazy() { var x = {get foo(){} } }", 1},
{nullptr, 0}};
for (int i = 0; test_cases[i].program; i++) {
const char* program = test_cases[i].program;
i::Factory* factory = CcTest::i_isolate()->factory();
i::Handle<i::String> source =
factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked();
i::Handle<i::Script> script = factory->NewScript(source);
i::ParseInfo info(script);
i::ScriptData* sd = nullptr;
info.set_cached_data(&sd);
info.set_compile_options(v8::ScriptCompiler::kProduceParserCache);
i::parsing::ParseProgram(&info, CcTest::i_isolate());
i::ParseData* pd = i::ParseData::FromCachedData(sd);
if (pd->FunctionCount() != test_cases[i].functions) {
FATAL(
"Expected preparse data for program:\n"
"\t%s\n"
"to contain %d functions, however, received %d functions.\n",
program, test_cases[i].functions, pd->FunctionCount());
}
delete sd;
delete pd;
}
}
TEST(FunctionDeclaresItselfStrict) {
// Tests that we produce the right kinds of errors when a function declares
// itself strict (we cannot produce there errors as soon as we see the

View File

@ -1235,6 +1235,26 @@ static Handle<SharedFunctionInfo> CompileScript(
.ToHandleChecked();
}
static Handle<SharedFunctionInfo> CompileScriptAndProduceCache(
Isolate* isolate, Handle<String> source, Handle<String> name,
ScriptData** script_data, v8::ScriptCompiler::CompileOptions options) {
Handle<SharedFunctionInfo> sfi =
Compiler::GetSharedFunctionInfoForScript(
source, name, 0, 0, v8::ScriptOriginOptions(), Handle<Object>(),
Handle<Context>(isolate->native_context()), nullptr, nullptr, options,
ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE,
Handle<FixedArray>())
.ToHandleChecked();
std::unique_ptr<ScriptCompiler::CachedData> cached_data(
ScriptCompiler::CreateCodeCache(ToApiHandle<UnboundScript>(sfi),
Utils::ToLocal(source)));
uint8_t* buffer = NewArray<uint8_t>(cached_data->length);
MemCopy(buffer, cached_data->data, cached_data->length);
*script_data = new i::ScriptData(buffer, cached_data->length);
(*script_data)->AcquireDataOwnership();
return sfi;
}
TEST(CodeSerializerOnePlusOne) {
LocalContext context;
Isolate* isolate = CcTest::i_isolate();
@ -1255,9 +1275,9 @@ TEST(CodeSerializerOnePlusOne) {
ScriptData* cache = nullptr;
Handle<SharedFunctionInfo> orig =
CompileScript(isolate, orig_source, Handle<String>(), &cache,
v8::ScriptCompiler::kProduceCodeCache);
Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
isolate, orig_source, Handle<String>(), &cache,
v8::ScriptCompiler::kNoCompileOptions);
int builtins_count = CountBuiltins();
@ -1297,8 +1317,8 @@ TEST(CodeSerializerPromotedToCompilationCache) {
.ToHandleChecked();
ScriptData* cache = nullptr;
CompileScript(isolate, src, src, &cache,
v8::ScriptCompiler::kProduceCodeCache);
CompileScriptAndProduceCache(isolate, src, src, &cache,
v8::ScriptCompiler::kNoCompileOptions);
DisallowCompilation no_compile_expected(isolate);
Handle<SharedFunctionInfo> copy = CompileScript(
@ -1332,11 +1352,11 @@ TEST(CodeSerializerInternalizedString) {
CHECK(orig_source->Equals(*copy_source));
Handle<JSObject> global(isolate->context()->global_object());
ScriptData* cache = nullptr;
Handle<SharedFunctionInfo> orig =
CompileScript(isolate, orig_source, Handle<String>(), &cache,
v8::ScriptCompiler::kProduceCodeCache);
i::ScriptData* script_data = nullptr;
Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
isolate, orig_source, Handle<String>(), &script_data,
v8::ScriptCompiler::kNoCompileOptions);
Handle<JSFunction> orig_fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
orig, isolate->native_context());
@ -1349,7 +1369,7 @@ TEST(CodeSerializerInternalizedString) {
Handle<SharedFunctionInfo> copy;
{
DisallowCompilation no_compile_expected(isolate);
copy = CompileScript(isolate, copy_source, Handle<String>(), &cache,
copy = CompileScript(isolate, copy_source, Handle<String>(), &script_data,
v8::ScriptCompiler::kConsumeCodeCache);
}
CHECK_NE(*orig, *copy);
@ -1368,7 +1388,7 @@ TEST(CodeSerializerInternalizedString) {
CHECK(Handle<String>::cast(copy_result)->Equals(*expected));
CHECK_EQ(builtins_count, CountBuiltins());
delete cache;
delete script_data;
}
TEST(CodeSerializerLargeCodeObject) {
@ -1393,9 +1413,9 @@ TEST(CodeSerializerLargeCodeObject) {
Handle<JSObject> global(isolate->context()->global_object());
ScriptData* cache = nullptr;
Handle<SharedFunctionInfo> orig =
CompileScript(isolate, source_str, Handle<String>(), &cache,
v8::ScriptCompiler::kProduceCodeCache);
Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
isolate, source_str, Handle<String>(), &cache,
v8::ScriptCompiler::kNoCompileOptions);
CHECK(isolate->heap()->InSpace(orig->abstract_code(), LO_SPACE));
@ -1459,9 +1479,9 @@ TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) {
Handle<JSObject> global(isolate->context()->global_object());
ScriptData* cache = nullptr;
Handle<SharedFunctionInfo> orig =
CompileScript(isolate, source_str, Handle<String>(), &cache,
v8::ScriptCompiler::kProduceCodeCache);
Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
isolate, source_str, Handle<String>(), &cache,
v8::ScriptCompiler::kNoCompileOptions);
CHECK(heap->InSpace(orig->abstract_code(), LO_SPACE));
@ -1522,9 +1542,9 @@ TEST(CodeSerializerLargeStrings) {
Handle<JSObject> global(isolate->context()->global_object());
ScriptData* cache = nullptr;
Handle<SharedFunctionInfo> orig =
CompileScript(isolate, source_str, Handle<String>(), &cache,
v8::ScriptCompiler::kProduceCodeCache);
Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
isolate, source_str, Handle<String>(), &cache,
v8::ScriptCompiler::kNoCompileOptions);
Handle<SharedFunctionInfo> copy;
{
@ -1590,9 +1610,9 @@ TEST(CodeSerializerThreeBigStrings) {
Handle<JSObject> global(isolate->context()->global_object());
ScriptData* cache = nullptr;
Handle<SharedFunctionInfo> orig =
CompileScript(isolate, source_str, Handle<String>(), &cache,
v8::ScriptCompiler::kProduceCodeCache);
Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
isolate, source_str, Handle<String>(), &cache,
v8::ScriptCompiler::kNoCompileOptions);
Handle<SharedFunctionInfo> copy;
{
@ -1708,9 +1728,9 @@ TEST(CodeSerializerExternalString) {
Handle<JSObject> global(isolate->context()->global_object());
ScriptData* cache = nullptr;
Handle<SharedFunctionInfo> orig =
CompileScript(isolate, source_string, Handle<String>(), &cache,
v8::ScriptCompiler::kProduceCodeCache);
Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
isolate, source_string, Handle<String>(), &cache,
v8::ScriptCompiler::kNoCompileOptions);
Handle<SharedFunctionInfo> copy;
{
@ -1765,9 +1785,9 @@ TEST(CodeSerializerLargeExternalString) {
Handle<JSObject> global(isolate->context()->global_object());
ScriptData* cache = nullptr;
Handle<SharedFunctionInfo> orig =
CompileScript(isolate, source_str, Handle<String>(), &cache,
v8::ScriptCompiler::kProduceCodeCache);
Handle<SharedFunctionInfo> orig = CompileScriptAndProduceCache(
isolate, source_str, Handle<String>(), &cache,
v8::ScriptCompiler::kNoCompileOptions);
Handle<SharedFunctionInfo> copy;
{
@ -1815,8 +1835,8 @@ TEST(CodeSerializerExternalScriptName) {
ScriptData* cache = nullptr;
Handle<SharedFunctionInfo> orig =
CompileScript(isolate, source_string, name, &cache,
v8::ScriptCompiler::kProduceCodeCache);
CompileScriptAndProduceCache(isolate, source_string, name, &cache,
v8::ScriptCompiler::kNoCompileOptions);
Handle<SharedFunctionInfo> copy;
{
@ -1848,7 +1868,7 @@ static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
}
}
v8::ScriptCompiler::CachedData* ProduceCache(
v8::ScriptCompiler::CachedData* CompileRunAndProduceCache(
const char* source, CodeCacheType cacheType = CodeCacheType::kLazy) {
v8::ScriptCompiler::CachedData* cache;
v8::Isolate::CreateParams create_params;
@ -1865,12 +1885,10 @@ v8::ScriptCompiler::CachedData* ProduceCache(
v8::ScriptCompiler::Source source(source_str, origin);
v8::ScriptCompiler::CompileOptions options;
switch (cacheType) {
case CodeCacheType::kLazy:
options = v8::ScriptCompiler::kProduceCodeCache;
break;
case CodeCacheType::kEager:
options = v8::ScriptCompiler::kProduceFullCodeCache;
break;
case CodeCacheType::kLazy:
case CodeCacheType::kAfterExecute:
options = v8::ScriptCompiler::kNoCompileOptions;
break;
@ -1881,6 +1899,10 @@ v8::ScriptCompiler::CachedData* ProduceCache(
v8::ScriptCompiler::CompileUnboundScript(isolate1, &source, options)
.ToLocalChecked();
if (cacheType != CodeCacheType::kAfterExecute) {
cache = ScriptCompiler::CreateCodeCache(script, source_str);
}
v8::Local<v8::Value> result = script->BindToCurrentContext()
->Run(isolate1->GetCurrentContext())
.ToLocalChecked();
@ -1891,13 +1913,6 @@ v8::ScriptCompiler::CachedData* ProduceCache(
if (cacheType == CodeCacheType::kAfterExecute) {
cache = ScriptCompiler::CreateCodeCache(script, source_str);
} else {
const ScriptCompiler::CachedData* data = source.GetCachedData();
CHECK(data);
uint8_t* buffer = NewArray<uint8_t>(data->length);
MemCopy(buffer, data->data, data->length);
cache = new v8::ScriptCompiler::CachedData(
buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
}
CHECK(cache);
}
@ -1916,7 +1931,7 @@ void CheckDeserializedFlag(v8::Local<v8::UnboundScript> script) {
TEST(CodeSerializerIsolates) {
const char* source = "function f() { return 'abc'; }; f() + 'def'";
v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(source);
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
@ -1963,7 +1978,7 @@ TEST(CodeSerializerIsolatesEager) {
"}"
"f()() + 'def'";
v8::ScriptCompiler::CachedData* cache =
ProduceCache(source, CodeCacheType::kEager);
CompileRunAndProduceCache(source, CodeCacheType::kEager);
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
@ -2010,7 +2025,7 @@ TEST(CodeSerializerAfterExecute) {
FLAG_opt = false;
const char* source = "function f() { return 'abc'; }; f() + 'def'";
v8::ScriptCompiler::CachedData* cache =
ProduceCache(source, CodeCacheType::kAfterExecute);
CompileRunAndProduceCache(source, CodeCacheType::kAfterExecute);
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
@ -2065,7 +2080,7 @@ TEST(CodeSerializerAfterExecute) {
TEST(CodeSerializerFlagChange) {
const char* source = "function f() { return 'abc'; }; f() + 'def'";
v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(source);
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
@ -2092,7 +2107,7 @@ TEST(CodeSerializerFlagChange) {
TEST(CodeSerializerBitFlip) {
const char* source = "function f() { return 'abc'; }; f() + 'def'";
v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
v8::ScriptCompiler::CachedData* cache = CompileRunAndProduceCache(source);
// Random bit flip.
const_cast<uint8_t*>(cache->data)[337] ^= 0x40;
@ -2141,15 +2156,10 @@ TEST(CodeSerializerWithHarmonyScoping) {
v8::ScriptCompiler::Source source(source_str, origin);
v8::Local<v8::UnboundScript> script =
v8::ScriptCompiler::CompileUnboundScript(
isolate1, &source, v8::ScriptCompiler::kProduceCodeCache)
isolate1, &source, v8::ScriptCompiler::kNoCompileOptions)
.ToLocalChecked();
const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
CHECK(data);
// Persist cached data.
uint8_t* buffer = NewArray<uint8_t>(data->length);
MemCopy(buffer, data->data, data->length);
cache = new v8::ScriptCompiler::CachedData(
buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
cache = v8::ScriptCompiler::CreateCodeCache(script, source_str);
CHECK(cache);
v8::Local<v8::Value> result = script->BindToCurrentContext()
->Run(isolate1->GetCurrentContext())
@ -2205,14 +2215,9 @@ TEST(Regress503552) {
Handle<String> source = isolate->factory()->NewStringFromAsciiChecked(
"function f() {} function g() {}");
ScriptData* script_data = nullptr;
Handle<SharedFunctionInfo> shared =
Compiler::GetSharedFunctionInfoForScript(
source, MaybeHandle<String>(), 0, 0, v8::ScriptOriginOptions(),
MaybeHandle<Object>(), Handle<Context>(isolate->native_context()),
nullptr, &script_data, v8::ScriptCompiler::kProduceCodeCache,
ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE,
MaybeHandle<FixedArray>())
.ToHandleChecked();
Handle<SharedFunctionInfo> shared = CompileScriptAndProduceCache(
isolate, source, Handle<String>(), &script_data,
v8::ScriptCompiler::kNoCompileOptions);
delete script_data;
heap::SimulateIncrementalMarking(isolate->heap());

View File

@ -39,7 +39,6 @@
#include "src/objects-inl.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parsing.h"
#include "src/parsing/preparse-data-format.h"
#include "src/parsing/preparse-data.h"
#include "src/parsing/preparser.h"
#include "src/parsing/scanner-character-streams.h"
@ -59,9 +58,9 @@ class StringResource8 : public v8::String::ExternalOneByteStringResource {
int length_;
};
std::pair<v8::base::TimeDelta, v8::base::TimeDelta> RunBaselineParser(
const char* fname, Encoding encoding, int repeat, v8::Isolate* isolate,
v8::Local<v8::Context> context) {
v8::base::TimeDelta RunBaselineParser(const char* fname, Encoding encoding,
int repeat, v8::Isolate* isolate,
v8::Local<v8::Context> context) {
int length = 0;
const byte* source = ReadFileAndRepeat(fname, &length, repeat);
v8::Local<v8::String> source_handle;
@ -87,42 +86,21 @@ std::pair<v8::base::TimeDelta, v8::base::TimeDelta> RunBaselineParser(
break;
}
}
v8::base::TimeDelta parse_time1, parse_time2;
v8::base::TimeDelta parse_time1;
Handle<Script> script =
reinterpret_cast<i::Isolate*>(isolate)->factory()->NewScript(
v8::Utils::OpenHandle(*source_handle));
i::ScriptData* cached_data_impl = NULL;
// First round of parsing (produce data to cache).
{
ParseInfo info(script);
info.set_cached_data(&cached_data_impl);
info.set_compile_options(v8::ScriptCompiler::kProduceParserCache);
v8::base::ElapsedTimer timer;
timer.Start();
bool success =
parsing::ParseProgram(&info, reinterpret_cast<i::Isolate*>(isolate));
parse_time1 = timer.Elapsed();
if (!success) {
fprintf(stderr, "Parsing failed\n");
return std::make_pair(v8::base::TimeDelta(), v8::base::TimeDelta());
}
ParseInfo info(script);
v8::base::ElapsedTimer timer;
timer.Start();
bool success =
parsing::ParseProgram(&info, reinterpret_cast<i::Isolate*>(isolate));
parse_time1 = timer.Elapsed();
if (!success) {
fprintf(stderr, "Parsing failed\n");
return v8::base::TimeDelta();
}
// Second round of parsing (consume cached data).
{
ParseInfo info(script);
info.set_cached_data(&cached_data_impl);
info.set_compile_options(v8::ScriptCompiler::kConsumeParserCache);
v8::base::ElapsedTimer timer;
timer.Start();
bool success =
parsing::ParseProgram(&info, reinterpret_cast<i::Isolate*>(isolate));
parse_time2 = timer.Elapsed();
if (!success) {
fprintf(stderr, "Parsing failed\n");
return std::make_pair(v8::base::TimeDelta(), v8::base::TimeDelta());
}
}
return std::make_pair(parse_time1, parse_time2);
return parse_time1;
}
@ -167,19 +145,14 @@ int main(int argc, char* argv[]) {
{
v8::Context::Scope scope(context);
double first_parse_total = 0;
double second_parse_total = 0;
for (size_t i = 0; i < fnames.size(); i++) {
std::pair<v8::base::TimeDelta, v8::base::TimeDelta> time =
RunBaselineParser(fnames[i].c_str(), encoding, repeat, isolate,
context);
first_parse_total += time.first.InMillisecondsF();
second_parse_total += time.second.InMillisecondsF();
v8::base::TimeDelta time = RunBaselineParser(
fnames[i].c_str(), encoding, repeat, isolate, context);
first_parse_total += time.InMillisecondsF();
}
if (benchmark.empty()) benchmark = "Baseline";
printf("%s(FirstParseRunTime): %.f ms\n", benchmark.c_str(),
printf("%s(ParseRunTime): %.f ms\n", benchmark.c_str(),
first_parse_total);
printf("%s(SecondParseRunTime): %.f ms\n", benchmark.c_str(),
second_parse_total);
}
}
v8::V8::Dispose();