summaryrefslogtreecommitdiff
path: root/deps/v8
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2010-11-30 11:34:27 -0800
committerRyan Dahl <ry@tinyclouds.org>2010-11-30 11:37:43 -0800
commit7286b7952150672cded846e5eee5c533e72f3e9e (patch)
treeca2402b34014b3ca916836eaf33156585501c466 /deps/v8
parent486c74e72bd015ac178f881806a1d36accdcecce (diff)
downloadnode-new-7286b7952150672cded846e5eee5c533e72f3e9e.tar.gz
Upgrade V8 to 2.5.9.1
Diffstat (limited to 'deps/v8')
-rw-r--r--deps/v8/AUTHORS1
-rw-r--r--deps/v8/ChangeLog25
-rw-r--r--deps/v8/include/v8.h5
-rw-r--r--deps/v8/preparser/preparser-process.cc227
-rw-r--r--deps/v8/samples/process.cc18
-rw-r--r--deps/v8/samples/shell.cc14
-rwxr-xr-xdeps/v8/src/SConscript2
-rw-r--r--deps/v8/src/api.cc9
-rw-r--r--deps/v8/src/arm/assembler-arm-inl.h6
-rw-r--r--deps/v8/src/arm/assembler-arm.cc25
-rw-r--r--deps/v8/src/arm/assembler-arm.h20
-rw-r--r--deps/v8/src/arm/builtins-arm.cc125
-rw-r--r--deps/v8/src/arm/codegen-arm.cc288
-rw-r--r--deps/v8/src/arm/codegen-arm.h8
-rw-r--r--deps/v8/src/arm/debug-arm.cc2
-rw-r--r--deps/v8/src/arm/ic-arm.cc79
-rw-r--r--deps/v8/src/arm/macro-assembler-arm.cc27
-rw-r--r--deps/v8/src/arm/macro-assembler-arm.h42
-rw-r--r--deps/v8/src/arm/stub-cache-arm.cc7
-rw-r--r--deps/v8/src/checks.cc1
-rw-r--r--deps/v8/src/checks.h34
-rw-r--r--deps/v8/src/conversions.cc6
-rw-r--r--deps/v8/src/dateparser-inl.h2
-rw-r--r--deps/v8/src/dateparser.h12
-rw-r--r--deps/v8/src/handles.cc2
-rw-r--r--deps/v8/src/hashmap.cc8
-rw-r--r--deps/v8/src/heap-profiler.cc10
-rw-r--r--deps/v8/src/ia32/macro-assembler-ia32.cc8
-rw-r--r--deps/v8/src/ia32/macro-assembler-ia32.h1
-rw-r--r--deps/v8/src/ia32/stub-cache-ia32.cc7
-rw-r--r--deps/v8/src/log.cc11
-rw-r--r--deps/v8/src/objects.cc3
-rw-r--r--deps/v8/src/parser.cc193
-rw-r--r--deps/v8/src/parser.h151
-rw-r--r--deps/v8/src/platform-freebsd.cc3
-rw-r--r--deps/v8/src/platform-linux.cc3
-rw-r--r--deps/v8/src/platform-macos.cc3
-rw-r--r--deps/v8/src/platform-openbsd.cc6
-rw-r--r--deps/v8/src/platform-solaris.cc3
-rw-r--r--deps/v8/src/platform-win32.cc3
-rw-r--r--deps/v8/src/platform.h17
-rw-r--r--deps/v8/src/preparse-data.cc180
-rw-r--r--deps/v8/src/preparse-data.h223
-rw-r--r--deps/v8/src/preparser.cc1184
-rw-r--r--deps/v8/src/preparser.h1188
-rw-r--r--deps/v8/src/profile-generator.cc23
-rw-r--r--deps/v8/src/profile-generator.h4
-rw-r--r--deps/v8/src/runtime.cc8
-rw-r--r--deps/v8/src/runtime.h2
-rw-r--r--deps/v8/src/string.js2
-rw-r--r--deps/v8/src/stub-cache.h2
-rw-r--r--deps/v8/src/token.cc3
-rw-r--r--deps/v8/src/v8.h2
-rw-r--r--deps/v8/src/v8checks.h64
-rw-r--r--deps/v8/src/version.cc4
-rw-r--r--deps/v8/src/x64/macro-assembler-x64.cc8
-rw-r--r--deps/v8/src/x64/macro-assembler-x64.h3
-rw-r--r--deps/v8/src/x64/stub-cache-x64.cc7
-rw-r--r--deps/v8/test/cctest/test-api.cc27
-rw-r--r--deps/v8/test/cctest/test-conversions.cc6
-rw-r--r--deps/v8/test/cctest/test-heap-profiler.cc15
-rw-r--r--deps/v8/test/cctest/test-log.cc42
-rwxr-xr-xdeps/v8/test/cctest/test-parsing.cc3
-rw-r--r--deps/v8/test/mjsunit/regress/regress-944.js46
-rw-r--r--deps/v8/test/mjsunit/string-split.js19
-rw-r--r--deps/v8/tools/gyp/v8.gyp7
-rwxr-xr-xdeps/v8/tools/presubmit.py2
-rw-r--r--deps/v8/tools/visual_studio/v8_base.vcproj32
68 files changed, 2767 insertions, 1756 deletions
diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS
index 68f9b63bab..3749cebcd1 100644
--- a/deps/v8/AUTHORS
+++ b/deps/v8/AUTHORS
@@ -9,7 +9,6 @@ ARM Ltd.
Hewlett-Packard Development Company, LP
Alexander Botero-Lowry <alexbl@FreeBSD.org>
-Alexandre Rames <alexandre.rames@arm.com>
Alexandre Vassalotti <avassalotti@gmail.com>
Andreas Anyuru <andreas.anyuru@gmail.com>
Burcu Dogan <burcujdogan@gmail.com>
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog
index 9f2005f40f..86e41e175b 100644
--- a/deps/v8/ChangeLog
+++ b/deps/v8/ChangeLog
@@ -1,3 +1,28 @@
+2010-11-29: Version 2.5.9
+
+ Fixed crashes during GC caused by partially initialize heap
+ objects.
+
+ Fixed bug in process sample that caused memory leaks.
+
+ Improved performance on ARM by implementing missing stubs and
+ inlining.
+
+ Improved heap profiler support.
+
+ Added separate seeding on Windows of the random number generator
+ used internally by the compiler (issue 936).
+
+ Exposed API for getting the name of the function used to construct
+ an object.
+
+ Fixed date parser to handle one and two digit millisecond
+ values (issue 944).
+
+ Fixed number parsing to disallow space between sign and
+ digits (issue 946).
+
+
2010-11-23: Version 2.5.8
Removed dependency on Gay's dtoa.
diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h
index 9baa17db1d..8ecf63aebd 100644
--- a/deps/v8/include/v8.h
+++ b/deps/v8/include/v8.h
@@ -1539,6 +1539,11 @@ class Object : public Value {
*/
V8EXPORT Local<String> ObjectProtoToString();
+ /**
+ * Returns the name of the function invoked as a constructor for this object.
+ */
+ V8EXPORT Local<String> GetConstructorName();
+
/** Gets the number of internal fields for this Object. */
V8EXPORT int InternalFieldCount();
/** Gets the value in an internal field. */
diff --git a/deps/v8/preparser/preparser-process.cc b/deps/v8/preparser/preparser-process.cc
new file mode 100644
index 0000000000..706a225969
--- /dev/null
+++ b/deps/v8/preparser/preparser-process.cc
@@ -0,0 +1,227 @@
+// 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 <stdarg.h>
+#include "../include/v8stdint.h"
+#include "globals.h"
+#include "checks.h"
+#include "allocation.h"
+#include "utils.h"
+#include "list.h"
+#include "smart-pointer.h"
+#include "scanner-base.h"
+#include "preparse-data.h"
+#include "preparser.h"
+
+enum ResultCode { kSuccess = 0, kErrorReading = 1, kErrorWriting = 2 };
+
+namespace v8 {
+namespace internal {
+
+// THIS FILE IS PROOF-OF-CONCEPT ONLY.
+// The final goal is a stand-alone preparser library.
+
+// UTF16Buffer based on an UTF-8 string in memory.
+class UTF8UTF16Buffer : public UTF16Buffer {
+ public:
+ UTF8UTF16Buffer(uint8_t* buffer, size_t length)
+ : UTF16Buffer(),
+ buffer_(buffer),
+ offset_(0),
+ end_offset_(static_cast<int>(length)) { }
+
+ virtual void PushBack(uc32 ch) {
+ // Pushback assumes that the character pushed back is the
+ // one that was most recently read, and jumps back in the
+ // UTF-8 stream by the length of that character's encoding.
+ offset_ -= unibrow::Utf8::Length(ch);
+ pos_--;
+#ifdef DEBUG
+ int tmp = 0;
+ ASSERT_EQ(ch, unibrow::Utf8::ValueOf(buffer_ + offset_,
+ end_offset_ - offset_,
+ &tmp);
+#endif
+ }
+
+ virtual uc32 Advance() {
+ if (offset_ == end_offset_) return -1;
+ uint8_t first_char = buffer_[offset_];
+ if (first_char <= unibrow::Utf8::kMaxOneByteChar) {
+ pos_++;
+ offset_++;
+ return static_cast<uc32>(first_char);
+ }
+ unibrow::uchar codepoint =
+ unibrow::Utf8::CalculateValue(buffer_ + offset_,
+ end_offset_ - offset_,
+ &offset_);
+ pos_++;
+ return static_cast<uc32>(codepoint);
+ }
+
+ virtual void SeekForward(int pos) {
+ while (pos_ < pos) {
+ uint8_t first_byte = buffer_[offset_++];
+ while (first_byte & 0x80u && offset_ < end_offset_) {
+ offset_++;
+ first_byte <<= 1;
+ }
+ pos_++;
+ }
+ }
+
+ private:
+ const uint8_t* buffer_;
+ unsigned offset_;
+ unsigned end_offset_;
+};
+
+
+class StandAloneJavaScriptScanner : public JavaScriptScanner {
+ public:
+ void Initialize(UTF16Buffer* source) {
+ source_ = source;
+ literal_flags_ = kLiteralString | kLiteralIdentifier;
+ Init();
+ // Skip initial whitespace allowing HTML comment ends just like
+ // after a newline and scan first token.
+ has_line_terminator_before_next_ = true;
+ SkipWhiteSpace();
+ Scan();
+ }
+};
+
+
+// Write a number to dest in network byte order.
+void WriteUInt32(FILE* dest, uint32_t value, bool* ok) {
+ for (int i = 3; i >= 0; i--) {
+ uint8_t byte = static_cast<uint8_t>(value >> (i << 3));
+ int result = fputc(byte, dest);
+ if (result == EOF) {
+ *ok = false;
+ return;
+ }
+ }
+}
+
+// Read number from FILE* in network byte order.
+uint32_t ReadUInt32(FILE* source, bool* ok) {
+ uint32_t n = 0;
+ for (int i = 0; i < 4; i++) {
+ int c = fgetc(source);
+ if (c == EOF) {
+ *ok = false;
+ return 0;
+ }
+ n = (n << 8) + static_cast<uint32_t>(c);
+ }
+ return n;
+}
+
+
+bool ReadBuffer(FILE* source, void* buffer, size_t length) {
+ size_t actually_read = fread(buffer, 1, length, stdin);
+ return (actually_read == length);
+}
+
+
+bool WriteBuffer(FILE* dest, void* buffer, size_t length) {
+ size_t actually_written = fwrite(buffer, 1, length, dest);
+ return (actually_written == length);
+}
+
+// Preparse stdin and output result on stdout.
+int PreParseIO() {
+ fprintf(stderr, "LOG: Enter parsing loop\n");
+ bool ok = true;
+ uint32_t length = ReadUInt32(stdin, &ok);
+ if (!ok) return kErrorReading;
+ SmartPointer<byte> buffer(NewArray<byte>(length));
+ if (!ReadBuffer(stdin, *buffer, length)) {
+ return kErrorReading;
+ }
+ UTF8UTF16Buffer input_buffer(*buffer, static_cast<size_t>(length));
+ StandAloneJavaScriptScanner scanner;
+ scanner.Initialize(&input_buffer);
+ CompleteParserRecorder recorder;
+ preparser::PreParser preparser;
+
+ if (!preparser.PreParseProgram(&scanner, &recorder, true)) {
+ if (scanner.stack_overflow()) {
+ // Report stack overflow error/no-preparser-data.
+ WriteUInt32(stdout, 0, &ok);
+ if (!ok) return kErrorWriting;
+ return 0;
+ }
+ }
+ Vector<unsigned> pre_data = recorder.ExtractData();
+
+ uint32_t size = static_cast<uint32_t>(pre_data.length() * sizeof(uint32_t));
+ WriteUInt32(stdout, size, &ok);
+ if (!ok) return kErrorWriting;
+ if (!WriteBuffer(stdout,
+ reinterpret_cast<byte*>(pre_data.start()),
+ size)) {
+ return kErrorWriting;
+ }
+ return 0;
+}
+
+// Functions declared by allocation.h
+
+void FatalProcessOutOfMemory(const char* location) {
+ V8_Fatal("", 0, location);
+}
+
+bool EnableSlowAsserts() { return true; }
+
+} } // namespace v8::internal
+
+
+int main(int argc, char* argv[]) {
+ int status = 0;
+ do {
+ status = v8::internal::PreParseIO();
+ } while (status == 0);
+ fprintf(stderr, "EXIT: Failure %d\n", status);
+ return EXIT_FAILURE;
+}
+
+
+// Fatal error handling declared by checks.h.
+
+extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) {
+ fflush(stdout);
+ fflush(stderr);
+ va_list arguments;
+ va_start(arguments, format);
+ vfprintf(stderr, format, arguments);
+ va_end(arguments);
+ fputs("\n#\n\n", stderr);
+ exit(EXIT_FAILURE);
+}
diff --git a/deps/v8/samples/process.cc b/deps/v8/samples/process.cc
index 9233c0dfa2..6be4ea542a 100644
--- a/deps/v8/samples/process.cc
+++ b/deps/v8/samples/process.cc
@@ -152,18 +152,16 @@ bool JsHttpRequestProcessor::Initialize(map<string, string>* opts,
Handle<ObjectTemplate> global = ObjectTemplate::New();
global->Set(String::New("log"), FunctionTemplate::New(LogCallback));
- // Each processor gets its own context so different processors
- // don't affect each other (ignore the first three lines).
- Handle<Context> context = Context::New(NULL, global);
-
- // Store the context in the processor object in a persistent handle,
- // since we want the reference to remain after we return from this
- // method.
- context_ = Persistent<Context>::New(context);
+ // Each processor gets its own context so different processors don't
+ // affect each other. Context::New returns a persistent handle which
+ // is what we need for the reference to remain after we return from
+ // this method. That persistent handle has to be disposed in the
+ // destructor.
+ context_ = Context::New(NULL, global);
// Enter the new context so all the following operations take place
// within it.
- Context::Scope context_scope(context);
+ Context::Scope context_scope(context_);
// Make the options mapping available within the context
if (!InstallMaps(opts, output))
@@ -176,7 +174,7 @@ bool JsHttpRequestProcessor::Initialize(map<string, string>* opts,
// The script compiled and ran correctly. Now we fetch out the
// Process function from the global object.
Handle<String> process_name = String::New("Process");
- Handle<Value> process_val = context->Global()->Get(process_name);
+ Handle<Value> process_val = context_->Global()->Get(process_name);
// If there is no Process function, or if it is not a function,
// bail out
diff --git a/deps/v8/samples/shell.cc b/deps/v8/samples/shell.cc
index 2bdc5a19da..1a13f5f80b 100644
--- a/deps/v8/samples/shell.cc
+++ b/deps/v8/samples/shell.cc
@@ -37,7 +37,6 @@ bool ExecuteString(v8::Handle<v8::String> source,
v8::Handle<v8::Value> name,
bool print_result,
bool report_exceptions);
-v8::Handle<v8::Value> PrintToInteger(const v8::Arguments& args);
v8::Handle<v8::Value> Print(const v8::Arguments& args);
v8::Handle<v8::Value> Read(const v8::Arguments& args);
v8::Handle<v8::Value> Load(const v8::Arguments& args);
@@ -54,8 +53,7 @@ int RunMain(int argc, char* argv[]) {
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
// Bind the global 'print' function to the C++ Print callback.
global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
-global->Set(v8::String::New("print2int"), v8::FunctionTemplate::New(PrintToInteger));
-// Bind the global 'read' function to the C++ Read callback.
+ // Bind the global 'read' function to the C++ Read callback.
global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read));
// Bind the global 'load' function to the C++ Load callback.
global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
@@ -140,16 +138,6 @@ v8::Handle<v8::Value> Print(const v8::Arguments& args) {
}
-v8::Handle<v8::Value> PrintToInteger(const v8::Arguments& args) {
- v8::HandleScope handle_scope;
- v8::String::Utf8Value str(args[0]);
- const char* cstr = ToCString(str);
- printf("%s -> %d\n", cstr, args[0]->ToInt32()->Value());
- fflush(stdout);
- return v8::Undefined();
-}
-
-
// The callback that is invoked by v8 whenever the JavaScript 'read'
// function is called. This function loads the content of the file named in
// the argument into a JavaScript string.
diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript
index 98e0a0ffa4..0e0679f93c 100755
--- a/deps/v8/src/SConscript
+++ b/deps/v8/src/SConscript
@@ -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
diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc
index b46cd02a3a..19af866c24 100644
--- a/deps/v8/src/api.cc
+++ b/deps/v8/src/api.cc
@@ -2451,6 +2451,15 @@ Local<String> v8::Object::ObjectProtoToString() {
}
+Local<String> v8::Object::GetConstructorName() {
+ ON_BAILOUT("v8::Object::GetConstructorName()", return Local<v8::String>());
+ ENTER_V8;
+ i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ i::Handle<i::String> name(self->constructor_name());
+ return Utils::ToLocal(name);
+}
+
+
bool v8::Object::Delete(v8::Handle<String> key) {
ON_BAILOUT("v8::Object::Delete()", return false);
ENTER_V8;
diff --git a/deps/v8/src/arm/assembler-arm-inl.h b/deps/v8/src/arm/assembler-arm-inl.h
index f72ad76abe..15720c956d 100644
--- a/deps/v8/src/arm/assembler-arm-inl.h
+++ b/deps/v8/src/arm/assembler-arm-inl.h
@@ -164,7 +164,7 @@ bool RelocInfo::IsPatchedReturnSequence() {
bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
Instr current_instr = Assembler::instr_at(pc_);
- return !Assembler::IsNop(current_instr, 2);
+ return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP);
}
@@ -288,9 +288,7 @@ Address Assembler::target_address_address_at(Address pc) {
}
#endif
- // Verify that the instruction to patch is a
- // ldr<cond> <Rd>, [pc +/- offset_12].
- ASSERT((instr & 0x0f7f0000) == 0x051f0000);
+ ASSERT(IsLdrPcImmediateOffset(instr));
int offset = instr & 0xfff; // offset_12 is unsigned
if ((instr & (1 << 23)) == 0) offset = -offset; // U bit defines offset sign
// Verify that the constant pool comes after the instruction referencing it.
diff --git a/deps/v8/src/arm/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc
index 4cb421c577..cfdd164961 100644
--- a/deps/v8/src/arm/assembler-arm.cc
+++ b/deps/v8/src/arm/assembler-arm.cc
@@ -397,13 +397,6 @@ void Assembler::CodeTargetAlign() {
}
-bool Assembler::IsNop(Instr instr, int type) {
- // Check for mov rx, rx.
- ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop.
- return instr == (al | 13*B21 | type*B12 | type);
-}
-
-
bool Assembler::IsBranch(Instr instr) {
return (instr & (B27 | B25)) == (B27 | B25);
}
@@ -510,6 +503,13 @@ bool Assembler::IsLdrRegFpNegOffset(Instr instr) {
}
+bool Assembler::IsLdrPcImmediateOffset(Instr instr) {
+ // Check the instruction is indeed a
+ // ldr<cond> <Rd>, [pc +/- offset_12].
+ return (instr & 0x0f7f0000) == 0x051f0000;
+}
+
+
// Labels refer to positions in the (to be) generated code.
// There are bound, linked, and unused labels.
//
@@ -1113,8 +1113,8 @@ void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
positions_recorder()->WriteRecordedPositions();
}
// Don't allow nop instructions in the form mov rn, rn to be generated using
- // the mov instruction. They must be generated using nop(int)
- // pseudo instructions.
+ // the mov instruction. They must be generated using nop(int/NopMarkerTypes)
+ // or MarkCode(int/NopMarkerTypes) pseudo instructions.
ASSERT(!(src.is_reg() && src.rm().is(dst) && s == LeaveCC && cond == al));
addrmod1(cond | 13*B21 | s, r0, dst, src);
}
@@ -2376,6 +2376,13 @@ void Assembler::nop(int type) {
}
+bool Assembler::IsNop(Instr instr, int type) {
+ // Check for mov rx, rx.
+ ASSERT(0 <= type && type <= 14); // mov pc, pc is not a nop.
+ return instr == (al | 13*B21 | type*B12 | type);
+}
+
+
bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) {
uint32_t dummy1;
uint32_t dummy2;
diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h
index 606ff86340..ee4c9aa52b 100644
--- a/deps/v8/src/arm/assembler-arm.h
+++ b/deps/v8/src/arm/assembler-arm.h
@@ -1079,7 +1079,22 @@ class Assembler : public Malloced {
const Condition cond = al);
// Pseudo instructions
- void nop(int type = 0);
+
+ // Different nop operations are used by the code generator to detect certain
+ // states of the generated code.
+ enum NopMarkerTypes {
+ NON_MARKING_NOP = 0,
+ DEBUG_BREAK_NOP,
+ // IC markers.
+ PROPERTY_ACCESS_INLINED,
+ PROPERTY_ACCESS_INLINED_CONTEXT,
+ PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE,
+ // Helper values.
+ LAST_CODE_MARKER,
+ FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED
+ };
+
+ void nop(int type = 0); // 0 is the default non-marking type.
void push(Register src, Condition cond = al) {
str(src, MemOperand(sp, 4, NegPreIndex), cond);
@@ -1151,7 +1166,6 @@ class Assembler : public Malloced {
static void instr_at_put(byte* pc, Instr instr) {
*reinterpret_cast<Instr*>(pc) = instr;
}
- static bool IsNop(Instr instr, int type = 0);
static bool IsBranch(Instr instr);
static int GetBranchOffset(Instr instr);
static bool IsLdrRegisterImmediate(Instr instr);
@@ -1168,6 +1182,8 @@ class Assembler : public Malloced {
static bool IsLdrRegFpOffset(Instr instr);
static bool IsStrRegFpNegOffset(Instr instr);
static bool IsLdrRegFpNegOffset(Instr instr);
+ static bool IsLdrPcImmediateOffset(Instr instr);
+ static bool IsNop(Instr instr, int type = NON_MARKING_NOP);
protected:
diff --git a/deps/v8/src/arm/builtins-arm.cc b/deps/v8/src/arm/builtins-arm.cc
index cf2f426243..862ef395f4 100644
--- a/deps/v8/src/arm/builtins-arm.cc
+++ b/deps/v8/src/arm/builtins-arm.cc
@@ -482,9 +482,128 @@ void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
- // TODO(849): implement custom construct stub.
- // Generate a copy of the generic stub for now.
- Generate_JSConstructStubGeneric(masm);
+ // ----------- S t a t e -------------
+ // -- r0 : number of arguments
+ // -- r1 : constructor function
+ // -- lr : return address
+ // -- sp[(argc - n - 1) * 4] : arg[n] (zero based)
+ // -- sp[argc * 4] : receiver
+ // -----------------------------------
+ __ IncrementCounter(&Counters::string_ctor_calls, 1, r2, r3);
+
+ Register function = r1;
+ if (FLAG_debug_code) {
+ __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, r2);
+ __ cmp(function, Operand(r2));
+ __ Assert(eq, "Unexpected String function");
+ }
+
+ // Load the first arguments in r0 and get rid of the rest.
+ Label no_arguments;
+ __ cmp(r0, Operand(0));
+ __ b(eq, &no_arguments);
+ // First args = sp[(argc - 1) * 4].
+ __ sub(r0, r0, Operand(1));
+ __ ldr(r0, MemOperand(sp, r0, LSL, kPointerSizeLog2, PreIndex));
+ // sp now point to args[0], drop args[0] + receiver.
+ __ Drop(2);
+
+ Register argument = r2;
+ Label not_cached, argument_is_string;
+ NumberToStringStub::GenerateLookupNumberStringCache(
+ masm,
+ r0, // Input.
+ argument, // Result.
+ r3, // Scratch.
+ r4, // Scratch.
+ r5, // Scratch.
+ false, // Is it a Smi?
+ &not_cached);
+ __ IncrementCounter(&Counters::string_ctor_cached_number, 1, r3, r4);
+ __ bind(&argument_is_string);
+
+ // ----------- S t a t e -------------
+ // -- r2 : argument converted to string
+ // -- r1 : constructor function
+ // -- lr : return address
+ // -----------------------------------
+
+ Label gc_required;
+ __ AllocateInNewSpace(JSValue::kSize,
+ r0, // Result.
+ r3, // Scratch.
+ r4, // Scratch.
+ &gc_required,
+ TAG_OBJECT);
+
+ // Initialising the String Object.
+ Register map = r3;
+ __ LoadGlobalFunctionInitialMap(function, map, r4);
+ if (FLAG_debug_code) {
+ __ ldrb(r4, FieldMemOperand(map, Map::kInstanceSizeOffset));
+ __ cmp(r4, Operand(JSValue::kSize >> kPointerSizeLog2));
+ __ Assert(eq, "Unexpected string wrapper instance size");
+ __ ldrb(r4, FieldMemOperand(map, Map::kUnusedPropertyFieldsOffset));
+ __ cmp(r4, Operand(0));
+ __ Assert(eq, "Unexpected unused properties of string wrapper");
+ }
+ __ str(map, FieldMemOperand(r0, HeapObject::kMapOffset));
+
+ __ LoadRoot(r3, Heap::kEmptyFixedArrayRootIndex);
+ __ str(r3, FieldMemOperand(r0, JSObject::kPropertiesOffset));
+ __ str(r3, FieldMemOperand(r0, JSObject::kElementsOffset));
+
+ __ str(argument, FieldMemOperand(r0, JSValue::kValueOffset));
+
+ // Ensure the object is fully initialized.
+ STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
+
+ __ Ret();
+
+ // The argument was not found in the number to string cache. Check
+ // if it's a string already before calling the conversion builtin.
+ Label convert_argument;
+ __ bind(&not_cached);
+ __ BranchOnSmi(r0, &convert_argument);
+
+ // Is it a String?
+ __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
+ __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+ ASSERT(kNotStringTag != 0);
+ __ tst(r3, Operand(kIsNotStringMask));
+ __ b(ne, &convert_argument);
+ __ mov(argument, r0);
+ __ IncrementCounter(&Counters::string_ctor_conversions, 1, r3, r4);
+ __ b(&argument_is_string);
+
+ // Invoke the conversion builtin and put the result into r2.
+ __ bind(&convert_argument);
+ __ push(function); // Preserve the function.
+ __ IncrementCounter(&Counters::string_ctor_conversions, 1, r3, r4);
+ __ EnterInternalFrame();
+ __ push(r0);
+ __ InvokeBuiltin(Builtins::TO_STRING, CALL_JS);
+ __ LeaveInternalFrame();
+ __ pop(function);
+ __ mov(argument, r0);
+ __ b(&argument_is_string);
+
+ // Load the empty string into r2, remove the receiver from the
+ // stack, and jump back to the case where the argument is a string.
+ __ bind(&no_arguments);
+ __ LoadRoot(argument, Heap::kEmptyStringRootIndex);
+ __ Drop(1);
+ __ b(&argument_is_string);
+
+ // At this point the argument is already a string. Call runtime to
+ // create a string wrapper.
+ __ bind(&gc_required);
+ __ IncrementCounter(&Counters::string_ctor_gc_required, 1, r3, r4);
+ __ EnterInternalFrame();
+ __ push(argument);
+ __ CallRuntime(Runtime::kNewStringWrapper, 1);
+ __ LeaveInternalFrame();
+ __ Ret();
}
diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc
index 3e6743afaf..27e14df481 100644
--- a/deps/v8/src/arm/codegen-arm.cc
+++ b/deps/v8/src/arm/codegen-arm.cc
@@ -6024,6 +6024,68 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
}
+class DeferredCountOperation: public DeferredCode {
+ public:
+ DeferredCountOperation(Register value,
+ bool is_increment,
+ bool is_postfix,
+ int target_size)
+ : value_(value),
+ is_increment_(is_increment),
+ is_postfix_(is_postfix),
+ target_size_(target_size) {}
+
+ virtual void Generate() {
+ VirtualFrame copied_frame(*frame_state()->frame());
+
+ Label slow;
+ // Check for smi operand.
+ __ tst(value_, Operand(kSmiTagMask));
+ __ b(ne, &slow);
+
+ // Revert optimistic increment/decrement.
+ if (is_increment_) {
+ __ sub(value_, value_, Operand(Smi::FromInt(1)));
+ } else {
+ __ add(value_, value_, Operand(Smi::FromInt(1)));
+ }
+
+ // Slow case: Convert to number. At this point the
+ // value to be incremented is in the value register..
+ __ bind(&slow);
+
+ // Convert the operand to a number.
+ copied_frame.EmitPush(value_);
+
+ copied_frame.InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, 1);
+
+ if (is_postfix_) {
+ // Postfix: store to result (on the stack).
+ __ str(r0, MemOperand(sp, target_size_ * kPointerSize));
+ }
+
+ copied_frame.EmitPush(r0);
+ copied_frame.EmitPush(Operand(Smi::FromInt(1)));
+
+ if (is_increment_) {
+ copied_frame.CallRuntime(Runtime::kNumberAdd, 2);
+ } else {
+ copied_frame.CallRuntime(Runtime::kNumberSub, 2);
+ }
+
+ __ Move(value_, r0);
+
+ copied_frame.MergeTo(frame_state()->frame());
+ }
+
+ private:
+ Register value_;
+ bool is_increment_;
+ bool is_postfix_;
+ int target_size_;
+};
+
+
void CodeGenerator::VisitCountOperation(CountOperation* node) {
#ifdef DEBUG
int original_height = frame_->height();
@@ -6083,9 +6145,7 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
// the target. It also pushes the current value of the target.
target.GetValue();
- JumpTarget slow;
- JumpTarget exit;
-
+ bool value_is_known_smi = frame_->KnownSmiAt(0);
Register value = frame_->PopToRegister();
// Postfix: Store the old value as the result.
@@ -6097,9 +6157,27 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
value = VirtualFrame::scratch0();
}
- // Check for smi operand.
- __ tst(value, Operand(kSmiTagMask));
- slow.Branch(ne);
+ // We can't use any type information here since the virtual frame from the
+ // deferred code may have lost information and we can't merge a virtual
+ // frame with less specific type knowledge to a virtual frame with more
+ // specific knowledge that has already used that specific knowledge to
+ // generate code.
+ frame_->ForgetTypeInfo();
+
+ // The constructor here will capture the current virtual frame and use it to
+ // merge to after the deferred code has run. No virtual frame changes are
+ // allowed from here until the 'BindExit' below.
+ DeferredCode* deferred =
+ new DeferredCountOperation(value,
+ is_increment,
+ is_postfix,
+ target.size());
+ if (!value_is_known_smi) {
+ // Check for smi operand.
+ __ tst(value, Operand(kSmiTagMask));
+
+ deferred->Branch(ne);
+ }
// Perform optimistic increment/decrement.
if (is_increment) {
@@ -6108,46 +6186,13 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
__ sub(value, value, Operand(Smi::FromInt(1)), SetCC);
}
- // If the increment/decrement didn't overflow, we're done.
- exit.Branch(vc);
-
- // Revert optimistic increment/decrement.
- if (is_increment) {
- __ sub(value, value, Operand(Smi::FromInt(1)));
- } else {
- __ add(value, value, Operand(Smi::FromInt(1)));
- }
-
- // Slow case: Convert to number. At this point the
- // value to be incremented is in the value register..
- slow.Bind();
-
- // Convert the operand to a number.
- frame_->EmitPush(value);
-
- {
- VirtualFrame::SpilledScope spilled(frame_);
- frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, 1);
-
- if (is_postfix) {
- // Postfix: store to result (on the stack).
- __ str(r0, frame_->ElementAt(target.size()));
- }
+ // If increment/decrement overflows, go to deferred code.
+ deferred->Branch(vs);
- // Compute the new value.
- frame_->EmitPush(r0);
- frame_->EmitPush(Operand(Smi::FromInt(1)));
- if (is_increment) {
- frame_->CallRuntime(Runtime::kNumberAdd, 2);
- } else {
- frame_->CallRuntime(Runtime::kNumberSub, 2);
- }
- }
+ deferred->BindExit();
- __ Move(value, r0);
// Store the new value in the target if not const.
// At this point the answer is in the value register.
- exit.Bind();
frame_->EmitPush(value);
// Set the target with the result, leaving the result on
// top of the stack. Removes the target from the stack if
@@ -6537,16 +6582,29 @@ void CodeGenerator::VisitCompareToNull(CompareToNull* node) {
class DeferredReferenceGetNamedValue: public DeferredCode {
public:
explicit DeferredReferenceGetNamedValue(Register receiver,
- Handle<String> name)
- : receiver_(receiver), name_(name) {
- set_comment("[ DeferredReferenceGetNamedValue");
+ Handle<String> name,
+ bool is_contextual)
+ : receiver_(receiver),
+ name_(name),
+ is_contextual_(is_contextual),
+ is_dont_delete_(false) {
+ set_comment(is_contextual
+ ? "[ DeferredReferenceGetNamedValue (contextual)"
+ : "[ DeferredReferenceGetNamedValue");
}
virtual void Generate();
+ void set_is_dont_delete(bool value) {
+ ASSERT(is_contextual_);
+ is_dont_delete_ = value;
+ }
+
private:
Register receiver_;
Handle<String> name_;
+ bool is_contextual_;
+ bool is_dont_delete_;
};
@@ -6573,10 +6631,20 @@ void DeferredReferenceGetNamedValue::Generate() {
// The rest of the instructions in the deferred code must be together.
{ Assembler::BlockConstPoolScope block_const_pool(masm_);
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
- __ Call(ic, RelocInfo::CODE_TARGET);
- // The call must be followed by a nop(1) instruction to indicate that the
- // in-object has been inlined.
- __ nop(PROPERTY_ACCESS_INLINED);
+ RelocInfo::Mode mode = is_contextual_
+ ? RelocInfo::CODE_TARGET_CONTEXT
+ : RelocInfo::CODE_TARGET;
+ __ Call(ic, mode);
+ // We must mark the code just after the call with the correct marker.
+ MacroAssembler::NopMarkerTypes code_marker;
+ if (is_contextual_) {
+ code_marker = is_dont_delete_
+ ? MacroAssembler::PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE
+ : MacroAssembler::PROPERTY_ACCESS_INLINED_CONTEXT;
+ } else {
+ code_marker = MacroAssembler::PROPERTY_ACCESS_INLINED;
+ }
+ __ MarkCode(code_marker);
// At this point the answer is in r0. We move it to the expected register
// if necessary.
@@ -6640,7 +6708,7 @@ void DeferredReferenceGetKeyedValue::Generate() {
__ Call(ic, RelocInfo::CODE_TARGET);
// The call must be followed by a nop instruction to indicate that the
// keyed load has been inlined.
- __ nop(PROPERTY_ACCESS_INLINED);
+ __ MarkCode(MacroAssembler::PROPERTY_ACCESS_INLINED);
// Now go back to the frame that we entered with. This will not overwrite
// the receiver or key registers since they were not in use when we came
@@ -6697,7 +6765,7 @@ void DeferredReferenceSetKeyedValue::Generate() {
__ Call(ic, RelocInfo::CODE_TARGET);
// The call must be followed by a nop instruction to indicate that the
// keyed store has been inlined.
- __ nop(PROPERTY_ACCESS_INLINED);
+ __ MarkCode(MacroAssembler::PROPERTY_ACCESS_INLINED);
// Block the constant pool for one more instruction after leaving this
// constant pool block scope to include the branch instruction ending the
@@ -6745,7 +6813,7 @@ void DeferredReferenceSetNamedValue::Generate() {
__ Call(ic, RelocInfo::CODE_TARGET);
// The call must be followed by a nop instruction to indicate that the
// named store has been inlined.
- __ nop(PROPERTY_ACCESS_INLINED);
+ __ MarkCode(MacroAssembler::PROPERTY_ACCESS_INLINED);
// Go back to the frame we entered with. The instructions
// generated by this merge are skipped over by the inline store
@@ -6763,7 +6831,14 @@ void DeferredReferenceSetNamedValue::Generate() {
// Consumes the top of stack (the receiver) and pushes the result instead.
void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
- if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) {
+ bool contextual_load_in_builtin =
+ is_contextual &&
+ (Bootstrapper::IsActive() ||
+ (!info_->closure().is_null() && info_->closure()->IsBuiltin()));
+
+ if (scope()->is_global_scope() ||
+ loop_nesting() == 0 ||
+ contextual_load_in_builtin) {
Comment cmnt(masm(), "[ Load from named Property");
// Setup the name register and call load IC.
frame_->CallLoadIC(name,
@@ -6773,12 +6848,19 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
frame_->EmitPush(r0); // Push answer.
} else {
// Inline the in-object property case.
- Comment cmnt(masm(), "[ Inlined named property load");
+ Comment cmnt(masm(), is_contextual
+ ? "[ Inlined contextual property load"
+ : "[ Inlined named property load");
// Counter will be decremented in the deferred code. Placed here to avoid
// having it in the instruction stream below where patching will occur.
- __ IncrementCounter(&Counters::named_load_inline, 1,
- frame_->scratch0(), frame_->scratch1());
+ if (is_contextual) {
+ __ IncrementCounter(&Counters::named_load_global_inline, 1,
+ frame_->scratch0(), frame_->scratch1());
+ } else {
+ __ IncrementCounter(&Counters::named_load_inline, 1,
+ frame_->scratch0(), frame_->scratch1());
+ }
// The following instructions are the inlined load of an in-object property.
// Parts of this code is patched, so the exact instructions generated needs
@@ -6789,19 +6871,57 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
Register receiver = frame_->PopToRegister();
DeferredReferenceGetNamedValue* deferred =
- new DeferredReferenceGetNamedValue(receiver, name);
+ new DeferredReferenceGetNamedValue(receiver, name, is_contextual);
+
+ bool is_dont_delete = false;
+ if (is_contextual) {
+ if (!info_->closure().is_null()) {
+ // When doing lazy compilation we can check if the global cell
+ // already exists and use its "don't delete" status as a hint.
+ AssertNoAllocation no_gc;
+ v8::internal::GlobalObject* global_object =
+ info_->closure()->context()->global();
+ LookupResult lookup;
+ global_object->LocalLookupRealNamedProperty(*name, &lookup);
+ if (lookup.IsProperty() && lookup.type() == NORMAL) {
+ ASSERT(lookup.holder() == global_object);
+ ASSERT(global_object->property_dictionary()->ValueAt(
+ lookup.GetDictionaryEntry())->IsJSGlobalPropertyCell());
+ is_dont_delete = lookup.IsDontDelete();
+ }
+ }
+ if (is_dont_delete) {
+ __ IncrementCounter(&Counters::dont_delete_hint_hit, 1,
+ frame_->scratch0(), frame_->scratch1());
+ }
+ }
+
+ { Assembler::BlockConstPoolScope block_const_pool(masm_);
+ if (!is_contextual) {
+ // Check that the receiver is a heap object.
+ __ tst(receiver, Operand(kSmiTagMask));
+ deferred->Branch(eq);
+ }
+
+ // Check for the_hole_value if necessary.
+ // Below we rely on the number of instructions generated, and we can't
+ // cope with the Check macro which does not generate a fixed number of
+ // instructions.
+ Label skip, check_the_hole, cont;
+ if (FLAG_debug_code && is_contextual && is_dont_delete) {
+ __ b(&skip);
+ __ bind(&check_the_hole);
+ __ Check(ne, "DontDelete cells can't contain the hole");
+ __ b(&cont);
+ __ bind(&skip);
+ }
#ifdef DEBUG
- int kInlinedNamedLoadInstructions = 7;
- Label check_inlined_codesize;
- masm_->bind(&check_inlined_codesize);
+ int InlinedNamedLoadInstructions = 5;
+ Label check_inlined_codesize;
+ masm_->bind(&check_inlined_codesize);
#endif
- { Assembler::BlockConstPoolScope block_const_pool(masm_);
- // Check that the receiver is a heap object.
- __ tst(receiver, Operand(kSmiTagMask));
- deferred->Branch(eq);
-
Register scratch = VirtualFrame::scratch0();
Register scratch2 = VirtualFrame::scratch1();
@@ -6812,12 +6932,42 @@ void CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
__ cmp(scratch, scratch2);
deferred->Branch(ne);
- // Initially use an invalid index. The index will be patched by the
- // inline cache code.
- __ ldr(receiver, MemOperand(receiver, 0));
+ if (is_contextual) {
+#ifdef DEBUG
+ InlinedNamedLoadInstructions += 1;
+#endif
+ // Load the (initially invalid) cell and get its value.
+ masm()->mov(receiver, Operand(Factory::null_value()));
+ __ ldr(receiver,
+ FieldMemOperand(receiver, JSGlobalPropertyCell::kValueOffset));
+
+ deferred->set_is_dont_delete(is_dont_delete);
+
+ if (!is_dont_delete) {
+#ifdef DEBUG
+ InlinedNamedLoadInstructions += 3;
+#endif
+ __ cmp(receiver, Operand(Factory::the_hole_value()));
+ deferred->Branch(eq);
+ } else if (FLAG_debug_code) {
+#ifdef DEBUG
+ InlinedNamedLoadInstructions += 3;
+#endif
+ __ cmp(receiver, Operand(Factory::the_hole_value()));
+ __ b(&check_the_hole, eq);
+ __ bind(&cont);
+ }
+ } else {
+ // Initially use an invalid index. The index will be patched by the
+ // inline cache code.
+ __ ldr(receiver, MemOperand(receiver, 0));
+ }
// Make sure that the expected number of instructions are generated.
- ASSERT_EQ(kInlinedNamedLoadInstructions,
+ // If the code before is updated, the offsets in ic-arm.cc
+ // LoadIC::PatchInlinedContextualLoad and PatchInlinedLoad need
+ // to be updated.
+ ASSERT_EQ(InlinedNamedLoadInstructions,
masm_->InstructionsGeneratedSince(&check_inlined_codesize));
}
diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h
index 6905d2331e..1930f5e1a4 100644
--- a/deps/v8/src/arm/codegen-arm.h
+++ b/deps/v8/src/arm/codegen-arm.h
@@ -194,14 +194,6 @@ enum ArgumentsAllocationMode {
};
-// Different nop operations are used by the code generator to detect certain
-// states of the generated code.
-enum NopMarkerTypes {
- NON_MARKING_NOP = 0,
- PROPERTY_ACCESS_INLINED
-};
-
-
// -------------------------------------------------------------------------
// CodeGenerator
diff --git a/deps/v8/src/arm/debug-arm.cc b/deps/v8/src/arm/debug-arm.cc
index 8128f7deaf..f19e69396e 100644
--- a/deps/v8/src/arm/debug-arm.cc
+++ b/deps/v8/src/arm/debug-arm.cc
@@ -279,7 +279,7 @@ void Debug::GenerateSlot(MacroAssembler* masm) {
__ bind(&check_codesize);
__ RecordDebugBreakSlot();
for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
- __ nop(2);
+ __ nop(MacroAssembler::DEBUG_BREAK_NOP);
}
ASSERT_EQ(Assembler::kDebugBreakSlotInstructions,
masm->InstructionsGeneratedSince(&check_codesize));
diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc
index 4c1f9835f4..ef7cf6af46 100644
--- a/deps/v8/src/arm/ic-arm.cc
+++ b/deps/v8/src/arm/ic-arm.cc
@@ -904,9 +904,9 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
__ TailCallExternalReference(ref, 2, 1);
}
-
-static inline bool IsInlinedICSite(Address address,
- Address* inline_end_address) {
+// Returns the code marker, or the 0 if the code is not marked.
+static inline int InlinedICSiteMarker(Address address,
+ Address* inline_end_address) {
// If the instruction after the call site is not the pseudo instruction nop1
// then this is not related to an inlined in-object property load. The nop1
// instruction is located just after the call to the IC in the deferred code
@@ -914,9 +914,11 @@ static inline bool IsInlinedICSite(Address address,
// a branch instruction for jumping back from the deferred code.
Address address_after_call = address + Assembler::kCallTargetAddressOffset;
Instr instr_after_call = Assembler::instr_at(address_after_call);
- if (!Assembler::IsNop(instr_after_call, PROPERTY_ACCESS_INLINED)) {
- return false;
- }
+ int code_marker = MacroAssembler::GetCodeMarker(instr_after_call);
+
+ // A negative result means the code is not marked.
+ if (code_marker <= 0) return 0;
+
Address address_after_nop = address_after_call + Assembler::kInstrSize;
Instr instr_after_nop = Assembler::instr_at(address_after_nop);
// There may be some reg-reg move and frame merging code to skip over before
@@ -933,7 +935,7 @@ static inline bool IsInlinedICSite(Address address,
ASSERT(b_offset < 0); // Jumping back from deferred code.
*inline_end_address = address_after_nop + b_offset;
- return true;
+ return code_marker;
}
@@ -941,7 +943,10 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
// Find the end of the inlined code for handling the load if this is an
// inlined IC call site.
Address inline_end_address;
- if (!IsInlinedICSite(address, &inline_end_address)) return false;
+ if (InlinedICSiteMarker(address, &inline_end_address)
+ != Assembler::PROPERTY_ACCESS_INLINED) {
+ return false;
+ }
// Patch the offset of the property load instruction (ldr r0, [r1, #+XXX]).
// The immediate must be representable in 12 bits.
@@ -959,8 +964,12 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
CPU::FlushICache(ldr_property_instr_address, 1 * Assembler::kInstrSize);
// Patch the map check.
+ // For PROPERTY_ACCESS_INLINED, the load map instruction is generated
+ // 4 instructions before the end of the inlined code.
+ // See codgen-arm.cc CodeGenerator::EmitNamedLoad.
+ int ldr_map_offset = -4;
Address ldr_map_instr_address =
- inline_end_address - 4 * Assembler::kInstrSize;
+ inline_end_address + ldr_map_offset * Assembler::kInstrSize;
Assembler::set_target_address_at(ldr_map_instr_address,
reinterpret_cast<Address>(map));
return true;
@@ -971,8 +980,41 @@ bool LoadIC::PatchInlinedContextualLoad(Address address,
Object* map,
Object* cell,
bool is_dont_delete) {
- // TODO(<bug#>): implement this.
- return false;
+ // Find the end of the inlined code for handling the contextual load if
+ // this is inlined IC call site.
+ Address inline_end_address;
+ int marker = InlinedICSiteMarker(address, &inline_end_address);
+ if (!((marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT) ||
+ (marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE))) {
+ return false;
+ }
+ // On ARM we don't rely on the is_dont_delete argument as the hint is already
+ // embedded in the code marker.
+ bool marker_is_dont_delete =
+ marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE;
+
+ // These are the offsets from the end of the inlined code.
+ // See codgen-arm.cc CodeGenerator::EmitNamedLoad.
+ int ldr_map_offset = marker_is_dont_delete ? -5: -8;
+ int ldr_cell_offset = marker_is_dont_delete ? -2: -5;
+ if (FLAG_debug_code && marker_is_dont_delete) {
+ // Three extra instructions were generated to check for the_hole_value.
+ ldr_map_offset -= 3;
+ ldr_cell_offset -= 3;
+ }
+ Address ldr_map_instr_address =
+ inline_end_address + ldr_map_offset * Assembler::kInstrSize;
+ Address ldr_cell_instr_address =
+ inline_end_address + ldr_cell_offset * Assembler::kInstrSize;
+
+ // Patch the map check.
+ Assembler::set_target_address_at(ldr_map_instr_address,
+ reinterpret_cast<Address>(map));
+ // Patch the cell address.
+ Assembler::set_target_address_at(ldr_cell_instr_address,
+ reinterpret_cast<Address>(cell));
+
+ return true;
}
@@ -980,7 +1022,10 @@ bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
// Find the end of the inlined code for the store if there is an
// inlined version of the store.
Address inline_end_address;
- if (!IsInlinedICSite(address, &inline_end_address)) return false;
+ if (InlinedICSiteMarker(address, &inline_end_address)
+ != Assembler::PROPERTY_ACCESS_INLINED) {
+ return false;
+ }
// Compute the address of the map load instruction.
Address ldr_map_instr_address =
@@ -1025,7 +1070,10 @@ bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
Address inline_end_address;
- if (!IsInlinedICSite(address, &inline_end_address)) return false;
+ if (InlinedICSiteMarker(address, &inline_end_address)
+ != Assembler::PROPERTY_ACCESS_INLINED) {
+ return false;
+ }
// Patch the map check.
Address ldr_map_instr_address =
@@ -1042,7 +1090,10 @@ bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
// Find the end of the inlined code for handling the store if this is an
// inlined IC call site.
Address inline_end_address;
- if (!IsInlinedICSite(address, &inline_end_address)) return false;
+ if (InlinedICSiteMarker(address, &inline_end_address)
+ != Assembler::PROPERTY_ACCESS_INLINED) {
+ return false;
+ }
// Patch the map check.
Address ldr_map_instr_address =
diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc
index d2c22af53d..ea85c79454 100644
--- a/deps/v8/src/arm/macro-assembler-arm.cc
+++ b/deps/v8/src/arm/macro-assembler-arm.cc
@@ -1693,6 +1693,33 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
}
+void MacroAssembler::LoadGlobalFunction(int index, Register function) {
+ // Load the global or builtins object from the current context.
+ ldr(function, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
+ // Load the global context from the global or builtins object.
+ ldr(function, FieldMemOperand(function,
+ GlobalObject::kGlobalContextOffset));
+ // Load the function from the global context.
+ ldr(function, MemOperand(function, Context::SlotOffset(index)));
+}
+
+
+void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
+ Register map,
+ Register scratch) {
+ // Load the initial map. The global functions all have initial maps.
+ ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
+ if (FLAG_debug_code) {
+ Label ok, fail;
+ CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, false);
+ b(&ok);
+ bind(&fail);
+ Abort("Global functions must have initial map");
+ bind(&ok);
+ }
+}
+
+
void MacroAssembler::JumpIfNotBothSmi(Register reg1,
Register reg2,
Label* on_not_both_smi) {
diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h
index 8d89d6984c..8bd134c38e 100644
--- a/deps/v8/src/arm/macro-assembler-arm.h
+++ b/deps/v8/src/arm/macro-assembler-arm.h
@@ -264,6 +264,14 @@ class MacroAssembler: public Assembler {
void LoadContext(Register dst, int context_chain_length);
+ void LoadGlobalFunction(int index, Register function);
+
+ // Load the initial map from the global function. The registers
+ // function and map can be the same, function is then overwritten.
+ void LoadGlobalFunctionInitialMap(Register function,
+ Register map,
+ Register scratch);
+
// ---------------------------------------------------------------------------
// JavaScript invokes
@@ -319,6 +327,40 @@ class MacroAssembler: public Assembler {
Register scratch,
Label* miss);
+ inline void MarkCode(NopMarkerTypes type) {
+ nop(type);
+ }
+
+ // Check if the given instruction is a 'type' marker.
+ // ie. check if is is a mov r<type>, r<type> (referenced as nop(type))
+ // These instructions are generated to mark special location in the code,
+ // like some special IC code.
+ static inline bool IsMarkedCode(Instr instr, int type) {
+ ASSERT((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER));
+ return IsNop(instr, type);
+ }
+
+
+ static inline int GetCodeMarker(Instr instr) {
+ int dst_reg_offset = 12;
+ int dst_mask = 0xf << dst_reg_offset;
+ int src_mask = 0xf;
+ int dst_reg = (instr & dst_mask) >> dst_reg_offset;
+ int src_reg = instr & src_mask;
+ uint32_t non_register_mask = ~(dst_mask | src_mask);
+ uint32_t mov_mask = al | 13 << 21;
+
+ // Return <n> if we have a mov rn rn, else return -1.
+ int type = ((instr & non_register_mask) == mov_mask) &&
+ (dst_reg == src_reg) &&
+ (FIRST_IC_MARKER <= dst_reg) && (dst_reg < LAST_CODE_MARKER)
+ ? src_reg
+ : -1;
+ ASSERT((type == -1) ||
+ ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)));
+ return type;
+ }
+
// ---------------------------------------------------------------------------
// Allocation support
diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc
index f3f7a5d4b3..0a5eac27f6 100644
--- a/deps/v8/src/arm/stub-cache-arm.cc
+++ b/deps/v8/src/arm/stub-cache-arm.cc
@@ -2902,8 +2902,7 @@ MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
}
-MaybeObject* ConstructStubCompiler::CompileConstructStub(
- SharedFunctionInfo* shared) {
+MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
// ----------- S t a t e -------------
// -- r0 : argc
// -- r1 : constructor
@@ -2987,6 +2986,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(
// r7: undefined
// Fill the initialized properties with a constant value or a passed argument
// depending on the this.x = ...; assignment in the function.
+ SharedFunctionInfo* shared = function->shared();
for (int i = 0; i < shared->this_property_assignments_count(); i++) {
if (shared->IsThisPropertyAssignmentArgument(i)) {
Label not_passed, next;
@@ -3011,8 +3011,9 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(
}
// Fill the unused in-object property fields with undefined.
+ ASSERT(function->has_initial_map());
for (int i = shared->this_property_assignments_count();
- i < shared->CalculateInObjectProperties();
+ i < function->initial_map()->inobject_properties();
i++) {
__ str(r7, MemOperand(r5, kPointerSize, PostIndex));
}
diff --git a/deps/v8/src/checks.cc b/deps/v8/src/checks.cc
index 1ab8802ec3..3c3d940be7 100644
--- a/deps/v8/src/checks.cc
+++ b/deps/v8/src/checks.cc
@@ -107,3 +107,4 @@ namespace v8 { namespace internal {
intptr_t HeapObjectTagMask() { return kHeapObjectTagMask; }
} } // namespace v8::internal
+
diff --git a/deps/v8/src/checks.h b/deps/v8/src/checks.h
index 6b493225ad..d49f97f132 100644
--- a/deps/v8/src/checks.h
+++ b/deps/v8/src/checks.h
@@ -31,7 +31,6 @@
#include <string.h>
extern "C" void V8_Fatal(const char* file, int line, const char* format, ...);
-void API_Fatal(const char* location, const char* format, ...);
// The FATAL, UNREACHABLE and UNIMPLEMENTED macros are useful during
// development, but they should not be relied on in the final product.
@@ -222,28 +221,6 @@ static inline void CheckNonEqualsHelper(const char* file,
}
-namespace v8 {
- class Value;
- template <class T> class Handle;
-}
-
-
-void CheckNonEqualsHelper(const char* file,
- int line,
- const char* unexpected_source,
- v8::Handle<v8::Value> unexpected,
- const char* value_source,
- v8::Handle<v8::Value> value);
-
-
-void CheckEqualsHelper(const char* file,
- int line,
- const char* expected_source,
- v8::Handle<v8::Value> expected,
- const char* value_source,
- v8::Handle<v8::Value> value);
-
-
#define CHECK_EQ(expected, value) CheckEqualsHelper(__FILE__, __LINE__, \
#expected, expected, #value, value)
@@ -307,17 +284,6 @@ bool EnableSlowAsserts();
// and release compilation modes behaviour.
#define STATIC_ASSERT(test) STATIC_CHECK(test)
-namespace v8 { namespace internal {
-
-intptr_t HeapObjectTagMask();
-
-} } // namespace v8::internal
-
-#define ASSERT_TAG_ALIGNED(address) \
- ASSERT((reinterpret_cast<intptr_t>(address) & HeapObjectTagMask()) == 0)
-
-#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & HeapObjectTagMask()) == 0)
-
#define ASSERT_NOT_NULL(p) ASSERT_NE(NULL, p)
#endif // V8_CHECKS_H_
diff --git a/deps/v8/src/conversions.cc b/deps/v8/src/conversions.cc
index 19fa7773ab..a954d6cc69 100644
--- a/deps/v8/src/conversions.cc
+++ b/deps/v8/src/conversions.cc
@@ -448,12 +448,12 @@ static double InternalStringToDouble(Iterator current,
bool sign = false;
if (*current == '+') {
- // Ignore leading sign; skip following spaces.
+ // Ignore leading sign.
++current;
- if (!AdvanceToNonspace(&current, end)) return JUNK_STRING_VALUE;
+ if (current == end) return JUNK_STRING_VALUE;
} else if (*current == '-') {
++current;
- if (!AdvanceToNonspace(&current, end)) return JUNK_STRING_VALUE;
+ if (current == end) return JUNK_STRING_VALUE;
sign = true;
}
diff --git a/deps/v8/src/dateparser-inl.h b/deps/v8/src/dateparser-inl.h
index e52cc94a48..ac28c62257 100644
--- a/deps/v8/src/dateparser-inl.h
+++ b/deps/v8/src/dateparser-inl.h
@@ -59,7 +59,7 @@ bool DateParser::Parse(Vector<Char> str, FixedArray* out) {
} else if (in.Skip('.') && time.IsExpecting(n)) {
time.Add(n);
if (!in.IsAsciiDigit()) return false;
- int n = in.ReadUnsignedNumber();
+ int n = in.ReadMilliseconds();
time.AddFinal(n);
} else if (tz.IsExpecting(n)) {
tz.SetAbsoluteMinute(n);
diff --git a/deps/v8/src/dateparser.h b/deps/v8/src/dateparser.h
index 28053f46d1..40e56f3024 100644
--- a/deps/v8/src/dateparser.h
+++ b/deps/v8/src/dateparser.h
@@ -87,6 +87,18 @@ class DateParser : public AllStatic {
return n;
}
+ // Read a string of digits, take the first three or fewer as an unsigned
+ // number of milliseconds, and ignore any digits after the first three.
+ int ReadMilliseconds() {
+ has_read_number_ = true;
+ int n = 0;
+ int power;
+ for (power = 100; IsAsciiDigit(); Next(), power = power / 10) {
+ n = n + power * (ch_ - '0');
+ }
+ return n;
+ }
+
// Read a word (sequence of chars. >= 'A'), fill the given buffer with a
// lower-case prefix, and pad any remainder of the buffer with zeroes.
// Return word length.
diff --git a/deps/v8/src/handles.cc b/deps/v8/src/handles.cc
index 3dfb886e99..37a5011ce7 100644
--- a/deps/v8/src/handles.cc
+++ b/deps/v8/src/handles.cc
@@ -143,7 +143,7 @@ Handle<JSGlobalProxy> ReinitializeJSGlobalProxy(
void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
// If objects constructed from this function exist then changing
- // 'estimated_nof_properties' is dangerous since the previois value might
+ // 'estimated_nof_properties' is dangerous since the previous value might
// have been compiled into the fast construct stub. More over, the inobject
// slack tracking logic might have adjusted the previous value, so even
// passing the same value is risky.
diff --git a/deps/v8/src/hashmap.cc b/deps/v8/src/hashmap.cc
index 3c4e5cdc60..1422afdc7e 100644
--- a/deps/v8/src/hashmap.cc
+++ b/deps/v8/src/hashmap.cc
@@ -25,7 +25,11 @@
// (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 "v8.h"
+#include "../include/v8stdint.h"
+#include "globals.h"
+#include "checks.h"
+#include "utils.h"
+#include "allocation.h"
#include "hashmap.h"
@@ -195,7 +199,7 @@ void HashMap::Initialize(uint32_t capacity) {
ASSERT(IsPowerOf2(capacity));
map_ = reinterpret_cast<Entry*>(allocator_->New(capacity * sizeof(Entry)));
if (map_ == NULL) {
- V8::FatalProcessOutOfMemory("HashMap::Initialize");
+ v8::internal::FatalProcessOutOfMemory("HashMap::Initialize");
return;
}
capacity_ = capacity;
diff --git a/deps/v8/src/heap-profiler.cc b/deps/v8/src/heap-profiler.cc
index 3fb1ec1122..91ac9867a2 100644
--- a/deps/v8/src/heap-profiler.cc
+++ b/deps/v8/src/heap-profiler.cc
@@ -69,7 +69,8 @@ class Clusterizer : public AllStatic {
JSObjectsCluster Clusterizer::Clusterize(HeapObject* obj, bool fine_grain) {
if (obj->IsJSObject()) {
JSObject* js_obj = JSObject::cast(obj);
- String* constructor = JSObject::cast(js_obj)->constructor_name();
+ String* constructor = GetConstructorNameForHeapProfile(
+ JSObject::cast(js_obj));
// Differentiate Object and Array instances.
if (fine_grain && (constructor == Heap::Object_symbol() ||
constructor == Heap::Array_symbol())) {
@@ -714,7 +715,7 @@ static void StackWeakReferenceCallback(Persistent<Value> object,
static void PrintProducerStackTrace(Object* obj, void* trace) {
if (!obj->IsJSObject()) return;
- String* constructor = JSObject::cast(obj)->constructor_name();
+ String* constructor = GetConstructorNameForHeapProfile(JSObject::cast(obj));
SmartPointer<char> s_name(
constructor->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL));
LOG(HeapSampleJSProducerEvent(GetConstructorName(*s_name),
@@ -886,7 +887,8 @@ static JSObjectsCluster HeapObjectAsCluster(HeapObject* object) {
return JSObjectsCluster(String::cast(object));
} else {
JSObject* js_obj = JSObject::cast(object);
- String* constructor = JSObject::cast(js_obj)->constructor_name();
+ String* constructor = GetConstructorNameForHeapProfile(
+ JSObject::cast(js_obj));
return JSObjectsCluster(constructor, object);
}
}
@@ -1064,6 +1066,8 @@ void AggregatedHeapSnapshotGenerator::FillHeapSnapshot(HeapSnapshot* snapshot) {
// Fill up references.
IterateRetainers<AllocatingRetainersIterator>(&entries_map);
+
+ snapshot->SetDominatorsToSelf();
}
diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc
index 61aadf7ebd..cbf93dd6a1 100644
--- a/deps/v8/src/ia32/macro-assembler-ia32.cc
+++ b/deps/v8/src/ia32/macro-assembler-ia32.cc
@@ -537,7 +537,6 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
void MacroAssembler::LoadAllocationTopHelper(Register result,
- Register result_end,
Register scratch,
AllocationFlags flags) {
ExternalReference new_space_allocation_top =
@@ -559,7 +558,6 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
if (scratch.is(no_reg)) {
mov(result, Operand::StaticVariable(new_space_allocation_top));
} else {
- ASSERT(!scratch.is(result_end));
mov(Operand(scratch), Immediate(new_space_allocation_top));
mov(result, Operand(scratch, 0));
}
@@ -608,7 +606,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
ASSERT(!result.is(result_end));
// Load address of new object into result.
- LoadAllocationTopHelper(result, result_end, scratch, flags);
+ LoadAllocationTopHelper(result, scratch, flags);
Register top_reg = result_end.is_valid() ? result_end : result;
@@ -664,7 +662,7 @@ void MacroAssembler::AllocateInNewSpace(int header_size,
ASSERT(!result.is(result_end));
// Load address of new object into result.
- LoadAllocationTopHelper(result, result_end, scratch, flags);
+ LoadAllocationTopHelper(result, scratch, flags);
// Calculate new top and bail out if new space is exhausted.
ExternalReference new_space_allocation_limit =
@@ -705,7 +703,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
ASSERT(!result.is(result_end));
// Load address of new object into result.
- LoadAllocationTopHelper(result, result_end, scratch, flags);
+ LoadAllocationTopHelper(result, scratch, flags);
// Calculate new top and bail out if new space is exhausted.
ExternalReference new_space_allocation_limit =
diff --git a/deps/v8/src/ia32/macro-assembler-ia32.h b/deps/v8/src/ia32/macro-assembler-ia32.h
index cea7a70183..d208dbe3fa 100644
--- a/deps/v8/src/ia32/macro-assembler-ia32.h
+++ b/deps/v8/src/ia32/macro-assembler-ia32.h
@@ -631,7 +631,6 @@ class MacroAssembler: public Assembler {
// Allocation support helpers.
void LoadAllocationTopHelper(Register result,
- Register result_end,
Register scratch,
AllocationFlags flags);
void UpdateAllocationTopHelper(Register result_end, Register scratch);
diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc
index 3120ff9da7..adcb5219ec 100644
--- a/deps/v8/src/ia32/stub-cache-ia32.cc
+++ b/deps/v8/src/ia32/stub-cache-ia32.cc
@@ -3021,8 +3021,7 @@ MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
// Specialized stub for constructing objects from functions which only have only
// simple assignments of the form this.x = ...; in their body.
-MaybeObject* ConstructStubCompiler::CompileConstructStub(
- SharedFunctionInfo* shared) {
+MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
// ----------- S t a t e -------------
// -- eax : argc
// -- edi : constructor
@@ -3098,6 +3097,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(
// edi: undefined
// Fill the initialized properties with a constant value or a passed argument
// depending on the this.x = ...; assignment in the function.
+ SharedFunctionInfo* shared = function->shared();
for (int i = 0; i < shared->this_property_assignments_count(); i++) {
if (shared->IsThisPropertyAssignmentArgument(i)) {
// Check if the argument assigned to the property is actually passed.
@@ -3125,8 +3125,9 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(
}
// Fill the unused in-object property fields with undefined.
+ ASSERT(function->has_initial_map());
for (int i = shared->this_property_assignments_count();
- i < shared->CalculateInObjectProperties();
+ i < function->initial_map()->inobject_properties();
i++) {
__ mov(Operand(edx, i * kPointerSize), edi);
}
diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc
index d12aafb6df..55f15debd0 100644
--- a/deps/v8/src/log.cc
+++ b/deps/v8/src/log.cc
@@ -194,11 +194,6 @@ class Ticker: public Sampler {
~Ticker() { if (IsActive()) Stop(); }
- virtual void SampleStack(TickSample* sample) {
- ASSERT(IsSynchronous());
- StackTracer::Trace(sample);
- }
-
virtual void Tick(TickSample* sample) {
if (profiler_) profiler_->Insert(sample);
if (window_) window_->AddState(sample->state);
@@ -224,6 +219,12 @@ class Ticker: public Sampler {
if (!window_ && IsActive()) Stop();
}
+ protected:
+ virtual void DoSampleStack(TickSample* sample) {
+ ASSERT(IsSynchronous());
+ StackTracer::Trace(sample);
+ }
+
private:
SlidingStateWindow* window_;
Profiler* profiler_;
diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc
index 8efb0daae6..f5d19e280d 100644
--- a/deps/v8/src/objects.cc
+++ b/deps/v8/src/objects.cc
@@ -1166,9 +1166,6 @@ String* JSObject::class_name() {
String* JSObject::constructor_name() {
- if (IsJSFunction()) {
- return Heap::closure_symbol();
- }
if (map()->constructor()->IsJSFunction()) {
JSFunction* constructor = JSFunction::cast(map()->constructor());
String* name = String::cast(constructor->shared()->name());
diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc
index 7e4a51e2fa..186d1020d7 100644
--- a/deps/v8/src/parser.cc
+++ b/deps/v8/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;
diff --git a/deps/v8/src/parser.h b/deps/v8/src/parser.h
index 9a84ab9071..a067bd7c7d 100644
--- a/deps/v8/src/parser.h
+++ b/deps/v8/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
diff --git a/deps/v8/src/platform-freebsd.cc b/deps/v8/src/platform-freebsd.cc
index 6b8f2c048a..0d89a16f59 100644
--- a/deps/v8/src/platform-freebsd.cc
+++ b/deps/v8/src/platform-freebsd.cc
@@ -620,7 +620,8 @@ Sampler::Sampler(int interval, bool profiling)
: interval_(interval),
profiling_(profiling),
synchronous_(profiling),
- active_(false) {
+ active_(false),
+ samples_taken_(0) {
data_ = new PlatformData();
}
diff --git a/deps/v8/src/platform-linux.cc b/deps/v8/src/platform-linux.cc
index 89003ba83f..cb8e919ea7 100644
--- a/deps/v8/src/platform-linux.cc
+++ b/deps/v8/src/platform-linux.cc
@@ -865,7 +865,8 @@ Sampler::Sampler(int interval, bool profiling)
: interval_(interval),
profiling_(profiling),
synchronous_(profiling),
- active_(false) {
+ active_(false),
+ samples_taken_(0) {
data_ = new PlatformData(this);
}
diff --git a/deps/v8/src/platform-macos.cc b/deps/v8/src/platform-macos.cc
index 5e0e78dbf8..c3f21dc514 100644
--- a/deps/v8/src/platform-macos.cc
+++ b/deps/v8/src/platform-macos.cc
@@ -634,7 +634,8 @@ Sampler::Sampler(int interval, bool profiling)
: interval_(interval),
profiling_(profiling),
synchronous_(profiling),
- active_(false) {
+ active_(false),
+ samples_taken_(0) {
data_ = new PlatformData(this);
}
diff --git a/deps/v8/src/platform-openbsd.cc b/deps/v8/src/platform-openbsd.cc
index e03059ad72..0751fc7eed 100644
--- a/deps/v8/src/platform-openbsd.cc
+++ b/deps/v8/src/platform-openbsd.cc
@@ -572,7 +572,11 @@ class Sampler::PlatformData : public Malloced {
Sampler::Sampler(int interval, bool profiling)
- : interval_(interval), profiling_(profiling), active_(false) {
+ : interval_(interval),
+ profiling_(profiling),
+ synchronous_(profiling),
+ active_(false),
+ samples_taken_(0) {
data_ = new PlatformData();
}
diff --git a/deps/v8/src/platform-solaris.cc b/deps/v8/src/platform-solaris.cc
index fcd69deb42..ff5d83b660 100644
--- a/deps/v8/src/platform-solaris.cc
+++ b/deps/v8/src/platform-solaris.cc
@@ -605,7 +605,8 @@ Sampler::Sampler(int interval, bool profiling)
: interval_(interval),
profiling_(profiling),
synchronous_(profiling),
- active_(false) {
+ active_(false),
+ samples_taken_(0) {
data_ = new PlatformData();
}
diff --git a/deps/v8/src/platform-win32.cc b/deps/v8/src/platform-win32.cc
index a0ba5e865c..c50424e57a 100644
--- a/deps/v8/src/platform-win32.cc
+++ b/deps/v8/src/platform-win32.cc
@@ -1903,7 +1903,8 @@ Sampler::Sampler(int interval, bool profiling)
: interval_(interval),
profiling_(profiling),
synchronous_(profiling),
- active_(false) {
+ active_(false),
+ samples_taken_(0) {
data_ = new PlatformData(this);
}
diff --git a/deps/v8/src/platform.h b/deps/v8/src/platform.h
index c4ef23013e..6c7294c242 100644
--- a/deps/v8/src/platform.h
+++ b/deps/v8/src/platform.h
@@ -559,11 +559,14 @@ class TickSample {
class Sampler {
public:
// Initialize sampler.
- explicit Sampler(int interval, bool profiling);
+ Sampler(int interval, bool profiling);
virtual ~Sampler();
// Performs stack sampling.
- virtual void SampleStack(TickSample* sample) = 0;
+ void SampleStack(TickSample* sample) {
+ DoSampleStack(sample);
+ IncSamplesTaken();
+ }
// This method is called for each sampling period with the current
// program counter.
@@ -585,14 +588,24 @@ class Sampler {
// Whether the sampler is running (that is, consumes resources).
bool IsActive() const { return active_; }
+ // Used in tests to make sure that stack sampling is performed.
+ int samples_taken() const { return samples_taken_; }
+ void ResetSamplesTaken() { samples_taken_ = 0; }
+
class PlatformData;
+ protected:
+ virtual void DoSampleStack(TickSample* sample) = 0;
+
private:
+ void IncSamplesTaken() { if (++samples_taken_ < 0) samples_taken_ = 0; }
+
const int interval_;
const bool profiling_;
const bool synchronous_;
bool active_;
PlatformData* data_; // Platform specific data.
+ int samples_taken_; // Counts stack samples taken.
DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler);
};
diff --git a/deps/v8/src/preparse-data.cc b/deps/v8/src/preparse-data.cc
new file mode 100644
index 0000000000..9a3677183e
--- /dev/null
+++ b/deps/v8/src/preparse-data.cc
@@ -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.
diff --git a/deps/v8/src/preparse-data.h b/deps/v8/src/preparse-data.h
new file mode 100644
index 0000000000..a96e50fa10
--- /dev/null
+++ b/deps/v8/src/preparse-data.h
@@ -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_
diff --git a/deps/v8/src/preparser.cc b/deps/v8/src/preparser.cc
new file mode 100644
index 0000000000..9061731237
--- /dev/null
+++ b/deps/v8/src/preparser.cc
@@ -0,0 +1,1184 @@
+// 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 "unicode.h"
+#include "globals.h"
+#include "checks.h"
+#include "allocation.h"
+#include "utils.h"
+#include "list.h"
+#include "scanner-base.h"
+#include "preparse-data.h"
+#include "preparser.h"
+
+namespace v8 {
+namespace preparser {
+
+// Preparsing checks a JavaScript program and emits preparse-data that helps
+// a later parsing to be faster.
+// See preparser-data.h for the data.
+
+// The PreParser checks that the syntax follows the grammar for JavaScript,
+// and collects some information about the program along the way.
+// The grammar check is only performed in order to understand the program
+// sufficiently to deduce some information about it, that can be used
+// to speed up later parsing. Finding errors is not the goal of pre-parsing,
+// rather it is to speed up properly written and correct programs.
+// That means that contextual checks (like a label being declared where
+// it is used) are generally omitted.
+
+namespace i = ::v8::internal;
+
+#define CHECK_OK ok); \
+ if (!*ok) return -1; \
+ ((void)0
+#define DUMMY ) // to make indentation work
+#undef DUMMY
+
+
+void PreParser::ReportUnexpectedToken(i::Token::Value token) {
+ // We don't report stack overflows here, to avoid increasing the
+ // stack depth even further. Instead we report it after parsing is
+ // over, in ParseProgram.
+ if (token == i::Token::ILLEGAL && scanner_->stack_overflow()) {
+ return;
+ }
+ i::JavaScriptScanner::Location source_location = scanner_->location();
+
+ // Four of the tokens are treated specially
+ switch (token) {
+ case i::Token::EOS:
+ return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ "unexpected_eos", NULL);
+ case i::Token::NUMBER:
+ return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ "unexpected_token_number", NULL);
+ case i::Token::STRING:
+ return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ "unexpected_token_string", NULL);
+ case i::Token::IDENTIFIER:
+ return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ "unexpected_token_identifier", NULL);
+ default:
+ const char* name = i::Token::String(token);
+ ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ "unexpected_token", name);
+ }
+}
+
+
+SourceElements PreParser::ParseSourceElements(int end_token,
+ bool* ok) {
+ // SourceElements ::
+ // (Statement)* <end_token>
+
+ while (peek() != end_token) {
+ ParseStatement(CHECK_OK);
+ }
+ return kUnknownSourceElements;
+}
+
+
+Statement PreParser::ParseStatement(bool* ok) {
+ // Statement ::
+ // Block
+ // VariableStatement
+ // EmptyStatement
+ // ExpressionStatement
+ // IfStatement
+ // IterationStatement
+ // ContinueStatement
+ // BreakStatement
+ // ReturnStatement
+ // WithStatement
+ // LabelledStatement
+ // SwitchStatement
+ // ThrowStatement
+ // TryStatement
+ // DebuggerStatement
+
+ // Note: Since labels can only be used by 'break' and 'continue'
+ // statements, which themselves are only valid within blocks,
+ // iterations or 'switch' statements (i.e., BreakableStatements),
+ // labels can be simply ignored in all other cases; except for
+ // trivial labeled break statements 'label: break label' which is
+ // parsed into an empty statement.
+
+ // Keep the source position of the statement
+ switch (peek()) {
+ case i::Token::LBRACE:
+ return ParseBlock(ok);
+
+ case i::Token::CONST:
+ case i::Token::VAR:
+ return ParseVariableStatement(ok);
+
+ case i::Token::SEMICOLON:
+ Next();
+ return kUnknownStatement;
+
+ case i::Token::IF:
+ return ParseIfStatement(ok);
+
+ case i::Token::DO:
+ return ParseDoWhileStatement(ok);
+
+ case i::Token::WHILE:
+ return ParseWhileStatement(ok);
+
+ case i::Token::FOR:
+ return ParseForStatement(ok);
+
+ case i::Token::CONTINUE:
+ return ParseContinueStatement(ok);
+
+ case i::Token::BREAK:
+ return ParseBreakStatement(ok);
+
+ case i::Token::RETURN:
+ return ParseReturnStatement(ok);
+
+ case i::Token::WITH:
+ return ParseWithStatement(ok);
+
+ case i::Token::SWITCH:
+ return ParseSwitchStatement(ok);
+
+ case i::Token::THROW:
+ return ParseThrowStatement(ok);
+
+ case i::Token::TRY:
+ return ParseTryStatement(ok);
+
+ case i::Token::FUNCTION:
+ return ParseFunctionDeclaration(ok);
+
+ case i::Token::NATIVE:
+ return ParseNativeDeclaration(ok);
+
+ case i::Token::DEBUGGER:
+ return ParseDebuggerStatement(ok);
+
+ default:
+ return ParseExpressionOrLabelledStatement(ok);
+ }
+}
+
+
+Statement PreParser::ParseFunctionDeclaration(bool* ok) {
+ // FunctionDeclaration ::
+ // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
+ Expect(i::Token::FUNCTION, CHECK_OK);
+ ParseIdentifier(CHECK_OK);
+ ParseFunctionLiteral(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+// Language extension which is only enabled for source files loaded
+// through the API's extension mechanism. A native function
+// declaration is resolved by looking up the function through a
+// callback provided by the extension.
+Statement PreParser::ParseNativeDeclaration(bool* ok) {
+ Expect(i::Token::NATIVE, CHECK_OK);
+ Expect(i::Token::FUNCTION, CHECK_OK);
+ ParseIdentifier(CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ bool done = (peek() == i::Token::RPAREN);
+ while (!done) {
+ ParseIdentifier(CHECK_OK);
+ done = (peek() == i::Token::RPAREN);
+ if (!done) {
+ Expect(i::Token::COMMA, CHECK_OK);
+ }
+ }
+ Expect(i::Token::RPAREN, CHECK_OK);
+ Expect(i::Token::SEMICOLON, CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseBlock(bool* ok) {
+ // Block ::
+ // '{' Statement* '}'
+
+ // Note that a Block does not introduce a new execution scope!
+ // (ECMA-262, 3rd, 12.2)
+ //
+ Expect(i::Token::LBRACE, CHECK_OK);
+ while (peek() != i::Token::RBRACE) {
+ ParseStatement(CHECK_OK);
+ }
+ Expect(i::Token::RBRACE, CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseVariableStatement(bool* ok) {
+ // VariableStatement ::
+ // VariableDeclarations ';'
+
+ Statement result = ParseVariableDeclarations(true, NULL, CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+ return result;
+}
+
+
+// If the variable declaration declares exactly one non-const
+// variable, then *var is set to that variable. In all other cases,
+// *var is untouched; in particular, it is the caller's responsibility
+// to initialize it properly. This mechanism is also used for the parsing
+// of 'for-in' loops.
+Statement PreParser::ParseVariableDeclarations(bool accept_IN,
+ int* num_decl,
+ bool* ok) {
+ // VariableDeclarations ::
+ // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
+
+ if (peek() == i::Token::VAR) {
+ Consume(i::Token::VAR);
+ } else if (peek() == i::Token::CONST) {
+ Consume(i::Token::CONST);
+ } else {
+ *ok = false;
+ return 0;
+ }
+
+ // The scope of a variable/const declared anywhere inside a function
+ // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). .
+ int nvars = 0; // the number of variables declared
+ do {
+ // Parse variable name.
+ if (nvars > 0) Consume(i::Token::COMMA);
+ ParseIdentifier(CHECK_OK);
+ nvars++;
+ if (peek() == i::Token::ASSIGN) {
+ Expect(i::Token::ASSIGN, CHECK_OK);
+ ParseAssignmentExpression(accept_IN, CHECK_OK);
+ }
+ } while (peek() == i::Token::COMMA);
+
+ if (num_decl != NULL) *num_decl = nvars;
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseExpressionOrLabelledStatement(
+ bool* ok) {
+ // ExpressionStatement | LabelledStatement ::
+ // Expression ';'
+ // Identifier ':' Statement
+
+ Expression expr = ParseExpression(true, CHECK_OK);
+ if (peek() == i::Token::COLON && expr == kIdentifierExpression) {
+ Consume(i::Token::COLON);
+ return ParseStatement(ok);
+ }
+ // Parsed expression statement.
+ ExpectSemicolon(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseIfStatement(bool* ok) {
+ // IfStatement ::
+ // 'if' '(' Expression ')' Statement ('else' Statement)?
+
+ Expect(i::Token::IF, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+ ParseStatement(CHECK_OK);
+ if (peek() == i::Token::ELSE) {
+ Next();
+ ParseStatement(CHECK_OK);
+ }
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseContinueStatement(bool* ok) {
+ // ContinueStatement ::
+ // 'continue' [no line terminator] Identifier? ';'
+
+ Expect(i::Token::CONTINUE, CHECK_OK);
+ i::Token::Value tok = peek();
+ if (!scanner_->has_line_terminator_before_next() &&
+ tok != i::Token::SEMICOLON &&
+ tok != i::Token::RBRACE &&
+ tok != i::Token::EOS) {
+ ParseIdentifier(CHECK_OK);
+ }
+ ExpectSemicolon(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseBreakStatement(bool* ok) {
+ // BreakStatement ::
+ // 'break' [no line terminator] Identifier? ';'
+
+ Expect(i::Token::BREAK, CHECK_OK);
+ i::Token::Value tok = peek();
+ if (!scanner_->has_line_terminator_before_next() &&
+ tok != i::Token::SEMICOLON &&
+ tok != i::Token::RBRACE &&
+ tok != i::Token::EOS) {
+ ParseIdentifier(CHECK_OK);
+ }
+ ExpectSemicolon(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseReturnStatement(bool* ok) {
+ // ReturnStatement ::
+ // 'return' [no line terminator] Expression? ';'
+
+ // Consume the return token. It is necessary to do the before
+ // reporting any errors on it, because of the way errors are
+ // reported (underlining).
+ Expect(i::Token::RETURN, CHECK_OK);
+
+ // An ECMAScript program is considered syntactically incorrect if it
+ // contains a return statement that is not within the body of a
+ // function. See ECMA-262, section 12.9, page 67.
+ // This is not handled during preparsing.
+
+ i::Token::Value tok = peek();
+ if (!scanner_->has_line_terminator_before_next() &&
+ tok != i::Token::SEMICOLON &&
+ tok != i::Token::RBRACE &&
+ tok != i::Token::EOS) {
+ ParseExpression(true, CHECK_OK);
+ }
+ ExpectSemicolon(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseWithStatement(bool* ok) {
+ // WithStatement ::
+ // 'with' '(' Expression ')' Statement
+ Expect(i::Token::WITH, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+
+ scope_->EnterWith();
+ ParseStatement(CHECK_OK);
+ scope_->LeaveWith();
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseSwitchStatement(bool* ok) {
+ // SwitchStatement ::
+ // 'switch' '(' Expression ')' '{' CaseClause* '}'
+
+ Expect(i::Token::SWITCH, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+
+ Expect(i::Token::LBRACE, CHECK_OK);
+ i::Token::Value token = peek();
+ while (token != i::Token::RBRACE) {
+ if (token == i::Token::CASE) {
+ Expect(i::Token::CASE, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::COLON, CHECK_OK);
+ } else if (token == i::Token::DEFAULT) {
+ Expect(i::Token::DEFAULT, CHECK_OK);
+ Expect(i::Token::COLON, CHECK_OK);
+ } else {
+ ParseStatement(CHECK_OK);
+ }
+ token = peek();
+ }
+ Expect(i::Token::RBRACE, CHECK_OK);
+
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseDoWhileStatement(bool* ok) {
+ // DoStatement ::
+ // 'do' Statement 'while' '(' Expression ')' ';'
+
+ Expect(i::Token::DO, CHECK_OK);
+ ParseStatement(CHECK_OK);
+ Expect(i::Token::WHILE, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseWhileStatement(bool* ok) {
+ // WhileStatement ::
+ // 'while' '(' Expression ')' Statement
+
+ Expect(i::Token::WHILE, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+ ParseStatement(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseForStatement(bool* ok) {
+ // ForStatement ::
+ // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
+
+ Expect(i::Token::FOR, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ if (peek() != i::Token::SEMICOLON) {
+ if (peek() == i::Token::VAR || peek() == i::Token::CONST) {
+ int decl_count;
+ ParseVariableDeclarations(false, &decl_count, CHECK_OK);
+ if (peek() == i::Token::IN && decl_count == 1) {
+ Expect(i::Token::IN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+
+ ParseStatement(CHECK_OK);
+ return kUnknownStatement;
+ }
+ } else {
+ ParseExpression(false, CHECK_OK);
+ if (peek() == i::Token::IN) {
+ Expect(i::Token::IN, CHECK_OK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+
+ ParseStatement(CHECK_OK);
+ return kUnknownStatement;
+ }
+ }
+ }
+
+ // Parsed initializer at this point.
+ Expect(i::Token::SEMICOLON, CHECK_OK);
+
+ if (peek() != i::Token::SEMICOLON) {
+ ParseExpression(true, CHECK_OK);
+ }
+ Expect(i::Token::SEMICOLON, CHECK_OK);
+
+ if (peek() != i::Token::RPAREN) {
+ ParseExpression(true, CHECK_OK);
+ }
+ Expect(i::Token::RPAREN, CHECK_OK);
+
+ ParseStatement(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseThrowStatement(bool* ok) {
+ // ThrowStatement ::
+ // 'throw' [no line terminator] Expression ';'
+
+ Expect(i::Token::THROW, CHECK_OK);
+ if (scanner_->has_line_terminator_before_next()) {
+ i::JavaScriptScanner::Location pos = scanner_->location();
+ ReportMessageAt(pos.beg_pos, pos.end_pos,
+ "newline_after_throw", NULL);
+ *ok = false;
+ return kUnknownStatement;
+ }
+ ParseExpression(true, CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseTryStatement(bool* ok) {
+ // TryStatement ::
+ // 'try' Block Catch
+ // 'try' Block Finally
+ // 'try' Block Catch Finally
+ //
+ // Catch ::
+ // 'catch' '(' Identifier ')' Block
+ //
+ // Finally ::
+ // 'finally' Block
+
+ // In preparsing, allow any number of catch/finally blocks, including zero
+ // of both.
+
+ Expect(i::Token::TRY, CHECK_OK);
+
+ ParseBlock(CHECK_OK);
+
+ bool catch_or_finally_seen = false;
+ if (peek() == i::Token::CATCH) {
+ Consume(i::Token::CATCH);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ ParseIdentifier(CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+ scope_->EnterWith();
+ ParseBlock(ok);
+ scope_->LeaveWith();
+ if (!*ok) return kUnknownStatement;
+ catch_or_finally_seen = true;
+ }
+ if (peek() == i::Token::FINALLY) {
+ Consume(i::Token::FINALLY);
+ ParseBlock(CHECK_OK);
+ catch_or_finally_seen = true;
+ }
+ if (!catch_or_finally_seen) {
+ *ok = false;
+ }
+ return kUnknownStatement;
+}
+
+
+Statement PreParser::ParseDebuggerStatement(bool* ok) {
+ // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
+ // contexts this is used as a statement which invokes the debugger as if a
+ // break point is present.
+ // DebuggerStatement ::
+ // 'debugger' ';'
+
+ Expect(i::Token::DEBUGGER, CHECK_OK);
+ ExpectSemicolon(CHECK_OK);
+ return kUnknownStatement;
+}
+
+
+// Precedence = 1
+Expression PreParser::ParseExpression(bool accept_IN, bool* ok) {
+ // Expression ::
+ // AssignmentExpression
+ // Expression ',' AssignmentExpression
+
+ Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK);
+ while (peek() == i::Token::COMMA) {
+ Expect(i::Token::COMMA, CHECK_OK);
+ ParseAssignmentExpression(accept_IN, CHECK_OK);
+ result = kUnknownExpression;
+ }
+ return result;
+}
+
+
+// Precedence = 2
+Expression PreParser::ParseAssignmentExpression(bool accept_IN,
+ bool* ok) {
+ // AssignmentExpression ::
+ // ConditionalExpression
+ // LeftHandSideExpression AssignmentOperator AssignmentExpression
+
+ Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
+
+ if (!i::Token::IsAssignmentOp(peek())) {
+ // Parsed conditional expression only (no assignment).
+ return expression;
+ }
+
+ i::Token::Value op = Next(); // Get assignment operator.
+ ParseAssignmentExpression(accept_IN, CHECK_OK);
+
+ if ((op == i::Token::ASSIGN) && (expression == kThisPropertyExpression)) {
+ scope_->AddProperty();
+ }
+
+ return kUnknownExpression;
+}
+
+
+// Precedence = 3
+Expression PreParser::ParseConditionalExpression(bool accept_IN,
+ bool* ok) {
+ // ConditionalExpression ::
+ // LogicalOrExpression
+ // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
+
+ // We start using the binary expression parser for prec >= 4 only!
+ Expression expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
+ if (peek() != i::Token::CONDITIONAL) return expression;
+ Consume(i::Token::CONDITIONAL);
+ // In parsing the first assignment expression in conditional
+ // expressions we always accept the 'in' keyword; see ECMA-262,
+ // section 11.12, page 58.
+ ParseAssignmentExpression(true, CHECK_OK);
+ Expect(i::Token::COLON, CHECK_OK);
+ ParseAssignmentExpression(accept_IN, CHECK_OK);
+ return kUnknownExpression;
+}
+
+
+int PreParser::Precedence(i::Token::Value tok, bool accept_IN) {
+ if (tok == i::Token::IN && !accept_IN)
+ return 0; // 0 precedence will terminate binary expression parsing
+
+ return i::Token::Precedence(tok);
+}
+
+
+// Precedence >= 4
+Expression PreParser::ParseBinaryExpression(int prec,
+ bool accept_IN,
+ bool* ok) {
+ Expression result = ParseUnaryExpression(CHECK_OK);
+ for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
+ // prec1 >= 4
+ while (Precedence(peek(), accept_IN) == prec1) {
+ Next();
+ ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
+ result = kUnknownExpression;
+ }
+ }
+ return result;
+}
+
+
+Expression PreParser::ParseUnaryExpression(bool* ok) {
+ // UnaryExpression ::
+ // PostfixExpression
+ // 'delete' UnaryExpression
+ // 'void' UnaryExpression
+ // 'typeof' UnaryExpression
+ // '++' UnaryExpression
+ // '--' UnaryExpression
+ // '+' UnaryExpression
+ // '-' UnaryExpression
+ // '~' UnaryExpression
+ // '!' UnaryExpression
+
+ i::Token::Value op = peek();
+ if (i::Token::IsUnaryOp(op) || i::Token::IsCountOp(op)) {
+ op = Next();
+ ParseUnaryExpression(ok);
+ return kUnknownExpression;
+ } else {
+ return ParsePostfixExpression(ok);
+ }
+}
+
+
+Expression PreParser::ParsePostfixExpression(bool* ok) {
+ // PostfixExpression ::
+ // LeftHandSideExpression ('++' | '--')?
+
+ Expression expression = ParseLeftHandSideExpression(CHECK_OK);
+ if (!scanner_->has_line_terminator_before_next() &&
+ i::Token::IsCountOp(peek())) {
+ Next();
+ return kUnknownExpression;
+ }
+ return expression;
+}
+
+
+Expression PreParser::ParseLeftHandSideExpression(bool* ok) {
+ // LeftHandSideExpression ::
+ // (NewExpression | MemberExpression) ...
+
+ Expression result;
+ if (peek() == i::Token::NEW) {
+ result = ParseNewExpression(CHECK_OK);
+ } else {
+ result = ParseMemberExpression(CHECK_OK);
+ }
+
+ while (true) {
+ switch (peek()) {
+ case i::Token::LBRACK: {
+ Consume(i::Token::LBRACK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RBRACK, CHECK_OK);
+ if (result == kThisExpression) {
+ result = kThisPropertyExpression;
+ } else {
+ result = kUnknownExpression;
+ }
+ break;
+ }
+
+ case i::Token::LPAREN: {
+ ParseArguments(CHECK_OK);
+ result = kUnknownExpression;
+ break;
+ }
+
+ case i::Token::PERIOD: {
+ Consume(i::Token::PERIOD);
+ ParseIdentifierName(CHECK_OK);
+ if (result == kThisExpression) {
+ result = kThisPropertyExpression;
+ } else {
+ result = kUnknownExpression;
+ }
+ break;
+ }
+
+ default:
+ return result;
+ }
+ }
+}
+
+
+Expression PreParser::ParseNewExpression(bool* ok) {
+ // NewExpression ::
+ // ('new')+ MemberExpression
+
+ // The grammar for new expressions is pretty warped. The keyword
+ // 'new' can either be a part of the new expression (where it isn't
+ // followed by an argument list) or a part of the member expression,
+ // where it must be followed by an argument list. To accommodate
+ // this, we parse the 'new' keywords greedily and keep track of how
+ // many we have parsed. This information is then passed on to the
+ // member expression parser, which is only allowed to match argument
+ // lists as long as it has 'new' prefixes left
+ unsigned new_count = 0;
+ do {
+ Consume(i::Token::NEW);
+ new_count++;
+ } while (peek() == i::Token::NEW);
+
+ return ParseMemberWithNewPrefixesExpression(new_count, ok);
+}
+
+
+Expression PreParser::ParseMemberExpression(bool* ok) {
+ return ParseMemberWithNewPrefixesExpression(0, ok);
+}
+
+
+Expression PreParser::ParseMemberWithNewPrefixesExpression(
+ unsigned new_count, bool* ok) {
+ // MemberExpression ::
+ // (PrimaryExpression | FunctionLiteral)
+ // ('[' Expression ']' | '.' Identifier | Arguments)*
+
+ // Parse the initial primary or function expression.
+ Expression result = kUnknownExpression;
+ if (peek() == i::Token::FUNCTION) {
+ Consume(i::Token::FUNCTION);
+ if (peek() == i::Token::IDENTIFIER) {
+ ParseIdentifier(CHECK_OK);
+ }
+ result = ParseFunctionLiteral(CHECK_OK);
+ } else {
+ result = ParsePrimaryExpression(CHECK_OK);
+ }
+
+ while (true) {
+ switch (peek()) {
+ case i::Token::LBRACK: {
+ Consume(i::Token::LBRACK);
+ ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RBRACK, CHECK_OK);
+ if (result == kThisExpression) {
+ result = kThisPropertyExpression;
+ } else {
+ result = kUnknownExpression;
+ }
+ break;
+ }
+ case i::Token::PERIOD: {
+ Consume(i::Token::PERIOD);
+ ParseIdentifierName(CHECK_OK);
+ if (result == kThisExpression) {
+ result = kThisPropertyExpression;
+ } else {
+ result = kUnknownExpression;
+ }
+ break;
+ }
+ case i::Token::LPAREN: {
+ if (new_count == 0) return result;
+ // Consume one of the new prefixes (already parsed).
+ ParseArguments(CHECK_OK);
+ new_count--;
+ result = kUnknownExpression;
+ break;
+ }
+ default:
+ return result;
+ }
+ }
+}
+
+
+Expression PreParser::ParsePrimaryExpression(bool* ok) {
+ // PrimaryExpression ::
+ // 'this'
+ // 'null'
+ // 'true'
+ // 'false'
+ // Identifier
+ // Number
+ // String
+ // ArrayLiteral
+ // ObjectLiteral
+ // RegExpLiteral
+ // '(' Expression ')'
+
+ Expression result = kUnknownExpression;
+ switch (peek()) {
+ case i::Token::THIS: {
+ Next();
+ result = kThisExpression;
+ break;
+ }
+
+ case i::Token::IDENTIFIER: {
+ ParseIdentifier(CHECK_OK);
+ result = kIdentifierExpression;
+ break;
+ }
+
+ case i::Token::NULL_LITERAL:
+ case i::Token::TRUE_LITERAL:
+ case i::Token::FALSE_LITERAL:
+ case i::Token::NUMBER: {
+ Next();
+ break;
+ }
+ case i::Token::STRING: {
+ Next();
+ result = GetStringSymbol();
+ break;
+ }
+
+ case i::Token::ASSIGN_DIV:
+ result = ParseRegExpLiteral(true, CHECK_OK);
+ break;
+
+ case i::Token::DIV:
+ result = ParseRegExpLiteral(false, CHECK_OK);
+ break;
+
+ case i::Token::LBRACK:
+ result = ParseArrayLiteral(CHECK_OK);
+ break;
+
+ case i::Token::LBRACE:
+ result = ParseObjectLiteral(CHECK_OK);
+ break;
+
+ case i::Token::LPAREN:
+ Consume(i::Token::LPAREN);
+ result = ParseExpression(true, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+ if (result == kIdentifierExpression) result = kUnknownExpression;
+ break;
+
+ case i::Token::MOD:
+ result = ParseV8Intrinsic(CHECK_OK);
+ break;
+
+ default: {
+ Next();
+ *ok = false;
+ return kUnknownExpression;
+ }
+ }
+
+ return result;
+}
+
+
+Expression PreParser::ParseArrayLiteral(bool* ok) {
+ // ArrayLiteral ::
+ // '[' Expression? (',' Expression?)* ']'
+ Expect(i::Token::LBRACK, CHECK_OK);
+ while (peek() != i::Token::RBRACK) {
+ if (peek() != i::Token::COMMA) {
+ ParseAssignmentExpression(true, CHECK_OK);
+ }
+ if (peek() != i::Token::RBRACK) {
+ Expect(i::Token::COMMA, CHECK_OK);
+ }
+ }
+ Expect(i::Token::RBRACK, CHECK_OK);
+
+ scope_->NextMaterializedLiteralIndex();
+ return kUnknownExpression;
+}
+
+
+Expression PreParser::ParseObjectLiteral(bool* ok) {
+ // ObjectLiteral ::
+ // '{' (
+ // ((IdentifierName | String | Number) ':' AssignmentExpression)
+ // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
+ // )*[','] '}'
+
+ Expect(i::Token::LBRACE, CHECK_OK);
+ while (peek() != i::Token::RBRACE) {
+ i::Token::Value next = peek();
+ switch (next) {
+ case i::Token::IDENTIFIER: {
+ bool is_getter = false;
+ bool is_setter = false;
+ ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
+ if ((is_getter || is_setter) && peek() != i::Token::COLON) {
+ i::Token::Value name = Next();
+ if (name != i::Token::IDENTIFIER &&
+ name != i::Token::NUMBER &&
+ name != i::Token::STRING &&
+ !i::Token::IsKeyword(name)) {
+ *ok = false;
+ return kUnknownExpression;
+ }
+ ParseFunctionLiteral(CHECK_OK);
+ if (peek() != i::Token::RBRACE) {
+ Expect(i::Token::COMMA, CHECK_OK);
+ }
+ continue; // restart the while
+ }
+ break;
+ }
+ case i::Token::STRING:
+ Consume(next);
+ GetStringSymbol();
+ break;
+ case i::Token::NUMBER:
+ Consume(next);
+ break;
+ default:
+ if (i::Token::IsKeyword(next)) {
+ Consume(next);
+ } else {
+ // Unexpected token.
+ *ok = false;
+ return kUnknownExpression;
+ }
+ }
+
+ Expect(i::Token::COLON, CHECK_OK);
+ ParseAssignmentExpression(true, CHECK_OK);
+
+ // TODO(1240767): Consider allowing trailing comma.
+ if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK);
+ }
+ Expect(i::Token::RBRACE, CHECK_OK);
+
+ scope_->NextMaterializedLiteralIndex();
+ return kUnknownExpression;
+}
+
+
+Expression PreParser::ParseRegExpLiteral(bool seen_equal,
+ bool* ok) {
+ if (!scanner_->ScanRegExpPattern(seen_equal)) {
+ Next();
+ i::JavaScriptScanner::Location location = scanner_->location();
+ ReportMessageAt(location.beg_pos, location.end_pos,
+ "unterminated_regexp", NULL);
+ *ok = false;
+ return kUnknownExpression;
+ }
+
+ scope_->NextMaterializedLiteralIndex();
+
+ if (!scanner_->ScanRegExpFlags()) {
+ Next();
+ i::JavaScriptScanner::Location location = scanner_->location();
+ ReportMessageAt(location.beg_pos, location.end_pos,
+ "invalid_regexp_flags", NULL);
+ *ok = false;
+ return kUnknownExpression;
+ }
+ Next();
+ return kUnknownExpression;
+}
+
+
+Arguments PreParser::ParseArguments(bool* ok) {
+ // Arguments ::
+ // '(' (AssignmentExpression)*[','] ')'
+
+ Expect(i::Token::LPAREN, CHECK_OK);
+ bool done = (peek() == i::Token::RPAREN);
+ int argc = 0;
+ while (!done) {
+ ParseAssignmentExpression(true, CHECK_OK);
+ argc++;
+ done = (peek() == i::Token::RPAREN);
+ if (!done) Expect(i::Token::COMMA, CHECK_OK);
+ }
+ Expect(i::Token::RPAREN, CHECK_OK);
+ return argc;
+}
+
+
+Expression PreParser::ParseFunctionLiteral(bool* ok) {
+ // Function ::
+ // '(' FormalParameterList? ')' '{' FunctionBody '}'
+
+ // Parse function body.
+ ScopeType outer_scope_type = scope_->type();
+ bool inside_with = scope_->IsInsideWith();
+ Scope function_scope(&scope_, kFunctionScope);
+
+ // FormalParameterList ::
+ // '(' (Identifier)*[','] ')'
+ Expect(i::Token::LPAREN, CHECK_OK);
+ bool done = (peek() == i::Token::RPAREN);
+ while (!done) {
+ ParseIdentifier(CHECK_OK);
+ done = (peek() == i::Token::RPAREN);
+ if (!done) {
+ Expect(i::Token::COMMA, CHECK_OK);
+ }
+ }
+ Expect(i::Token::RPAREN, CHECK_OK);
+
+ Expect(i::Token::LBRACE, CHECK_OK);
+ int function_block_pos = scanner_->location().beg_pos;
+
+ // Determine if the function will be lazily compiled.
+ // Currently only happens to top-level functions.
+ // Optimistically assume that all top-level functions are lazily compiled.
+ bool is_lazily_compiled =
+ (outer_scope_type == kTopLevelScope && !inside_with && allow_lazy_);
+
+ if (is_lazily_compiled) {
+ log_->PauseRecording();
+ ParseSourceElements(i::Token::RBRACE, ok);
+ log_->ResumeRecording();
+ if (!*ok) return kUnknownExpression;
+
+ Expect(i::Token::RBRACE, CHECK_OK);
+
+ int end_pos = scanner_->location().end_pos;
+ log_->LogFunction(function_block_pos, end_pos,
+ function_scope.materialized_literal_count(),
+ function_scope.expected_properties());
+ } else {
+ ParseSourceElements(i::Token::RBRACE, CHECK_OK);
+ Expect(i::Token::RBRACE, CHECK_OK);
+ }
+ return kUnknownExpression;
+}
+
+
+Expression PreParser::ParseV8Intrinsic(bool* ok) {
+ // CallRuntime ::
+ // '%' Identifier Arguments
+
+ Expect(i::Token::MOD, CHECK_OK);
+ ParseIdentifier(CHECK_OK);
+ ParseArguments(CHECK_OK);
+
+ return kUnknownExpression;
+}
+
+
+void PreParser::ExpectSemicolon(bool* ok) {
+ // Check for automatic semicolon insertion according to
+ // the rules given in ECMA-262, section 7.9, page 21.
+ i::Token::Value tok = peek();
+ if (tok == i::Token::SEMICOLON) {
+ Next();
+ return;
+ }
+ if (scanner_->has_line_terminator_before_next() ||
+ tok == i::Token::RBRACE ||
+ tok == i::Token::EOS) {
+ return;
+ }
+ Expect(i::Token::SEMICOLON, ok);
+}
+
+
+Identifier PreParser::GetIdentifierSymbol() {
+ const char* literal_chars = scanner_->literal_string();
+ int literal_length = scanner_->literal_length();
+ int identifier_pos = scanner_->location().beg_pos;
+
+ log_->LogSymbol(identifier_pos, literal_chars, literal_length);
+
+ return kUnknownExpression;
+}
+
+
+Expression PreParser::GetStringSymbol() {
+ const char* literal_chars = scanner_->literal_string();
+ int literal_length = scanner_->literal_length();
+
+ int literal_position = scanner_->location().beg_pos;
+ log_->LogSymbol(literal_position, literal_chars, literal_length);
+
+ return kUnknownExpression;
+}
+
+
+Identifier PreParser::ParseIdentifier(bool* ok) {
+ Expect(i::Token::IDENTIFIER, ok);
+ if (!*ok) return kUnknownIdentifier;
+ return GetIdentifierSymbol();
+}
+
+
+Identifier PreParser::ParseIdentifierName(bool* ok) {
+ i::Token::Value next = Next();
+ if (i::Token::IsKeyword(next)) {
+ int pos = scanner_->location().beg_pos;
+ const char* keyword = i::Token::String(next);
+ log_->LogSymbol(pos, keyword, i::StrLength(keyword));
+ return kUnknownExpression;
+ }
+ if (next == i::Token::IDENTIFIER) {
+ return GetIdentifierSymbol();
+ }
+ *ok = false;
+ return kUnknownIdentifier;
+}
+
+
+// This function reads an identifier and determines whether or not it
+// is 'get' or 'set'. The reason for not using ParseIdentifier and
+// checking on the output is that this involves heap allocation which
+// we can't do during preparsing.
+Identifier PreParser::ParseIdentifierOrGetOrSet(bool* is_get,
+ bool* is_set,
+ bool* ok) {
+ Expect(i::Token::IDENTIFIER, CHECK_OK);
+ if (scanner_->literal_length() == 3) {
+ const char* token = scanner_->literal_string();
+ *is_get = strncmp(token, "get", 3) == 0;
+ *is_set = !*is_get && strncmp(token, "set", 3) == 0;
+ }
+ return GetIdentifierSymbol();
+}
+
+#undef CHECK_OK
+} } // v8::preparser
diff --git a/deps/v8/src/preparser.h b/deps/v8/src/preparser.h
index 8e8dfbe052..b783d65db3 100644
--- a/deps/v8/src/preparser.h
+++ b/deps/v8/src/preparser.h
@@ -28,15 +28,12 @@
#ifndef V8_PREPARSER_H
#define V8_PREPARSER_H
-#include "unicode.h"
-#include "utils.h"
-
namespace v8 {
namespace preparser {
// Preparsing checks a JavaScript program and emits preparse-data that helps
// a later parsing to be faster.
-// See preparser-data.h for the data.
+// See preparse-data.h for the data.
// The PreParser checks that the syntax follows the grammar for JavaScript,
// and collects some information about the program along the way.
@@ -76,7 +73,6 @@ typedef int Identifier;
typedef int Arguments;
-template <typename Scanner, typename PreParserLog>
class PreParser {
public:
PreParser() : scope_(NULL), allow_lazy_(true) { }
@@ -86,8 +82,8 @@ class PreParser {
// success (even if parsing failed, the pre-parse data successfully
// captured the syntax error), and false if a stack-overflow happened
// during parsing.
- bool PreParseProgram(Scanner* scanner,
- PreParserLog* log,
+ bool PreParseProgram(i::JavaScriptScanner* scanner,
+ i::ParserRecorder* log,
bool allow_lazy) {
allow_lazy_ = allow_lazy;
scanner_ = scanner;
@@ -235,1185 +231,11 @@ class PreParser {
static int Precedence(i::Token::Value tok, bool accept_IN);
- Scanner* scanner_;
- PreParserLog* log_;
+ i::JavaScriptScanner* scanner_;
+ i::ParserRecorder* log_;
Scope* scope_;
bool allow_lazy_;
};
-
-
-#define CHECK_OK ok); \
- if (!*ok) return -1; \
- ((void)0
-#define DUMMY ) // to make indentation work
-#undef DUMMY
-
-
-template <typename Scanner, typename Log>
-void PreParser<Scanner, Log>::ReportUnexpectedToken(i::Token::Value token) {
- // We don't report stack overflows here, to avoid increasing the
- // stack depth even further. Instead we report it after parsing is
- // over, in ParseProgram.
- if (token == i::Token::ILLEGAL && scanner_->stack_overflow()) {
- return;
- }
- typename Scanner::Location source_location = scanner_->location();
-
- // Four of the tokens are treated specially
- switch (token) {
- case i::Token::EOS:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_eos", NULL);
- case i::Token::NUMBER:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token_number", NULL);
- case i::Token::STRING:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token_string", NULL);
- case i::Token::IDENTIFIER:
- return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token_identifier", NULL);
- default:
- const char* name = i::Token::String(token);
- ReportMessageAt(source_location.beg_pos, source_location.end_pos,
- "unexpected_token", name);
- }
-}
-
-
-template <typename Scanner, typename Log>
-SourceElements PreParser<Scanner, Log>::ParseSourceElements(int end_token,
- bool* ok) {
- // SourceElements ::
- // (Statement)* <end_token>
-
- while (peek() != end_token) {
- ParseStatement(CHECK_OK);
- }
- return kUnknownSourceElements;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseStatement(bool* ok) {
- // Statement ::
- // Block
- // VariableStatement
- // EmptyStatement
- // ExpressionStatement
- // IfStatement
- // IterationStatement
- // ContinueStatement
- // BreakStatement
- // ReturnStatement
- // WithStatement
- // LabelledStatement
- // SwitchStatement
- // ThrowStatement
- // TryStatement
- // DebuggerStatement
-
- // Note: Since labels can only be used by 'break' and 'continue'
- // statements, which themselves are only valid within blocks,
- // iterations or 'switch' statements (i.e., BreakableStatements),
- // labels can be simply ignored in all other cases; except for
- // trivial labeled break statements 'label: break label' which is
- // parsed into an empty statement.
-
- // Keep the source position of the statement
- switch (peek()) {
- case i::Token::LBRACE:
- return ParseBlock(ok);
-
- case i::Token::CONST:
- case i::Token::VAR:
- return ParseVariableStatement(ok);
-
- case i::Token::SEMICOLON:
- Next();
- return kUnknownStatement;
-
- case i::Token::IF:
- return ParseIfStatement(ok);
-
- case i::Token::DO:
- return ParseDoWhileStatement(ok);
-
- case i::Token::WHILE:
- return ParseWhileStatement(ok);
-
- case i::Token::FOR:
- return ParseForStatement(ok);
-
- case i::Token::CONTINUE:
- return ParseContinueStatement(ok);
-
- case i::Token::BREAK:
- return ParseBreakStatement(ok);
-
- case i::Token::RETURN:
- return ParseReturnStatement(ok);
-
- case i::Token::WITH:
- return ParseWithStatement(ok);
-
- case i::Token::SWITCH:
- return ParseSwitchStatement(ok);
-
- case i::Token::THROW:
- return ParseThrowStatement(ok);
-
- case i::Token::TRY:
- return ParseTryStatement(ok);
-
- case i::Token::FUNCTION:
- return ParseFunctionDeclaration(ok);
-
- case i::Token::NATIVE:
- return ParseNativeDeclaration(ok);
-
- case i::Token::DEBUGGER:
- return ParseDebuggerStatement(ok);
-
- default:
- return ParseExpressionOrLabelledStatement(ok);
- }
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseFunctionDeclaration(bool* ok) {
- // FunctionDeclaration ::
- // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
- Expect(i::Token::FUNCTION, CHECK_OK);
- ParseIdentifier(CHECK_OK);
- ParseFunctionLiteral(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-// Language extension which is only enabled for source files loaded
-// through the API's extension mechanism. A native function
-// declaration is resolved by looking up the function through a
-// callback provided by the extension.
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseNativeDeclaration(bool* ok) {
- Expect(i::Token::NATIVE, CHECK_OK);
- Expect(i::Token::FUNCTION, CHECK_OK);
- ParseIdentifier(CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- bool done = (peek() == i::Token::RPAREN);
- while (!done) {
- ParseIdentifier(CHECK_OK);
- done = (peek() == i::Token::RPAREN);
- if (!done) {
- Expect(i::Token::COMMA, CHECK_OK);
- }
- }
- Expect(i::Token::RPAREN, CHECK_OK);
- Expect(i::Token::SEMICOLON, CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseBlock(bool* ok) {
- // Block ::
- // '{' Statement* '}'
-
- // Note that a Block does not introduce a new execution scope!
- // (ECMA-262, 3rd, 12.2)
- //
- Expect(i::Token::LBRACE, CHECK_OK);
- while (peek() != i::Token::RBRACE) {
- ParseStatement(CHECK_OK);
- }
- Expect(i::Token::RBRACE, CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseVariableStatement(bool* ok) {
- // VariableStatement ::
- // VariableDeclarations ';'
-
- Statement result = ParseVariableDeclarations(true, NULL, CHECK_OK);
- ExpectSemicolon(CHECK_OK);
- return result;
-}
-
-
-// If the variable declaration declares exactly one non-const
-// variable, then *var is set to that variable. In all other cases,
-// *var is untouched; in particular, it is the caller's responsibility
-// to initialize it properly. This mechanism is also used for the parsing
-// of 'for-in' loops.
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseVariableDeclarations(bool accept_IN,
- int* num_decl,
- bool* ok) {
- // VariableDeclarations ::
- // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
-
- if (peek() == i::Token::VAR) {
- Consume(i::Token::VAR);
- } else if (peek() == i::Token::CONST) {
- Consume(i::Token::CONST);
- } else {
- *ok = false;
- return 0;
- }
-
- // The scope of a variable/const declared anywhere inside a function
- // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). .
- int nvars = 0; // the number of variables declared
- do {
- // Parse variable name.
- if (nvars > 0) Consume(i::Token::COMMA);
- ParseIdentifier(CHECK_OK);
- nvars++;
- if (peek() == i::Token::ASSIGN) {
- Expect(i::Token::ASSIGN, CHECK_OK);
- ParseAssignmentExpression(accept_IN, CHECK_OK);
- }
- } while (peek() == i::Token::COMMA);
-
- if (num_decl != NULL) *num_decl = nvars;
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseExpressionOrLabelledStatement(
- bool* ok) {
- // ExpressionStatement | LabelledStatement ::
- // Expression ';'
- // Identifier ':' Statement
-
- Expression expr = ParseExpression(true, CHECK_OK);
- if (peek() == i::Token::COLON && expr == kIdentifierExpression) {
- Consume(i::Token::COLON);
- return ParseStatement(ok);
- }
- // Parsed expression statement.
- ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseIfStatement(bool* ok) {
- // IfStatement ::
- // 'if' '(' Expression ')' Statement ('else' Statement)?
-
- Expect(i::Token::IF, CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
- ParseStatement(CHECK_OK);
- if (peek() == i::Token::ELSE) {
- Next();
- ParseStatement(CHECK_OK);
- }
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseContinueStatement(bool* ok) {
- // ContinueStatement ::
- // 'continue' [no line terminator] Identifier? ';'
-
- Expect(i::Token::CONTINUE, CHECK_OK);
- i::Token::Value tok = peek();
- if (!scanner_->has_line_terminator_before_next() &&
- tok != i::Token::SEMICOLON &&
- tok != i::Token::RBRACE &&
- tok != i::Token::EOS) {
- ParseIdentifier(CHECK_OK);
- }
- ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseBreakStatement(bool* ok) {
- // BreakStatement ::
- // 'break' [no line terminator] Identifier? ';'
-
- Expect(i::Token::BREAK, CHECK_OK);
- i::Token::Value tok = peek();
- if (!scanner_->has_line_terminator_before_next() &&
- tok != i::Token::SEMICOLON &&
- tok != i::Token::RBRACE &&
- tok != i::Token::EOS) {
- ParseIdentifier(CHECK_OK);
- }
- ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseReturnStatement(bool* ok) {
- // ReturnStatement ::
- // 'return' [no line terminator] Expression? ';'
-
- // Consume the return token. It is necessary to do the before
- // reporting any errors on it, because of the way errors are
- // reported (underlining).
- Expect(i::Token::RETURN, CHECK_OK);
-
- // An ECMAScript program is considered syntactically incorrect if it
- // contains a return statement that is not within the body of a
- // function. See ECMA-262, section 12.9, page 67.
- // This is not handled during preparsing.
-
- i::Token::Value tok = peek();
- if (!scanner_->has_line_terminator_before_next() &&
- tok != i::Token::SEMICOLON &&
- tok != i::Token::RBRACE &&
- tok != i::Token::EOS) {
- ParseExpression(true, CHECK_OK);
- }
- ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseWithStatement(bool* ok) {
- // WithStatement ::
- // 'with' '(' Expression ')' Statement
- Expect(i::Token::WITH, CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
-
- scope_->EnterWith();
- ParseStatement(CHECK_OK);
- scope_->LeaveWith();
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseSwitchStatement(bool* ok) {
- // SwitchStatement ::
- // 'switch' '(' Expression ')' '{' CaseClause* '}'
-
- Expect(i::Token::SWITCH, CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
-
- Expect(i::Token::LBRACE, CHECK_OK);
- i::Token::Value token = peek();
- while (token != i::Token::RBRACE) {
- if (token == i::Token::CASE) {
- Expect(i::Token::CASE, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::COLON, CHECK_OK);
- } else if (token == i::Token::DEFAULT) {
- Expect(i::Token::DEFAULT, CHECK_OK);
- Expect(i::Token::COLON, CHECK_OK);
- } else {
- ParseStatement(CHECK_OK);
- }
- token = peek();
- }
- Expect(i::Token::RBRACE, CHECK_OK);
-
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseDoWhileStatement(bool* ok) {
- // DoStatement ::
- // 'do' Statement 'while' '(' Expression ')' ';'
-
- Expect(i::Token::DO, CHECK_OK);
- ParseStatement(CHECK_OK);
- Expect(i::Token::WHILE, CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseWhileStatement(bool* ok) {
- // WhileStatement ::
- // 'while' '(' Expression ')' Statement
-
- Expect(i::Token::WHILE, CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
- ParseStatement(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseForStatement(bool* ok) {
- // ForStatement ::
- // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
-
- Expect(i::Token::FOR, CHECK_OK);
- Expect(i::Token::LPAREN, CHECK_OK);
- if (peek() != i::Token::SEMICOLON) {
- if (peek() == i::Token::VAR || peek() == i::Token::CONST) {
- int decl_count;
- ParseVariableDeclarations(false, &decl_count, CHECK_OK);
- if (peek() == i::Token::IN && decl_count == 1) {
- Expect(i::Token::IN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
-
- ParseStatement(CHECK_OK);
- return kUnknownStatement;
- }
- } else {
- ParseExpression(false, CHECK_OK);
- if (peek() == i::Token::IN) {
- Expect(i::Token::IN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
-
- ParseStatement(CHECK_OK);
- return kUnknownStatement;
- }
- }
- }
-
- // Parsed initializer at this point.
- Expect(i::Token::SEMICOLON, CHECK_OK);
-
- if (peek() != i::Token::SEMICOLON) {
- ParseExpression(true, CHECK_OK);
- }
- Expect(i::Token::SEMICOLON, CHECK_OK);
-
- if (peek() != i::Token::RPAREN) {
- ParseExpression(true, CHECK_OK);
- }
- Expect(i::Token::RPAREN, CHECK_OK);
-
- ParseStatement(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseThrowStatement(bool* ok) {
- // ThrowStatement ::
- // 'throw' [no line terminator] Expression ';'
-
- Expect(i::Token::THROW, CHECK_OK);
- if (scanner_->has_line_terminator_before_next()) {
- typename Scanner::Location pos = scanner_->location();
- ReportMessageAt(pos.beg_pos, pos.end_pos,
- "newline_after_throw", NULL);
- *ok = false;
- return kUnknownStatement;
- }
- ParseExpression(true, CHECK_OK);
- ExpectSemicolon(CHECK_OK);
-
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseTryStatement(bool* ok) {
- // TryStatement ::
- // 'try' Block Catch
- // 'try' Block Finally
- // 'try' Block Catch Finally
- //
- // Catch ::
- // 'catch' '(' Identifier ')' Block
- //
- // Finally ::
- // 'finally' Block
-
- // In preparsing, allow any number of catch/finally blocks, including zero
- // of both.
-
- Expect(i::Token::TRY, CHECK_OK);
-
- ParseBlock(CHECK_OK);
-
- bool catch_or_finally_seen = false;
- if (peek() == i::Token::CATCH) {
- Consume(i::Token::CATCH);
- Expect(i::Token::LPAREN, CHECK_OK);
- ParseIdentifier(CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
- scope_->EnterWith();
- ParseBlock(ok);
- scope_->LeaveWith();
- if (!*ok) return kUnknownStatement;
- catch_or_finally_seen = true;
- }
- if (peek() == i::Token::FINALLY) {
- Consume(i::Token::FINALLY);
- ParseBlock(CHECK_OK);
- catch_or_finally_seen = true;
- }
- if (!catch_or_finally_seen) {
- *ok = false;
- }
- return kUnknownStatement;
-}
-
-
-template <typename Scanner, typename Log>
-Statement PreParser<Scanner, Log>::ParseDebuggerStatement(bool* ok) {
- // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
- // contexts this is used as a statement which invokes the debugger as if a
- // break point is present.
- // DebuggerStatement ::
- // 'debugger' ';'
-
- Expect(i::Token::DEBUGGER, CHECK_OK);
- ExpectSemicolon(CHECK_OK);
- return kUnknownStatement;
-}
-
-
-// Precedence = 1
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseExpression(bool accept_IN, bool* ok) {
- // Expression ::
- // AssignmentExpression
- // Expression ',' AssignmentExpression
-
- Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK);
- while (peek() == i::Token::COMMA) {
- Expect(i::Token::COMMA, CHECK_OK);
- ParseAssignmentExpression(accept_IN, CHECK_OK);
- result = kUnknownExpression;
- }
- return result;
-}
-
-
-// Precedence = 2
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseAssignmentExpression(bool accept_IN,
- bool* ok) {
- // AssignmentExpression ::
- // ConditionalExpression
- // LeftHandSideExpression AssignmentOperator AssignmentExpression
-
- Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
-
- if (!i::Token::IsAssignmentOp(peek())) {
- // Parsed conditional expression only (no assignment).
- return expression;
- }
-
- i::Token::Value op = Next(); // Get assignment operator.
- ParseAssignmentExpression(accept_IN, CHECK_OK);
-
- if ((op == i::Token::ASSIGN) && (expression == kThisPropertyExpression)) {
- scope_->AddProperty();
- }
-
- return kUnknownExpression;
-}
-
-
-// Precedence = 3
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseConditionalExpression(bool accept_IN,
- bool* ok) {
- // ConditionalExpression ::
- // LogicalOrExpression
- // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
-
- // We start using the binary expression parser for prec >= 4 only!
- Expression expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
- if (peek() != i::Token::CONDITIONAL) return expression;
- Consume(i::Token::CONDITIONAL);
- // In parsing the first assignment expression in conditional
- // expressions we always accept the 'in' keyword; see ECMA-262,
- // section 11.12, page 58.
- ParseAssignmentExpression(true, CHECK_OK);
- Expect(i::Token::COLON, CHECK_OK);
- ParseAssignmentExpression(accept_IN, CHECK_OK);
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-int PreParser<Scanner, Log>::Precedence(i::Token::Value tok, bool accept_IN) {
- if (tok == i::Token::IN && !accept_IN)
- return 0; // 0 precedence will terminate binary expression parsing
-
- return i::Token::Precedence(tok);
-}
-
-
-// Precedence >= 4
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseBinaryExpression(int prec,
- bool accept_IN,
- bool* ok) {
- Expression result = ParseUnaryExpression(CHECK_OK);
- for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
- // prec1 >= 4
- while (Precedence(peek(), accept_IN) == prec1) {
- Next();
- ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
- result = kUnknownExpression;
- }
- }
- return result;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseUnaryExpression(bool* ok) {
- // UnaryExpression ::
- // PostfixExpression
- // 'delete' UnaryExpression
- // 'void' UnaryExpression
- // 'typeof' UnaryExpression
- // '++' UnaryExpression
- // '--' UnaryExpression
- // '+' UnaryExpression
- // '-' UnaryExpression
- // '~' UnaryExpression
- // '!' UnaryExpression
-
- i::Token::Value op = peek();
- if (i::Token::IsUnaryOp(op) || i::Token::IsCountOp(op)) {
- op = Next();
- ParseUnaryExpression(ok);
- return kUnknownExpression;
- } else {
- return ParsePostfixExpression(ok);
- }
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParsePostfixExpression(bool* ok) {
- // PostfixExpression ::
- // LeftHandSideExpression ('++' | '--')?
-
- Expression expression = ParseLeftHandSideExpression(CHECK_OK);
- if (!scanner_->has_line_terminator_before_next() &&
- i::Token::IsCountOp(peek())) {
- Next();
- return kUnknownExpression;
- }
- return expression;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseLeftHandSideExpression(bool* ok) {
- // LeftHandSideExpression ::
- // (NewExpression | MemberExpression) ...
-
- Expression result;
- if (peek() == i::Token::NEW) {
- result = ParseNewExpression(CHECK_OK);
- } else {
- result = ParseMemberExpression(CHECK_OK);
- }
-
- while (true) {
- switch (peek()) {
- case i::Token::LBRACK: {
- Consume(i::Token::LBRACK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RBRACK, CHECK_OK);
- if (result == kThisExpression) {
- result = kThisPropertyExpression;
- } else {
- result = kUnknownExpression;
- }
- break;
- }
-
- case i::Token::LPAREN: {
- ParseArguments(CHECK_OK);
- result = kUnknownExpression;
- break;
- }
-
- case i::Token::PERIOD: {
- Consume(i::Token::PERIOD);
- ParseIdentifierName(CHECK_OK);
- if (result == kThisExpression) {
- result = kThisPropertyExpression;
- } else {
- result = kUnknownExpression;
- }
- break;
- }
-
- default:
- return result;
- }
- }
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseNewExpression(bool* ok) {
- // NewExpression ::
- // ('new')+ MemberExpression
-
- // The grammar for new expressions is pretty warped. The keyword
- // 'new' can either be a part of the new expression (where it isn't
- // followed by an argument list) or a part of the member expression,
- // where it must be followed by an argument list. To accommodate
- // this, we parse the 'new' keywords greedily and keep track of how
- // many we have parsed. This information is then passed on to the
- // member expression parser, which is only allowed to match argument
- // lists as long as it has 'new' prefixes left
- unsigned new_count = 0;
- do {
- Consume(i::Token::NEW);
- new_count++;
- } while (peek() == i::Token::NEW);
-
- return ParseMemberWithNewPrefixesExpression(new_count, ok);
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseMemberExpression(bool* ok) {
- return ParseMemberWithNewPrefixesExpression(0, ok);
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseMemberWithNewPrefixesExpression(
- unsigned new_count, bool* ok) {
- // MemberExpression ::
- // (PrimaryExpression | FunctionLiteral)
- // ('[' Expression ']' | '.' Identifier | Arguments)*
-
- // Parse the initial primary or function expression.
- Expression result = kUnknownExpression;
- if (peek() == i::Token::FUNCTION) {
- Consume(i::Token::FUNCTION);
- if (peek() == i::Token::IDENTIFIER) {
- ParseIdentifier(CHECK_OK);
- }
- result = ParseFunctionLiteral(CHECK_OK);
- } else {
- result = ParsePrimaryExpression(CHECK_OK);
- }
-
- while (true) {
- switch (peek()) {
- case i::Token::LBRACK: {
- Consume(i::Token::LBRACK);
- ParseExpression(true, CHECK_OK);
- Expect(i::Token::RBRACK, CHECK_OK);
- if (result == kThisExpression) {
- result = kThisPropertyExpression;
- } else {
- result = kUnknownExpression;
- }
- break;
- }
- case i::Token::PERIOD: {
- Consume(i::Token::PERIOD);
- ParseIdentifierName(CHECK_OK);
- if (result == kThisExpression) {
- result = kThisPropertyExpression;
- } else {
- result = kUnknownExpression;
- }
- break;
- }
- case i::Token::LPAREN: {
- if (new_count == 0) return result;
- // Consume one of the new prefixes (already parsed).
- ParseArguments(CHECK_OK);
- new_count--;
- result = kUnknownExpression;
- break;
- }
- default:
- return result;
- }
- }
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParsePrimaryExpression(bool* ok) {
- // PrimaryExpression ::
- // 'this'
- // 'null'
- // 'true'
- // 'false'
- // Identifier
- // Number
- // String
- // ArrayLiteral
- // ObjectLiteral
- // RegExpLiteral
- // '(' Expression ')'
-
- Expression result = kUnknownExpression;
- switch (peek()) {
- case i::Token::THIS: {
- Next();
- result = kThisExpression;
- break;
- }
-
- case i::Token::IDENTIFIER: {
- ParseIdentifier(CHECK_OK);
- result = kIdentifierExpression;
- break;
- }
-
- case i::Token::NULL_LITERAL:
- case i::Token::TRUE_LITERAL:
- case i::Token::FALSE_LITERAL:
- case i::Token::NUMBER: {
- Next();
- break;
- }
- case i::Token::STRING: {
- Next();
- result = GetStringSymbol();
- break;
- }
-
- case i::Token::ASSIGN_DIV:
- result = ParseRegExpLiteral(true, CHECK_OK);
- break;
-
- case i::Token::DIV:
- result = ParseRegExpLiteral(false, CHECK_OK);
- break;
-
- case i::Token::LBRACK:
- result = ParseArrayLiteral(CHECK_OK);
- break;
-
- case i::Token::LBRACE:
- result = ParseObjectLiteral(CHECK_OK);
- break;
-
- case i::Token::LPAREN:
- Consume(i::Token::LPAREN);
- result = ParseExpression(true, CHECK_OK);
- Expect(i::Token::RPAREN, CHECK_OK);
- if (result == kIdentifierExpression) result = kUnknownExpression;
- break;
-
- case i::Token::MOD:
- result = ParseV8Intrinsic(CHECK_OK);
- break;
-
- default: {
- Next();
- *ok = false;
- return kUnknownExpression;
- }
- }
-
- return result;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseArrayLiteral(bool* ok) {
- // ArrayLiteral ::
- // '[' Expression? (',' Expression?)* ']'
- Expect(i::Token::LBRACK, CHECK_OK);
- while (peek() != i::Token::RBRACK) {
- if (peek() != i::Token::COMMA) {
- ParseAssignmentExpression(true, CHECK_OK);
- }
- if (peek() != i::Token::RBRACK) {
- Expect(i::Token::COMMA, CHECK_OK);
- }
- }
- Expect(i::Token::RBRACK, CHECK_OK);
-
- scope_->NextMaterializedLiteralIndex();
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseObjectLiteral(bool* ok) {
- // ObjectLiteral ::
- // '{' (
- // ((IdentifierName | String | Number) ':' AssignmentExpression)
- // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
- // )*[','] '}'
-
- Expect(i::Token::LBRACE, CHECK_OK);
- while (peek() != i::Token::RBRACE) {
- i::Token::Value next = peek();
- switch (next) {
- case i::Token::IDENTIFIER: {
- bool is_getter = false;
- bool is_setter = false;
- ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
- if ((is_getter || is_setter) && peek() != i::Token::COLON) {
- i::Token::Value name = Next();
- if (name != i::Token::IDENTIFIER &&
- name != i::Token::NUMBER &&
- name != i::Token::STRING &&
- !i::Token::IsKeyword(name)) {
- *ok = false;
- return kUnknownExpression;
- }
- ParseFunctionLiteral(CHECK_OK);
- if (peek() != i::Token::RBRACE) {
- Expect(i::Token::COMMA, CHECK_OK);
- }
- continue; // restart the while
- }
- break;
- }
- case i::Token::STRING:
- Consume(next);
- GetStringSymbol();
- break;
- case i::Token::NUMBER:
- Consume(next);
- break;
- default:
- if (i::Token::IsKeyword(next)) {
- Consume(next);
- } else {
- // Unexpected token.
- *ok = false;
- return kUnknownExpression;
- }
- }
-
- Expect(i::Token::COLON, CHECK_OK);
- ParseAssignmentExpression(true, CHECK_OK);
-
- // TODO(1240767): Consider allowing trailing comma.
- if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK);
- }
- Expect(i::Token::RBRACE, CHECK_OK);
-
- scope_->NextMaterializedLiteralIndex();
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseRegExpLiteral(bool seen_equal,
- bool* ok) {
- if (!scanner_->ScanRegExpPattern(seen_equal)) {
- Next();
- typename Scanner::Location location = scanner_->location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "unterminated_regexp", NULL);
- *ok = false;
- return kUnknownExpression;
- }
-
- scope_->NextMaterializedLiteralIndex();
-
- if (!scanner_->ScanRegExpFlags()) {
- Next();
- typename Scanner::Location location = scanner_->location();
- ReportMessageAt(location.beg_pos, location.end_pos,
- "invalid_regexp_flags", NULL);
- *ok = false;
- return kUnknownExpression;
- }
- Next();
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Arguments PreParser<Scanner, Log>::ParseArguments(bool* ok) {
- // Arguments ::
- // '(' (AssignmentExpression)*[','] ')'
-
- Expect(i::Token::LPAREN, CHECK_OK);
- bool done = (peek() == i::Token::RPAREN);
- int argc = 0;
- while (!done) {
- ParseAssignmentExpression(true, CHECK_OK);
- argc++;
- done = (peek() == i::Token::RPAREN);
- if (!done) Expect(i::Token::COMMA, CHECK_OK);
- }
- Expect(i::Token::RPAREN, CHECK_OK);
- return argc;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseFunctionLiteral(bool* ok) {
- // Function ::
- // '(' FormalParameterList? ')' '{' FunctionBody '}'
-
- // Parse function body.
- ScopeType outer_scope_type = scope_->type();
- bool inside_with = scope_->IsInsideWith();
- Scope function_scope(&scope_, kFunctionScope);
-
- // FormalParameterList ::
- // '(' (Identifier)*[','] ')'
- Expect(i::Token::LPAREN, CHECK_OK);
- bool done = (peek() == i::Token::RPAREN);
- while (!done) {
- ParseIdentifier(CHECK_OK);
- done = (peek() == i::Token::RPAREN);
- if (!done) {
- Expect(i::Token::COMMA, CHECK_OK);
- }
- }
- Expect(i::Token::RPAREN, CHECK_OK);
-
- Expect(i::Token::LBRACE, CHECK_OK);
- int function_block_pos = scanner_->location().beg_pos;
-
- // Determine if the function will be lazily compiled.
- // Currently only happens to top-level functions.
- // Optimistically assume that all top-level functions are lazily compiled.
- bool is_lazily_compiled =
- (outer_scope_type == kTopLevelScope && !inside_with && allow_lazy_);
-
- if (is_lazily_compiled) {
- log_->PauseRecording();
- ParseSourceElements(i::Token::RBRACE, ok);
- log_->ResumeRecording();
- if (!*ok) return kUnknownExpression;
-
- Expect(i::Token::RBRACE, CHECK_OK);
-
- int end_pos = scanner_->location().end_pos;
- log_->LogFunction(function_block_pos, end_pos,
- function_scope.materialized_literal_count(),
- function_scope.expected_properties());
- } else {
- ParseSourceElements(i::Token::RBRACE, CHECK_OK);
- Expect(i::Token::RBRACE, CHECK_OK);
- }
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseV8Intrinsic(bool* ok) {
- // CallRuntime ::
- // '%' Identifier Arguments
-
- Expect(i::Token::MOD, CHECK_OK);
- ParseIdentifier(CHECK_OK);
- ParseArguments(CHECK_OK);
-
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-void PreParser<Scanner, Log>::ExpectSemicolon(bool* ok) {
- // Check for automatic semicolon insertion according to
- // the rules given in ECMA-262, section 7.9, page 21.
- i::Token::Value tok = peek();
- if (tok == i::Token::SEMICOLON) {
- Next();
- return;
- }
- if (scanner_->has_line_terminator_before_next() ||
- tok == i::Token::RBRACE ||
- tok == i::Token::EOS) {
- return;
- }
- Expect(i::Token::SEMICOLON, ok);
-}
-
-
-template <typename Scanner, typename Log>
-Identifier PreParser<Scanner, Log>::GetIdentifierSymbol() {
- const char* literal_chars = scanner_->literal_string();
- int literal_length = scanner_->literal_length();
- int identifier_pos = scanner_->location().beg_pos;
-
- log_->LogSymbol(identifier_pos, literal_chars, literal_length);
-
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::GetStringSymbol() {
- const char* literal_chars = scanner_->literal_string();
- int literal_length = scanner_->literal_length();
-
- int literal_position = scanner_->location().beg_pos;
- log_->LogSymbol(literal_position, literal_chars, literal_length);
-
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Identifier PreParser<Scanner, Log>::ParseIdentifier(bool* ok) {
- Expect(i::Token::IDENTIFIER, ok);
- if (!*ok) return kUnknownIdentifier;
- return GetIdentifierSymbol();
-}
-
-
-template <typename Scanner, typename Log>
-Identifier PreParser<Scanner, Log>::ParseIdentifierName(bool* ok) {
- i::Token::Value next = Next();
- if (i::Token::IsKeyword(next)) {
- int pos = scanner_->location().beg_pos;
- const char* keyword = i::Token::String(next);
- log_->LogSymbol(pos, keyword, i::StrLength(keyword));
- return kUnknownExpression;
- }
- if (next == i::Token::IDENTIFIER) {
- return GetIdentifierSymbol();
- }
- *ok = false;
- return kUnknownIdentifier;
-}
-
-
-// This function reads an identifier and determines whether or not it
-// is 'get' or 'set'. The reason for not using ParseIdentifier and
-// checking on the output is that this involves heap allocation which
-// we can't do during preparsing.
-template <typename Scanner, typename Log>
-Identifier PreParser<Scanner, Log>::ParseIdentifierOrGetOrSet(bool* is_get,
- bool* is_set,
- bool* ok) {
- Expect(i::Token::IDENTIFIER, CHECK_OK);
- if (scanner_->literal_length() == 3) {
- const char* token = scanner_->literal_string();
- *is_get = strncmp(token, "get", 3) == 0;
- *is_set = !*is_get && strncmp(token, "set", 3) == 0;
- }
- return GetIdentifierSymbol();
-}
-
-#undef CHECK_OK
} } // v8::preparser
#endif // V8_PREPARSER_H
diff --git a/deps/v8/src/profile-generator.cc b/deps/v8/src/profile-generator.cc
index e0b63f950c..640f13cd62 100644
--- a/deps/v8/src/profile-generator.cc
+++ b/deps/v8/src/profile-generator.cc
@@ -1295,8 +1295,8 @@ HeapEntry* HeapSnapshot::AddEntry(HeapObject* object,
} else if (object->IsJSObject()) {
return AddEntry(object,
HeapEntry::kObject,
- collection_->GetName(
- JSObject::cast(object)->constructor_name()),
+ collection_->GetName(GetConstructorNameForHeapProfile(
+ JSObject::cast(object))),
children_count,
retainers_count);
} else if (object->IsString()) {
@@ -1462,6 +1462,14 @@ void HeapSnapshot::BuildDominatorTree(const Vector<HeapEntry*>& entries,
}
+void HeapSnapshot::SetDominatorsToSelf() {
+ for (int i = 0; i < entries_.length(); ++i) {
+ HeapEntry* entry = entries_[i];
+ if (entry->dominator() == NULL) entry->set_dominator(entry);
+ }
+}
+
+
void HeapSnapshot::SetEntriesDominators() {
// This array is used for maintaining reverse postorder of nodes.
ScopedVector<HeapEntry*> ordered_entries(entries_.length());
@@ -1473,10 +1481,7 @@ void HeapSnapshot::SetEntriesDominators() {
ordered_entries[i]->set_dominator(dominators[i]);
}
// For nodes unreachable from root, set dominator to itself.
- for (int i = 0; i < entries_.length(); ++i) {
- HeapEntry* entry = entries_[i];
- if (entry->dominator() == NULL) entry->set_dominator(entry);
- }
+ SetDominatorsToSelf();
}
@@ -2764,6 +2769,12 @@ void HeapSnapshotJSONSerializer::SortHashMap(
sorted_entries->Sort(SortUsingEntryValue);
}
+
+String* GetConstructorNameForHeapProfile(JSObject* object) {
+ if (object->IsJSFunction()) return Heap::closure_symbol();
+ return object->constructor_name();
+}
+
} } // namespace v8::internal
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/deps/v8/src/profile-generator.h b/deps/v8/src/profile-generator.h
index 30d70a2c74..55c57fd528 100644
--- a/deps/v8/src/profile-generator.h
+++ b/deps/v8/src/profile-generator.h
@@ -700,6 +700,7 @@ class HeapSnapshot {
List<HeapEntry*>* GetSortedEntriesList();
template<class Visitor>
void IterateEntries(Visitor* visitor) { entries_.Iterate(visitor); }
+ void SetDominatorsToSelf();
void Print(int max_depth);
void PrintEntriesSize();
@@ -1072,6 +1073,9 @@ class HeapSnapshotJSONSerializer {
DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
};
+
+String* GetConstructorNameForHeapProfile(JSObject* object);
+
} } // namespace v8::internal
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc
index e20c94fddc..c43a1ab327 100644
--- a/deps/v8/src/runtime.cc
+++ b/deps/v8/src/runtime.cc
@@ -5020,11 +5020,12 @@ static int CopyCachedAsciiCharsToArray(const char* chars,
// For example, "foo" => ["f", "o", "o"].
static MaybeObject* Runtime_StringToArray(Arguments args) {
HandleScope scope;
- ASSERT(args.length() == 1);
+ ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(String, s, 0);
+ CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
s->TryFlatten();
- const int length = s->length();
+ const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
Handle<FixedArray> elements;
if (s->IsFlat() && s->IsAsciiRepresentation()) {
@@ -6391,7 +6392,7 @@ static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
}
if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ConstructStubCompiler compiler;
- MaybeObject* code = compiler.CompileConstructStub(function->shared());
+ MaybeObject* code = compiler.CompileConstructStub(*function);
if (!code->IsFailure()) {
function->shared()->set_construct_stub(
Code::cast(code->ToObjectUnchecked()));
@@ -6459,7 +6460,6 @@ static MaybeObject* Runtime_NewObject(Arguments args) {
// track one initial_map at a time, so we force the completion before the
// function is called as a constructor for the first time.
shared->CompleteInobjectSlackTracking();
- TrySettingInlineConstructStub(function);
}
bool first_allocation = !shared->live_objects_may_exist();
diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h
index e36988da44..f9ebbc42ef 100644
--- a/deps/v8/src/runtime.h
+++ b/deps/v8/src/runtime.h
@@ -175,7 +175,7 @@ namespace internal {
F(StringReplaceRegExpWithString, 4, 1) \
F(StringMatch, 3, 1) \
F(StringTrim, 3, 1) \
- F(StringToArray, 1, 1) \
+ F(StringToArray, 2, 1) \
F(NewStringWrapper, 1, 1) \
\
/* Numbers */ \
diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js
index d82ce05237..3b3c82bb72 100644
--- a/deps/v8/src/string.js
+++ b/deps/v8/src/string.js
@@ -552,7 +552,7 @@ function StringSplit(separator, limit) {
var separator_length = separator.length;
// If the separator string is empty then return the elements in the subject.
- if (separator_length === 0) return %StringToArray(subject);
+ if (separator_length === 0) return %StringToArray(subject, limit);
var result = %StringSplit(subject, separator, limit);
diff --git a/deps/v8/src/stub-cache.h b/deps/v8/src/stub-cache.h
index 4886c7eb29..cef5481c3f 100644
--- a/deps/v8/src/stub-cache.h
+++ b/deps/v8/src/stub-cache.h
@@ -740,7 +740,7 @@ class ConstructStubCompiler: public StubCompiler {
public:
explicit ConstructStubCompiler() {}
- MUST_USE_RESULT MaybeObject* CompileConstructStub(SharedFunctionInfo* shared);
+ MUST_USE_RESULT MaybeObject* CompileConstructStub(JSFunction* function);
private:
MaybeObject* GetCode();
diff --git a/deps/v8/src/token.cc b/deps/v8/src/token.cc
index 21fa9ee4d7..488e90979f 100644
--- a/deps/v8/src/token.cc
+++ b/deps/v8/src/token.cc
@@ -25,8 +25,7 @@
// (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 "v8.h"
-
+#include "../include/v8stdint.h"
#include "token.h"
namespace v8 {
diff --git a/deps/v8/src/v8.h b/deps/v8/src/v8.h
index 74e98f151d..a2313b0e3c 100644
--- a/deps/v8/src/v8.h
+++ b/deps/v8/src/v8.h
@@ -54,7 +54,7 @@
// Basic includes
#include "../include/v8.h"
#include "v8globals.h"
-#include "checks.h"
+#include "v8checks.h"
#include "allocation.h"
#include "v8utils.h"
#include "flags.h"
diff --git a/deps/v8/src/v8checks.h b/deps/v8/src/v8checks.h
new file mode 100644
index 0000000000..9857f73d17
--- /dev/null
+++ b/deps/v8/src/v8checks.h
@@ -0,0 +1,64 @@
+// Copyright 2006-2008 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_V8CHECKS_H_
+#define V8_V8CHECKS_H_
+
+#include "checks.h"
+
+void API_Fatal(const char* location, const char* format, ...);
+
+namespace v8 {
+ class Value;
+ template <class T> class Handle;
+
+namespace internal {
+ intptr_t HeapObjectTagMask();
+
+} } // namespace v8::internal
+
+
+void CheckNonEqualsHelper(const char* file,
+ int line,
+ const char* unexpected_source,
+ v8::Handle<v8::Value> unexpected,
+ const char* value_source,
+ v8::Handle<v8::Value> value);
+
+void CheckEqualsHelper(const char* file,
+ int line,
+ const char* expected_source,
+ v8::Handle<v8::Value> expected,
+ const char* value_source,
+ v8::Handle<v8::Value> value);
+
+#define ASSERT_TAG_ALIGNED(address) \
+ ASSERT((reinterpret_cast<intptr_t>(address) & HeapObjectTagMask()) == 0)
+
+#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & HeapObjectTagMask()) == 0)
+
+#endif // V8_V8CHECKS_H_
diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc
index 0e0a7cf42e..6e5b68f2fa 100644
--- a/deps/v8/src/version.cc
+++ b/deps/v8/src/version.cc
@@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 2
#define MINOR_VERSION 5
-#define BUILD_NUMBER 8
-#define PATCH_LEVEL 0
+#define BUILD_NUMBER 9
+#define PATCH_LEVEL 1
#define CANDIDATE_VERSION false
// Define SONAME to have the SCons build the put a specific SONAME into the
diff --git a/deps/v8/src/x64/macro-assembler-x64.cc b/deps/v8/src/x64/macro-assembler-x64.cc
index 834a6f6ef5..d9198338b2 100644
--- a/deps/v8/src/x64/macro-assembler-x64.cc
+++ b/deps/v8/src/x64/macro-assembler-x64.cc
@@ -1889,7 +1889,6 @@ void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
void MacroAssembler::LoadAllocationTopHelper(Register result,
- Register result_end,
Register scratch,
AllocationFlags flags) {
ExternalReference new_space_allocation_top =
@@ -1911,7 +1910,6 @@ void MacroAssembler::LoadAllocationTopHelper(Register result,
// Move address of new object to result. Use scratch register if available,
// and keep address in scratch until call to UpdateAllocationTopHelper.
if (scratch.is_valid()) {
- ASSERT(!scratch.is(result_end));
movq(scratch, new_space_allocation_top);
movq(result, Operand(scratch, 0));
} else if (result.is(rax)) {
@@ -1972,7 +1970,7 @@ void MacroAssembler::AllocateInNewSpace(int object_size,
ASSERT(!result.is(result_end));
// Load address of new object into result.
- LoadAllocationTopHelper(result, result_end, scratch, flags);
+ LoadAllocationTopHelper(result, scratch, flags);
// Calculate new top and bail out if new space is exhausted.
ExternalReference new_space_allocation_limit =
@@ -2029,7 +2027,7 @@ void MacroAssembler::AllocateInNewSpace(int header_size,
ASSERT(!result.is(result_end));
// Load address of new object into result.
- LoadAllocationTopHelper(result, result_end, scratch, flags);
+ LoadAllocationTopHelper(result, scratch, flags);
// Calculate new top and bail out if new space is exhausted.
ExternalReference new_space_allocation_limit =
@@ -2071,7 +2069,7 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
ASSERT(!result.is(result_end));
// Load address of new object into result.
- LoadAllocationTopHelper(result, result_end, scratch, flags);
+ LoadAllocationTopHelper(result, scratch, flags);
// Calculate new top and bail out if new space is exhausted.
ExternalReference new_space_allocation_limit =
diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h
index 5b082fd627..0b7e6018f5 100644
--- a/deps/v8/src/x64/macro-assembler-x64.h
+++ b/deps/v8/src/x64/macro-assembler-x64.h
@@ -950,12 +950,9 @@ class MacroAssembler: public Assembler {
// Allocation support helpers.
// Loads the top of new-space into the result register.
- // If flags contains RESULT_CONTAINS_TOP then result_end is valid and
- // already contains the top of new-space, and scratch is invalid.
// Otherwise the address of the new-space top is loaded into scratch (if
// scratch is valid), and the new-space top is loaded into result.
void LoadAllocationTopHelper(Register result,
- Register result_end,
Register scratch,
AllocationFlags flags);
// Update allocation top with value in result_end register.
diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc
index dbf93f5ff2..7ba482c865 100644
--- a/deps/v8/src/x64/stub-cache-x64.cc
+++ b/deps/v8/src/x64/stub-cache-x64.cc
@@ -2890,8 +2890,7 @@ void StubCompiler::GenerateLoadConstant(JSObject* object,
// Specialized stub for constructing objects from functions which only have only
// simple assignments of the form this.x = ...; in their body.
-MaybeObject* ConstructStubCompiler::CompileConstructStub(
- SharedFunctionInfo* shared) {
+MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) {
// ----------- S t a t e -------------
// -- rax : argc
// -- rdi : constructor
@@ -2964,6 +2963,7 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(
// r9: first in-object property of the JSObject
// Fill the initialized properties with a constant value or a passed argument
// depending on the this.x = ...; assignment in the function.
+ SharedFunctionInfo* shared = function->shared();
for (int i = 0; i < shared->this_property_assignments_count(); i++) {
if (shared->IsThisPropertyAssignmentArgument(i)) {
// Check if the argument assigned to the property is actually passed.
@@ -2983,8 +2983,9 @@ MaybeObject* ConstructStubCompiler::CompileConstructStub(
}
// Fill the unused in-object property fields with undefined.
+ ASSERT(function->has_initial_map());
for (int i = shared->this_property_assignments_count();
- i < shared->CalculateInObjectProperties();
+ i < function->initial_map()->inobject_properties();
i++) {
__ movq(Operand(r9, i * kPointerSize), r8);
}
diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc
index 5322314417..8ce7a79a9b 100644
--- a/deps/v8/test/cctest/test-api.cc
+++ b/deps/v8/test/cctest/test-api.cc
@@ -7819,6 +7819,31 @@ THREADED_TEST(ObjectProtoToString) {
}
+THREADED_TEST(ObjectGetConstructorName) {
+ v8::HandleScope scope;
+ LocalContext context;
+ v8_compile("function Parent() {};"
+ "function Child() {};"
+ "Child.prototype = new Parent();"
+ "var outer = { inner: function() { } };"
+ "var p = new Parent();"
+ "var c = new Child();"
+ "var x = new outer.inner();")->Run();
+
+ Local<v8::Value> p = context->Global()->Get(v8_str("p"));
+ CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
+ v8_str("Parent")));
+
+ Local<v8::Value> c = context->Global()->Get(v8_str("c"));
+ CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
+ v8_str("Child")));
+
+ Local<v8::Value> x = context->Global()->Get(v8_str("x"));
+ CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
+ v8_str("outer.inner")));
+}
+
+
bool ApiTestFuzzer::fuzzing_ = false;
i::Semaphore* ApiTestFuzzer::all_tests_done_=
i::OS::CreateSemaphore(0);
@@ -8734,7 +8759,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;
diff --git a/deps/v8/test/cctest/test-conversions.cc b/deps/v8/test/cctest/test-conversions.cc
index eef7184828..1b5cc2dee8 100644
--- a/deps/v8/test/cctest/test-conversions.cc
+++ b/deps/v8/test/cctest/test-conversions.cc
@@ -104,8 +104,10 @@ TEST(IntegerStrLiteral) {
CHECK_EQ(0.0, StringToDouble("000", NO_FLAGS));
CHECK_EQ(1.0, StringToDouble("1", NO_FLAGS));
CHECK_EQ(-1.0, StringToDouble("-1", NO_FLAGS));
- CHECK_EQ(-1.0, StringToDouble(" - 1 ", NO_FLAGS));
- CHECK_EQ(1.0, StringToDouble(" + 1 ", NO_FLAGS));
+ CHECK_EQ(-1.0, StringToDouble(" -1 ", NO_FLAGS));
+ CHECK_EQ(1.0, StringToDouble(" +1 ", NO_FLAGS));
+ CHECK(isnan(StringToDouble(" - 1 ", NO_FLAGS)));
+ CHECK(isnan(StringToDouble(" + 1 ", NO_FLAGS)));
CHECK_EQ(0.0, StringToDouble("0e0", ALLOW_HEX | ALLOW_OCTALS));
CHECK_EQ(0.0, StringToDouble("0e1", ALLOW_HEX | ALLOW_OCTALS));
diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc
index 4dd7fe823f..95314d74a4 100644
--- a/deps/v8/test/cctest/test-heap-profiler.cc
+++ b/deps/v8/test/cctest/test-heap-profiler.cc
@@ -1178,4 +1178,19 @@ TEST(HeapSnapshotJSONSerializationAborting) {
CHECK_EQ(0, stream.eos_signaled());
}
+
+// Must not crash in debug mode.
+TEST(AggregatedHeapSnapshotJSONSerialization) {
+ v8::HandleScope scope;
+ LocalContext env;
+
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(
+ v8::String::New("agg"), v8::HeapSnapshot::kAggregated);
+ TestJSONStream stream;
+ snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
+ CHECK_GT(stream.size(), 0);
+ CHECK_EQ(1, stream.eos_signaled());
+}
+
#endif // ENABLE_LOGGING_AND_PROFILING
diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc
index 7168737416..710c10e996 100644
--- a/deps/v8/test/cctest/test-log.cc
+++ b/deps/v8/test/cctest/test-log.cc
@@ -139,6 +139,12 @@ namespace internal {
class LoggerTestHelper : public AllStatic {
public:
static bool IsSamplerActive() { return Logger::IsProfilerSamplerActive(); }
+ static void ResetSamplesTaken() {
+ reinterpret_cast<Sampler*>(Logger::ticker_)->ResetSamplesTaken();
+ }
+ static bool has_samples_taken() {
+ return reinterpret_cast<Sampler*>(Logger::ticker_)->samples_taken() > 0;
+ }
};
} // namespace v8::internal
@@ -147,24 +153,6 @@ class LoggerTestHelper : public AllStatic {
using v8::internal::LoggerTestHelper;
-// Under Linux, we need to check if signals were delivered to avoid false
-// positives. Under other platforms profiling is done via a high-priority
-// thread, so this case never happen.
-static bool was_sigprof_received = true;
-#ifdef __linux__
-
-struct sigaction old_sigprof_handler;
-pthread_t our_thread;
-
-static void SigProfSignalHandler(int signal, siginfo_t* info, void* context) {
- if (signal != SIGPROF || !pthread_equal(pthread_self(), our_thread)) return;
- was_sigprof_received = true;
- old_sigprof_handler.sa_sigaction(signal, info, context);
-}
-
-#endif // __linux__
-
-
namespace {
class ScopedLoggerInitializer {
@@ -258,6 +246,9 @@ class LogBufferMatcher {
static void CheckThatProfilerWorks(LogBufferMatcher* matcher) {
+ CHECK(!LoggerTestHelper::IsSamplerActive());
+ LoggerTestHelper::ResetSamplesTaken();
+
Logger::ResumeProfiler(v8::PROFILER_MODULE_CPU, 0);
CHECK(LoggerTestHelper::IsSamplerActive());
@@ -266,19 +257,6 @@ static void CheckThatProfilerWorks(LogBufferMatcher* matcher) {
const char* code_creation = "\ncode-creation,"; // eq. to /^code-creation,/
CHECK_NE(NULL, matcher->Find(code_creation));
-#ifdef __linux__
- // Intercept SIGPROF handler to make sure that the test process
- // had received it. Under load, system can defer it causing test failure.
- // It is important to execute this after 'ResumeProfiler'.
- our_thread = pthread_self();
- was_sigprof_received = false;
- struct sigaction sa;
- sa.sa_sigaction = SigProfSignalHandler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_SIGINFO;
- CHECK_EQ(0, sigaction(SIGPROF, &sa, &old_sigprof_handler));
-#endif // __linux__
-
// Force compiler to generate new code by parametrizing source.
EmbeddedVector<char, 100> script_src;
i::OS::SNPrintF(script_src,
@@ -306,7 +284,7 @@ static void CheckThatProfilerWorks(LogBufferMatcher* matcher) {
CHECK_NE(NULL, matcher->Find(code_creation));
const char* tick = "\ntick,";
const bool ticks_found = matcher->Find(tick) != NULL;
- CHECK_EQ(was_sigprof_received, ticks_found);
+ CHECK_EQ(LoggerTestHelper::has_samples_taken(), ticks_found);
}
diff --git a/deps/v8/test/cctest/test-parsing.cc b/deps/v8/test/cctest/test-parsing.cc
index 243d47884a..a93fc2712d 100755
--- a/deps/v8/test/cctest/test-parsing.cc
+++ b/deps/v8/test/cctest/test-parsing.cc
@@ -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());
diff --git a/deps/v8/test/mjsunit/regress/regress-944.js b/deps/v8/test/mjsunit/regress/regress-944.js
new file mode 100644
index 0000000000..d165336f1f
--- /dev/null
+++ b/deps/v8/test/mjsunit/regress/regress-944.js
@@ -0,0 +1,46 @@
+// 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.
+
+// Check for parsing of proper ES5 15.9.1.15 (ISO 8601 / RFC 3339) time
+// strings that contain millisecond values with exactly 3 digits (as is
+// required by the spec format if the string has milliseconds at all).
+assertEquals(1290722550521, Date.parse("2010-11-25T22:02:30.521Z"));
+
+// Check for parsing of extension/generalization of the ES5 15.9.1.15 spec
+// format where millisecond values have only 1 or 2 digits.
+assertEquals(1290722550500, Date.parse("2010-11-25T22:02:30.5Z"));
+assertEquals(1290722550520, Date.parse("2010-11-25T22:02:30.52Z"));
+assertFalse(Date.parse("2010-11-25T22:02:30.5Z") === Date.parse("2010-11-25T22:02:30.005Z"));
+
+// Check that we truncate millisecond values having more than 3 digits.
+assertEquals(Date.parse("2010-11-25T22:02:30.1005Z"), Date.parse("2010-11-25T22:02:30.100Z"));
+
+// Check that we accept lots of digits.
+assertEquals(Date.parse("2010-11-25T22:02:30.999Z"), Date.parse("2010-11-25T22:02:30.99999999999999999999999999999999999999999999999999999999999999999999999999999999999999Z"));
+
+// Fail if there's a decimal point but zero digits for (expected) milliseconds.
+assertTrue(isNaN(Date.parse("2010-11-25T22:02:30.Z")));
diff --git a/deps/v8/test/mjsunit/string-split.js b/deps/v8/test/mjsunit/string-split.js
index c741f6a3e5..6fcf55799e 100644
--- a/deps/v8/test/mjsunit/string-split.js
+++ b/deps/v8/test/mjsunit/string-split.js
@@ -97,3 +97,22 @@ assertEquals([""], ''.split(/./));
assertEquals([], ''.split(/.?/));
assertEquals([], ''.split(/.??/));
assertEquals([], ''.split(/()()/));
+
+
+// Issue http://code.google.com/p/v8/issues/detail?id=929
+// (Splitting with empty separator and a limit.)
+
+function numberObj(num) {
+ return {valueOf: function() { return num; }};
+}
+
+assertEquals([], "abc".split("", 0));
+assertEquals([], "abc".split("", numberObj(0)));
+assertEquals(["a"], "abc".split("", 1));
+assertEquals(["a"], "abc".split("", numberObj(1)));
+assertEquals(["a", "b"], "abc".split("", 2));
+assertEquals(["a", "b"], "abc".split("", numberObj(2)));
+assertEquals(["a", "b", "c"], "abc".split("", 3));
+assertEquals(["a", "b", "c"], "abc".split("", numberObj(3)));
+assertEquals(["a", "b", "c"], "abc".split("", 4));
+assertEquals(["a", "b", "c"], "abc".split("", numberObj(4)));
diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp
index 43e1bd4150..c1a5aab198 100644
--- a/deps/v8/tools/gyp/v8.gyp
+++ b/deps/v8/tools/gyp/v8.gyp
@@ -406,6 +406,10 @@
'../../src/parser.cc',
'../../src/parser.h',
'../../src/platform.h',
+ '../../src/preparse-data.cc',
+ '../../src/preparse-data.h',
+ '../../src/preparser.cc',
+ '../../src/preparser.h',
'../../src/prettyprinter.cc',
'../../src/prettyprinter.h',
'../../src/property.cc',
@@ -471,8 +475,11 @@
'../../src/v8-counters.h',
'../../src/v8.cc',
'../../src/v8.h',
+ '../../src/v8checks.h',
+ '../../src/v8globals.h',
'../../src/v8threads.cc',
'../../src/v8threads.h',
+ '../../src/v8utils.h',
'../../src/variables.cc',
'../../src/variables.h',
'../../src/version.cc',
diff --git a/deps/v8/tools/presubmit.py b/deps/v8/tools/presubmit.py
index ebf8bd8939..1d80f92b8b 100755
--- a/deps/v8/tools/presubmit.py
+++ b/deps/v8/tools/presubmit.py
@@ -195,7 +195,7 @@ class CppLintProcessor(SourceFileProcessor):
or (name in CppLintProcessor.IGNORE_LINT))
def GetPathsToSearch(self):
- return ['src', 'include', 'samples', join('test', 'cctest')]
+ return ['src', 'preparser', 'include', 'samples', join('test', 'cctest')]
def ProcessFiles(self, files, path):
good_files_cache = FileContentsCache('.cpplint-cache')
diff --git a/deps/v8/tools/visual_studio/v8_base.vcproj b/deps/v8/tools/visual_studio/v8_base.vcproj
index 95eb196d31..902faff635 100644
--- a/deps/v8/tools/visual_studio/v8_base.vcproj
+++ b/deps/v8/tools/visual_studio/v8_base.vcproj
@@ -762,6 +762,22 @@
>
</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"
>
</File>
@@ -1034,6 +1050,14 @@
>
</File>
<File
+ RelativePath="..\..\src\v8checks.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\v8globals.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\v8threads.cc"
>
</File>
@@ -1042,6 +1066,10 @@
>
</File>
<File
+ RelativePath="..\..\src\v8utils.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\variables.cc"
>
</File>
@@ -1157,6 +1185,10 @@
RelativePath="..\..\include\v8.h"
>
</File>
+ <File
+ RelativePath="..\..\include\v8stdint.h"
+ >
+ </File>
</Filter>
</Files>
<Globals>