Revision: 20075
Author: [email protected]
Date: Wed Mar 19 13:24:13 2014 UTC
Log: New compilation API, part 2.
This CL makes the Parser produce the data PreParser used to produce. This
enables us to get rid of the unnecessary preparsing phase.
The first part is here: https://codereview.chromium.org/199063003/
BUG=
[email protected], [email protected]
Review URL: https://codereview.chromium.org/203353002
http://code.google.com/p/v8/source/detail?r=20075
Modified:
/branches/bleeding_edge/include/v8.h
/branches/bleeding_edge/src/api.cc
/branches/bleeding_edge/src/bootstrapper.cc
/branches/bleeding_edge/src/compiler.cc
/branches/bleeding_edge/src/compiler.h
/branches/bleeding_edge/src/d8.cc
/branches/bleeding_edge/src/debug.cc
/branches/bleeding_edge/src/parser.cc
/branches/bleeding_edge/src/parser.h
/branches/bleeding_edge/src/preparser.h
/branches/bleeding_edge/test/cctest/cctest.h
/branches/bleeding_edge/test/cctest/test-api.cc
/branches/bleeding_edge/test/cctest/test-compiler.cc
/branches/bleeding_edge/test/cctest/test-debug.cc
/branches/bleeding_edge/test/cctest/test-parsing.cc
=======================================
--- /branches/bleeding_edge/include/v8.h Wed Mar 19 13:06:53 2014 UTC
+++ /branches/bleeding_edge/include/v8.h Wed Mar 19 13:24:13 2014 UTC
@@ -1097,25 +1097,52 @@
* UnboundScript.
*/
struct V8_EXPORT CachedData {
- CachedData() : data(NULL), length(0) {}
- // Caller keeps the ownership of data and guarantees that the data
stays
- // alive long enough.
- CachedData(const uint8_t* data, int length) : data(data),
length(length) {}
+ enum BufferPolicy {
+ BufferNotOwned,
+ BufferOwned
+ };
+
+ CachedData() : data(NULL), length(0), buffer_policy(BufferNotOwned) {}
+
+ // If buffer_policy is BufferNotOwned, the caller keeps the ownership
of
+ // data and guarantees that it stays alive until the CachedData object
is
+ // destroyed. If the policy is BufferOwned, the given data will be
deleted
+ // (with delete[]) when the CachedData object is destroyed.
+ CachedData(const uint8_t* data, int length,
+ BufferPolicy buffer_policy = BufferNotOwned);
+ ~CachedData();
// TODO(marja): Async compilation; add constructors which take a
callback
// which will be called when V8 no longer needs the data.
const uint8_t* data;
int length;
+ BufferPolicy buffer_policy;
+
+ private:
+ // Prevent copying. Not implemented.
+ CachedData(const CachedData&);
};
/**
* Source code which can be then compiled to a UnboundScript or
* BoundScript.
*/
- struct V8_EXPORT Source {
+ class V8_EXPORT Source {
+ public:
+ // Source takes ownership of CachedData.
Source(Local<String> source_string, const ScriptOrigin& origin,
- const CachedData& cached_data = CachedData());
- Source(Local<String> source_string,
- const CachedData& cached_data = CachedData());
+ CachedData* cached_data = NULL);
+ Source(Local<String> source_string, CachedData* cached_data = NULL);
+ ~Source();
+
+ // Ownership of the CachedData or its buffers is *not* transferred to
the
+ // caller. The CachedData object is alive as long as the Source object
is
+ // alive.
+ const CachedData* GetCachedData() const;
+
+ private:
+ friend class ScriptCompiler;
+ // Prevent copying. Not implemented.
+ Source(const Source&);
Local<String> source_string;
@@ -1125,8 +1152,10 @@
Handle<Integer> resource_column_offset;
Handle<Boolean> resource_is_shared_cross_origin;
- // Cached data from previous compilation (if any).
- CachedData cached_data;
+ // Cached data from previous compilation (if any), or generated during
+ // compilation (if the generate_cached_data flag is passed to
+ // ScriptCompiler).
+ CachedData* cached_data;
};
enum CompileOptions {
@@ -1142,7 +1171,7 @@
* bound to a context).
*/
static Local<UnboundScript> CompileUnbound(
- Isolate* isolate, const Source& source,
+ Isolate* isolate, Source* source,
CompileOptions options = kNoCompileOptions);
/**
@@ -1157,7 +1186,7 @@
* context.
*/
static Local<Script> Compile(
- Isolate* isolate, const Source& source,
+ Isolate* isolate, Source* source,
CompileOptions options = kNoCompileOptions);
};
=======================================
--- /branches/bleeding_edge/src/api.cc Wed Mar 19 13:06:53 2014 UTC
+++ /branches/bleeding_edge/src/api.cc Wed Mar 19 13:24:13 2014 UTC
@@ -1617,8 +1617,20 @@
// Internally, UnboundScript is a SharedFunctionInfo, and Script is a
// JSFunction.
+ScriptCompiler::CachedData::CachedData(const uint8_t* data_, int length_,
+ BufferPolicy buffer_policy_)
+ : data(data_), length(length_), buffer_policy(buffer_policy_) {}
+
+
+ScriptCompiler::CachedData::~CachedData() {
+ if (buffer_policy == BufferOwned) {
+ delete[] data;
+ }
+}
+
+
ScriptCompiler::Source::Source(Local<String> string, const ScriptOrigin&
origin,
- const CachedData& data)
+ CachedData* data)
: source_string(string),
resource_name(origin.ResourceName()),
resource_line_offset(origin.ResourceLineOffset()),
@@ -1628,8 +1640,19 @@
ScriptCompiler::Source::Source(Local<String> string,
- const CachedData& data)
+ CachedData* data)
: source_string(string), cached_data(data) {}
+
+
+ScriptCompiler::Source::~Source() {
+ delete cached_data;
+}
+
+
+const ScriptCompiler::CachedData* ScriptCompiler::Source::GetCachedData()
+ const {
+ return cached_data;
+}
Local<Script> UnboundScript::BindToCurrentContext() {
@@ -1730,12 +1753,41 @@
Local<UnboundScript> ScriptCompiler::CompileUnbound(
Isolate* v8_isolate,
- const Source& source,
+ Source* source,
CompileOptions options) {
- // FIXME(marja): This function cannot yet create cached data (if options
|
- // produce_data_to_cache is true), but the PreCompile function is still
there
- // for doing it.
- i::Handle<i::String> str = Utils::OpenHandle(*(source.source_string));
+ i::ScriptDataImpl* script_data_impl = NULL;
+ i::CachedDataMode cached_data_mode = i::NO_CACHED_DATA;
+ if (options & kProduceDataToCache) {
+ cached_data_mode = i::PRODUCE_CACHED_DATA;
+ ASSERT(source->cached_data == NULL);
+ if (source->cached_data) {
+ // Asked to produce cached data even though there is some already ->
not
+ // good. In release mode, try to do the right thing: Just regenerate
the
+ // data.
+ delete source->cached_data;
+ source->cached_data = NULL;
+ }
+ } else if (source->cached_data) {
+ // FIXME(marja): Make compiler use CachedData directly. Aligning needs
to be
+ // taken care of.
+ script_data_impl = static_cast<i::ScriptDataImpl*>(ScriptData::New(
+ reinterpret_cast<const char*>(source->cached_data->data),
+ source->cached_data->length));
+ // We assert that the pre-data is sane, even though we can actually
+ // handle it if it turns out not to be in release mode.
+ ASSERT(script_data_impl->SanityCheck());
+ if (script_data_impl->SanityCheck()) {
+ cached_data_mode = i::CONSUME_CACHED_DATA;
+ } else {
+ // If the pre-data isn't sane we simply ignore it.
+ delete script_data_impl;
+ script_data_impl = NULL;
+ delete source->cached_data;
+ source->cached_data = NULL;
+ }
+ }
+
+ i::Handle<i::String> str = Utils::OpenHandle(*(source->source_string));
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ON_BAILOUT(isolate, "v8::ScriptCompiler::CompileUnbound()",
return Local<UnboundScript>());
@@ -1747,37 +1799,22 @@
int line_offset = 0;
int column_offset = 0;
bool is_shared_cross_origin = false;
- if (!source.resource_name.IsEmpty()) {
- name_obj = Utils::OpenHandle(*source.resource_name);
+ if (!source->resource_name.IsEmpty()) {
+ name_obj = Utils::OpenHandle(*(source->resource_name));
}
- if (!source.resource_line_offset.IsEmpty()) {
- line_offset = static_cast<int>(source.resource_line_offset->Value());
+ if (!source->resource_line_offset.IsEmpty()) {
+ line_offset =
static_cast<int>(source->resource_line_offset->Value());
}
- if (!source.resource_column_offset.IsEmpty()) {
+ if (!source->resource_column_offset.IsEmpty()) {
column_offset =
- static_cast<int>(source.resource_column_offset->Value());
+ static_cast<int>(source->resource_column_offset->Value());
}
- if (!source.resource_is_shared_cross_origin.IsEmpty()) {
+ if (!source->resource_is_shared_cross_origin.IsEmpty()) {
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
is_shared_cross_origin =
- source.resource_is_shared_cross_origin == v8::True(v8_isolate);
+ source->resource_is_shared_cross_origin == v8::True(v8_isolate);
}
EXCEPTION_PREAMBLE(isolate);
- i::ScriptDataImpl* pre_data_impl = NULL;
- if (source.cached_data.data) {
- // FIXME(marja): Make compiler use CachedData directly.
- pre_data_impl = static_cast<i::ScriptDataImpl*>(ScriptData::New(
- reinterpret_cast<const char*>(source.cached_data.data),
- source.cached_data.length));
- }
- // We assert that the pre-data is sane, even though we can actually
- // handle it if it turns out not to be in release mode.
- ASSERT(pre_data_impl == NULL || pre_data_impl->SanityCheck());
- // If the pre-data isn't sane we simply ignore it
- if (pre_data_impl != NULL && !pre_data_impl->SanityCheck()) {
- delete pre_data_impl;
- pre_data_impl = NULL;
- }
i::Handle<i::SharedFunctionInfo> result =
i::Compiler::CompileScript(str,
name_obj,
@@ -1786,12 +1823,21 @@
is_shared_cross_origin,
isolate->global_context(),
NULL,
- pre_data_impl,
+ &script_data_impl,
+ cached_data_mode,
i::NOT_NATIVES_CODE);
has_pending_exception = result.is_null();
EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
raw_result = *result;
- delete pre_data_impl;
+ if ((options & kProduceDataToCache) && script_data_impl != NULL) {
+ // script_data_impl now contains the data that was generated. source
will
+ // take the ownership.
+ source->cached_data = new CachedData(
+ reinterpret_cast<const uint8_t*>(script_data_impl->Data()),
+ script_data_impl->Length(), CachedData::BufferOwned);
+ script_data_impl->owns_store_ = false;
+ }
+ delete script_data_impl;
}
i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
return ToApiHandle<UnboundScript>(result);
@@ -1800,7 +1846,7 @@
Local<Script> ScriptCompiler::Compile(
Isolate* v8_isolate,
- const Source& source,
+ Source* source,
CompileOptions options) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ON_BAILOUT(isolate, "v8::ScriptCompiler::Compile()",
@@ -1818,20 +1864,22 @@
v8::ScriptOrigin* origin,
ScriptData* script_data) {
i::Handle<i::String> str = Utils::OpenHandle(*source);
- ScriptCompiler::CachedData cached_data;
+ ScriptCompiler::CachedData* cached_data = NULL;
if (script_data) {
- cached_data = ScriptCompiler::CachedData(
+ cached_data = new ScriptCompiler::CachedData(
reinterpret_cast<const uint8_t*>(script_data->Data()),
script_data->Length());
}
if (origin) {
+ ScriptCompiler::Source script_source(source, *origin, cached_data);
return ScriptCompiler::Compile(
reinterpret_cast<v8::Isolate*>(str->GetIsolate()),
- ScriptCompiler::Source(source, *origin, cached_data));
+ &script_source);
}
+ ScriptCompiler::Source script_source(source, cached_data);
return ScriptCompiler::Compile(
reinterpret_cast<v8::Isolate*>(str->GetIsolate()),
- ScriptCompiler::Source(source, cached_data));
+ &script_source);
}
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Tue Mar 18 09:57:14 2014 UTC
+++ /branches/bleeding_edge/src/bootstrapper.cc Wed Mar 19 13:24:13 2014 UTC
@@ -1524,6 +1524,7 @@
top_context,
extension,
NULL,
+ NO_CACHED_DATA,
use_runtime_context ? NATIVES_CODE : NOT_NATIVES_CODE);
if (function_info.is_null()) return false;
if (cache != NULL) cache->Add(name, function_info);
=======================================
--- /branches/bleeding_edge/src/compiler.cc Mon Mar 17 08:31:21 2014 UTC
+++ /branches/bleeding_edge/src/compiler.cc Wed Mar 19 13:24:13 2014 UTC
@@ -115,7 +115,8 @@
scope_ = NULL;
global_scope_ = NULL;
extension_ = NULL;
- pre_parse_data_ = NULL;
+ cached_data_ = NULL;
+ cached_data_mode_ = NO_CACHED_DATA;
zone_ = zone;
deferred_handles_ = NULL;
code_stub_ = NULL;
@@ -782,15 +783,18 @@
ASSERT(info->is_eval() || info->is_global());
bool parse_allow_lazy =
- (info->pre_parse_data() != NULL ||
+ (info->cached_data_mode() == CONSUME_CACHED_DATA ||
String::cast(script->source())->length() >
FLAG_min_preparse_length) &&
!DebuggerWantsEagerCompilation(info);
- if (!parse_allow_lazy && info->pre_parse_data() != NULL) {
- // We are going to parse eagerly, but we have preparse data produced
by lazy
- // preparsing. We cannot use it, since it won't contain all the
symbols we
- // need for eager parsing.
- info->SetPreParseData(NULL);
+ if (!parse_allow_lazy && info->cached_data_mode() != NO_CACHED_DATA) {
+ // We are going to parse eagerly, but we either 1) have cached data
produced
+ // by lazy parsing or 2) are asked to generate cached data. We cannot
use
+ // the existing data, since it won't contain all the symbols we need
for
+ // eager parsing. In addition, it doesn't make sense to produce the
data
+ // when parsing eagerly. That data would contain all symbols, but no
+ // functions, so it cannot be used to aid lazy parsing later.
+ info->SetCachedData(NULL, NO_CACHED_DATA);
}
Handle<SharedFunctionInfo> result;
@@ -910,15 +914,25 @@
}
-Handle<SharedFunctionInfo> Compiler::CompileScript(Handle<String> source,
- Handle<Object>
script_name,
- int line_offset,
- int column_offset,
- bool
is_shared_cross_origin,
- Handle<Context> context,
- v8::Extension*
extension,
- ScriptDataImpl*
pre_data,
- NativesFlag natives) {
+Handle<SharedFunctionInfo> Compiler::CompileScript(
+ Handle<String> source,
+ Handle<Object> script_name,
+ int line_offset,
+ int column_offset,
+ bool is_shared_cross_origin,
+ Handle<Context> context,
+ v8::Extension* extension,
+ ScriptDataImpl** cached_data,
+ CachedDataMode cached_data_mode,
+ NativesFlag natives) {
+ if (cached_data_mode == NO_CACHED_DATA) {
+ cached_data = NULL;
+ } else if (cached_data_mode == PRODUCE_CACHED_DATA) {
+ ASSERT(cached_data && !*cached_data);
+ } else {
+ ASSERT(cached_data_mode == CONSUME_CACHED_DATA);
+ ASSERT(cached_data && *cached_data);
+ }
Isolate* isolate = source->GetIsolate();
int source_length = source->length();
isolate->counters()->total_load_size()->Increment(source_length);
@@ -963,7 +977,7 @@
CompilationInfoWithZone info(script);
info.MarkAsGlobal();
info.SetExtension(extension);
- info.SetPreParseData(pre_data);
+ info.SetCachedData(cached_data, cached_data_mode);
info.SetContext(context);
if (FLAG_use_strict) info.SetStrictMode(STRICT);
result = CompileToplevel(&info);
=======================================
--- /branches/bleeding_edge/src/compiler.h Mon Mar 17 08:31:21 2014 UTC
+++ /branches/bleeding_edge/src/compiler.h Wed Mar 19 13:24:13 2014 UTC
@@ -45,6 +45,12 @@
ONLY_SINGLE_FUNCTION_LITERAL // Only a single FunctionLiteral
expression.
};
+enum CachedDataMode {
+ NO_CACHED_DATA,
+ CONSUME_CACHED_DATA,
+ PRODUCE_CACHED_DATA
+};
+
struct OffsetRange {
OffsetRange(int from, int to) : from(from), to(to) {}
int from;
@@ -77,7 +83,10 @@
Handle<Script> script() const { return script_; }
HydrogenCodeStub* code_stub() const {return code_stub_; }
v8::Extension* extension() const { return extension_; }
- ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; }
+ ScriptDataImpl** cached_data() const { return cached_data_; }
+ CachedDataMode cached_data_mode() const {
+ return cached_data_mode_;
+ }
Handle<Context> context() const { return context_; }
BailoutId osr_ast_id() const { return osr_ast_id_; }
Handle<Code> unoptimized_code() const { return unoptimized_code_; }
@@ -180,9 +189,15 @@
ASSERT(!is_lazy());
extension_ = extension;
}
- void SetPreParseData(ScriptDataImpl* pre_parse_data) {
- ASSERT(!is_lazy());
- pre_parse_data_ = pre_parse_data;
+ void SetCachedData(ScriptDataImpl** cached_data,
+ CachedDataMode cached_data_mode) {
+ cached_data_mode_ = cached_data_mode;
+ if (cached_data_mode == NO_CACHED_DATA) {
+ cached_data_ = NULL;
+ } else {
+ ASSERT(!is_lazy());
+ cached_data_ = cached_data;
+ }
}
void SetContext(Handle<Context> context) {
context_ = context;
@@ -397,7 +412,8 @@
// Fields possibly needed for eager compilation, NULL by default.
v8::Extension* extension_;
- ScriptDataImpl* pre_parse_data_;
+ ScriptDataImpl** cached_data_;
+ CachedDataMode cached_data_mode_;
// The context of the caller for eval code, and the global context for a
// global script. Will be a null handle otherwise.
@@ -617,15 +633,17 @@
int scope_position);
// Compile a String source within a context.
- static Handle<SharedFunctionInfo> CompileScript(Handle<String> source,
- Handle<Object>
script_name,
- int line_offset,
- int column_offset,
- bool
is_shared_cross_origin,
- Handle<Context> context,
- v8::Extension* extension,
- ScriptDataImpl* pre_data,
- NativesFlag
is_natives_code);
+ static Handle<SharedFunctionInfo> CompileScript(
+ Handle<String> source,
+ Handle<Object> script_name,
+ int line_offset,
+ int column_offset,
+ bool is_shared_cross_origin,
+ Handle<Context> context,
+ v8::Extension* extension,
+ ScriptDataImpl** cached_data,
+ CachedDataMode cached_data_mode,
+ NativesFlag is_natives_code);
// Create a shared function info object (the code may be lazily
compiled).
static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral*
node,
=======================================
--- /branches/bleeding_edge/src/d8.cc Fri Mar 14 10:20:33 2014 UTC
+++ /branches/bleeding_edge/src/d8.cc Wed Mar 19 13:24:13 2014 UTC
@@ -206,8 +206,9 @@
try_catch.SetVerbose(true);
}
ScriptOrigin origin(name);
- Handle<UnboundScript> script = ScriptCompiler::CompileUnbound(
- isolate, ScriptCompiler::Source(source, origin));
+ ScriptCompiler::Source script_source(source, origin);
+ Handle<UnboundScript> script =
+ ScriptCompiler::CompileUnbound(isolate, &script_source);
if (script.IsEmpty()) {
// Print errors that happened during compilation.
if (report_exceptions && !FLAG_debugger)
@@ -407,8 +408,9 @@
Throw(args.GetIsolate(), "Invalid argument");
return;
}
+ ScriptCompiler::Source script_source(args[1]->ToString());
Handle<UnboundScript> script = ScriptCompiler::CompileUnbound(
- isolate, ScriptCompiler::Source(args[1]->ToString()));
+ isolate, &script_source);
if (script.IsEmpty()) return;
Local<Context> realm = Local<Context>::New(isolate,
data->realms_[index]);
realm->Enter();
=======================================
--- /branches/bleeding_edge/src/debug.cc Wed Mar 12 15:40:41 2014 UTC
+++ /branches/bleeding_edge/src/debug.cc Wed Mar 19 13:24:13 2014 UTC
@@ -762,7 +762,7 @@
script_name, 0, 0,
false,
context,
- NULL, NULL,
+ NULL, NULL, NO_CACHED_DATA,
NATIVES_CODE);
// Silently ignore stack overflows during compilation.
=======================================
--- /branches/bleeding_edge/src/parser.cc Mon Mar 17 13:54:42 2014 UTC
+++ /branches/bleeding_edge/src/parser.cc Wed Mar 19 13:24:13 2014 UTC
@@ -203,19 +203,6 @@
new(zone()) RegExpQuantifier(min, max, quantifier_type, atom),
zone());
LAST(ADD_TERM);
}
-
-
-Handle<String> Parser::LookupSymbol(int symbol_id) {
- // If there is no preparser symbol data, a negative number will be
passed. In
- // that case, we'll just read the literal from Scanner. This also guards
- // against corrupt preparse data where the symbol id is larger than the
symbol
- // count.
- if (symbol_id < 0 ||
- (pre_parse_data_ && symbol_id >= pre_parse_data_->symbol_count())) {
- return scanner()->AllocateInternalizedString(isolate_);
- }
- return LookupCachedSymbol(symbol_id);
-}
Handle<String> Parser::LookupCachedSymbol(int symbol_id) {
@@ -600,11 +587,19 @@
Handle<String> ParserTraits::GetSymbol(Scanner* scanner) {
- int symbol_id = -1;
- if (parser_->pre_parse_data() != NULL) {
- symbol_id = parser_->pre_parse_data()->GetSymbolIdentifier();
+ if (parser_->cached_data_mode() == CONSUME_CACHED_DATA) {
+ int symbol_id = (*parser_->cached_data())->GetSymbolIdentifier();
+ // If there is no symbol data, -1 will be returned.
+ if (symbol_id >= 0 &&
+ symbol_id < (*parser_->cached_data())->symbol_count()) {
+ return parser_->LookupCachedSymbol(symbol_id);
+ }
+ } else if (parser_->cached_data_mode() == PRODUCE_CACHED_DATA) {
+ if (parser_->log_->ShouldLogSymbols()) {
+ parser_->scanner()->LogSymbol(parser_->log_, parser_->position());
+ }
}
- return parser_->LookupSymbol(symbol_id);
+ return parser_->scanner()->AllocateInternalizedString(parser_->isolate_);
}
@@ -702,6 +697,7 @@
: ParserBase<ParserTraits>(&scanner_,
info->isolate()->stack_guard()->real_climit(),
info->extension(),
+ NULL,
info->zone(),
this),
isolate_(info->isolate()),
@@ -711,7 +707,8 @@
reusable_preparser_(NULL),
original_scope_(NULL),
target_stack_(NULL),
- pre_parse_data_(NULL),
+ cached_data_(NULL),
+ cached_data_mode_(NO_CACHED_DATA),
info_(info) {
ASSERT(!script_.is_null());
isolate_->set_ast_node_id(0);
@@ -738,6 +735,13 @@
fni_ = new(zone()) FuncNameInferrer(isolate(), zone());
// Initialize parser state.
+ CompleteParserRecorder recorder;
+ if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
+ log_ = &recorder;
+ } else if (cached_data_mode_ == CONSUME_CACHED_DATA) {
+ (*cached_data_)->Initialize();
+ }
+
source->TryFlatten();
FunctionLiteral* result;
if (source->IsExternalTwoByteString()) {
@@ -767,6 +771,11 @@
}
PrintF(" - took %0.3f ms]\n", ms);
}
+ if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
+ Vector<unsigned> store = recorder.ExtractData();
+ *cached_data_ = new ScriptDataImpl(store);
+ log_ = NULL;
+ }
return result;
}
@@ -775,7 +784,6 @@
Handle<String> source) {
ASSERT(scope_ == NULL);
ASSERT(target_stack_ == NULL);
- if (pre_parse_data_ != NULL) pre_parse_data_->Initialize();
Handle<String> no_name = isolate()->factory()->empty_string();
@@ -3580,11 +3588,11 @@
if (is_lazily_parsed) {
int function_block_pos = position();
FunctionEntry entry;
- if (pre_parse_data_ != NULL) {
- // If we have pre_parse_data_, we use it to skip parsing the
function
- // body. The preparser data contains the information we need to
- // construct the lazy function.
- entry = pre_parse_data()->GetFunctionEntry(function_block_pos);
+ if (cached_data_mode_ == CONSUME_CACHED_DATA) {
+ // If we have cached data, we use it to skip parsing the function
body.
+ // The data contains the information we need to construct the lazy
+ // function.
+ entry = (*cached_data())->GetFunctionEntry(function_block_pos);
if (entry.is_valid()) {
if (entry.end_pos() <= function_block_pos) {
// End position greater than end of stream is safe, and hard
@@ -3605,21 +3613,17 @@
// an entry for the function. As a safety net, fall back to eager
// parsing. It is unclear whether PreParser's laziness analysis
can
// produce different results than the Parser's laziness analysis
(see
- // https://codereview.chromium.org/7565003 ). This safety net is
- // guarding against the case where Parser thinks a function
should be
- // lazily parsed, but PreParser thinks it should be eagerly
parsed --
- // in that case we fall back to eager parsing in Parser, too.
Note
- // that the opposite case is worse: if PreParser thinks a
function
- // should be lazily parsed, but Parser thinks it should be
eagerly
- // parsed, it will never advance the preparse data beyond that
- // function and all further laziness will fail (all functions
will be
- // parsed eagerly).
+ // https://codereview.chromium.org/7565003 ). In this case, we
must
+ // discard all the preparse data, since the symbol data will be
wrong.
is_lazily_parsed = false;
+ cached_data_mode_ = NO_CACHED_DATA;
}
} else {
- // With no preparser data, we partially parse the function, without
+ // With no cached data, we partially parse the function, without
// building an AST. This gathers the data needed to build a lazy
// function.
+ // FIXME(marja): Now the PreParser doesn't need to log functions /
+ // symbols; only errors -> clean that up.
SingletonLogger logger;
PreParser::PreParseResult result =
LazyParseFunctionLiteral(&logger);
if (result == PreParser::kPreParseStackOverflow) {
@@ -3648,6 +3652,15 @@
materialized_literal_count = logger.literals();
expected_property_count = logger.properties();
scope_->SetStrictMode(logger.strict_mode());
+ if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
+ ASSERT(log_);
+ // Position right after terminal '}'.
+ int body_end = scanner()->location().end_pos;
+ log_->LogFunction(function_block_pos, body_end,
+ materialized_literal_count,
+ expected_property_count,
+ scope_->strict_mode());
+ }
}
}
@@ -4922,12 +4935,13 @@
result = ParseProgram();
}
} else {
- ScriptDataImpl* pre_parse_data = info()->pre_parse_data();
- set_pre_parse_data(pre_parse_data);
- if (pre_parse_data != NULL && pre_parse_data->has_error()) {
- Scanner::Location loc = pre_parse_data->MessageLocation();
- const char* message = pre_parse_data->BuildMessage();
- Vector<const char*> args = pre_parse_data->BuildArgs();
+ SetCachedData(info()->cached_data(), info()->cached_data_mode());
+ if (info()->cached_data_mode() == CONSUME_CACHED_DATA &&
+ (*info()->cached_data())->has_error()) {
+ ScriptDataImpl* cached_data = *(info()->cached_data());
+ Scanner::Location loc = cached_data->MessageLocation();
+ const char* message = cached_data->BuildMessage();
+ Vector<const char*> args = cached_data->BuildArgs();
ParserTraits::ReportMessageAt(loc, message, args);
DeleteArray(message);
for (int i = 0; i < args.length(); i++) {
=======================================
--- /branches/bleeding_edge/src/parser.h Mon Mar 17 13:54:42 2014 UTC
+++ /branches/bleeding_edge/src/parser.h Wed Mar 19 13:24:13 2014 UTC
@@ -30,12 +30,15 @@
#include "allocation.h"
#include "ast.h"
+#include "compiler.h" // For CachedDataMode
#include "preparse-data-format.h"
#include "preparse-data.h"
#include "scopes.h"
#include "preparser.h"
namespace v8 {
+class ScriptCompiler;
+
namespace internal {
class CompilationInfo;
@@ -117,6 +120,7 @@
unsigned version() { return
store_[PreparseDataConstants::kVersionOffset]; }
private:
+ friend class v8::ScriptCompiler;
Vector<unsigned> store_;
unsigned char* symbol_data_;
unsigned char* symbol_data_end_;
@@ -649,14 +653,22 @@
// Report syntax error
void ReportInvalidPreparseData(Handle<String> name, bool* ok);
- void set_pre_parse_data(ScriptDataImpl *data) {
- pre_parse_data_ = data;
- symbol_cache_.Initialize(data ? data->symbol_count() : 0, zone());
+ void SetCachedData(ScriptDataImpl** data,
+ CachedDataMode cached_data_mode) {
+ cached_data_mode_ = cached_data_mode;
+ if (cached_data_mode == NO_CACHED_DATA) {
+ cached_data_ = NULL;
+ } else {
+ ASSERT(data != NULL);
+ cached_data_ = data;
+ symbol_cache_.Initialize(*data ? (*data)->symbol_count() : 0,
zone());
+ }
}
bool inside_with() const { return scope_->inside_with(); }
Mode mode() const { return mode_; }
- ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; }
+ ScriptDataImpl** cached_data() const { return cached_data_; }
+ CachedDataMode cached_data_mode() const { return cached_data_mode_; }
Scope* DeclarationScope(VariableMode mode) {
return IsLexicalVariableMode(mode)
? scope_ : scope_->DeclarationScope();
@@ -770,8 +782,6 @@
Scope* NewScope(Scope* parent, ScopeType type);
- Handle<String> LookupSymbol(int symbol_id);
-
Handle<String> LookupCachedSymbol(int symbol_id);
// Generate AST node that throw a ReferenceError with the given type.
@@ -804,7 +814,8 @@
PreParser* reusable_preparser_;
Scope* original_scope_; // for ES5 function declarations in sloppy eval
Target* target_stack_; // for break, continue statements
- ScriptDataImpl* pre_parse_data_;
+ ScriptDataImpl** cached_data_;
+ CachedDataMode cached_data_mode_;
Mode mode_;
=======================================
--- /branches/bleeding_edge/src/preparser.h Tue Mar 18 17:05:38 2014 UTC
+++ /branches/bleeding_edge/src/preparser.h Wed Mar 19 13:24:13 2014 UTC
@@ -87,6 +87,7 @@
ParserBase(Scanner* scanner, uintptr_t stack_limit,
v8::Extension* extension,
+ ParserRecorder* log,
typename Traits::Type::Zone* zone,
typename Traits::Type::Parser this_object)
: Traits(this_object),
@@ -95,6 +96,7 @@
function_state_(NULL),
extension_(extension),
fni_(NULL),
+ log_(log),
scanner_(scanner),
stack_limit_(stack_limit),
stack_overflow_(false),
@@ -457,6 +459,7 @@
FunctionState* function_state_; // Function state stack.
v8::Extension* extension_;
FuncNameInferrer* fni_;
+ ParserRecorder* log_;
private:
Scanner* scanner_;
@@ -948,11 +951,9 @@
kPreParseSuccess
};
- PreParser(Scanner* scanner,
- ParserRecorder* log,
- uintptr_t stack_limit)
- : ParserBase<PreParserTraits>(scanner, stack_limit, NULL, NULL,
this),
- log_(log) {}
+ PreParser(Scanner* scanner, ParserRecorder* log, uintptr_t stack_limit)
+ : ParserBase<PreParserTraits>(scanner, stack_limit, NULL, log, NULL,
+ this) {}
// Pre-parse the program from the character stream; returns true on
// success (even if parsing failed, the pre-parse data successfully
@@ -1111,11 +1112,8 @@
Expression GetStringSymbol();
bool CheckInOrOf(bool accept_OF);
-
- ParserRecorder* log_;
};
-
template<class Traits>
ParserBase<Traits>::FunctionState::FunctionState(
FunctionState** function_state_stack,
=======================================
--- /branches/bleeding_edge/test/cctest/cctest.h Fri Mar 14 10:20:33 2014
UTC
+++ /branches/bleeding_edge/test/cctest/cctest.h Wed Mar 19 13:24:13 2014
UTC
@@ -316,8 +316,9 @@
static inline v8::Local<v8::Script> CompileWithOrigin(
v8::Local<v8::String> source, v8::Local<v8::String> origin_url) {
v8::ScriptOrigin origin(origin_url);
+ v8::ScriptCompiler::Source script_source(source, origin);
return v8::ScriptCompiler::Compile(
- v8::Isolate::GetCurrent(), v8::ScriptCompiler::Source(source,
origin));
+ v8::Isolate::GetCurrent(), &script_source);
}
@@ -350,11 +351,11 @@
v8::String::NewFromUtf8(isolate, source);
v8::ScriptData* preparse = v8::ScriptData::PreCompile(source_string);
v8::ScriptCompiler::Source script_source(
- source_string, v8::ScriptCompiler::CachedData(
+ source_string, new v8::ScriptCompiler::CachedData(
reinterpret_cast<const
uint8_t*>(preparse->Data()),
preparse->Length()));
- v8::Local<v8::Script> script = v8::ScriptCompiler::Compile(
- isolate, v8::ScriptCompiler::Source(script_source));
+ v8::Local<v8::Script> script =
+ v8::ScriptCompiler::Compile(isolate, &script_source);
v8::Local<v8::Value> result = script->Run();
delete preparse;
return result;
@@ -370,18 +371,17 @@
v8::ScriptOrigin origin(v8_str(origin_url),
v8::Integer::New(isolate, line_number),
v8::Integer::New(isolate, column_number));
- return v8::ScriptCompiler::Compile(
- isolate, v8::ScriptCompiler::Source(v8_str(source), origin))
- ->Run();
+ v8::ScriptCompiler::Source script_source(v8_str(source), origin);
+ return v8::ScriptCompiler::Compile(isolate, &script_source)->Run();
}
static inline v8::Local<v8::Value> CompileRunWithOrigin(
v8::Local<v8::String> source, const char* origin_url) {
- v8::ScriptOrigin origin(v8_str(origin_url));
- return v8::ScriptCompiler::Compile(
- v8::Isolate::GetCurrent(),
- v8::ScriptCompiler::Source(source, origin))->Run();
+ v8::ScriptCompiler::Source script_source(
+ source, v8::ScriptOrigin(v8_str(origin_url)));
+ return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(),
&script_source)
+ ->Run();
}
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Wed Mar 19 13:06:53
2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-api.cc Wed Mar 19 13:24:13
2014 UTC
@@ -14956,10 +14956,10 @@
v8::ScriptCompiler::Source script_source(
String::NewFromUtf8(isolate, script),
- v8::ScriptCompiler::CachedData(
+ new v8::ScriptCompiler::CachedData(
reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
Local<v8::UnboundScript> compiled_script =
- v8::ScriptCompiler::CompileUnbound(isolate, script_source);
+ v8::ScriptCompiler::CompileUnbound(isolate, &script_source);
CHECK(try_catch.HasCaught());
String::Utf8Value exception_value(try_catch.Message()->Get());
@@ -14979,10 +14979,10 @@
200;
v8::ScriptCompiler::Source script_source2(
String::NewFromUtf8(isolate, script),
- v8::ScriptCompiler::CachedData(
+ new v8::ScriptCompiler::CachedData(
reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
compiled_script =
- v8::ScriptCompiler::CompileUnbound(isolate, script_source2);
+ v8::ScriptCompiler::CompileUnbound(isolate, &script_source2);
CHECK(!try_catch.HasCaught());
delete sd;
@@ -17091,12 +17091,11 @@
LocalContext c1;
v8::HandleScope scope(c1->GetIsolate());
const char *source = "foo";
- v8::Handle<v8::Script> dep =
- v8_compile(source);
+ v8::Handle<v8::Script> dep = v8_compile(source);
+ v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
+ c1->GetIsolate(), source));
v8::Handle<v8::UnboundScript> indep =
- v8::ScriptCompiler::CompileUnbound(
- c1->GetIsolate(),
v8::ScriptCompiler::Source(v8::String::NewFromUtf8(
- c1->GetIsolate(), source)));
+ v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
v8::Integer::New(c1->GetIsolate(), 100));
CHECK_EQ(dep->Run()->Int32Value(), 100);
@@ -17118,9 +17117,8 @@
v8::String::NewFromUtf8(context->GetIsolate(), source);
v8::Handle<v8::String> origin =
v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
- v8::ScriptCompiler::CompileUnbound(
- context->GetIsolate(),
- v8::ScriptCompiler::Source(src, v8::ScriptOrigin(origin)))
+ v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
+ v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
->BindToCurrentContext()
->Run();
CHECK(try_catch.HasCaught());
@@ -17228,10 +17226,10 @@
"var x;eval('new foo();');";
v8::Handle<v8::String> overview_src =
v8::String::NewFromUtf8(isolate, overview_source);
+ v8::ScriptCompiler::Source script_source(overview_src,
+ v8::ScriptOrigin(origin));
v8::Handle<Value> overview_result(
- v8::ScriptCompiler::CompileUnbound(
- isolate,
- v8::ScriptCompiler::Source(overview_src,
v8::ScriptOrigin(origin)))
+ v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
->BindToCurrentContext()
->Run());
CHECK(!overview_result.IsEmpty());
@@ -17252,9 +17250,9 @@
v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
+ v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
v8::Handle<v8::UnboundScript> detailed_script(
- v8::ScriptCompiler::CompileUnbound(
- isolate, v8::ScriptCompiler::Source(detailed_src,
detailed_origin)));
+ v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
v8::Handle<Value> detailed_result(
detailed_script->BindToCurrentContext()->Run());
CHECK(!detailed_result.IsEmpty());
=======================================
--- /branches/bleeding_edge/test/cctest/test-compiler.cc Mon Mar 17
08:31:21 2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-compiler.cc Wed Mar 19
13:24:13 2014 UTC
@@ -66,7 +66,7 @@
0,
false,
Handle<Context>(isolate->native_context()),
- NULL, NULL,
+ NULL, NULL, NO_CACHED_DATA,
NOT_NATIVES_CODE);
return isolate->factory()->NewFunctionFromSharedFunctionInfo(
shared_function, isolate->native_context());
=======================================
--- /branches/bleeding_edge/test/cctest/test-debug.cc Fri Mar 14 10:20:33
2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-debug.cc Wed Mar 19 13:24:13
2014 UTC
@@ -7007,16 +7007,16 @@
v8::HandleScope scope(isolate);
v8::Handle<v8::Value> obj =
v8::Debug::GetMirror(v8::String::NewFromUtf8(isolate, "hodja"));
- v8::Handle<v8::Function> run_test =
- v8::Handle<v8::Function>::Cast(
- v8::ScriptCompiler::CompileUnbound(
- isolate,
- v8::ScriptCompiler::Source(v8_str(
- "function runTest(mirror) {"
- " return mirror.isString() && (mirror.length() == 5);"
- "}"
- ""
- "runTest;")))->BindToCurrentContext()->Run());
+ v8::ScriptCompiler::Source source(v8_str(
+ "function runTest(mirror) {"
+ " return mirror.isString() && (mirror.length() == 5);"
+ "}"
+ ""
+ "runTest;"));
+ v8::Handle<v8::Function> run_test = v8::Handle<v8::Function>::Cast(
+ v8::ScriptCompiler::CompileUnbound(isolate, &source)
+ ->BindToCurrentContext()
+ ->Run());
v8::Handle<v8::Value> result = run_test->Call(env->Global(), 1, &obj);
CHECK(result->IsTrue());
}
=======================================
--- /branches/bleeding_edge/test/cctest/test-parsing.cc Mon Mar 17 16:04:47
2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-parsing.cc Wed Mar 19 13:24:13
2014 UTC
@@ -215,11 +215,11 @@
ScriptResource* resource = new ScriptResource(source, source_length);
v8::ScriptCompiler::Source script_source(
v8::String::NewExternal(isolate, resource),
- v8::ScriptCompiler::CachedData(
+ new v8::ScriptCompiler::CachedData(
reinterpret_cast<const uint8_t*>(preparse->Data()),
preparse->Length()));
v8::ScriptCompiler::Compile(isolate,
- v8::ScriptCompiler::Source(script_source));
+ &script_source);
}
{
@@ -228,10 +228,10 @@
ScriptResource* resource = new ScriptResource(source, source_length);
v8::ScriptCompiler::Source script_source(
v8::String::NewExternal(isolate, resource),
- v8::ScriptCompiler::CachedData(
+ new v8::ScriptCompiler::CachedData(
reinterpret_cast<const uint8_t*>(preparse->Data()),
preparse->Length()));
- v8::ScriptCompiler::CompileUnbound(isolate, script_source);
+ v8::ScriptCompiler::CompileUnbound(isolate, &script_source);
}
delete preparse;
i::FLAG_lazy = lazy_flag;
@@ -263,6 +263,10 @@
TEST(PreparseFunctionDataIsUsed) {
// This tests that we actually do use the function data generated by the
// preparser.
+
+ // Make preparsing work for short scripts.
+ i::FLAG_min_preparse_length = 0;
+
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handles(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
@@ -271,28 +275,31 @@
CcTest::i_isolate()->stack_guard()->SetStackLimit(
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
- const char* good_source =
+ const char* good_code =
"function this_is_lazy() { var a; } function foo() { return 25; }
foo();";
// Insert a syntax error inside the lazy function.
- const char* bad_source =
+ const char* bad_code =
"function this_is_lazy() { if ( } function foo() { return 25; }
foo();";
- v8::ScriptData* preparse =
v8::ScriptData::PreCompile(v8_str(good_source));
- CHECK(!preparse->HasError());
+ v8::ScriptCompiler::Source good_source(v8_str(good_code));
+ v8::ScriptCompiler::Compile(isolate, &good_source,
+ v8::ScriptCompiler::kProduceDataToCache);
+
+ const v8::ScriptCompiler::CachedData* cached_data =
+ good_source.GetCachedData();
+ CHECK(cached_data->data != NULL);
+ 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 source(
- v8_str(bad_source),
- v8::ScriptCompiler::CachedData(
- reinterpret_cast<const uint8_t*>(preparse->Data()),
- preparse->Length()));
+ v8::ScriptCompiler::Source bad_source(
+ v8_str(bad_code), new v8::ScriptCompiler::CachedData(
+ cached_data->data, cached_data->length));
v8::Local<v8::Value> result =
- v8::ScriptCompiler::Compile(CcTest::isolate(), source)->Run();
+ v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
CHECK(result->IsInt32());
CHECK_EQ(25, result->Int32Value());
- delete preparse;
}
@@ -304,6 +311,9 @@
// source code again without preparse data and it will fail).
i::FLAG_crankshaft = false;
+ // Make preparsing work for short scripts.
+ i::FLAG_min_preparse_length = 0;
+
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handles(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
@@ -313,30 +323,33 @@
reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
// Note that the ( before function makes the function not lazily
compiled.
- const char* good_source =
+ const char* good_code =
"(function weird() { var foo = 26; return foo; })()";
// Insert an undefined identifier. If the preparser data is used, the
symbol
// stream is used instead, and this identifier resolves to "foo".
- const char* bad_source =
+ const char* bad_code =
"(function weird() { var foo = 26; return wut; })()";
- v8::ScriptData* preparse =
v8::ScriptData::PreCompile(v8_str(good_source));
- CHECK(!preparse->HasError());
+ v8::ScriptCompiler::Source good_source(v8_str(good_code));
+ v8::ScriptCompiler::Compile(isolate, &good_source,
+ v8::ScriptCompiler::kProduceDataToCache);
+
+ const v8::ScriptCompiler::CachedData* cached_data =
+ good_source.GetCachedData();
+ CHECK(cached_data->data != NULL);
+ CHECK_GT(cached_data->length, 0);
// Now compile the erroneous code with the good preparse data. If the
preparse
// data is used, we will see a second occurrence of "foo" instead of the
// unknown "wut".
- v8::ScriptCompiler::Source source(
- v8_str(bad_source),
- v8::ScriptCompiler::CachedData(
- reinterpret_cast<const uint8_t*>(preparse->Data()),
- preparse->Length()));
+ v8::ScriptCompiler::Source bad_source(
+ v8_str(bad_code), new v8::ScriptCompiler::CachedData(
+ cached_data->data, cached_data->length));
v8::Local<v8::Value> result =
- v8::ScriptCompiler::Compile(CcTest::isolate(), source)->Run();
+ v8::ScriptCompiler::Compile(isolate, &bad_source)->Run();
CHECK(result->IsInt32());
CHECK_EQ(26, result->Int32Value());
- delete preparse;
}
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.