* 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;
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 {
* bound to a context).
*/
static Local<UnboundScript> CompileUnbound(
- Isolate* isolate, const Source& source,
+ Isolate* isolate, Source* source,
CompileOptions options = kNoCompileOptions);
/**
* context.
*/
static Local<Script> Compile(
- Isolate* isolate, const Source& source,
+ Isolate* isolate, Source* source,
CompileOptions options = kNoCompileOptions);
};
// 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()),
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() {
i::Handle<i::HeapObject> obj =
i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
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>());
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,
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);
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()",
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);
}
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);
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;
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;
}
-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);
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);
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;
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_; }
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;
// 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.
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,
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)
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();
script_name, 0, 0,
false,
context,
- NULL, NULL,
+ NULL, NULL, NO_CACHED_DATA,
NATIVES_CODE);
// Silently ignore stack overflows during compilation.
}
-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) {
// Make sure the cache is large enough to hold the symbol identifier.
if (symbol_cache_.length() <= symbol_id) {
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_);
}
: ParserBase<ParserTraits>(&scanner_,
info->isolate()->stack_guard()->real_climit(),
info->extension(),
+ NULL,
info->zone(),
this),
isolate_(info->isolate()),
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);
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()) {
}
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;
}
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();
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
// 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) {
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());
+ }
}
}
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++) {
#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;
unsigned version() { return store_[PreparseDataConstants::kVersionOffset]; }
private:
+ friend class v8::ScriptCompiler;
Vector<unsigned> store_;
unsigned char* symbol_data_;
unsigned char* symbol_data_end_;
// 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();
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.
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_;
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),
function_state_(NULL),
extension_(extension),
fni_(NULL),
+ log_(log),
scanner_(scanner),
stack_limit_(stack_limit),
stack_overflow_(false),
FunctionState* function_state_; // Function state stack.
v8::Extension* extension_;
FuncNameInferrer* fni_;
+ ParserRecorder* log_;
private:
Scanner* scanner_;
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
Expression GetStringSymbol();
bool CheckInOrOf(bool accept_OF);
-
- ParserRecorder* log_;
};
-
template<class Traits>
ParserBase<Traits>::FunctionState::FunctionState(
FunctionState** function_state_stack,
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);
}
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;
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();
}
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());
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;
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);
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());
"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());
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());
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());
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());
}
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);
}
{
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;
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);
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;
}
// 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);
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;
}