summaryrefslogtreecommitdiffstats
path: root/preparser
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-11-30 15:57:28 +0000
committerBen Murdoch <benm@google.com>2011-12-02 17:27:08 +0000
commit257744e915dfc84d6d07a6b2accf8402d9ffc708 (patch)
tree19d8782d5686697f36b1771e7fcd46f290b82c3c /preparser
parent92022043ea907575278de828a5c9cf6939b51e5e (diff)
downloadandroid_external_v8-257744e915dfc84d6d07a6b2accf8402d9ffc708.tar.gz
android_external_v8-257744e915dfc84d6d07a6b2accf8402d9ffc708.tar.bz2
android_external_v8-257744e915dfc84d6d07a6b2accf8402d9ffc708.zip
Upgrade to V8 3.3
Merge V8 at 3.3.10.39 Simple merge required updates to makefiles only. Bug: 5688872 Change-Id: I14703f418235f5ce6013b9b3e2e502407a9f6dfd
Diffstat (limited to 'preparser')
-rw-r--r--preparser/preparser-process.cc300
1 files changed, 255 insertions, 45 deletions
diff --git a/preparser/preparser-process.cc b/preparser/preparser-process.cc
index fb6e3866..a19c66b7 100644
--- a/preparser/preparser-process.cc
+++ b/preparser/preparser-process.cc
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -28,23 +28,38 @@
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
+#include <string.h>
#include "../include/v8stdint.h"
#include "../include/v8-preparser.h"
+#include "../src/preparse-data-format.h"
+
+namespace i = v8::internal;
+
// This file is only used for testing the stand-alone preparser
// library.
-// The first (and only) argument must be the path of a JavaScript file.
-// This file is preparsed and the resulting preparser data is written
-// to stdout. Diagnostic output is output on stderr.
-// The file must contain only ASCII characters (UTF-8 isn't supported).
+// The first argument must be the path of a JavaScript source file, or
+// the flags "-e" and the next argument is then the source of a JavaScript
+// program.
+// Optionally this can be followed by the word "throws" (case sensitive),
+// which signals that the parsing is expected to throw - the default is
+// to expect the parsing to not throw.
+// The command line can further be followed by a message text (the
+// *type* of the exception to throw), and even more optionally, the
+// start and end position reported with the exception.
+//
+// This source file is preparsed and tested against the expectations, and if
+// successful, the resulting preparser data is written to stdout.
+// Diagnostic output is output on stderr.
+// The source file must contain only ASCII characters (UTF-8 isn't supported).
// The file is read into memory, so it should have a reasonable size.
// Adapts an ASCII string to the UnicodeInputStream interface.
class AsciiInputStream : public v8::UnicodeInputStream {
public:
- AsciiInputStream(uint8_t* buffer, size_t length)
+ AsciiInputStream(const uint8_t* buffer, size_t length)
: buffer_(buffer),
end_offset_(static_cast<int>(length)),
offset_(0) { }
@@ -97,73 +112,268 @@ bool WriteBuffer(FILE* dest, const void* buffer, size_t length) {
}
+class PreparseDataInterpreter {
+ public:
+ PreparseDataInterpreter(const uint8_t* data, int length)
+ : data_(data), length_(length), message_(NULL) { }
+
+ ~PreparseDataInterpreter() {
+ if (message_ != NULL) delete[] message_;
+ }
+
+ bool valid() {
+ int header_length =
+ i::PreparseDataConstants::kHeaderSize * sizeof(int); // NOLINT
+ return length_ >= header_length;
+ }
+
+ bool throws() {
+ return valid() &&
+ word(i::PreparseDataConstants::kHasErrorOffset) != 0;
+ }
+
+ const char* message() {
+ if (message_ != NULL) return message_;
+ if (!throws()) return NULL;
+ int text_pos = i::PreparseDataConstants::kHeaderSize +
+ i::PreparseDataConstants::kMessageTextPos;
+ int length = word(text_pos);
+ char* buffer = new char[length + 1];
+ for (int i = 1; i <= length; i++) {
+ int character = word(text_pos + i);
+ buffer[i - 1] = character;
+ }
+ buffer[length] = '\0';
+ message_ = buffer;
+ return buffer;
+ }
+
+ int beg_pos() {
+ if (!throws()) return -1;
+ return word(i::PreparseDataConstants::kHeaderSize +
+ i::PreparseDataConstants::kMessageStartPos);
+ }
+
+ int end_pos() {
+ if (!throws()) return -1;
+ return word(i::PreparseDataConstants::kHeaderSize +
+ i::PreparseDataConstants::kMessageEndPos);
+ }
+
+ private:
+ int word(int offset) {
+ const int* word_data = reinterpret_cast<const int*>(data_);
+ if (word_data + offset < reinterpret_cast<const int*>(data_ + length_)) {
+ return word_data[offset];
+ }
+ return -1;
+ }
+
+ const uint8_t* const data_;
+ const int length_;
+ const char* message_;
+};
+
+
template <typename T>
class ScopedPointer {
public:
+ explicit ScopedPointer() : pointer_(NULL) {}
explicit ScopedPointer(T* pointer) : pointer_(pointer) {}
- ~ScopedPointer() { delete[] pointer_; }
+ ~ScopedPointer() { if (pointer_ != NULL) delete[] pointer_; }
T& operator[](int index) { return pointer_[index]; }
T* operator*() { return pointer_ ;}
+ T* operator=(T* new_value) {
+ if (pointer_ != NULL) delete[] pointer_;
+ pointer_ = new_value;
+ return new_value;
+ }
private:
T* pointer_;
};
-int main(int argc, char* argv[]) {
- // Check for filename argument.
- if (argc < 2) {
- fprintf(stderr, "ERROR: No filename on command line.\n");
+
+void fail(v8::PreParserData* data, const char* message, ...) {
+ va_list args;
+ va_start(args, message);
+ vfprintf(stderr, message, args);
+ va_end(args);
+ fflush(stderr);
+ // Print preparser data to stdout.
+ uint32_t size = data->size();
+ fprintf(stderr, "LOG: data size: %u\n", size);
+ if (!WriteBuffer(stdout, data->data(), size)) {
+ perror("ERROR: Writing data");
fflush(stderr);
- return EXIT_FAILURE;
}
- const char* filename = argv[1];
+ exit(EXIT_FAILURE);
+};
- // Open JS file.
- FILE* input = fopen(filename, "rb");
- if (input == NULL) {
- perror("ERROR: Error opening file");
- fflush(stderr);
- return EXIT_FAILURE;
+
+bool IsFlag(const char* arg) {
+ // Anything starting with '-' is considered a flag.
+ // It's summarily ignored for now.
+ return arg[0] == '-';
+}
+
+
+struct ExceptionExpectation {
+ ExceptionExpectation()
+ : throws(false), type(NULL), beg_pos(-1), end_pos(-1) { }
+ bool throws;
+ const char* type;
+ int beg_pos;
+ int end_pos;
+};
+
+
+void CheckException(v8::PreParserData* data,
+ ExceptionExpectation* expects) {
+ PreparseDataInterpreter reader(data->data(), data->size());
+ if (expects->throws) {
+ if (!reader.throws()) {
+ if (expects->type == NULL) {
+ fail(data, "Didn't throw as expected\n");
+ } else {
+ fail(data, "Didn't throw \"%s\" as expected\n", expects->type);
+ }
+ }
+ if (expects->type != NULL) {
+ const char* actual_message = reader.message();
+ if (strcmp(expects->type, actual_message)) {
+ fail(data, "Wrong error message. Expected <%s>, found <%s> at %d..%d\n",
+ expects->type, actual_message, reader.beg_pos(), reader.end_pos());
+ }
+ }
+ if (expects->beg_pos >= 0) {
+ if (expects->beg_pos != reader.beg_pos()) {
+ fail(data, "Wrong error start position: Expected %i, found %i\n",
+ expects->beg_pos, reader.beg_pos());
+ }
+ }
+ if (expects->end_pos >= 0) {
+ if (expects->end_pos != reader.end_pos()) {
+ fail(data, "Wrong error end position: Expected %i, found %i\n",
+ expects->end_pos, reader.end_pos());
+ }
+ }
+ } else if (reader.throws()) {
+ const char* message = reader.message();
+ fail(data, "Throws unexpectedly with message: %s at location %d-%d\n",
+ message, reader.beg_pos(), reader.end_pos());
}
+}
- // Find length of JS file.
- if (fseek(input, 0, SEEK_END) != 0) {
- perror("ERROR: Error during seek");
- fflush(stderr);
- return EXIT_FAILURE;
+
+ExceptionExpectation ParseExpectation(int argc, const char* argv[]) {
+ ExceptionExpectation expects;
+
+ // Parse exception expectations from (the remainder of) the command line.
+ int arg_index = 0;
+ // Skip any flags.
+ while (argc > arg_index && IsFlag(argv[arg_index])) arg_index++;
+ if (argc > arg_index) {
+ if (strncmp("throws", argv[arg_index], 7)) {
+ // First argument after filename, if present, must be the verbatim
+ // "throws", marking that the preparsing should fail with an exception.
+ fail(NULL, "ERROR: Extra arguments not prefixed by \"throws\".\n");
+ }
+ expects.throws = true;
+ do {
+ arg_index++;
+ } while (argc > arg_index && IsFlag(argv[arg_index]));
+ if (argc > arg_index) {
+ // Next argument is the exception type identifier.
+ expects.type = argv[arg_index];
+ do {
+ arg_index++;
+ } while (argc > arg_index && IsFlag(argv[arg_index]));
+ if (argc > arg_index) {
+ expects.beg_pos = atoi(argv[arg_index]);
+ do {
+ arg_index++;
+ } while (argc > arg_index && IsFlag(argv[arg_index]));
+ if (argc > arg_index) {
+ expects.end_pos = atoi(argv[arg_index]);
+ }
+ }
+ }
}
- size_t length = static_cast<size_t>(ftell(input));
- rewind(input);
+ return expects;
+}
- // Read JS file into memory buffer.
- ScopedPointer<uint8_t> buffer(new uint8_t[length]);
- if (!ReadBuffer(input, *buffer, length)) {
- perror("ERROR: Reading file");
- fflush(stderr);
- return EXIT_FAILURE;
+
+int main(int argc, const char* argv[]) {
+ // Parse command line.
+ // Format: preparser (<scriptfile> | -e "<source>")
+ // ["throws" [<exn-type> [<start> [<end>]]]]
+ // Any flags (except an initial -s) are ignored.
+
+ // Check for mandatory filename argument.
+ int arg_index = 1;
+ if (argc <= arg_index) {
+ fail(NULL, "ERROR: No filename on command line.\n");
+ }
+ const uint8_t* source = NULL;
+ const char* filename = argv[arg_index];
+ if (!strcmp(filename, "-e")) {
+ arg_index++;
+ if (argc <= arg_index) {
+ fail(NULL, "ERROR: No source after -e on command line.\n");
+ }
+ source = reinterpret_cast<const uint8_t*>(argv[arg_index]);
+ }
+ // Check remainder of command line for exception expectations.
+ arg_index++;
+ ExceptionExpectation expects =
+ ParseExpectation(argc - arg_index, argv + arg_index);
+
+ ScopedPointer<uint8_t> buffer;
+ size_t length;
+
+ if (source == NULL) {
+ // Open JS file.
+ FILE* input = fopen(filename, "rb");
+ if (input == NULL) {
+ perror("ERROR: Error opening file");
+ fflush(stderr);
+ return EXIT_FAILURE;
+ }
+ // Find length of JS file.
+ if (fseek(input, 0, SEEK_END) != 0) {
+ perror("ERROR: Error during seek");
+ fflush(stderr);
+ return EXIT_FAILURE;
+ }
+ length = static_cast<size_t>(ftell(input));
+ rewind(input);
+ // Read JS file into memory buffer.
+ buffer = new uint8_t[length];
+ if (!ReadBuffer(input, *buffer, length)) {
+ perror("ERROR: Reading file");
+ fflush(stderr);
+ return EXIT_FAILURE;
+ }
+ fclose(input);
+ source = *buffer;
+ } else {
+ length = strlen(reinterpret_cast<const char*>(source));
}
- fclose(input);
// Preparse input file.
- AsciiInputStream input_buffer(*buffer, length);
+ AsciiInputStream input_buffer(source, length);
size_t kMaxStackSize = 64 * 1024 * sizeof(void*); // NOLINT
v8::PreParserData data = v8::Preparse(&input_buffer, kMaxStackSize);
// Fail if stack overflow.
if (data.stack_overflow()) {
- fprintf(stderr, "ERROR: Stack overflow\n");
- fflush(stderr);
- return EXIT_FAILURE;
+ fail(&data, "ERROR: Stack overflow\n");
}
- // Print preparser data to stdout.
- uint32_t size = data.size();
- fprintf(stderr, "LOG: Success, data size: %u\n", size);
- fflush(stderr);
- if (!WriteBuffer(stdout, data.data(), size)) {
- perror("ERROR: Writing data");
- return EXIT_FAILURE;
- }
+ // Check that the expected exception is thrown, if an exception is
+ // expected.
+ CheckException(&data, &expects);
return EXIT_SUCCESS;
}