/**
* Compiles the specified script (context-independent).
+ * Cached data as part of the source object can be optionally produced to be
+ * consumed later to speed up compilation of identical source scripts.
+ *
+ * Note that when producing cached data, the source must point to NULL for
+ * cached data. When consuming cached data, the cached data must have been
+ * produced by the same version of V8.
*
* \param source Script source code.
* \return Compiled script object (context independent; for running it must be
Isolate* v8_isolate,
Source* source,
CompileOptions options) {
- i::ScriptData* script_data_impl = NULL;
+ i::ScriptData* script_data = NULL;
i::CachedDataMode cached_data_mode = i::NO_CACHED_DATA;
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
ON_BAILOUT(isolate, "v8::ScriptCompiler::CompileUnbound()",
return Local<UnboundScript>());
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. Fail the compilation.
- EXCEPTION_PREAMBLE(isolate);
- i::Handle<i::Object> result = isolate->factory()->NewSyntaxError(
- "invalid_cached_data", isolate->factory()->NewJSArray(0));
- isolate->Throw(*result);
- isolate->ReportPendingMessages();
- has_pending_exception = true;
- EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
- }
+ CHECK(source->cached_data == NULL);
} else if (source->cached_data) {
cached_data_mode = i::CONSUME_CACHED_DATA;
- // ScriptData takes care of aligning, in case the data is not aligned
- // correctly.
- script_data_impl = i::ScriptData::New(
- reinterpret_cast<const char*>(source->cached_data->data),
- source->cached_data->length);
- // If the cached data is not valid, fail the compilation.
- if (script_data_impl == NULL || !script_data_impl->SanityCheck()) {
- EXCEPTION_PREAMBLE(isolate);
- i::Handle<i::Object> result = isolate->factory()->NewSyntaxError(
- "invalid_cached_data", isolate->factory()->NewJSArray(0));
- isolate->Throw(*result);
- isolate->ReportPendingMessages();
- delete script_data_impl;
- has_pending_exception = true;
- EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
- }
+ // ScriptData takes care of pointer-aligning the data.
+ script_data = new i::ScriptData(source->cached_data->data,
+ source->cached_data->length);
}
i::Handle<i::String> str = Utils::OpenHandle(*(source->source_string));
source->resource_is_shared_cross_origin == v8::True(v8_isolate);
}
EXCEPTION_PREAMBLE(isolate);
- i::Handle<i::SharedFunctionInfo> result =
- i::Compiler::CompileScript(str,
- name_obj,
- line_offset,
- column_offset,
- is_shared_cross_origin,
- isolate->global_context(),
- NULL,
- &script_data_impl,
- cached_data_mode,
- i::NOT_NATIVES_CODE);
+ i::Handle<i::SharedFunctionInfo> result = i::Compiler::CompileScript(
+ str, name_obj, line_offset, column_offset, is_shared_cross_origin,
+ isolate->global_context(), NULL, &script_data, cached_data_mode,
+ i::NOT_NATIVES_CODE);
has_pending_exception = result.is_null();
if (has_pending_exception && cached_data_mode == i::CONSUME_CACHED_DATA) {
// This case won't happen during normal operation; we have compiled
// successfully and produced cached data, and but the second compilation
// of the same source code fails.
- delete script_data_impl;
- script_data_impl = NULL;
+ delete script_data;
+ script_data = NULL;
}
EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
raw_result = *result;
- if ((options & kProduceDataToCache) && script_data_impl != NULL) {
+ if ((options & kProduceDataToCache) && script_data != 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;
+ script_data->data(), script_data->length(), CachedData::BufferOwned);
+ script_data->ReleaseDataOwnership();
}
- delete script_data_impl;
+ delete script_data;
}
i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
return ToApiHandle<UnboundScript>(result);
namespace internal {
+ScriptData::ScriptData(const byte* data, int length)
+ : owns_data_(false), data_(data), length_(length) {
+ if (!IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment)) {
+ byte* copy = NewArray<byte>(length);
+ ASSERT(IsAligned(reinterpret_cast<intptr_t>(data_), kPointerAlignment));
+ CopyBytes(copy, data, length);
+ data_ = copy;
+ AcquireDataOwnership();
+ }
+}
+
+
CompilationInfo::CompilationInfo(Handle<Script> script,
Zone* zone)
: flags_(StrictModeField::encode(SLOPPY)),
namespace internal {
class AstValueFactory;
-class ScriptData;
class HydrogenCodeStub;
// ParseRestriction is used to restrict the set of valid statements in a
int to;
};
+
+class ScriptData {
+ public:
+ ScriptData(const byte* data, int length);
+ ~ScriptData() {
+ if (owns_data_) DeleteArray(data_);
+ }
+
+ const byte* data() const { return data_; }
+ int length() const { return length_; }
+
+ void AcquireDataOwnership() {
+ ASSERT(!owns_data_);
+ owns_data_ = true;
+ }
+
+ void ReleaseDataOwnership() {
+ ASSERT(owns_data_);
+ owns_data_ = false;
+ }
+
+ private:
+ bool owns_data_;
+ const byte* data_;
+ int length_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScriptData);
+};
+
+
// CompilationInfo encapsulates some information known at compile time. It
// is constructed based on the resources available at compile-time.
class CompilationInfo {
DISALLOW_COPY_AND_ASSIGN(CompilationPhase);
};
-
} } // namespace v8::internal
#endif // V8_COMPILER_H_
array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"],
object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"],
illegal_access: ["Illegal access"],
- invalid_cached_data_function: ["Invalid cached data for function ", "%0"],
- invalid_cached_data: ["Invalid cached data"],
strict_mode_with: ["Strict mode code may not include a with statement"],
strict_eval_arguments: ["Unexpected eval or arguments in strict mode"],
too_many_arguments: ["Too many arguments in function call (only 65535 allowed)"],
class Compressor {
public:
virtual ~Compressor() {}
- virtual bool Compress(i::Vector<char> input) = 0;
- virtual i::Vector<char>* output() = 0;
+ virtual bool Compress(i::Vector<i::byte> input) = 0;
+ virtual i::Vector<i::byte>* output() = 0;
};
startup_blob_file_ = GetFileDescriptorOrDie(startup_blob_file);
}
- void WriteSnapshot(const i::List<char>& snapshot_data,
+ void WriteSnapshot(const i::List<i::byte>& snapshot_data,
const i::Serializer& serializer,
- const i::List<char>& context_snapshot_data,
+ const i::List<i::byte>& context_snapshot_data,
const i::Serializer& context_serializer) const {
WriteSnapshotFile(snapshot_data, serializer,
context_snapshot_data, context_serializer);
}
private:
- void MaybeWriteStartupBlob(const i::List<char>& snapshot_data,
+ void MaybeWriteStartupBlob(const i::List<i::byte>& snapshot_data,
const i::Serializer& serializer,
- const i::List<char>& context_snapshot_data,
+ const i::List<i::byte>& context_snapshot_data,
const i::Serializer& context_serializer) const {
if (!startup_blob_file_)
return;
- i::List<char> startup_blob;
+ i::List<i::byte> startup_blob;
i::ListSnapshotSink sink(&startup_blob);
int spaces[] = {
i::MAP_SPACE, i::CELL_SPACE, i::PROPERTY_CELL_SPACE
};
- i::byte* snapshot_bytes = reinterpret_cast<i::byte*>(snapshot_data.begin());
+ i::byte* snapshot_bytes = snapshot_data.begin();
sink.PutBlob(snapshot_bytes, snapshot_data.length(), "snapshot");
for (size_t i = 0; i < ARRAY_SIZE(spaces); ++i)
sink.PutInt(serializer.CurrentAllocationAddress(spaces[i]), "spaces");
- i::byte* context_bytes =
- reinterpret_cast<i::byte*>(context_snapshot_data.begin());
+ i::byte* context_bytes = context_snapshot_data.begin();
sink.PutBlob(context_bytes, context_snapshot_data.length(), "context");
for (size_t i = 0; i < ARRAY_SIZE(spaces); ++i)
sink.PutInt(context_serializer.CurrentAllocationAddress(spaces[i]),
}
}
- void WriteSnapshotFile(const i::List<char>& snapshot_data,
+ void WriteSnapshotFile(const i::List<i::byte>& snapshot_data,
const i::Serializer& serializer,
- const i::List<char>& context_snapshot_data,
+ const i::List<i::byte>& context_snapshot_data,
const i::Serializer& context_serializer) const {
WriteFilePrefix();
WriteData("", snapshot_data, raw_file_);
fprintf(fp_, "} // namespace v8\n");
}
- void WriteData(const char* prefix,
- const i::List<char>& source_data,
+ void WriteData(const char* prefix, const i::List<i::byte>& source_data,
FILE* raw_file) const {
- const i::List <char>* data_to_be_written = NULL;
- i::List<char> compressed_data;
+ const i::List<i::byte>* data_to_be_written = NULL;
+ i::List<i::byte> compressed_data;
if (!compressor_) {
data_to_be_written = &source_data;
} else if (compressor_->Compress(source_data.ToVector())) {
WriteData(prefix, source_data, data_to_be_written);
}
- void MaybeWriteRawFile(const i::List<char>* data, FILE* raw_file) const {
+ void MaybeWriteRawFile(const i::List<i::byte>* data, FILE* raw_file) const {
if (!data || !raw_file)
return;
}
}
- void WriteData(const char* prefix,
- const i::List<char>& source_data,
- const i::List<char>* data_to_be_written) const {
+ void WriteData(const char* prefix, const i::List<i::byte>& source_data,
+ const i::List<i::byte>* data_to_be_written) const {
fprintf(fp_, "const byte Snapshot::%sdata_[] = {\n", prefix);
WriteSnapshotData(data_to_be_written);
fprintf(fp_, "};\n");
prefix, name, ser.CurrentAllocationAddress(space));
}
- void WriteSnapshotData(const i::List<char>* data) const {
+ void WriteSnapshotData(const i::List<i::byte>* data) const {
for (int i = 0; i < data->length(); i++) {
if ((i & 0x1f) == 0x1f)
fprintf(fp_, "\n");
// This results in a somewhat smaller snapshot, probably because it gets
// rid of some things that are cached between garbage collections.
- i::List<char> snapshot_data;
+ i::List<i::byte> snapshot_data;
i::ListSnapshotSink snapshot_sink(&snapshot_data);
i::StartupSerializer ser(internal_isolate, &snapshot_sink);
ser.SerializeStrongReferences();
- i::List<char> context_data;
+ i::List<i::byte> context_data;
i::ListSnapshotSink contex_sink(&context_data);
i::PartialSerializer context_ser(internal_isolate, &ser, &contex_sink);
context_ser.Serialize(&raw_context);
}
-ScriptData* ScriptData::New(const char* data, int length, bool owns_store) {
- // The length is obviously invalid.
- if (length % sizeof(unsigned) != 0) {
- return NULL;
- }
-
- int deserialized_data_length = length / sizeof(unsigned);
- unsigned* deserialized_data;
- owns_store =
- owns_store || reinterpret_cast<intptr_t>(data) % sizeof(unsigned) != 0;
- if (owns_store) {
- // Copy the data to align it.
- deserialized_data = i::NewArray<unsigned>(deserialized_data_length);
- i::CopyBytes(reinterpret_cast<char*>(deserialized_data),
- data, static_cast<size_t>(length));
- } else {
- // If aligned, don't create a copy of the data.
- deserialized_data = reinterpret_cast<unsigned*>(const_cast<char*>(data));
- }
- return new ScriptData(
- Vector<unsigned>(deserialized_data, deserialized_data_length),
- owns_store);
-}
-
-
-FunctionEntry ScriptData::GetFunctionEntry(int start) {
+FunctionEntry ParseData::GetFunctionEntry(int start) {
// The current pre-data entry must be a FunctionEntry with the given
// start position.
- if ((function_index_ + FunctionEntry::kSize <= store_.length())
- && (static_cast<int>(store_[function_index_]) == start)) {
+ if ((function_index_ + FunctionEntry::kSize <= Length()) &&
+ (static_cast<int>(Data()[function_index_]) == start)) {
int index = function_index_;
function_index_ += FunctionEntry::kSize;
- return FunctionEntry(store_.SubVector(index,
- index + FunctionEntry::kSize));
+ Vector<unsigned> subvector(&(Data()[index]), FunctionEntry::kSize);
+ return FunctionEntry(subvector);
}
return FunctionEntry();
}
-int ScriptData::GetSymbolIdentifier() {
- return ReadNumber(&symbol_data_);
+int ParseData::FunctionCount() {
+ int functions_size = FunctionsSize();
+ if (functions_size < 0) return 0;
+ if (functions_size % FunctionEntry::kSize != 0) return 0;
+ return functions_size / FunctionEntry::kSize;
}
-bool ScriptData::SanityCheck() {
+bool ParseData::IsSane() {
// Check that the header data is valid and doesn't specify
// point to positions outside the store.
- 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() <= 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() <= PreparseDataConstants::kHeaderSize + pos) {
- return false;
- }
- int length = static_cast<int>(Read(pos));
- if (length < 0) return false;
- pos += 1 + length;
- }
- if (store_.length() < PreparseDataConstants::kHeaderSize + pos) {
- return false;
- }
- return true;
- }
+ int data_length = Length();
+ if (data_length < PreparseDataConstants::kHeaderSize) return false;
+ if (Magic() != PreparseDataConstants::kMagicNumber) return false;
+ if (Version() != PreparseDataConstants::kCurrentVersion) return false;
+ if (HasError()) return false;
// Check that the space allocated for function entries is sane.
- int functions_size =
- static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
+ int functions_size = FunctionsSize();
if (functions_size < 0) return false;
if (functions_size % FunctionEntry::kSize != 0) return false;
// Check that the total size has room for header and function entries.
int minimum_size =
PreparseDataConstants::kHeaderSize + functions_size;
- if (store_.length() < minimum_size) return false;
+ if (data_length < minimum_size) return false;
return true;
}
-
-const char* ScriptData::ReadString(unsigned* start, int* chars) {
- int length = start[0];
- char* result = NewArray<char>(length + 1);
- for (int i = 0; i < length; i++) {
- result[i] = start[i + 1];
+void ParseData::Initialize() {
+ // Prepares state for use.
+ int data_length = Length();
+ if (data_length >= PreparseDataConstants::kHeaderSize) {
+ function_index_ = PreparseDataConstants::kHeaderSize;
}
- result[length] = '\0';
- if (chars != NULL) *chars = length;
- return result;
-}
-
-
-Scanner::Location ScriptData::MessageLocation() const {
- int beg_pos = Read(PreparseDataConstants::kMessageStartPos);
- int end_pos = Read(PreparseDataConstants::kMessageEndPos);
- return Scanner::Location(beg_pos, end_pos);
}
-bool ScriptData::IsReferenceError() const {
- return Read(PreparseDataConstants::kIsReferenceErrorPos);
+bool ParseData::HasError() {
+ return Data()[PreparseDataConstants::kHasErrorOffset];
}
-const char* ScriptData::BuildMessage() const {
- unsigned* start = ReadAddress(PreparseDataConstants::kMessageTextPos);
- return ReadString(start, NULL);
+unsigned ParseData::Magic() {
+ return Data()[PreparseDataConstants::kMagicOffset];
}
-const char* ScriptData::BuildArg() const {
- int arg_count = Read(PreparseDataConstants::kMessageArgCountPos);
- ASSERT(arg_count == 0 || arg_count == 1);
- if (arg_count == 0) {
- return NULL;
- }
- // Position after text found by skipping past length field and
- // length field content words.
- int pos = PreparseDataConstants::kMessageTextPos + 1
- + Read(PreparseDataConstants::kMessageTextPos);
- int count = 0;
- return ReadString(ReadAddress(pos), &count);
+unsigned ParseData::Version() {
+ return Data()[PreparseDataConstants::kVersionOffset];
}
-unsigned ScriptData::Read(int position) const {
- return store_[PreparseDataConstants::kHeaderSize + position];
+int ParseData::FunctionsSize() {
+ return static_cast<int>(Data()[PreparseDataConstants::kFunctionsSizeOffset]);
}
-unsigned* ScriptData::ReadAddress(int position) const {
- return &store_[PreparseDataConstants::kHeaderSize + position];
+void Parser::SetCachedData() {
+ if (cached_data_mode() == NO_CACHED_DATA) {
+ cached_parse_data_ = NULL;
+ } else {
+ ASSERT(info_->cached_data() != NULL);
+ if (cached_data_mode() == CONSUME_CACHED_DATA) {
+ cached_parse_data_ = new ParseData(*info_->cached_data());
+ }
+ }
}
Parser::Parser(CompilationInfo* info)
: ParserBase<ParserTraits>(&scanner_,
info->isolate()->stack_guard()->real_climit(),
- info->extension(),
- NULL,
- info->zone(),
- this),
+ info->extension(), NULL, info->zone(), this),
isolate_(info->isolate()),
script_(info->script()),
scanner_(isolate_->unicode_cache()),
reusable_preparser_(NULL),
original_scope_(NULL),
target_stack_(NULL),
- cached_data_(NULL),
- cached_data_mode_(NO_CACHED_DATA),
+ cached_parse_data_(NULL),
ast_value_factory_(NULL),
info_(info),
has_pending_error_(false),
// Initialize parser state.
CompleteParserRecorder recorder;
- if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
+ if (cached_data_mode() == PRODUCE_CACHED_DATA) {
log_ = &recorder;
- } else if (cached_data_mode_ == CONSUME_CACHED_DATA) {
- (*cached_data_)->Initialize();
+ } else if (cached_data_mode() == CONSUME_CACHED_DATA) {
+ cached_parse_data_->Initialize();
}
source = String::Flatten(source);
}
PrintF(" - took %0.3f ms]\n", ms);
}
- if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
- if (result != NULL) {
- Vector<unsigned> store = recorder.ExtractData();
- *cached_data_ = new ScriptData(store);
- }
+ if (cached_data_mode() == PRODUCE_CACHED_DATA) {
+ if (result != NULL) *info_->cached_data() = recorder.GetScriptData();
log_ = NULL;
}
return result;
}
-void Parser::ReportInvalidCachedData(const AstRawString* name, bool* ok) {
- ParserTraits::ReportMessage("invalid_cached_data_function", name);
- *ok = false;
-}
-
-
bool CompileTimeValue::IsCompileTimeValue(Expression* expression) {
if (expression->IsLiteral()) return true;
MaterializedLiteral* lit = expression->AsMaterializedLiteral();
int* expected_property_count,
bool* ok) {
int function_block_pos = position();
- if (cached_data_mode_ == CONSUME_CACHED_DATA) {
+ 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.
FunctionEntry 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 to check.
- ReportInvalidCachedData(function_name, ok);
- if (!*ok) {
- return;
- }
- }
- scanner()->SeekForward(entry.end_pos() - 1);
-
- scope_->set_end_position(entry.end_pos());
- Expect(Token::RBRACE, ok);
- if (!*ok) {
- return;
- }
- isolate()->counters()->total_preparse_skipped()->Increment(
- scope_->end_position() - function_block_pos);
- *materialized_literal_count = entry.literal_count();
- *expected_property_count = entry.property_count();
- scope_->SetStrictMode(entry.strict_mode());
- } else {
- // This case happens when we have preparse data but it doesn't contain an
- // entry for the function. Fail the compilation.
- ReportInvalidCachedData(function_name, ok);
+ cached_parse_data_->GetFunctionEntry(function_block_pos);
+ // Check that cached data is valid.
+ CHECK(entry.is_valid());
+ // End position greater than end of stream is safe, and hard to check.
+ CHECK(entry.end_pos() > function_block_pos);
+ scanner()->SeekForward(entry.end_pos() - 1);
+
+ scope_->set_end_position(entry.end_pos());
+ Expect(Token::RBRACE, ok);
+ if (!*ok) {
return;
}
+ isolate()->counters()->total_preparse_skipped()->Increment(
+ scope_->end_position() - function_block_pos);
+ *materialized_literal_count = entry.literal_count();
+ *expected_property_count = entry.property_count();
+ scope_->SetStrictMode(entry.strict_mode());
} else {
// With no cached data, we partially parse the function, without building an
// AST. This gathers the data needed to build a lazy function.
*materialized_literal_count = logger.literals();
*expected_property_count = logger.properties();
scope_->SetStrictMode(logger.strict_mode());
- if (cached_data_mode_ == PRODUCE_CACHED_DATA) {
+ if (cached_data_mode() == PRODUCE_CACHED_DATA) {
ASSERT(log_);
// Position right after terminal '}'.
int body_end = scanner()->location().end_pos;
// ----------------------------------------------------------------------------
// The Parser interface.
-ScriptData::~ScriptData() {
- if (owns_store_) store_.Dispose();
-}
-
-
-int ScriptData::Length() {
- return store_.length() * sizeof(unsigned);
-}
-
-
-const char* ScriptData::Data() {
- return reinterpret_cast<const char*>(store_.start());
-}
-
-
-bool ScriptData::HasError() {
- return has_error();
-}
-
-
-void ScriptData::Initialize() {
- // Prepares state for use.
- 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 {
- // Partial preparse causes no symbol information.
- symbol_data_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
- }
- symbol_data_end_ = reinterpret_cast<byte*>(&store_[0] + store_.length());
- }
-}
-
-
-int ScriptData::ReadNumber(byte** source) {
- // Reads a number from symbol_data_ in base 128. The most significant
- // bit marks that there are more digits.
- // If the first byte is 0x80 (kNumberTerminator), it would normally
- // represent a leading zero. Since that is useless, and therefore won't
- // appear as the first digit of any actual value, it is used to
- // mark the end of the input stream.
- byte* data = *source;
- if (data >= symbol_data_end_) return -1;
- byte input = *data;
- if (input == PreparseDataConstants::kNumberTerminator) {
- // End of stream marker.
- return -1;
- }
- int result = input & 0x7f;
- data++;
- while ((input & 0x80u) != 0) {
- if (data >= symbol_data_end_) return -1;
- input = *data;
- result = (result << 7) | (input & 0x7f);
- data++;
- }
- *source = data;
- return result;
-}
-
-
bool RegExpParser::ParseRegExp(FlatStringReader* input,
bool multiline,
RegExpCompileData* result,
result = ParseProgram();
}
} else {
- SetCachedData(info()->cached_data(), info()->cached_data_mode());
+ SetCachedData();
result = ParseProgram();
}
info()->SetFunction(result);
};
-class ScriptData {
+// Wrapper around ScriptData to provide parser-specific functionality.
+class ParseData {
public:
- explicit ScriptData(Vector<unsigned> store)
- : store_(store),
- owns_store_(true) { }
-
- ScriptData(Vector<unsigned> store, bool owns_store)
- : store_(store),
- owns_store_(owns_store) { }
-
- // The created ScriptData won't take ownership of the data. If the alignment
- // is not correct, this will copy the data (and the created ScriptData will
- // take ownership of the copy).
- static ScriptData* New(const char* data, int length, bool owns_store = false);
-
- virtual ~ScriptData();
- virtual int Length();
- virtual const char* Data();
- virtual bool HasError();
-
+ explicit ParseData(ScriptData* script_data) : script_data_(script_data) {
+ CHECK(IsAligned(script_data->length(), sizeof(unsigned)));
+ CHECK(IsSane());
+ }
void Initialize();
- void ReadNextSymbolPosition();
-
FunctionEntry GetFunctionEntry(int start);
- int GetSymbolIdentifier();
- bool SanityCheck();
-
- Scanner::Location MessageLocation() const;
- bool IsReferenceError() const;
- const char* BuildMessage() const;
- const char* BuildArg() const;
-
- int function_count() {
- int functions_size =
- static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
- if (functions_size < 0) return 0;
- if (functions_size % FunctionEntry::kSize != 0) return 0;
- return functions_size / FunctionEntry::kSize;
+ int FunctionCount();
+
+ bool HasError();
+
+ unsigned* Data() { // Writable data as unsigned int array.
+ return reinterpret_cast<unsigned*>(const_cast<byte*>(script_data_->data()));
}
- // The following functions should only be called if SanityCheck has
- // returned true.
- bool has_error() { return store_[PreparseDataConstants::kHasErrorOffset]; }
- unsigned magic() { return store_[PreparseDataConstants::kMagicOffset]; }
- unsigned version() { return store_[PreparseDataConstants::kVersionOffset]; }
private:
- // Disable copying and assigning; because of owns_store they won't be correct.
- ScriptData(const ScriptData&);
- ScriptData& operator=(const ScriptData&);
-
- friend class v8::ScriptCompiler;
- Vector<unsigned> store_;
- unsigned char* symbol_data_;
- unsigned char* symbol_data_end_;
- int function_index_;
- bool owns_store_;
+ bool IsSane();
+ unsigned Magic();
+ unsigned Version();
+ int FunctionsSize();
+ int Length() const {
+ // Script data length is already checked to be a multiple of unsigned size.
+ return script_data_->length() / sizeof(unsigned);
+ }
- unsigned Read(int position) const;
- unsigned* ReadAddress(int position) const;
- // Reads a number from the current symbols
- int ReadNumber(byte** source);
+ ScriptData* script_data_;
+ int function_index_;
- // Read strings written by ParserRecorder::WriteString.
- static const char* ReadString(unsigned* start, int* chars);
+ DISALLOW_COPY_AND_ASSIGN(ParseData);
};
-
// ----------------------------------------------------------------------------
// REGEXP PARSING
FunctionLiteral* DoParseProgram(CompilationInfo* info,
Handle<String> source);
- // Report syntax error
- void ReportInvalidCachedData(const AstRawString* name, bool* ok);
-
- void SetCachedData(ScriptData** 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;
- }
- }
+ void SetCachedData();
bool inside_with() const { return scope_->inside_with(); }
- ScriptData** cached_data() const { return cached_data_; }
- CachedDataMode cached_data_mode() const { return cached_data_mode_; }
+ CachedDataMode cached_data_mode() const { return info_->cached_data_mode(); }
Scope* DeclarationScope(VariableMode mode) {
return IsLexicalVariableMode(mode)
? scope_ : scope_->DeclarationScope();
PreParser* reusable_preparser_;
Scope* original_scope_; // for ES5 function declarations in sloppy eval
Target* target_stack_; // for break, continue statements
- ScriptData** cached_data_;
+ ParseData* cached_parse_data_;
CachedDataMode cached_data_mode_;
AstValueFactory* ast_value_factory_;
#include "include/v8stdint.h"
#include "src/base/logging.h"
+#include "src/compiler.h"
#include "src/globals.h"
#include "src/hashmap.h"
#include "src/preparse-data.h"
const char* message,
const char* arg_opt,
bool is_reference_error) {
- if (has_error()) return;
+ if (HasError()) return;
preamble_[PreparseDataConstants::kHasErrorOffset] = true;
function_store_.Reset();
STATIC_ASSERT(PreparseDataConstants::kMessageStartPos == 0);
}
-Vector<unsigned> CompleteParserRecorder::ExtractData() {
+ScriptData* CompleteParserRecorder::GetScriptData() {
int function_size = function_store_.size();
int total_size = PreparseDataConstants::kHeaderSize + function_size;
- Vector<unsigned> data = Vector<unsigned>::New(total_size);
+ unsigned* data = NewArray<unsigned>(total_size);
preamble_[PreparseDataConstants::kFunctionsSizeOffset] = function_size;
- MemCopy(data.start(), preamble_, sizeof(preamble_));
+ MemCopy(data, preamble_, sizeof(preamble_));
if (function_size > 0) {
- function_store_.WriteTo(data.SubVector(PreparseDataConstants::kHeaderSize,
- total_size));
+ function_store_.WriteTo(Vector<unsigned>(
+ data + PreparseDataConstants::kHeaderSize, function_size));
}
- return data;
+ ASSERT(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
+ ScriptData* result = new ScriptData(reinterpret_cast<byte*>(data),
+ total_size * sizeof(unsigned));
+ result->AcquireDataOwnership();
+ return result;
}
namespace v8 {
namespace internal {
+class ScriptData;
+
// Abstract interface for preparse data recorder.
class ParserRecorder {
const char* message,
const char* argument_opt,
bool is_reference_error_);
- Vector<unsigned> ExtractData();
+ ScriptData* GetScriptData();
- private:
- bool has_error() {
+ bool HasError() {
return static_cast<bool>(preamble_[PreparseDataConstants::kHasErrorOffset]);
}
+ Vector<unsigned> ErrorMessageData() {
+ ASSERT(HasError());
+ return function_store_.ToVector();
+ }
+ private:
void WriteString(Vector<const char> str);
// Write a non-negative number to the symbol store.
}
-void Serializer::PadByte() { sink_->Put(kNop, "Padding"); }
-
-
void Serializer::Pad() {
// The non-branching GetInt will read up to 3 bytes too far, so we need
// to pad the snapshot to make sure we don't read over the end.
- for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) PadByte();
+ for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) {
+ sink_->Put(kNop, "Padding");
+ }
}
ScriptData* CodeSerializer::Serialize(Handle<SharedFunctionInfo> info) {
// Serialize code object.
- List<char> payload;
- ListSnapshotSink listsink(&payload);
- CodeSerializer ser(info->GetIsolate(), &listsink);
+ List<byte> payload;
+ ListSnapshotSink list_sink(&payload);
+ CodeSerializer cs(info->GetIsolate(), &list_sink);
DisallowHeapAllocation no_gc;
Object** location = Handle<Object>::cast(info).location();
- ser.VisitPointer(location);
- ser.Pad();
-
- // Allocate storage. The payload length may not be aligned. Round up.
- // TODO(yangguo) replace ScriptData with a more generic super class.
- int payload_length = payload.length();
- int raw_length = payload_length / sizeof(unsigned) + kHeaderSize;
- if (!IsAligned(payload_length, sizeof(unsigned))) raw_length++;
- unsigned* raw_data = i::NewArray<unsigned>(raw_length);
- char* payload_data = reinterpret_cast<char*>(raw_data + kHeaderSize);
-
- // Write header.
- raw_data[kVersionHashOffset] = Version::Hash();
- raw_data[kPayloadLengthOffset] = payload_length;
- STATIC_ASSERT(NEW_SPACE == 0);
- for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
- raw_data[kReservationsOffset + i] = ser.CurrentAllocationAddress(i);
- }
+ cs.VisitPointer(location);
+ cs.Pad();
- CopyBytes(payload_data, payload.begin(), static_cast<size_t>(payload_length));
-
- return new ScriptData(Vector<unsigned>(raw_data, raw_length), true);
+ SerializedCodeData data(&payload, &cs);
+ return data.GetScriptData();
}
Object* CodeSerializer::Deserialize(Isolate* isolate, ScriptData* data) {
- const unsigned* raw_data = reinterpret_cast<const unsigned*>(data->Data());
- CHECK_EQ(Version::Hash(), raw_data[kVersionHashOffset]);
- int payload_length = raw_data[kPayloadLengthOffset];
- const byte* payload_data =
- reinterpret_cast<const byte*>(raw_data + kHeaderSize);
- ASSERT_LE(payload_length, data->Length() - kHeaderSize);
-
- SnapshotByteSource payload(payload_data, payload_length);
+ SerializedCodeData scd(data);
+ SnapshotByteSource payload(scd.Payload(), scd.PayloadLength());
Deserializer deserializer(&payload);
STATIC_ASSERT(NEW_SPACE == 0);
// TODO(yangguo) what happens if remaining new space is too small?
for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
- deserializer.set_reservation(
- i, raw_data[CodeSerializer::kReservationsOffset + i]);
+ deserializer.set_reservation(i, scd.GetReservation(i));
}
Object* root;
deserializer.DeserializePartial(isolate, &root);
ASSERT(root->IsSharedFunctionInfo());
return root;
}
+
+
+SerializedCodeData::SerializedCodeData(List<byte>* payload, CodeSerializer* cs)
+ : owns_script_data_(true) {
+ int data_length = payload->length() + kHeaderEntries * kIntSize;
+ byte* data = NewArray<byte>(data_length);
+ ASSERT(IsAligned(reinterpret_cast<intptr_t>(data), kPointerAlignment));
+ CopyBytes(data + kHeaderEntries * kIntSize, payload->begin(),
+ static_cast<size_t>(payload->length()));
+ script_data_ = new ScriptData(data, data_length);
+ script_data_->AcquireDataOwnership();
+ SetHeaderValue(kVersionHashOffset, Version::Hash());
+ STATIC_ASSERT(NEW_SPACE == 0);
+ for (int i = NEW_SPACE; i <= PROPERTY_CELL_SPACE; i++) {
+ SetHeaderValue(kReservationsOffset + i, cs->CurrentAllocationAddress(i));
+ }
+}
+
+
+bool SerializedCodeData::IsSane() {
+ return GetHeaderValue(kVersionHashOffset) == Version::Hash() &&
+ PayloadLength() >= SharedFunctionInfo::kSize;
+}
} } // namespace v8::internal
#ifndef V8_SERIALIZE_H_
#define V8_SERIALIZE_H_
+#include "src/compiler.h"
#include "src/hashmap.h"
#include "src/heap-profiler.h"
#include "src/isolate.h"
-#include "src/parser.h"
#include "src/snapshot-source-sink.h"
namespace v8 {
SerializationAddressMapper address_mapper_;
intptr_t root_index_wave_front_;
void Pad();
- void PadByte();
friend class ObjectSerializer;
friend class Deserializer;
static const int kPayloadLengthOffset = 1;
static const int kReservationsOffset = 2;
};
+
+
+// Wrapper around ScriptData to provide code-serializer-specific functionality.
+class SerializedCodeData {
+ public:
+ // Used by when consuming.
+ explicit SerializedCodeData(ScriptData* data)
+ : script_data_(data), owns_script_data_(false) {
+ CHECK(IsSane());
+ }
+
+ // Used when producing.
+ SerializedCodeData(List<byte>* payload, CodeSerializer* cs);
+
+ ~SerializedCodeData() {
+ if (owns_script_data_) delete script_data_;
+ }
+
+ // Return ScriptData object and relinquish ownership over it to the caller.
+ ScriptData* GetScriptData() {
+ ScriptData* result = script_data_;
+ script_data_ = NULL;
+ ASSERT(owns_script_data_);
+ owns_script_data_ = false;
+ return result;
+ }
+
+ const byte* Payload() const {
+ return script_data_->data() + kHeaderEntries * kIntSize;
+ }
+
+ int PayloadLength() const {
+ return script_data_->length() - kHeaderEntries * kIntSize;
+ }
+
+ int GetReservation(int space) const {
+ return GetHeaderValue(kReservationsOffset + space);
+ }
+
+ private:
+ void SetHeaderValue(int offset, int value) {
+ reinterpret_cast<int*>(const_cast<byte*>(script_data_->data()))[offset] =
+ value;
+ }
+
+ int GetHeaderValue(int offset) const {
+ return reinterpret_cast<const int*>(script_data_->data())[offset];
+ }
+
+ bool IsSane();
+
+ // The data header consists of int-sized entries:
+ // [0] version hash
+ // [1..7] reservation sizes for spaces from NEW_SPACE to PROPERTY_CELL_SPACE.
+ static const int kVersionHashOffset = 0;
+ static const int kReservationsOffset = 1;
+ static const int kHeaderEntries = 8;
+
+ ScriptData* script_data_;
+ bool owns_script_data_;
+};
} } // namespace v8::internal
#endif // V8_SERIALIZE_H_
}
-void DebugSnapshotSink::Put(int byte, const char* description) {
- PrintF("%24s: %x\n", description, byte);
- sink_->Put(byte, description);
+void DebugSnapshotSink::Put(byte b, const char* description) {
+ PrintF("%24s: %x\n", description, b);
+ sink_->Put(b, description);
}
} // namespace v8::internal
class SnapshotByteSink {
public:
virtual ~SnapshotByteSink() { }
- virtual void Put(int byte, const char* description) = 0;
- virtual void PutSection(int byte, const char* description) {
- Put(byte, description);
+ virtual void Put(byte b, const char* description) = 0;
+ virtual void PutSection(int b, const char* description) {
+ ASSERT_LE(b, kMaxUInt8);
+ Put(static_cast<byte>(b), description);
}
void PutInt(uintptr_t integer, const char* description);
void PutRaw(byte* data, int number_of_bytes, const char* description);
public:
DummySnapshotSink() : length_(0) {}
virtual ~DummySnapshotSink() {}
- virtual void Put(int byte, const char* description) { length_++; }
+ virtual void Put(byte b, const char* description) { length_++; }
virtual int Position() { return length_; }
private:
class DebugSnapshotSink : public SnapshotByteSink {
public:
explicit DebugSnapshotSink(SnapshotByteSink* chained) : sink_(chained) {}
- virtual void Put(int byte, const char* description) V8_OVERRIDE;
+ virtual void Put(byte b, const char* description) V8_OVERRIDE;
virtual int Position() V8_OVERRIDE { return sink_->Position(); }
private:
class ListSnapshotSink : public i::SnapshotByteSink {
public:
- explicit ListSnapshotSink(i::List<char>* data) : data_(data) {}
- virtual void Put(int byte, const char* description) V8_OVERRIDE {
- data_->Add(byte);
+ explicit ListSnapshotSink(i::List<byte>* data) : data_(data) {}
+ virtual void Put(byte b, const char* description) V8_OVERRIDE {
+ data_->Add(b);
}
virtual int Position() V8_OVERRIDE { return data_->length(); }
private:
- i::List<char>* data_;
+ i::List<byte>* data_;
};
} // namespace v8::internal
v8::ScriptCompiler::kProduceDataToCache);
// Serialize.
const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
- char* serialized_data = i::NewArray<char>(cd->length);
+ i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
i::MemCopy(serialized_data, cd->data, cd->length);
// Deserialize.
- i::ScriptData* deserialized = i::ScriptData::New(serialized_data, cd->length);
+ i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
// Verify that the original is the same as the deserialized.
- CHECK_EQ(cd->length, deserialized->Length());
- CHECK_EQ(0, memcmp(cd->data, deserialized->Data(), cd->length));
+ CHECK_EQ(cd->length, deserialized->length());
+ CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
delete deserialized;
i::DeleteArray(serialized_data);
}
-// Attempts to deserialize bad data.
-TEST(PreCompileDeserializationError) {
- v8::V8::Initialize();
- const char* data = "DONT CARE";
- int invalid_size = 3;
- i::ScriptData* sd = i::ScriptData::New(data, invalid_size);
- CHECK_EQ(NULL, sd);
-}
-
-
-TEST(CompileWithInvalidCachedData) {
- v8::V8::Initialize();
- v8::Isolate* isolate = CcTest::isolate();
- LocalContext context;
- v8::HandleScope scope(context->GetIsolate());
- i::FLAG_min_preparse_length = 0;
-
- const char* script = "function foo(){ return 5;}\n"
- "function bar(){ return 6 + 7;} foo();";
- v8::ScriptCompiler::Source source(v8_str(script));
- v8::ScriptCompiler::Compile(isolate, &source,
- v8::ScriptCompiler::kProduceDataToCache);
- // source owns its cached data. Create a ScriptData based on it. The user
- // never needs to create ScriptDatas any more; we only need it here because we
- // want to modify the data before passing it back.
- const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
- // ScriptData does not take ownership of the buffers passed to it.
- i::ScriptData* sd =
- i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
- CHECK(!sd->HasError());
- // ScriptData private implementation details
- const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
- const int kFunctionEntrySize = i::FunctionEntry::kSize;
- const int kFunctionEntryStartOffset = 0;
- const int kFunctionEntryEndOffset = 1;
- unsigned* sd_data =
- reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
-
- // Overwrite function bar's end position with 0.
- sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
- v8::TryCatch try_catch;
-
- // Make the script slightly different so that we don't hit the compilation
- // cache. Don't change the lenghts of tokens.
- const char* script2 = "function foo(){ return 6;}\n"
- "function bar(){ return 6 + 7;} foo();";
- v8::ScriptCompiler::Source source2(
- v8_str(script2),
- // CachedData doesn't take ownership of the buffers, Source takes
- // ownership of CachedData.
- new v8::ScriptCompiler::CachedData(
- reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
- Local<v8::UnboundScript> compiled_script =
- v8::ScriptCompiler::CompileUnbound(isolate, &source2);
-
- CHECK(try_catch.HasCaught());
- {
- String::Utf8Value exception_value(try_catch.Message()->Get());
- CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
- *exception_value);
- }
-
- try_catch.Reset();
- delete sd;
-
- // Overwrite function bar's start position with 200. The function entry will
- // not be found when searching for it by position, and the compilation fails.
-
- // ScriptData does not take ownership of the buffers passed to it.
- sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
- sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
- sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
- 200;
- const char* script3 = "function foo(){ return 7;}\n"
- "function bar(){ return 6 + 7;} foo();";
- v8::ScriptCompiler::Source source3(
- v8_str(script3),
- new v8::ScriptCompiler::CachedData(
- reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
- compiled_script =
- v8::ScriptCompiler::CompileUnbound(isolate, &source3);
- CHECK(try_catch.HasCaught());
- {
- String::Utf8Value exception_value(try_catch.Message()->Get());
- CHECK_EQ("Uncaught SyntaxError: Invalid cached data for function bar",
- *exception_value);
- }
- CHECK(compiled_script.IsEmpty());
- try_catch.Reset();
- delete sd;
-
- // Try passing in cached data which is obviously invalid (wrong length).
- sd = i::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
- const char* script4 =
- "function foo(){ return 8;}\n"
- "function bar(){ return 6 + 7;} foo();";
- v8::ScriptCompiler::Source source4(
- v8_str(script4),
- new v8::ScriptCompiler::CachedData(
- reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length() - 1));
- compiled_script =
- v8::ScriptCompiler::CompileUnbound(isolate, &source4);
- CHECK(try_catch.HasCaught());
- {
- String::Utf8Value exception_value(try_catch.Message()->Get());
- CHECK_EQ("Uncaught SyntaxError: Invalid cached data",
- *exception_value);
- }
- CHECK(compiled_script.IsEmpty());
- delete sd;
-}
-
-
// This tests that we do not allow dictionary load/call inline caches
// to use functions that have not yet been compiled. The potential
// problem of loading a function that has not yet been compiled can
preparser.set_allow_lazy(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
- i::ScriptData data(log.ExtractData());
- CHECK(!data.has_error());
+ CHECK(!log.HasError());
}
for (int i = 0; fail_tests[i]; i++) {
i::PreParser::PreParseResult result = preparser.PreParseProgram();
// Even in the case of a syntax error, kPreParseSuccess is returned.
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
- i::ScriptData data(log.ExtractData());
- CHECK(data.has_error());
+ CHECK(log.HasError());
}
}
preparser.set_allow_natives_syntax(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
- i::ScriptData data(log.ExtractData());
- CHECK(!data.has_error());
+ CHECK(!log.HasError());
}
}
preparser.set_allow_lazy(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
- i::ScriptData data(log.ExtractData());
- // Data contains syntax error.
- CHECK(data.has_error());
+ CHECK(log.HasError());
}
}
i::PreParser::PreParseResult result = preparser.PreParseProgram();
// Even in the case of a syntax error, kPreParseSuccess is returned.
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
- i::ScriptData data(log.ExtractData());
- CHECK(data.has_error());
+ CHECK(log.HasError());
}
preparser.set_allow_lazy(true);
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
- i::ScriptData data(log.ExtractData());
- CHECK(!data.has_error());
- data.Initialize();
+ i::ScriptData* sd = log.GetScriptData();
+ i::ParseData pd(sd);
+ pd.Initialize();
int first_function =
static_cast<int>(strstr(program, "function") - program);
int first_lbrace = first_function + i::StrLength("function () ");
CHECK_EQ('{', program[first_lbrace]);
- i::FunctionEntry entry1 = data.GetFunctionEntry(first_lbrace);
+ i::FunctionEntry entry1 = pd.GetFunctionEntry(first_lbrace);
CHECK(!entry1.is_valid());
int second_function =
int second_lbrace =
second_function + i::StrLength("function () ");
CHECK_EQ('{', program[second_lbrace]);
- i::FunctionEntry entry2 = data.GetFunctionEntry(second_lbrace);
+ i::FunctionEntry entry2 = pd.GetFunctionEntry(second_lbrace);
CHECK(entry2.is_valid());
CHECK_EQ('}', program[entry2.end_pos() - 1]);
+ delete sd;
}
}
-i::Handle<i::String> FormatMessage(i::ScriptData* data) {
+const char* ReadString(unsigned* start) {
+ int length = start[0];
+ char* result = i::NewArray<char>(length + 1);
+ for (int i = 0; i < length; i++) {
+ result[i] = start[i + 1];
+ }
+ result[length] = '\0';
+ return result;
+}
+
+
+i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) {
i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory();
- const char* message = data->BuildMessage();
+ const char* message =
+ ReadString(&data[i::PreparseDataConstants::kMessageTextPos]);
i::Handle<i::String> format = v8::Utils::OpenHandle(
*v8::String::NewFromUtf8(CcTest::isolate(), message));
- const char* arg = data->BuildArg();
- i::Handle<i::JSArray> args_array = factory->NewJSArray(arg == NULL ? 0 : 1);
- if (arg != NULL) {
- i::JSArray::SetElement(
- args_array, 0, v8::Utils::OpenHandle(*v8::String::NewFromUtf8(
- CcTest::isolate(), arg)),
- NONE, i::SLOPPY).Check();
+ int arg_count = data[i::PreparseDataConstants::kMessageArgCountPos];
+ const char* arg = NULL;
+ i::Handle<i::JSArray> args_array;
+ if (arg_count == 1) {
+ // Position after text found by skipping past length field and
+ // length field content words.
+ int pos = i::PreparseDataConstants::kMessageTextPos + 1 +
+ data[i::PreparseDataConstants::kMessageTextPos];
+ arg = ReadString(&data[pos]);
+ args_array = factory->NewJSArray(1);
+ i::JSArray::SetElement(args_array, 0, v8::Utils::OpenHandle(*v8_str(arg)),
+ NONE, i::SLOPPY).Check();
+ } else {
+ CHECK_EQ(0, arg_count);
+ args_array = factory->NewJSArray(0);
}
+
i::Handle<i::JSObject> builtins(isolate->js_builtins_object());
i::Handle<i::Object> format_fun = i::Object::GetProperty(
isolate, builtins, "FormatMessage").ToHandleChecked();
CHECK(result->IsString());
i::DeleteArray(message);
i::DeleteArray(arg);
+ data.Dispose();
return i::Handle<i::String>::cast(result);
}
i::PreParser::PreParseResult result = preparser.PreParseProgram();
CHECK_EQ(i::PreParser::kPreParseSuccess, result);
}
- i::ScriptData data(log.ExtractData());
+
+ bool preparse_error = log.HasError();
// Parse the data
i::FunctionLiteral* function;
CHECK(false);
}
- if (!data.has_error()) {
+ if (!preparse_error) {
v8::base::OS::Print(
"Parser failed on:\n"
"\t%s\n"
CHECK(false);
}
// Check that preparser and parser produce the same error.
- i::Handle<i::String> preparser_message = FormatMessage(&data);
+ i::Handle<i::String> preparser_message =
+ FormatMessage(log.ErrorMessageData());
if (!i::String::Equals(message_string, preparser_message)) {
v8::base::OS::Print(
"Expected parser and preparser to produce the same error on:\n"
preparser_message->ToCString().get());
CHECK(false);
}
- } else if (data.has_error()) {
+ } else if (preparse_error) {
v8::base::OS::Print(
"Preparser failed on:\n"
"\t%s\n"
"with error:\n"
"\t%s\n"
"However, the parser succeeded",
- source->ToCString().get(), FormatMessage(&data)->ToCString().get());
+ source->ToCString().get(), FormatMessage(log.ErrorMessageData()));
CHECK(false);
} else if (result == kError) {
v8::base::OS::Print(
factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked();
i::Handle<i::Script> script = factory->NewScript(source);
i::CompilationInfoWithZone info(script);
- i::ScriptData* data = NULL;
- info.SetCachedData(&data, i::PRODUCE_CACHED_DATA);
+ i::ScriptData* sd = NULL;
+ info.SetCachedData(&sd, i::PRODUCE_CACHED_DATA);
i::Parser::Parse(&info, true);
- CHECK(data);
- CHECK(!data->HasError());
+ i::ParseData pd(sd);
- if (data->function_count() != test_cases[i].functions) {
+ if (pd.FunctionCount() != test_cases[i].functions) {
v8::base::OS::Print(
"Expected preparse data for program:\n"
"\t%s\n"
"to contain %d functions, however, received %d functions.\n",
- program, test_cases[i].functions,
- data->function_count());
+ program, test_cases[i].functions, pd.FunctionCount());
CHECK(false);
}
- delete data;
+ delete sd;
}
}
fclose(fp_);
}
}
- virtual void Put(int byte, const char* description) {
+ virtual void Put(byte b, const char* description) {
if (fp_ != NULL) {
- fputc(byte, fp_);
+ fputc(b, fp_);
}
}
virtual int Position() {