Untemplated preparser.h and made it depend on virtual types.
Extracted preparse-data specification and logging classes. Review URL: http://codereview.chromium.org/5166006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5877 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
052f595184
commit
dc390d0e1f
@ -89,6 +89,8 @@ SOURCES = {
|
||||
objects-visiting.cc
|
||||
oprofile-agent.cc
|
||||
parser.cc
|
||||
preparser.cc
|
||||
preparse-data.cc
|
||||
profile-generator.cc
|
||||
property.cc
|
||||
regexp-macro-assembler-irregexp.cc
|
||||
|
193
src/parser.cc
193
src/parser.cc
@ -356,65 +356,6 @@ Handle<String> Parser::LookupCachedSymbol(int symbol_id,
|
||||
}
|
||||
|
||||
|
||||
Vector<unsigned> PartialParserRecorder::ExtractData() {
|
||||
int function_size = function_store_.size();
|
||||
int total_size = ScriptDataImpl::kHeaderSize + function_size;
|
||||
Vector<unsigned> data = Vector<unsigned>::New(total_size);
|
||||
preamble_[ScriptDataImpl::kFunctionsSizeOffset] = function_size;
|
||||
preamble_[ScriptDataImpl::kSymbolCountOffset] = 0;
|
||||
memcpy(data.start(), preamble_, sizeof(preamble_));
|
||||
int symbol_start = ScriptDataImpl::kHeaderSize + function_size;
|
||||
if (function_size > 0) {
|
||||
function_store_.WriteTo(data.SubVector(ScriptDataImpl::kHeaderSize,
|
||||
symbol_start));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void CompleteParserRecorder::LogSymbol(int start, Vector<const char> literal) {
|
||||
if (!is_recording_) return;
|
||||
|
||||
int hash = vector_hash(literal);
|
||||
HashMap::Entry* entry = symbol_table_.Lookup(&literal, hash, true);
|
||||
int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
|
||||
if (id == 0) {
|
||||
// Put (symbol_id_ + 1) into entry and increment it.
|
||||
id = ++symbol_id_;
|
||||
entry->value = reinterpret_cast<void*>(id);
|
||||
Vector<Vector<const char> > symbol = symbol_entries_.AddBlock(1, literal);
|
||||
entry->key = &symbol[0];
|
||||
}
|
||||
WriteNumber(id - 1);
|
||||
}
|
||||
|
||||
|
||||
Vector<unsigned> CompleteParserRecorder::ExtractData() {
|
||||
int function_size = function_store_.size();
|
||||
// Add terminator to symbols, then pad to unsigned size.
|
||||
int symbol_size = symbol_store_.size();
|
||||
int padding = sizeof(unsigned) - (symbol_size % sizeof(unsigned));
|
||||
symbol_store_.AddBlock(padding, ScriptDataImpl::kNumberTerminator);
|
||||
symbol_size += padding;
|
||||
int total_size = ScriptDataImpl::kHeaderSize + function_size
|
||||
+ (symbol_size / sizeof(unsigned));
|
||||
Vector<unsigned> data = Vector<unsigned>::New(total_size);
|
||||
preamble_[ScriptDataImpl::kFunctionsSizeOffset] = function_size;
|
||||
preamble_[ScriptDataImpl::kSymbolCountOffset] = symbol_id_;
|
||||
memcpy(data.start(), preamble_, sizeof(preamble_));
|
||||
int symbol_start = ScriptDataImpl::kHeaderSize + function_size;
|
||||
if (function_size > 0) {
|
||||
function_store_.WriteTo(data.SubVector(ScriptDataImpl::kHeaderSize,
|
||||
symbol_start));
|
||||
}
|
||||
if (!has_error()) {
|
||||
symbol_store_.WriteTo(
|
||||
Vector<byte>::cast(data.SubVector(symbol_start, total_size)));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
FunctionEntry ScriptDataImpl::GetFunctionEntry(int start) {
|
||||
// The current pre-data entry must be a FunctionEntry with the given
|
||||
// start position.
|
||||
@ -437,92 +378,52 @@ int ScriptDataImpl::GetSymbolIdentifier() {
|
||||
bool ScriptDataImpl::SanityCheck() {
|
||||
// Check that the header data is valid and doesn't specify
|
||||
// point to positions outside the store.
|
||||
if (store_.length() < ScriptDataImpl::kHeaderSize) return false;
|
||||
if (magic() != ScriptDataImpl::kMagicNumber) return false;
|
||||
if (version() != ScriptDataImpl::kCurrentVersion) return false;
|
||||
if (store_.length() < PreparseDataConstants::kHeaderSize) return false;
|
||||
if (magic() != PreparseDataConstants::kMagicNumber) return false;
|
||||
if (version() != PreparseDataConstants::kCurrentVersion) return false;
|
||||
if (has_error()) {
|
||||
// Extra sane sanity check for error message encoding.
|
||||
if (store_.length() <= kHeaderSize + kMessageTextPos) return false;
|
||||
if (Read(kMessageStartPos) > Read(kMessageEndPos)) return false;
|
||||
unsigned arg_count = Read(kMessageArgCountPos);
|
||||
int pos = kMessageTextPos;
|
||||
if (store_.length() <= PreparseDataConstants::kHeaderSize
|
||||
+ PreparseDataConstants::kMessageTextPos) {
|
||||
return false;
|
||||
}
|
||||
if (Read(PreparseDataConstants::kMessageStartPos) >
|
||||
Read(PreparseDataConstants::kMessageEndPos)) {
|
||||
return false;
|
||||
}
|
||||
unsigned arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
|
||||
int pos = PreparseDataConstants::kMessageTextPos;
|
||||
for (unsigned int i = 0; i <= arg_count; i++) {
|
||||
if (store_.length() <= kHeaderSize + pos) return false;
|
||||
if (store_.length() <= PreparseDataConstants::kHeaderSize + pos) {
|
||||
return false;
|
||||
}
|
||||
int length = static_cast<int>(Read(pos));
|
||||
if (length < 0) return false;
|
||||
pos += 1 + length;
|
||||
}
|
||||
if (store_.length() < kHeaderSize + pos) return false;
|
||||
if (store_.length() < PreparseDataConstants::kHeaderSize + pos) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Check that the space allocated for function entries is sane.
|
||||
int functions_size =
|
||||
static_cast<int>(store_[ScriptDataImpl::kFunctionsSizeOffset]);
|
||||
static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
|
||||
if (functions_size < 0) return false;
|
||||
if (functions_size % FunctionEntry::kSize != 0) return false;
|
||||
// Check that the count of symbols is non-negative.
|
||||
int symbol_count =
|
||||
static_cast<int>(store_[ScriptDataImpl::kSymbolCountOffset]);
|
||||
static_cast<int>(store_[PreparseDataConstants::kSymbolCountOffset]);
|
||||
if (symbol_count < 0) return false;
|
||||
// Check that the total size has room for header and function entries.
|
||||
int minimum_size =
|
||||
ScriptDataImpl::kHeaderSize + functions_size;
|
||||
PreparseDataConstants::kHeaderSize + functions_size;
|
||||
if (store_.length() < minimum_size) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PartialParserRecorder::PartialParserRecorder()
|
||||
: function_store_(0),
|
||||
is_recording_(true),
|
||||
pause_count_(0) {
|
||||
preamble_[ScriptDataImpl::kMagicOffset] = ScriptDataImpl::kMagicNumber;
|
||||
preamble_[ScriptDataImpl::kVersionOffset] = ScriptDataImpl::kCurrentVersion;
|
||||
preamble_[ScriptDataImpl::kHasErrorOffset] = false;
|
||||
preamble_[ScriptDataImpl::kFunctionsSizeOffset] = 0;
|
||||
preamble_[ScriptDataImpl::kSymbolCountOffset] = 0;
|
||||
preamble_[ScriptDataImpl::kSizeOffset] = 0;
|
||||
ASSERT_EQ(6, ScriptDataImpl::kHeaderSize);
|
||||
#ifdef DEBUG
|
||||
prev_start_ = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
CompleteParserRecorder::CompleteParserRecorder()
|
||||
: PartialParserRecorder(),
|
||||
symbol_store_(0),
|
||||
symbol_entries_(0),
|
||||
symbol_table_(vector_compare),
|
||||
symbol_id_(0) {
|
||||
}
|
||||
|
||||
|
||||
void PartialParserRecorder::WriteString(Vector<const char> str) {
|
||||
function_store_.Add(str.length());
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
function_store_.Add(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CompleteParserRecorder::WriteNumber(int number) {
|
||||
ASSERT(number >= 0);
|
||||
|
||||
int mask = (1 << 28) - 1;
|
||||
for (int i = 28; i > 0; i -= 7) {
|
||||
if (number > mask) {
|
||||
symbol_store_.Add(static_cast<byte>(number >> i) | 0x80u);
|
||||
number &= mask;
|
||||
}
|
||||
mask >>= 7;
|
||||
}
|
||||
symbol_store_.Add(static_cast<byte>(number));
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* ScriptDataImpl::ReadString(unsigned* start, int* chars) {
|
||||
int length = start[0];
|
||||
char* result = NewArray<char>(length + 1);
|
||||
@ -534,47 +435,26 @@ const char* ScriptDataImpl::ReadString(unsigned* start, int* chars) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void PartialParserRecorder::LogMessage(Scanner::Location loc,
|
||||
const char* message,
|
||||
Vector<const char*> args) {
|
||||
if (has_error()) return;
|
||||
preamble_[ScriptDataImpl::kHasErrorOffset] = true;
|
||||
function_store_.Reset();
|
||||
STATIC_ASSERT(ScriptDataImpl::kMessageStartPos == 0);
|
||||
function_store_.Add(loc.beg_pos);
|
||||
STATIC_ASSERT(ScriptDataImpl::kMessageEndPos == 1);
|
||||
function_store_.Add(loc.end_pos);
|
||||
STATIC_ASSERT(ScriptDataImpl::kMessageArgCountPos == 2);
|
||||
function_store_.Add(args.length());
|
||||
STATIC_ASSERT(ScriptDataImpl::kMessageTextPos == 3);
|
||||
WriteString(CStrVector(message));
|
||||
for (int i = 0; i < args.length(); i++) {
|
||||
WriteString(CStrVector(args[i]));
|
||||
}
|
||||
is_recording_ = false;
|
||||
}
|
||||
|
||||
|
||||
Scanner::Location ScriptDataImpl::MessageLocation() {
|
||||
int beg_pos = Read(kMessageStartPos);
|
||||
int end_pos = Read(kMessageEndPos);
|
||||
int beg_pos = Read(PreparseDataConstants::kMessageStartPos);
|
||||
int end_pos = Read(PreparseDataConstants::kMessageEndPos);
|
||||
return Scanner::Location(beg_pos, end_pos);
|
||||
}
|
||||
|
||||
|
||||
const char* ScriptDataImpl::BuildMessage() {
|
||||
unsigned* start = ReadAddress(kMessageTextPos);
|
||||
unsigned* start = ReadAddress(PreparseDataConstants::kMessageTextPos);
|
||||
return ReadString(start, NULL);
|
||||
}
|
||||
|
||||
|
||||
Vector<const char*> ScriptDataImpl::BuildArgs() {
|
||||
int arg_count = Read(kMessageArgCountPos);
|
||||
int arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
|
||||
const char** array = NewArray<const char*>(arg_count);
|
||||
// Position after text found by skipping past length field and
|
||||
// length field content words.
|
||||
int pos = kMessageTextPos + 1 + Read(kMessageTextPos);
|
||||
int pos = PreparseDataConstants::kMessageTextPos + 1
|
||||
+ Read(PreparseDataConstants::kMessageTextPos);
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
int count = 0;
|
||||
array[i] = ReadString(ReadAddress(pos), &count);
|
||||
@ -585,12 +465,12 @@ Vector<const char*> ScriptDataImpl::BuildArgs() {
|
||||
|
||||
|
||||
unsigned ScriptDataImpl::Read(int position) {
|
||||
return store_[ScriptDataImpl::kHeaderSize + position];
|
||||
return store_[PreparseDataConstants::kHeaderSize + position];
|
||||
}
|
||||
|
||||
|
||||
unsigned* ScriptDataImpl::ReadAddress(int position) {
|
||||
return &store_[ScriptDataImpl::kHeaderSize + position];
|
||||
return &store_[PreparseDataConstants::kHeaderSize + position];
|
||||
}
|
||||
|
||||
|
||||
@ -4601,9 +4481,10 @@ bool ScriptDataImpl::HasError() {
|
||||
|
||||
void ScriptDataImpl::Initialize() {
|
||||
// Prepares state for use.
|
||||
if (store_.length() >= kHeaderSize) {
|
||||
function_index_ = kHeaderSize;
|
||||
int symbol_data_offset = kHeaderSize + store_[kFunctionsSizeOffset];
|
||||
if (store_.length() >= PreparseDataConstants::kHeaderSize) {
|
||||
function_index_ = PreparseDataConstants::kHeaderSize;
|
||||
int symbol_data_offset = PreparseDataConstants::kHeaderSize
|
||||
+ store_[PreparseDataConstants::kFunctionsSizeOffset];
|
||||
if (store_.length() > symbol_data_offset) {
|
||||
symbol_data_ = reinterpret_cast<byte*>(&store_[symbol_data_offset]);
|
||||
} else {
|
||||
@ -4625,7 +4506,7 @@ int ScriptDataImpl::ReadNumber(byte** source) {
|
||||
byte* data = *source;
|
||||
if (data >= symbol_data_end_) return -1;
|
||||
byte input = *data;
|
||||
if (input == kNumberTerminator) {
|
||||
if (input == PreparseDataConstants::kNumberTerminator) {
|
||||
// End of stream marker.
|
||||
return -1;
|
||||
}
|
||||
@ -4646,11 +4527,11 @@ int ScriptDataImpl::ReadNumber(byte** source) {
|
||||
static ScriptDataImpl* DoPreParse(Handle<String> source,
|
||||
unibrow::CharacterStream* stream,
|
||||
bool allow_lazy,
|
||||
PartialParserRecorder* recorder,
|
||||
ParserRecorder* recorder,
|
||||
int literal_flags) {
|
||||
V8JavaScriptScanner scanner;
|
||||
scanner.Initialize(source, stream, literal_flags);
|
||||
preparser::PreParser<JavaScriptScanner, PartialParserRecorder> preparser;
|
||||
preparser::PreParser preparser;
|
||||
if (!preparser.PreParseProgram(&scanner, recorder, allow_lazy)) {
|
||||
Top::StackOverflow();
|
||||
return NULL;
|
||||
|
151
src/parser.h
151
src/parser.h
@ -32,6 +32,7 @@
|
||||
#include "ast.h"
|
||||
#include "scanner.h"
|
||||
#include "scopes.h"
|
||||
#include "preparse-data.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -123,32 +124,15 @@ class ScriptDataImpl : public ScriptData {
|
||||
Vector<const char*> BuildArgs();
|
||||
|
||||
int symbol_count() {
|
||||
return (store_.length() > kHeaderSize) ? store_[kSymbolCountOffset] : 0;
|
||||
return (store_.length() > PreparseDataConstants::kHeaderSize)
|
||||
? store_[PreparseDataConstants::kSymbolCountOffset]
|
||||
: 0;
|
||||
}
|
||||
// The following functions should only be called if SanityCheck has
|
||||
// returned true.
|
||||
bool has_error() { return store_[kHasErrorOffset]; }
|
||||
unsigned magic() { return store_[kMagicOffset]; }
|
||||
unsigned version() { return store_[kVersionOffset]; }
|
||||
|
||||
static const unsigned kMagicNumber = 0xBadDead;
|
||||
static const unsigned kCurrentVersion = 5;
|
||||
|
||||
static const int kMagicOffset = 0;
|
||||
static const int kVersionOffset = 1;
|
||||
static const int kHasErrorOffset = 2;
|
||||
static const int kFunctionsSizeOffset = 3;
|
||||
static const int kSymbolCountOffset = 4;
|
||||
static const int kSizeOffset = 5;
|
||||
static const int kHeaderSize = 6;
|
||||
|
||||
// If encoding a message, the following positions are fixed.
|
||||
static const int kMessageStartPos = 0;
|
||||
static const int kMessageEndPos = 1;
|
||||
static const int kMessageArgCountPos = 2;
|
||||
static const int kMessageTextPos = 3;
|
||||
|
||||
static const byte kNumberTerminator = 0x80u;
|
||||
bool has_error() { return store_[PreparseDataConstants::kHasErrorOffset]; }
|
||||
unsigned magic() { return store_[PreparseDataConstants::kMagicOffset]; }
|
||||
unsigned version() { return store_[PreparseDataConstants::kVersionOffset]; }
|
||||
|
||||
private:
|
||||
Vector<unsigned> store_;
|
||||
@ -177,127 +161,6 @@ class ScriptDataImpl : public ScriptData {
|
||||
};
|
||||
|
||||
|
||||
// Record only functions.
|
||||
class PartialParserRecorder {
|
||||
public:
|
||||
PartialParserRecorder();
|
||||
virtual ~PartialParserRecorder() {}
|
||||
|
||||
void LogFunction(int start, int end, int literals, int properties) {
|
||||
function_store_.Add(start);
|
||||
function_store_.Add(end);
|
||||
function_store_.Add(literals);
|
||||
function_store_.Add(properties);
|
||||
}
|
||||
|
||||
virtual void LogSymbol(int start, const char* symbol, int length) { }
|
||||
|
||||
// Logs an error message and marks the log as containing an error.
|
||||
// Further logging will be ignored, and ExtractData will return a vector
|
||||
// representing the error only.
|
||||
void LogMessage(int start,
|
||||
int end,
|
||||
const char* message,
|
||||
const char* argument_opt) {
|
||||
Scanner::Location location(start, end);
|
||||
Vector<const char*> arguments;
|
||||
if (argument_opt != NULL) {
|
||||
arguments = Vector<const char*>(&argument_opt, 1);
|
||||
}
|
||||
this->LogMessage(location, message, arguments);
|
||||
}
|
||||
|
||||
int function_position() { return function_store_.size(); }
|
||||
|
||||
void LogMessage(Scanner::Location loc,
|
||||
const char* message,
|
||||
Vector<const char*> args);
|
||||
|
||||
virtual Vector<unsigned> ExtractData();
|
||||
|
||||
void PauseRecording() {
|
||||
pause_count_++;
|
||||
is_recording_ = false;
|
||||
}
|
||||
|
||||
void ResumeRecording() {
|
||||
ASSERT(pause_count_ > 0);
|
||||
if (--pause_count_ == 0) is_recording_ = !has_error();
|
||||
}
|
||||
|
||||
int symbol_position() { return 0; }
|
||||
int symbol_ids() { return 0; }
|
||||
|
||||
protected:
|
||||
bool has_error() {
|
||||
return static_cast<bool>(preamble_[ScriptDataImpl::kHasErrorOffset]);
|
||||
}
|
||||
|
||||
bool is_recording() {
|
||||
return is_recording_;
|
||||
}
|
||||
|
||||
void WriteString(Vector<const char> str);
|
||||
|
||||
Collector<unsigned> function_store_;
|
||||
unsigned preamble_[ScriptDataImpl::kHeaderSize];
|
||||
bool is_recording_;
|
||||
int pause_count_;
|
||||
|
||||
#ifdef DEBUG
|
||||
int prev_start_;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// Record both functions and symbols.
|
||||
class CompleteParserRecorder: public PartialParserRecorder {
|
||||
public:
|
||||
CompleteParserRecorder();
|
||||
virtual ~CompleteParserRecorder() { }
|
||||
|
||||
void LogSymbol(int start, Vector<const char> literal);
|
||||
|
||||
virtual void LogSymbol(int start, const char* symbol, int length) {
|
||||
LogSymbol(start, Vector<const char>(symbol, length));
|
||||
}
|
||||
|
||||
virtual Vector<unsigned> ExtractData();
|
||||
|
||||
int symbol_position() { return symbol_store_.size(); }
|
||||
int symbol_ids() { return symbol_id_; }
|
||||
|
||||
private:
|
||||
static int vector_hash(Vector<const char> string) {
|
||||
int hash = 0;
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
int c = string[i];
|
||||
hash += c;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
static bool vector_compare(void* a, void* b) {
|
||||
Vector<const char>* string1 = reinterpret_cast<Vector<const char>* >(a);
|
||||
Vector<const char>* string2 = reinterpret_cast<Vector<const char>* >(b);
|
||||
int length = string1->length();
|
||||
if (string2->length() != length) return false;
|
||||
return memcmp(string1->start(), string2->start(), length) == 0;
|
||||
}
|
||||
|
||||
// Write a non-negative number to the symbol store.
|
||||
void WriteNumber(int number);
|
||||
|
||||
Collector<byte> symbol_store_;
|
||||
Collector<Vector<const char> > symbol_entries_;
|
||||
HashMap symbol_table_;
|
||||
int symbol_id_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ParserApi {
|
||||
public:
|
||||
// Parses the source code represented by the compilation info and sets its
|
||||
|
180
src/preparse-data.cc
Normal file
180
src/preparse-data.cc
Normal file
@ -0,0 +1,180 @@
|
||||
// Copyright 2010 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "../include/v8stdint.h"
|
||||
#include "globals.h"
|
||||
#include "checks.h"
|
||||
#include "allocation.h"
|
||||
#include "utils.h"
|
||||
#include "list-inl.h"
|
||||
#include "hashmap.h"
|
||||
#include "preparse-data.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// FunctionLoggingParserRecorder
|
||||
|
||||
FunctionLoggingParserRecorder::FunctionLoggingParserRecorder()
|
||||
: function_store_(0),
|
||||
is_recording_(true),
|
||||
pause_count_(0) {
|
||||
preamble_[PreparseDataConstants::kMagicOffset] =
|
||||
PreparseDataConstants::kMagicNumber;
|
||||
preamble_[PreparseDataConstants::kVersionOffset] =
|
||||
PreparseDataConstants::kCurrentVersion;
|
||||
preamble_[PreparseDataConstants::kHasErrorOffset] = false;
|
||||
preamble_[PreparseDataConstants::kFunctionsSizeOffset] = 0;
|
||||
preamble_[PreparseDataConstants::kSymbolCountOffset] = 0;
|
||||
preamble_[PreparseDataConstants::kSizeOffset] = 0;
|
||||
ASSERT_EQ(6, PreparseDataConstants::kHeaderSize);
|
||||
#ifdef DEBUG
|
||||
prev_start_ = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void FunctionLoggingParserRecorder::LogMessage(int start_pos,
|
||||
int end_pos,
|
||||
const char* message,
|
||||
const char* arg_opt) {
|
||||
if (has_error()) return;
|
||||
preamble_[PreparseDataConstants::kHasErrorOffset] = true;
|
||||
function_store_.Reset();
|
||||
STATIC_ASSERT(PreparseDataConstants::kMessageStartPos == 0);
|
||||
function_store_.Add(start_pos);
|
||||
STATIC_ASSERT(PreparseDataConstants::kMessageEndPos == 1);
|
||||
function_store_.Add(end_pos);
|
||||
STATIC_ASSERT(PreparseDataConstants::kMessageArgCountPos == 2);
|
||||
function_store_.Add((arg_opt == NULL) ? 0 : 1);
|
||||
STATIC_ASSERT(PreparseDataConstants::kMessageTextPos == 3);
|
||||
WriteString(CStrVector(message));
|
||||
if (arg_opt) WriteString(CStrVector(arg_opt));
|
||||
is_recording_ = false;
|
||||
}
|
||||
|
||||
|
||||
void FunctionLoggingParserRecorder::WriteString(Vector<const char> str) {
|
||||
function_store_.Add(str.length());
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
function_store_.Add(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// PartialParserRecorder - Record both function entries and symbols.
|
||||
|
||||
Vector<unsigned> PartialParserRecorder::ExtractData() {
|
||||
int function_size = function_store_.size();
|
||||
int total_size = PreparseDataConstants::kHeaderSize + function_size;
|
||||
Vector<unsigned> data = Vector<unsigned>::New(total_size);
|
||||
preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
|
||||
preamble_[PreparseDataConstants::kSymbolCountOffset] = 0;
|
||||
memcpy(data.start(), preamble_, sizeof(preamble_));
|
||||
int symbol_start = PreparseDataConstants::kHeaderSize + function_size;
|
||||
if (function_size > 0) {
|
||||
function_store_.WriteTo(data.SubVector(PreparseDataConstants::kHeaderSize,
|
||||
symbol_start));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CompleteParserRecorder - Record both function entries and symbols.
|
||||
|
||||
CompleteParserRecorder::CompleteParserRecorder()
|
||||
: FunctionLoggingParserRecorder(),
|
||||
symbol_store_(0),
|
||||
symbol_entries_(0),
|
||||
symbol_table_(vector_compare),
|
||||
symbol_id_(0) {
|
||||
}
|
||||
|
||||
|
||||
void CompleteParserRecorder::LogSymbol(
|
||||
int start, const char* literal_chars, int length) {
|
||||
if (!is_recording_) return;
|
||||
|
||||
Vector<const char> literal(literal_chars, length);
|
||||
int hash = vector_hash(literal);
|
||||
HashMap::Entry* entry = symbol_table_.Lookup(&literal, hash, true);
|
||||
int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
|
||||
if (id == 0) {
|
||||
// Put (symbol_id_ + 1) into entry and increment it.
|
||||
id = ++symbol_id_;
|
||||
entry->value = reinterpret_cast<void*>(id);
|
||||
Vector<Vector<const char> > symbol = symbol_entries_.AddBlock(1, literal);
|
||||
entry->key = &symbol[0];
|
||||
}
|
||||
WriteNumber(id - 1);
|
||||
}
|
||||
|
||||
|
||||
Vector<unsigned> CompleteParserRecorder::ExtractData() {
|
||||
int function_size = function_store_.size();
|
||||
// Add terminator to symbols, then pad to unsigned size.
|
||||
int symbol_size = symbol_store_.size();
|
||||
int padding = sizeof(unsigned) - (symbol_size % sizeof(unsigned));
|
||||
symbol_store_.AddBlock(padding, PreparseDataConstants::kNumberTerminator);
|
||||
symbol_size += padding;
|
||||
int total_size = PreparseDataConstants::kHeaderSize + function_size
|
||||
+ (symbol_size / sizeof(unsigned));
|
||||
Vector<unsigned> data = Vector<unsigned>::New(total_size);
|
||||
preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
|
||||
preamble_[PreparseDataConstants::kSymbolCountOffset] = symbol_id_;
|
||||
memcpy(data.start(), preamble_, sizeof(preamble_));
|
||||
int symbol_start = PreparseDataConstants::kHeaderSize + function_size;
|
||||
if (function_size > 0) {
|
||||
function_store_.WriteTo(data.SubVector(PreparseDataConstants::kHeaderSize,
|
||||
symbol_start));
|
||||
}
|
||||
if (!has_error()) {
|
||||
symbol_store_.WriteTo(
|
||||
Vector<byte>::cast(data.SubVector(symbol_start, total_size)));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void CompleteParserRecorder::WriteNumber(int number) {
|
||||
ASSERT(number >= 0);
|
||||
|
||||
int mask = (1 << 28) - 1;
|
||||
for (int i = 28; i > 0; i -= 7) {
|
||||
if (number > mask) {
|
||||
symbol_store_.Add(static_cast<byte>(number >> i) | 0x80u);
|
||||
number &= mask;
|
||||
}
|
||||
mask >>= 7;
|
||||
}
|
||||
symbol_store_.Add(static_cast<byte>(number));
|
||||
}
|
||||
|
||||
|
||||
} } // namespace v8::internal.
|
223
src/preparse-data.h
Normal file
223
src/preparse-data.h
Normal file
@ -0,0 +1,223 @@
|
||||
// Copyright 2010 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef V8_PREPARSER_DATA_H_
|
||||
#define V8_PREPARSER_DATA_H_
|
||||
|
||||
#include "hashmap.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Generic and general data used by preparse data recorders and readers.
|
||||
|
||||
class PreparseDataConstants : public AllStatic {
|
||||
public:
|
||||
// Layout and constants of the preparse data exchange format.
|
||||
static const unsigned kMagicNumber = 0xBadDead;
|
||||
static const unsigned kCurrentVersion = 5;
|
||||
|
||||
static const int kMagicOffset = 0;
|
||||
static const int kVersionOffset = 1;
|
||||
static const int kHasErrorOffset = 2;
|
||||
static const int kFunctionsSizeOffset = 3;
|
||||
static const int kSymbolCountOffset = 4;
|
||||
static const int kSizeOffset = 5;
|
||||
static const int kHeaderSize = 6;
|
||||
|
||||
// If encoding a message, the following positions are fixed.
|
||||
static const int kMessageStartPos = 0;
|
||||
static const int kMessageEndPos = 1;
|
||||
static const int kMessageArgCountPos = 2;
|
||||
static const int kMessageTextPos = 3;
|
||||
|
||||
static const byte kNumberTerminator = 0x80u;
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ParserRecorder - Logging of preparser data.
|
||||
|
||||
// Abstract interface for preparse data recorder.
|
||||
class ParserRecorder {
|
||||
public:
|
||||
ParserRecorder() { }
|
||||
virtual ~ParserRecorder() { }
|
||||
|
||||
// Logs the scope and some details of a function literal in the source.
|
||||
virtual void LogFunction(int start,
|
||||
int end,
|
||||
int literals,
|
||||
int properties) = 0;
|
||||
|
||||
// Logs a symbol creation of a literal or identifier.
|
||||
virtual void LogSymbol(int start, const char* symbol, int length) = 0;
|
||||
|
||||
// Logs an error message and marks the log as containing an error.
|
||||
// Further logging will be ignored, and ExtractData will return a vector
|
||||
// representing the error only.
|
||||
virtual void LogMessage(int start,
|
||||
int end,
|
||||
const char* message,
|
||||
const char* argument_opt) = 0;
|
||||
|
||||
virtual int function_position() = 0;
|
||||
|
||||
virtual int symbol_position() = 0;
|
||||
|
||||
virtual int symbol_ids() = 0;
|
||||
|
||||
virtual Vector<unsigned> ExtractData() = 0;
|
||||
|
||||
virtual void PauseRecording() = 0;
|
||||
|
||||
virtual void ResumeRecording() = 0;
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// FunctionLoggingParserRecorder - Record only function entries
|
||||
|
||||
class FunctionLoggingParserRecorder : public ParserRecorder {
|
||||
public:
|
||||
FunctionLoggingParserRecorder();
|
||||
virtual ~FunctionLoggingParserRecorder() {}
|
||||
|
||||
virtual void LogFunction(int start, int end, int literals, int properties) {
|
||||
function_store_.Add(start);
|
||||
function_store_.Add(end);
|
||||
function_store_.Add(literals);
|
||||
function_store_.Add(properties);
|
||||
}
|
||||
|
||||
// Logs an error message and marks the log as containing an error.
|
||||
// Further logging will be ignored, and ExtractData will return a vector
|
||||
// representing the error only.
|
||||
virtual void LogMessage(int start,
|
||||
int end,
|
||||
const char* message,
|
||||
const char* argument_opt);
|
||||
|
||||
virtual int function_position() { return function_store_.size(); }
|
||||
|
||||
|
||||
virtual Vector<unsigned> ExtractData() = 0;
|
||||
|
||||
virtual void PauseRecording() {
|
||||
pause_count_++;
|
||||
is_recording_ = false;
|
||||
}
|
||||
|
||||
virtual void ResumeRecording() {
|
||||
ASSERT(pause_count_ > 0);
|
||||
if (--pause_count_ == 0) is_recording_ = !has_error();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool has_error() {
|
||||
return static_cast<bool>(preamble_[PreparseDataConstants::kHasErrorOffset]);
|
||||
}
|
||||
|
||||
bool is_recording() {
|
||||
return is_recording_;
|
||||
}
|
||||
|
||||
void WriteString(Vector<const char> str);
|
||||
|
||||
Collector<unsigned> function_store_;
|
||||
unsigned preamble_[PreparseDataConstants::kHeaderSize];
|
||||
bool is_recording_;
|
||||
int pause_count_;
|
||||
|
||||
#ifdef DEBUG
|
||||
int prev_start_;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// PartialParserRecorder - Record only function entries
|
||||
|
||||
class PartialParserRecorder : public FunctionLoggingParserRecorder {
|
||||
public:
|
||||
PartialParserRecorder() : FunctionLoggingParserRecorder() { }
|
||||
virtual void LogSymbol(int start, const char* symbol, int length) { }
|
||||
virtual ~PartialParserRecorder() { }
|
||||
virtual Vector<unsigned> ExtractData();
|
||||
virtual int symbol_position() { return 0; }
|
||||
virtual int symbol_ids() { return 0; }
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CompleteParserRecorder - Record both function entries and symbols.
|
||||
|
||||
class CompleteParserRecorder: public FunctionLoggingParserRecorder {
|
||||
public:
|
||||
CompleteParserRecorder();
|
||||
virtual ~CompleteParserRecorder() { }
|
||||
|
||||
virtual void LogSymbol(int start, const char* symbol, int length);
|
||||
|
||||
virtual Vector<unsigned> ExtractData();
|
||||
|
||||
virtual int symbol_position() { return symbol_store_.size(); }
|
||||
virtual int symbol_ids() { return symbol_id_; }
|
||||
|
||||
private:
|
||||
static int vector_hash(Vector<const char> string) {
|
||||
int hash = 0;
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
int c = string[i];
|
||||
hash += c;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
static bool vector_compare(void* a, void* b) {
|
||||
Vector<const char>* string1 = reinterpret_cast<Vector<const char>* >(a);
|
||||
Vector<const char>* string2 = reinterpret_cast<Vector<const char>* >(b);
|
||||
int length = string1->length();
|
||||
if (string2->length() != length) return false;
|
||||
return memcmp(string1->start(), string2->start(), length) == 0;
|
||||
}
|
||||
|
||||
// Write a non-negative number to the symbol store.
|
||||
void WriteNumber(int number);
|
||||
|
||||
Collector<byte> symbol_store_;
|
||||
Collector<Vector<const char> > symbol_entries_;
|
||||
HashMap symbol_table_;
|
||||
int symbol_id_;
|
||||
};
|
||||
|
||||
|
||||
} } // namespace v8::internal.
|
||||
|
||||
#endif // V8_PREPARSER_DATA_H_
|
1184
src/preparser.cc
Normal file
1184
src/preparser.cc
Normal file
File diff suppressed because it is too large
Load Diff
1188
src/preparser.h
1188
src/preparser.h
File diff suppressed because it is too large
Load Diff
@ -8734,7 +8734,7 @@ TEST(PreCompileInvalidPreparseDataError) {
|
||||
v8::ScriptData::PreCompile(script, i::StrLength(script));
|
||||
CHECK(!sd->HasError());
|
||||
// ScriptDataImpl private implementation details
|
||||
const int kHeaderSize = i::ScriptDataImpl::kHeaderSize;
|
||||
const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
|
||||
const int kFunctionEntrySize = i::FunctionEntry::kSize;
|
||||
const int kFunctionEntryStartOffset = 0;
|
||||
const int kFunctionEntryEndOffset = 1;
|
||||
|
@ -263,8 +263,7 @@ TEST(StandAlonePreParser) {
|
||||
i::CompleteParserRecorder log;
|
||||
i::V8JavaScriptScanner scanner;
|
||||
scanner.Initialize(i::Handle<i::String>::null(), &stream);
|
||||
v8::preparser::PreParser<i::V8JavaScriptScanner,
|
||||
i::CompleteParserRecorder> preparser;
|
||||
v8::preparser::PreParser preparser;
|
||||
bool result = preparser.PreParseProgram(&scanner, &log, true);
|
||||
CHECK(result);
|
||||
i::ScriptDataImpl data(log.ExtractData());
|
||||
|
@ -761,6 +761,22 @@
|
||||
RelativePath="..\..\src\parser.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\preparser.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\preparser.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\preparse-data.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\preparse-data.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\profile-generator.cc"
|
||||
>
|
||||
|
Loading…
Reference in New Issue
Block a user