Version 2.5.5
Added more aggressive GC of external objects in near out-of-memory situations.
Fixed a bug that gave the incorrect result for String.split called on the empty string (issue 924).
git-svn-id: http://v8.googlecode.com/svn/trunk@5780 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index ac63a71..ea07009 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,15 @@
+2010-11-08: Version 2.5.5
+
+ Added more aggressive GC of external objects in near out-of-memory
+ situations.
+
+ Fixed a bug that gave the incorrect result for String.split called
+ on the empty string (issue 924).
+
+
2010-11-03: Version 2.5.4
- Improved V8 VFPv3 runtime detection to address issue 914.
+ Improved V8 VFPv3 runtime detection to address issue 914.
2010-11-01: Version 2.5.3
diff --git a/include/v8-debug.h b/include/v8-debug.h
index 4314727..f17b848 100755
--- a/include/v8-debug.h
+++ b/include/v8-debug.h
@@ -142,7 +142,7 @@
virtual ~Message() {}
};
-
+
/**
* An event details object passed to the debug event listener.
@@ -300,7 +300,7 @@
* get access to information otherwise not available during normal JavaScript
* execution e.g. details on stack frames. Receiver of the function call will
* be the debugger context global object, however this is a subject to change.
- * The following example show a JavaScript function which when passed to
+ * The following example show a JavaScript function which when passed to
* v8::Debug::Call will return the current line of JavaScript execution.
*
* \code
diff --git a/include/v8.h b/include/v8.h
index c7e4552..8c730df 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -38,23 +38,9 @@
#ifndef V8_H_
#define V8_H_
-#include <stdio.h>
+#include "v8stdint.h"
#ifdef _WIN32
-// When compiling on MinGW stdint.h is available.
-#ifdef __MINGW32__
-#include <stdint.h>
-#else // __MINGW32__
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef short int16_t; // NOLINT
-typedef unsigned short uint16_t; // NOLINT
-typedef int int32_t;
-typedef unsigned int uint32_t;
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-// intptr_t and friends are defined in crtdefs.h through stdio.h.
-#endif // __MINGW32__
// Setup for Windows DLL export/import. When building the V8 DLL the
// BUILDING_V8_SHARED needs to be defined. When building a program which uses
@@ -76,8 +62,6 @@
#else // _WIN32
-#include <stdint.h>
-
// Setup for Linux shared library export. There is no need to distinguish
// between building or using the V8 shared library, but we should not
// export symbols when we are building a static library.
@@ -127,7 +111,6 @@
class Object;
class Heap;
class Top;
-
}
@@ -476,10 +459,10 @@
level = 0;
}
};
-
+
void Leave();
-
+
internal::Object** prev_next_;
internal::Object** prev_limit_;
@@ -1055,7 +1038,7 @@
*/
V8EXPORT bool IsExternalAscii() const;
- class V8EXPORT ExternalStringResourceBase {
+ class V8EXPORT ExternalStringResourceBase { // NOLINT
public:
virtual ~ExternalStringResourceBase() {}
@@ -3260,8 +3243,8 @@
/**
* An interface for exporting data from V8, using "push" model.
*/
-class V8EXPORT OutputStream {
-public:
+class V8EXPORT OutputStream { // NOLINT
+ public:
enum OutputEncoding {
kAscii = 0 // 7-bit ASCII.
};
@@ -3291,6 +3274,8 @@
namespace internal {
+const int kPointerSize = sizeof(void*); // NOLINT
+const int kIntSize = sizeof(int); // NOLINT
// Tag information for HeapObject.
const int kHeapObjectTag = 1;
@@ -3326,19 +3311,19 @@
}
};
-const int kSmiShiftSize = SmiConstants<sizeof(void*)>::kSmiShiftSize;
-const int kSmiValueSize = SmiConstants<sizeof(void*)>::kSmiValueSize;
+const int kSmiShiftSize = SmiConstants<kPointerSize>::kSmiShiftSize;
+const int kSmiValueSize = SmiConstants<kPointerSize>::kSmiValueSize;
template <size_t ptr_size> struct InternalConstants;
// Internal constants for 32-bit systems.
template <> struct InternalConstants<4> {
- static const int kStringResourceOffset = 3 * sizeof(void*);
+ static const int kStringResourceOffset = 3 * kPointerSize;
};
// Internal constants for 64-bit systems.
template <> struct InternalConstants<8> {
- static const int kStringResourceOffset = 3 * sizeof(void*);
+ static const int kStringResourceOffset = 3 * kPointerSize;
};
/**
@@ -3352,12 +3337,12 @@
// These values match non-compiler-dependent values defined within
// the implementation of v8.
static const int kHeapObjectMapOffset = 0;
- static const int kMapInstanceTypeOffset = sizeof(void*) + sizeof(int);
+ static const int kMapInstanceTypeOffset = kPointerSize + kIntSize;
static const int kStringResourceOffset =
- InternalConstants<sizeof(void*)>::kStringResourceOffset;
+ InternalConstants<kPointerSize>::kStringResourceOffset;
- static const int kProxyProxyOffset = sizeof(void*);
- static const int kJSObjectHeaderSize = 3 * sizeof(void*);
+ static const int kProxyProxyOffset = kPointerSize;
+ static const int kJSObjectHeaderSize = 3 * kPointerSize;
static const int kFullStringRepresentationMask = 0x07;
static const int kExternalTwoByteRepresentationTag = 0x02;
@@ -3375,7 +3360,7 @@
}
static inline int SmiValue(internal::Object* value) {
- return SmiConstants<sizeof(void*)>::SmiToInt(value);
+ return SmiConstants<kPointerSize>::SmiToInt(value);
}
static inline int GetInstanceType(internal::Object* obj) {
@@ -3404,10 +3389,9 @@
uint8_t* addr = reinterpret_cast<uint8_t*>(ptr) + offset - kHeapObjectTag;
return *reinterpret_cast<T*>(addr);
}
-
};
-}
+} // namespace internal
template <class T>
@@ -3567,7 +3551,7 @@
// If the object is a plain JSObject, which is the common case,
// we know where to find the internal fields and can return the
// value directly.
- int offset = I::kJSObjectHeaderSize + (sizeof(void*) * index);
+ int offset = I::kJSObjectHeaderSize + (internal::kPointerSize * index);
O* value = I::ReadField<O*>(obj, offset);
O** result = HandleScope::CreateHandle(value);
return Local<Value>(reinterpret_cast<Value*>(result));
@@ -3603,7 +3587,7 @@
// If the object is a plain JSObject, which is the common case,
// we know where to find the internal fields and can return the
// value directly.
- int offset = I::kJSObjectHeaderSize + (sizeof(void*) * index);
+ int offset = I::kJSObjectHeaderSize + (internal::kPointerSize * index);
O* value = I::ReadField<O*>(obj, offset);
return I::GetExternalPointer(value);
}
diff --git a/include/v8stdint.h b/include/v8stdint.h
new file mode 100644
index 0000000..50b4f29
--- /dev/null
+++ b/include/v8stdint.h
@@ -0,0 +1,53 @@
+// 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.
+
+// Load definitions of standard types.
+
+#ifndef V8STDINT_H_
+#define V8STDINT_H_
+
+#include <stdio.h>
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t; // NOLINT
+typedef unsigned short uint16_t; // NOLINT
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+// intptr_t and friends are defined in crtdefs.h through stdio.h.
+
+#else
+
+#include <stdint.h>
+
+#endif
+
+#endif // V8STDINT_H_
diff --git a/src/SConscript b/src/SConscript
index 8995d48..596caf7 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -95,6 +95,7 @@
register-allocator.cc
rewriter.cc
runtime.cc
+ scanner-base.cc
scanner.cc
scopeinfo.cc
scopes.cc
diff --git a/src/api.cc b/src/api.cc
index 617922d..ee7ad3a 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -43,7 +43,6 @@
#include "serialize.h"
#include "snapshot.h"
#include "top.h"
-#include "utils.h"
#include "v8threads.h"
#include "version.h"
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index ebbd9b1..72835ba 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -317,7 +317,8 @@
static const int kMinimalBufferSize = 4*KB;
static byte* spare_buffer_ = NULL;
-Assembler::Assembler(void* buffer, int buffer_size) {
+Assembler::Assembler(void* buffer, int buffer_size)
+ : positions_recorder_(this) {
if (buffer == NULL) {
// Do our own buffer management.
if (buffer_size <= kMinimalBufferSize) {
@@ -354,10 +355,6 @@
no_const_pool_before_ = 0;
last_const_pool_end_ = 0;
last_bound_pos_ = 0;
- current_statement_position_ = RelocInfo::kNoPosition;
- current_position_ = RelocInfo::kNoPosition;
- written_statement_position_ = current_statement_position_;
- written_position_ = current_position_;
}
@@ -752,15 +749,15 @@
// if they can be encoded in the ARM's 12 bits of immediate-offset instruction
// space. There is no guarantee that the relocated location can be similarly
// encoded.
-static bool MustUseConstantPool(RelocInfo::Mode rmode) {
- if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
+bool Operand::must_use_constant_pool() const {
+ if (rmode_ == RelocInfo::EXTERNAL_REFERENCE) {
#ifdef DEBUG
if (!Serializer::enabled()) {
Serializer::TooLateToEnableNow();
}
#endif // def DEBUG
return Serializer::enabled();
- } else if (rmode == RelocInfo::NONE) {
+ } else if (rmode_ == RelocInfo::NONE) {
return false;
}
return true;
@@ -769,7 +766,7 @@
bool Operand::is_single_instruction() const {
if (rm_.is_valid()) return true;
- if (MustUseConstantPool(rmode_)) return false;
+ if (must_use_constant_pool()) return false;
uint32_t dummy1, dummy2;
return fits_shifter(imm32_, &dummy1, &dummy2, NULL);
}
@@ -785,7 +782,7 @@
// Immediate.
uint32_t rotate_imm;
uint32_t immed_8;
- if (MustUseConstantPool(x.rmode_) ||
+ if (x.must_use_constant_pool() ||
!fits_shifter(x.imm32_, &rotate_imm, &immed_8, &instr)) {
// The immediate operand cannot be encoded as a shifter operand, so load
// it first to register ip and change the original instruction to use ip.
@@ -794,8 +791,7 @@
CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed
Condition cond = static_cast<Condition>(instr & CondMask);
if ((instr & ~CondMask) == 13*B21) { // mov, S not set
- if (MustUseConstantPool(x.rmode_) ||
- !CpuFeatures::IsSupported(ARMv7)) {
+ if (x.must_use_constant_pool() || !CpuFeatures::IsSupported(ARMv7)) {
RecordRelocInfo(x.rmode_, x.imm32_);
ldr(rd, MemOperand(pc, 0), cond);
} else {
@@ -806,7 +802,7 @@
} else {
// If this is not a mov or mvn instruction we may still be able to avoid
// a constant pool entry by using mvn or movw.
- if (!MustUseConstantPool(x.rmode_) &&
+ if (!x.must_use_constant_pool() &&
(instr & kMovMvnMask) != kMovMvnPattern) {
mov(ip, x, LeaveCC, cond);
} else {
@@ -999,7 +995,7 @@
void Assembler::blx(int branch_offset) { // v5 and above
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
ASSERT((branch_offset & 1) == 0);
int h = ((branch_offset & 2) >> 1)*B24;
int imm24 = branch_offset >> 2;
@@ -1009,14 +1005,14 @@
void Assembler::blx(Register target, Condition cond) { // v5 and above
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
ASSERT(!target.is(pc));
emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | 3*B4 | target.code());
}
void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
ASSERT(!target.is(pc)); // use of pc is actually allowed, but discouraged
emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | B4 | target.code());
}
@@ -1114,7 +1110,7 @@
void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
if (dst.is(pc)) {
- WriteRecordedPositions();
+ 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)
@@ -1339,7 +1335,7 @@
// Immediate.
uint32_t rotate_imm;
uint32_t immed_8;
- if (MustUseConstantPool(src.rmode_) ||
+ if (src.must_use_constant_pool() ||
!fits_shifter(src.imm32_, &rotate_imm, &immed_8, NULL)) {
// Immediate operand cannot be encoded, load it first to register ip.
RecordRelocInfo(src.rmode_, src.imm32_);
@@ -1359,7 +1355,7 @@
// Load/Store instructions.
void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
if (dst.is(pc)) {
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
}
addrmod2(cond | B26 | L, dst, src);
@@ -2377,14 +2373,14 @@
// Debugging.
void Assembler::RecordJSReturn() {
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
CheckBuffer();
RecordRelocInfo(RelocInfo::JS_RETURN);
}
void Assembler::RecordDebugBreakSlot() {
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
CheckBuffer();
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
}
@@ -2398,47 +2394,6 @@
}
-void Assembler::RecordPosition(int pos) {
- if (pos == RelocInfo::kNoPosition) return;
- ASSERT(pos >= 0);
- current_position_ = pos;
-}
-
-
-void Assembler::RecordStatementPosition(int pos) {
- if (pos == RelocInfo::kNoPosition) return;
- ASSERT(pos >= 0);
- current_statement_position_ = pos;
-}
-
-
-bool Assembler::WriteRecordedPositions() {
- bool written = false;
-
- // Write the statement position if it is different from what was written last
- // time.
- if (current_statement_position_ != written_statement_position_) {
- CheckBuffer();
- RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
- written_statement_position_ = current_statement_position_;
- written = true;
- }
-
- // Write the position if it is different from what was written last time and
- // also different from the written statement position.
- if (current_position_ != written_position_ &&
- current_position_ != written_statement_position_) {
- CheckBuffer();
- RecordRelocInfo(RelocInfo::POSITION, current_position_);
- written_position_ = current_position_;
- written = true;
- }
-
- // Return whether something was written.
- return written;
-}
-
-
void Assembler::GrowBuffer() {
if (!own_buffer_) FATAL("external code buffer is too small");
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index 5b647a7..0579235 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -448,6 +448,7 @@
// Return true of this operand fits in one instruction so that no
// 2-instruction solution with a load into the ip register is necessary.
bool is_single_instruction() const;
+ bool must_use_constant_pool() const;
inline int32_t immediate() const {
ASSERT(!rm_.is_valid());
@@ -1117,13 +1118,9 @@
// Use --debug_code to enable.
void RecordComment(const char* msg);
- void RecordPosition(int pos);
- void RecordStatementPosition(int pos);
- bool WriteRecordedPositions();
-
int pc_offset() const { return pc_ - buffer_; }
- int current_position() const { return current_position_; }
- int current_statement_position() const { return current_statement_position_; }
+
+ PositionsRecorder* positions_recorder() { return &positions_recorder_; }
bool can_peephole_optimize(int instructions) {
if (!FLAG_peephole_optimization) return false;
@@ -1259,12 +1256,6 @@
// The bound position, before this we cannot do instruction elimination.
int last_bound_pos_;
- // source position information
- int current_position_;
- int current_statement_position_;
- int written_position_;
- int written_statement_position_;
-
// Code emission
inline void CheckBuffer();
void GrowBuffer();
@@ -1290,8 +1281,21 @@
friend class RelocInfo;
friend class CodePatcher;
friend class BlockConstPoolScope;
+
+ PositionsRecorder positions_recorder_;
+ friend class PositionsRecorder;
+ friend class EnsureSpace;
};
+
+class EnsureSpace BASE_EMBEDDED {
+ public:
+ explicit EnsureSpace(Assembler* assembler) {
+ assembler->CheckBuffer();
+ }
+};
+
+
} } // namespace v8::internal
#endif // V8_ARM_ASSEMBLER_ARM_H_
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 9935e03..bf27d0c 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -1688,12 +1688,14 @@
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- for (int i = 0; i < arg_count; i++) {
- VisitForStackValue(args->at(i));
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i));
+ }
+ __ mov(r2, Operand(name));
}
- __ mov(r2, Operand(name));
// Record source position for debugger.
- SetSourcePosition(expr->position());
+ SetSourcePosition(expr->position(), FORCED_POSITION);
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
@@ -1710,13 +1712,15 @@
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- for (int i = 0; i < arg_count; i++) {
- VisitForStackValue(args->at(i));
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i));
+ }
+ VisitForAccumulatorValue(key);
+ __ mov(r2, r0);
}
- VisitForAccumulatorValue(key);
- __ mov(r2, r0);
// Record source position for debugger.
- SetSourcePosition(expr->position());
+ SetSourcePosition(expr->position(), FORCED_POSITION);
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
@@ -1732,11 +1736,13 @@
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- for (int i = 0; i < arg_count; i++) {
- VisitForStackValue(args->at(i));
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i));
+ }
}
// Record source position for debugger.
- SetSourcePosition(expr->position());
+ SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@@ -1756,41 +1762,45 @@
// resolve the function we need to call and the receiver of the
// call. Then we call the resolved function using the given
// arguments.
- VisitForStackValue(fun);
- __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
- __ push(r2); // Reserved receiver slot.
-
- // Push the arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- for (int i = 0; i < arg_count; i++) {
- VisitForStackValue(args->at(i));
- }
- // Push copy of the function - found below the arguments.
- __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
- __ push(r1);
+ { PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
+ VisitForStackValue(fun);
+ __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
+ __ push(r2); // Reserved receiver slot.
- // Push copy of the first argument or undefined if it doesn't exist.
- if (arg_count > 0) {
- __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
+ // Push the arguments.
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i));
+ }
+
+ // Push copy of the function - found below the arguments.
+ __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ push(r1);
- } else {
- __ push(r2);
+
+ // Push copy of the first argument or undefined if it doesn't exist.
+ if (arg_count > 0) {
+ __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
+ __ push(r1);
+ } else {
+ __ push(r2);
+ }
+
+ // Push the receiver of the enclosing function and do runtime call.
+ __ ldr(r1,
+ MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
+ __ push(r1);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+
+ // The runtime call returns a pair of values in r0 (function) and
+ // r1 (receiver). Touch up the stack with the right values.
+ __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
+ __ str(r1, MemOperand(sp, arg_count * kPointerSize));
}
- // Push the receiver of the enclosing function and do runtime call.
- __ ldr(r1, MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
- __ push(r1);
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
-
- // The runtime call returns a pair of values in r0 (function) and
- // r1 (receiver). Touch up the stack with the right values.
- __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
- __ str(r1, MemOperand(sp, arg_count * kPointerSize));
-
// Record source position for debugger.
- SetSourcePosition(expr->position());
+ SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@@ -1807,12 +1817,14 @@
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow,
- &done);
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ // Generate code for loading from variables potentially shadowed
+ // by eval-introduced variables.
+ EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
+ NOT_INSIDE_TYPEOF,
+ &slow,
+ &done);
+ }
__ bind(&slow);
// Call the runtime to find the function to call (returned in r0)
@@ -1846,17 +1858,23 @@
Literal* key = prop->key()->AsLiteral();
if (key != NULL && key->handle()->IsSymbol()) {
// Call to a named property, use call IC.
- VisitForStackValue(prop->obj());
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(prop->obj());
+ }
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else {
// Call to a keyed property.
// For a synthetic property use keyed load IC followed by function call,
// for a regular property use keyed CallIC.
- VisitForStackValue(prop->obj());
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(prop->obj());
+ }
if (prop->is_synthetic()) {
- VisitForAccumulatorValue(prop->key());
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ VisitForAccumulatorValue(prop->key());
+ }
// Record source code position for IC call.
- SetSourcePosition(prop->position());
+ SetSourcePosition(prop->position(), FORCED_POSITION);
__ pop(r1); // We do not need to keep the receiver.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
@@ -1879,7 +1897,10 @@
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
- VisitForStackValue(fun);
+
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(fun);
+ }
// Load global receiver object.
__ ldr(r1, CodeGenerator::GlobalObject());
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 7f6090b..d2c22af 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -129,7 +129,7 @@
// address is loaded. The mov method will automatically record
// positions when pc is the target, since this is not the case here
// we have to do it explicitly.
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
mov(ip, Operand(target, rmode), LeaveCC, cond);
blx(ip, cond);
@@ -220,20 +220,20 @@
void MacroAssembler::And(Register dst, Register src1, const Operand& src2,
Condition cond) {
- if (!CpuFeatures::IsSupported(ARMv7) || src2.is_single_instruction()) {
- and_(dst, src1, src2, LeaveCC, cond);
- return;
- }
- int32_t immediate = src2.immediate();
- if (immediate == 0) {
+ if (!src2.is_reg() &&
+ !src2.must_use_constant_pool() &&
+ src2.immediate() == 0) {
mov(dst, Operand(0, RelocInfo::NONE), LeaveCC, cond);
- return;
+
+ } else if (!src2.is_single_instruction() &&
+ !src2.must_use_constant_pool() &&
+ CpuFeatures::IsSupported(ARMv7) &&
+ IsPowerOf2(src2.immediate() + 1)) {
+ ubfx(dst, src1, 0, WhichPowerOf2(src2.immediate() + 1), cond);
+
+ } else {
+ and_(dst, src1, src2, LeaveCC, cond);
}
- if (IsPowerOf2(immediate + 1) && ((immediate & 1) != 0)) {
- ubfx(dst, src1, 0, WhichPowerOf2(immediate + 1), cond);
- return;
- }
- and_(dst, src1, src2, LeaveCC, cond);
}
diff --git a/src/assembler.cc b/src/assembler.cc
index ce90dce..7493673 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -804,4 +804,53 @@
}
#endif
+
+void PositionsRecorder::RecordPosition(int pos,
+ PositionRecordingType recording_type) {
+ ASSERT(pos != RelocInfo::kNoPosition);
+ ASSERT(pos >= 0);
+ current_position_ = pos;
+ current_position_recording_type_ = recording_type;
+}
+
+
+void PositionsRecorder::RecordStatementPosition(int pos) {
+ ASSERT(pos != RelocInfo::kNoPosition);
+ ASSERT(pos >= 0);
+ current_statement_position_ = pos;
+}
+
+
+bool PositionsRecorder::WriteRecordedPositions() {
+ bool written = false;
+
+ // Write the statement position if it is different from what was written last
+ // time.
+ if (current_statement_position_ != written_statement_position_) {
+ EnsureSpace ensure_space(assembler_);
+ assembler_->RecordRelocInfo(RelocInfo::STATEMENT_POSITION,
+ current_statement_position_);
+ written_statement_position_ = current_statement_position_;
+ written = true;
+ }
+
+ // Write the position if it is different from what was written last time and
+ // also different from the written statement position or was forced.
+ if (current_position_ != written_position_ &&
+ (current_position_ != current_statement_position_ || !written) &&
+ (current_position_ != written_statement_position_
+ || current_position_recording_type_ == FORCED_POSITION)) {
+ EnsureSpace ensure_space(assembler_);
+ assembler_->RecordRelocInfo(RelocInfo::POSITION, current_position_);
+ written_position_ = current_position_;
+ written = true;
+ }
+
+ current_position_recording_type_ = NORMAL_POSITION;
+
+ // Return whether something was written.
+ return written;
+}
+
+
} } // namespace v8::internal
diff --git a/src/assembler.h b/src/assembler.h
index 6681177..09159fe 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -585,6 +585,67 @@
// -----------------------------------------------------------------------------
+// Position recording support
+
+enum PositionRecordingType { FORCED_POSITION, NORMAL_POSITION };
+
+class PositionsRecorder BASE_EMBEDDED {
+ public:
+ explicit PositionsRecorder(Assembler* assembler)
+ : assembler_(assembler),
+ current_position_(RelocInfo::kNoPosition),
+ current_position_recording_type_(NORMAL_POSITION),
+ written_position_(RelocInfo::kNoPosition),
+ current_statement_position_(RelocInfo::kNoPosition),
+ written_statement_position_(RelocInfo::kNoPosition) { }
+
+ // Set current position to pos. If recording_type is FORCED_POSITION then
+ // WriteRecordedPositions will write this position even if it is equal to
+ // statement position previously written for another pc.
+ void RecordPosition(int pos,
+ PositionRecordingType recording_type = NORMAL_POSITION);
+
+ // Set current statement position to pos.
+ void RecordStatementPosition(int pos);
+
+ // Write recorded positions to relocation information.
+ bool WriteRecordedPositions();
+
+ int current_position() const { return current_position_; }
+
+ int current_statement_position() const { return current_statement_position_; }
+
+ private:
+ Assembler* assembler_;
+
+ int current_position_;
+ PositionRecordingType current_position_recording_type_;
+ int written_position_;
+
+ int current_statement_position_;
+ int written_statement_position_;
+};
+
+
+class PreserveStatementPositionScope BASE_EMBEDDED {
+ public:
+ explicit PreserveStatementPositionScope(PositionsRecorder* positions_recorder)
+ : positions_recorder_(positions_recorder),
+ statement_position_(positions_recorder->current_statement_position()) {}
+
+ ~PreserveStatementPositionScope() {
+ if (statement_position_ != RelocInfo::kNoPosition) {
+ positions_recorder_->RecordStatementPosition(statement_position_);
+ }
+ }
+
+ private:
+ PositionsRecorder* positions_recorder_;
+ int statement_position_;
+};
+
+
+// -----------------------------------------------------------------------------
// Utility functions
static inline bool is_intn(int x, int n) {
diff --git a/src/checks.cc b/src/checks.cc
index b5df316..1ab8802 100644
--- a/src/checks.cc
+++ b/src/checks.cc
@@ -98,3 +98,12 @@
i::OS::PrintError("\n#\n\n");
i::OS::Abort();
}
+
+
+namespace v8 { namespace internal {
+
+ bool EnableSlowAsserts() { return FLAG_enable_slow_asserts; }
+
+ intptr_t HeapObjectTagMask() { return kHeapObjectTagMask; }
+
+} } // namespace v8::internal
diff --git a/src/checks.h b/src/checks.h
index 5ea5992..e070477 100644
--- a/src/checks.h
+++ b/src/checks.h
@@ -30,7 +30,7 @@
#include <string.h>
-#include "flags.h"
+#include "../include/v8stdint.h"
extern "C" void V8_Fatal(const char* file, int line, const char* format, ...);
void API_Fatal(const char* location, const char* format, ...);
@@ -279,6 +279,12 @@
SEMI_STATIC_JOIN(__StaticAssertTypedef__, __LINE__)
+namespace v8 { namespace internal {
+
+bool EnableSlowAsserts();
+
+} } // namespace v8::internal
+
// The ASSERT macro is equivalent to CHECK except that it only
// generates code in debug builds.
#ifdef DEBUG
@@ -287,7 +293,7 @@
#define ASSERT_EQ(v1, v2) CHECK_EQ(v1, v2)
#define ASSERT_NE(v1, v2) CHECK_NE(v1, v2)
#define ASSERT_GE(v1, v2) CHECK_GE(v1, v2)
-#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition)
+#define SLOW_ASSERT(condition) if (EnableSlowAsserts()) CHECK(condition)
#else
#define ASSERT_RESULT(expr) (expr)
#define ASSERT(condition) ((void) 0)
@@ -303,11 +309,16 @@
// 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) & kHeapObjectTagMask) == 0)
+ ASSERT((reinterpret_cast<intptr_t>(address) & HeapObjectTagMask()) == 0)
-#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & kHeapObjectTagMask) == 0)
+#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & HeapObjectTagMask()) == 0)
#define ASSERT_NOT_NULL(p) ASSERT_NE(NULL, p)
diff --git a/src/codegen.cc b/src/codegen.cc
index bda697a..2e32418 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -70,9 +70,10 @@
DeferredCode* code = deferred_.RemoveLast();
ASSERT(masm_ == code->masm());
// Record position of deferred code stub.
- masm_->RecordStatementPosition(code->statement_position());
+ masm_->positions_recorder()->RecordStatementPosition(
+ code->statement_position());
if (code->position() != RelocInfo::kNoPosition) {
- masm_->RecordPosition(code->position());
+ masm_->positions_recorder()->RecordPosition(code->position());
}
// Generate the code.
Comment cmnt(masm_, code->comment());
@@ -402,10 +403,10 @@
int pos,
bool right_here) {
if (pos != RelocInfo::kNoPosition) {
- masm->RecordStatementPosition(pos);
- masm->RecordPosition(pos);
+ masm->positions_recorder()->RecordStatementPosition(pos);
+ masm->positions_recorder()->RecordPosition(pos);
if (right_here) {
- return masm->WriteRecordedPositions();
+ return masm->positions_recorder()->WriteRecordedPositions();
}
}
return false;
@@ -435,7 +436,7 @@
void CodeGenerator::CodeForSourcePosition(int pos) {
if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
- masm()->RecordPosition(pos);
+ masm()->positions_recorder()->RecordPosition(pos);
}
}
diff --git a/src/conversions.cc b/src/conversions.cc
index 790e807..4cc6744 100644
--- a/src/conversions.cc
+++ b/src/conversions.cc
@@ -816,7 +816,7 @@
char* DoubleToFixedCString(double value, int f) {
- const int kMaxDigitsBeforePoint = 20;
+ const int kMaxDigitsBeforePoint = 21;
const double kFirstNonFixed = 1e21;
const int kMaxDigitsAfterPoint = 20;
ASSERT(f >= 0);
@@ -840,9 +840,9 @@
// Find a sufficiently precise decimal representation of n.
int decimal_point;
int sign;
- // Add space for the '.' and the '\0' byte.
+ // Add space for the '\0' byte.
const int kDecimalRepCapacity =
- kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 2;
+ kMaxDigitsBeforePoint + kMaxDigitsAfterPoint + 1;
char decimal_rep[kDecimalRepCapacity];
int decimal_rep_length;
bool status = DoubleToAscii(value, DTOA_FIXED, f,
diff --git a/src/debug.cc b/src/debug.cc
index 24f0409..f3bf954 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -1839,6 +1839,7 @@
void Debug::ClearMirrorCache() {
+ PostponeInterruptsScope postpone;
HandleScope scope;
ASSERT(Top::context() == *Debug::debug_context());
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index 80f3788..c770e18 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -563,9 +563,10 @@
}
-void FullCodeGenerator::SetSourcePosition(int pos) {
+void FullCodeGenerator::SetSourcePosition(
+ int pos, PositionRecordingType recording_type) {
if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
- masm_->RecordPosition(pos);
+ masm_->positions_recorder()->RecordPosition(pos, recording_type);
}
}
diff --git a/src/full-codegen.h b/src/full-codegen.h
index 201507b..a3270aa 100644
--- a/src/full-codegen.h
+++ b/src/full-codegen.h
@@ -423,7 +423,9 @@
void SetStatementPosition(Statement* stmt);
void SetExpressionPosition(Expression* expr, int pos);
void SetStatementPosition(int pos);
- void SetSourcePosition(int pos);
+ void SetSourcePosition(
+ int pos,
+ PositionRecordingType recording_type = NORMAL_POSITION);
// Non-local control flow support.
void EnterFinallyBlock();
diff --git a/src/global-handles.cc b/src/global-handles.cc
index 9ede908..5339840 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -372,13 +372,14 @@
int post_gc_processing_count = 0;
-void GlobalHandles::PostGarbageCollectionProcessing() {
+bool GlobalHandles::PostGarbageCollectionProcessing() {
// Process weak global handle callbacks. This must be done after the
// GC is completely done, because the callbacks may invoke arbitrary
// API functions.
// At the same time deallocate all DESTROYED nodes.
ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
const int initial_post_gc_processing_count = ++post_gc_processing_count;
+ bool next_gc_likely_to_collect_more = false;
Node** p = &head_;
while (*p != NULL) {
if ((*p)->PostGarbageCollectionProcessing()) {
@@ -399,6 +400,7 @@
}
node->set_next_free(first_deallocated());
set_first_deallocated(node);
+ next_gc_likely_to_collect_more = true;
} else {
p = (*p)->next_addr();
}
@@ -407,6 +409,8 @@
if (first_deallocated()) {
first_deallocated()->set_next(head());
}
+
+ return next_gc_likely_to_collect_more;
}
diff --git a/src/global-handles.h b/src/global-handles.h
index 659f86e..37b2b44 100644
--- a/src/global-handles.h
+++ b/src/global-handles.h
@@ -96,7 +96,8 @@
static bool IsWeak(Object** location);
// Process pending weak handles.
- static void PostGarbageCollectionProcessing();
+ // Returns true if next major GC is likely to collect more garbage.
+ static bool PostGarbageCollectionProcessing();
// Iterates over all strong handles.
static void IterateStrongRoots(ObjectVisitor* v);
diff --git a/src/globals.h b/src/globals.h
index c218f80..a74b6c7 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -193,10 +193,9 @@
const int kCharSize = sizeof(char); // NOLINT
const int kShortSize = sizeof(short); // NOLINT
-const int kIntSize = sizeof(int); // NOLINT
const int kDoubleSize = sizeof(double); // NOLINT
-const int kPointerSize = sizeof(void*); // NOLINT
const int kIntptrSize = sizeof(intptr_t); // NOLINT
+// kIntSize and kPointerSize are defined in include/v8.h.
#if V8_HOST_ARCH_64_BIT
const int kPointerSizeLog2 = 3;
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 15feb9d..ba50c0f 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -330,6 +330,11 @@
}
+bool Heap::CollectGarbage(AllocationSpace space) {
+ return CollectGarbage(space, SelectGarbageCollector(space));
+}
+
+
MaybeObject* Heap::PrepareForCompare(String* str) {
// Always flatten small strings and force flattening of long strings
// after we have accumulated a certain amount we failed to flatten.
@@ -413,7 +418,7 @@
} \
if (!__maybe_object__->IsRetryAfterGC()) RETURN_EMPTY; \
Counters::gc_last_resort_from_handles.Increment(); \
- Heap::CollectAllGarbage(false); \
+ Heap::CollectAllAvailableGarbage(); \
{ \
AlwaysAllocateScope __scope__; \
__maybe_object__ = FUNCTION_CALL; \
diff --git a/src/heap.cc b/src/heap.cc
index b037efd..226a202 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -429,7 +429,31 @@
}
-void Heap::CollectGarbage(AllocationSpace space) {
+void Heap::CollectAllAvailableGarbage() {
+ // Since we are ignoring the return value, the exact choice of space does
+ // not matter, so long as we do not specify NEW_SPACE, which would not
+ // cause a full GC.
+ MarkCompactCollector::SetForceCompaction(true);
+
+ // Major GC would invoke weak handle callbacks on weakly reachable
+ // handles, but won't collect weakly reachable objects until next
+ // major GC. Therefore if we collect aggressively and weak handle callback
+ // has been invoked, we rerun major GC to release objects which become
+ // garbage.
+ // Note: as weak callbacks can execute arbitrary code, we cannot
+ // hope that eventually there will be no weak callbacks invocations.
+ // Therefore stop recollecting after several attempts.
+ const int kMaxNumberOfAttempts = 7;
+ for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) {
+ if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR)) {
+ break;
+ }
+ }
+ MarkCompactCollector::SetForceCompaction(false);
+}
+
+
+bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) {
// The VM is in the GC state until exiting this function.
VMState state(GC);
@@ -442,13 +466,14 @@
allocation_timeout_ = Max(6, FLAG_gc_interval);
#endif
+ bool next_gc_likely_to_collect_more = false;
+
{ GCTracer tracer;
GarbageCollectionPrologue();
// The GC count was incremented in the prologue. Tell the tracer about
// it.
tracer.set_gc_count(gc_count_);
- GarbageCollector collector = SelectGarbageCollector(space);
// Tell the tracer which collector we've selected.
tracer.set_collector(collector);
@@ -456,7 +481,8 @@
? &Counters::gc_scavenger
: &Counters::gc_compactor;
rate->Start();
- PerformGarbageCollection(collector, &tracer);
+ next_gc_likely_to_collect_more =
+ PerformGarbageCollection(collector, &tracer);
rate->Stop();
GarbageCollectionEpilogue();
@@ -467,6 +493,8 @@
if (FLAG_log_gc) HeapProfiler::WriteSample();
if (CpuProfiler::is_profiling()) CpuProfiler::ProcessMovedFunctions();
#endif
+
+ return next_gc_likely_to_collect_more;
}
@@ -653,8 +681,10 @@
survival_rate_ = survival_rate;
}
-void Heap::PerformGarbageCollection(GarbageCollector collector,
+bool Heap::PerformGarbageCollection(GarbageCollector collector,
GCTracer* tracer) {
+ bool next_gc_likely_to_collect_more = false;
+
if (collector != SCAVENGER) {
PROFILE(CodeMovingGCEvent());
}
@@ -720,7 +750,8 @@
if (collector == MARK_COMPACTOR) {
DisableAssertNoAllocation allow_allocation;
GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
- GlobalHandles::PostGarbageCollectionProcessing();
+ next_gc_likely_to_collect_more =
+ GlobalHandles::PostGarbageCollectionProcessing();
}
// Update relocatables.
@@ -747,6 +778,8 @@
global_gc_epilogue_callback_();
}
VerifySymbolTable();
+
+ return next_gc_likely_to_collect_more;
}
diff --git a/src/heap.h b/src/heap.h
index 8ff2f5f..714bf0d 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -705,13 +705,22 @@
static void GarbageCollectionEpilogue();
// Performs garbage collection operation.
- // Returns whether required_space bytes are available after the collection.
- static void CollectGarbage(AllocationSpace space);
+ // Returns whether there is a chance that another major GC could
+ // collect more garbage.
+ static bool CollectGarbage(AllocationSpace space, GarbageCollector collector);
+
+ // Performs garbage collection operation.
+ // Returns whether there is a chance that another major GC could
+ // collect more garbage.
+ inline static bool CollectGarbage(AllocationSpace space);
// Performs a full garbage collection. Force compaction if the
// parameter is true.
static void CollectAllGarbage(bool force_compaction);
+ // Last hope GC, should try to squeeze as much as possible.
+ static void CollectAllAvailableGarbage();
+
// Notify the heap that a context has been disposed.
static int NotifyContextDisposed() { return ++contexts_disposed_; }
@@ -1246,7 +1255,9 @@
static GarbageCollector SelectGarbageCollector(AllocationSpace space);
// Performs garbage collection
- static void PerformGarbageCollection(GarbageCollector collector,
+ // Returns whether there is a chance another major GC could
+ // collect more garbage.
+ static bool PerformGarbageCollection(GarbageCollector collector,
GCTracer* tracer);
// Allocate an uninitialized object in map space. The behavior is identical
diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc
index 019f478..125f503 100644
--- a/src/ia32/assembler-ia32.cc
+++ b/src/ia32/assembler-ia32.cc
@@ -298,7 +298,8 @@
// Spare buffer.
byte* Assembler::spare_buffer_ = NULL;
-Assembler::Assembler(void* buffer, int buffer_size) {
+Assembler::Assembler(void* buffer, int buffer_size)
+ : positions_recorder_(this) {
if (buffer == NULL) {
// Do our own buffer management.
if (buffer_size <= kMinimalBufferSize) {
@@ -339,10 +340,6 @@
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
last_pc_ = NULL;
- current_statement_position_ = RelocInfo::kNoPosition;
- current_position_ = RelocInfo::kNoPosition;
- written_statement_position_ = current_statement_position_;
- written_position_ = current_position_;
#ifdef GENERATED_CODE_COVERAGE
InitCoverageLog();
#endif
@@ -1581,7 +1578,7 @@
void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) {
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
last_pc_ = pc_;
ASSERT(RelocInfo::IsCodeTarget(rmode));
@@ -2464,14 +2461,14 @@
void Assembler::RecordJSReturn() {
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::JS_RETURN);
}
void Assembler::RecordDebugBreakSlot() {
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
}
@@ -2485,47 +2482,6 @@
}
-void Assembler::RecordPosition(int pos) {
- ASSERT(pos != RelocInfo::kNoPosition);
- ASSERT(pos >= 0);
- current_position_ = pos;
-}
-
-
-void Assembler::RecordStatementPosition(int pos) {
- ASSERT(pos != RelocInfo::kNoPosition);
- ASSERT(pos >= 0);
- current_statement_position_ = pos;
-}
-
-
-bool Assembler::WriteRecordedPositions() {
- bool written = false;
-
- // Write the statement position if it is different from what was written last
- // time.
- if (current_statement_position_ != written_statement_position_) {
- EnsureSpace ensure_space(this);
- RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
- written_statement_position_ = current_statement_position_;
- written = true;
- }
-
- // Write the position if it is different from what was written last time and
- // also different from the written statement position.
- if (current_position_ != written_position_ &&
- current_position_ != written_statement_position_) {
- EnsureSpace ensure_space(this);
- RecordRelocInfo(RelocInfo::POSITION, current_position_);
- written_position_ = current_position_;
- written = true;
- }
-
- // Return whether something was written.
- return written;
-}
-
-
void Assembler::GrowBuffer() {
ASSERT(overflow());
if (!own_buffer_) FATAL("external code buffer is too small");
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index 5286788..624be0c 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -847,17 +847,11 @@
// Use --debug_code to enable.
void RecordComment(const char* msg);
- void RecordPosition(int pos);
- void RecordStatementPosition(int pos);
- bool WriteRecordedPositions();
-
// Writes a single word of data in the code stream.
// Used for inline tables, e.g., jump-tables.
void dd(uint32_t data, RelocInfo::Mode reloc_info);
int pc_offset() const { return pc_ - buffer_; }
- int current_statement_position() const { return current_statement_position_; }
- int current_position() const { return current_position_; }
// Check if there is less than kGap bytes available in the buffer.
// If this is the case, we need to grow the buffer before emitting
@@ -869,6 +863,8 @@
static bool IsNop(Address addr) { return *addr == 0x90; }
+ PositionsRecorder* positions_recorder() { return &positions_recorder_; }
+
// Avoid overflows for displacements etc.
static const int kMaximalBufferSize = 512*MB;
static const int kMinimalBufferSize = 4*KB;
@@ -947,11 +943,9 @@
// push-pop elimination
byte* last_pc_;
- // source position information
- int current_statement_position_;
- int current_position_;
- int written_statement_position_;
- int written_position_;
+ PositionsRecorder positions_recorder_;
+
+ friend class PositionsRecorder;
};
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index aa03789..7295340 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -3734,7 +3734,7 @@
CodeForStatementPosition(node);
Load(node->expression());
Result return_value = frame_->Pop();
- masm()->WriteRecordedPositions();
+ masm()->positions_recorder()->WriteRecordedPositions();
if (function_return_is_shadowed_) {
function_return_.Jump(&return_value);
} else {
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index ee4e645..1ea719d 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -1996,12 +1996,14 @@
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- for (int i = 0; i < arg_count; i++) {
- VisitForStackValue(args->at(i));
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i));
+ }
+ __ Set(ecx, Immediate(name));
}
- __ Set(ecx, Immediate(name));
// Record source position of the IC call.
- SetSourcePosition(expr->position());
+ SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
EmitCallIC(ic, mode);
@@ -2017,13 +2019,15 @@
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- for (int i = 0; i < arg_count; i++) {
- VisitForStackValue(args->at(i));
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i));
+ }
+ VisitForAccumulatorValue(key);
+ __ mov(ecx, eax);
}
- VisitForAccumulatorValue(key);
- __ mov(ecx, eax);
// Record source position of the IC call.
- SetSourcePosition(expr->position());
+ SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(
arg_count, in_loop);
@@ -2038,11 +2042,13 @@
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- for (int i = 0; i < arg_count; i++) {
- VisitForStackValue(args->at(i));
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i));
+ }
}
// Record source position for debugger.
- SetSourcePosition(expr->position());
+ SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@@ -2062,37 +2068,39 @@
// resolve the function we need to call and the receiver of the
// call. Then we call the resolved function using the given
// arguments.
- VisitForStackValue(fun);
- __ push(Immediate(Factory::undefined_value())); // Reserved receiver slot.
-
- // Push the arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- for (int i = 0; i < arg_count; i++) {
- VisitForStackValue(args->at(i));
- }
-
- // Push copy of the function - found below the arguments.
- __ push(Operand(esp, (arg_count + 1) * kPointerSize));
-
- // Push copy of the first argument or undefined if it doesn't exist.
- if (arg_count > 0) {
- __ push(Operand(esp, arg_count * kPointerSize));
- } else {
+ { PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
+ VisitForStackValue(fun);
+ // Reserved receiver slot.
__ push(Immediate(Factory::undefined_value()));
+
+ // Push the arguments.
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i));
+ }
+
+ // Push copy of the function - found below the arguments.
+ __ push(Operand(esp, (arg_count + 1) * kPointerSize));
+
+ // Push copy of the first argument or undefined if it doesn't exist.
+ if (arg_count > 0) {
+ __ push(Operand(esp, arg_count * kPointerSize));
+ } else {
+ __ push(Immediate(Factory::undefined_value()));
+ }
+
+ // Push the receiver of the enclosing function and do runtime call.
+ __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+
+ // The runtime call returns a pair of values in eax (function) and
+ // edx (receiver). Touch up the stack with the right values.
+ __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
+ __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
}
-
- // Push the receiver of the enclosing function and do runtime call.
- __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
-
- // The runtime call returns a pair of values in eax (function) and
- // edx (receiver). Touch up the stack with the right values.
- __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
- __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
-
// Record source position for debugger.
- SetSourcePosition(expr->position());
+ SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@@ -2108,12 +2116,14 @@
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow,
- &done);
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ // Generate code for loading from variables potentially shadowed
+ // by eval-introduced variables.
+ EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
+ NOT_INSIDE_TYPEOF,
+ &slow,
+ &done);
+ }
__ bind(&slow);
// Call the runtime to find the function to call (returned in eax)
@@ -2152,11 +2162,15 @@
// Call to a keyed property.
// For a synthetic property use keyed load IC followed by function call,
// for a regular property use keyed EmitCallIC.
- VisitForStackValue(prop->obj());
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(prop->obj());
+ }
if (prop->is_synthetic()) {
- VisitForAccumulatorValue(prop->key());
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ VisitForAccumulatorValue(prop->key());
+ }
// Record source code position for IC call.
- SetSourcePosition(prop->position());
+ SetSourcePosition(prop->position(), FORCED_POSITION);
__ pop(edx); // We do not need to keep the receiver.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
@@ -2181,7 +2195,9 @@
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
- VisitForStackValue(fun);
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(fun);
+ }
// Load global receiver object.
__ mov(ebx, CodeGenerator::GlobalObject());
__ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index b5f4dee..a0bc086 100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -33,7 +33,6 @@
#include "ic-inl.h"
#include "runtime.h"
#include "stub-cache.h"
-#include "utils.h"
namespace v8 {
namespace internal {
diff --git a/src/jump-target-heavy.cc b/src/jump-target-heavy.cc
index e0585e7..c3c22f1 100644
--- a/src/jump-target-heavy.cc
+++ b/src/jump-target-heavy.cc
@@ -414,8 +414,9 @@
DeferredCode::DeferredCode()
: masm_(CodeGeneratorScope::Current()->masm()),
- statement_position_(masm_->current_statement_position()),
- position_(masm_->current_position()),
+ statement_position_(masm_->positions_recorder()->
+ current_statement_position()),
+ position_(masm_->positions_recorder()->current_position()),
frame_state_(CodeGeneratorScope::Current()->frame()) {
ASSERT(statement_position_ != RelocInfo::kNoPosition);
ASSERT(position_ != RelocInfo::kNoPosition);
diff --git a/src/jump-target-light.cc b/src/jump-target-light.cc
index 19f7bfe..36dc176 100644
--- a/src/jump-target-light.cc
+++ b/src/jump-target-light.cc
@@ -36,8 +36,9 @@
DeferredCode::DeferredCode()
: masm_(CodeGeneratorScope::Current()->masm()),
- statement_position_(masm_->current_statement_position()),
- position_(masm_->current_position()),
+ statement_position_(masm_->positions_recorder()->
+ current_statement_position()),
+ position_(masm_->positions_recorder()->current_position()),
frame_state_(*CodeGeneratorScope::Current()->frame()) {
ASSERT(statement_position_ != RelocInfo::kNoPosition);
ASSERT(position_ != RelocInfo::kNoPosition);
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 1852b54..399ef35 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2671,6 +2671,7 @@
#else
#define PSEUDO_SMI_ACCESSORS_LO(holder, name, offset) \
+ STATIC_ASSERT(holder::offset % kPointerSize == 0); \
int holder::name() { \
int value = READ_INT_FIELD(this, offset); \
ASSERT(kHeapObjectTag == 1); \
@@ -2686,30 +2687,36 @@
(value << 1) & ~kHeapObjectTag); \
}
-#define PSEUDO_SMI_ACCESSORS_HI(holder, name, offset) \
+#define PSEUDO_SMI_ACCESSORS_HI(holder, name, offset) \
+ STATIC_ASSERT(holder::offset % kPointerSize == kIntSize); \
INT_ACCESSORS(holder, name, offset)
-
PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, length, kLengthOffset)
-PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, formal_parameter_count,
- kFormalParameterCountOffset)
+PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
+ formal_parameter_count,
+ kFormalParameterCountOffset)
-PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, expected_nof_properties,
- kExpectedNofPropertiesOffset)
+PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
+ expected_nof_properties,
+ kExpectedNofPropertiesOffset)
PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, num_literals, kNumLiteralsOffset)
-PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, start_position_and_type,
- kStartPositionAndTypeOffset)
-PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, end_position, kEndPositionOffset)
+PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, end_position, kEndPositionOffset)
+PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
+ start_position_and_type,
+ kStartPositionAndTypeOffset)
-PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, function_token_position,
- kFunctionTokenPositionOffset)
-PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo, compiler_hints,
- kCompilerHintsOffset)
+PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
+ function_token_position,
+ kFunctionTokenPositionOffset)
+PSEUDO_SMI_ACCESSORS_HI(SharedFunctionInfo,
+ compiler_hints,
+ kCompilerHintsOffset)
-PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo, this_property_assignments_count,
- kThisPropertyAssignmentsCountOffset)
+PSEUDO_SMI_ACCESSORS_LO(SharedFunctionInfo,
+ this_property_assignments_count,
+ kThisPropertyAssignmentsCountOffset)
#endif
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index ef4ca16..89003ba 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -828,8 +828,17 @@
syscall(SYS_tgkill, vm_tgid_, vm_tid_, SIGPROF);
// Convert ms to us and subtract 100 us to compensate delays
// occuring during signal delivery.
- int result = usleep(sampler_->interval_ * 1000 - 100);
- ASSERT(result == 0 || errno == EINTR);
+ const useconds_t interval = sampler_->interval_ * 1000 - 100;
+ int result = usleep(interval);
+#ifdef DEBUG
+ if (result != 0 && errno != EINTR) {
+ fprintf(stderr,
+ "SignalSender usleep error; interval = %u, errno = %d\n",
+ interval,
+ errno);
+ ASSERT(result == 0 || errno == EINTR);
+ }
+#endif
USE(result);
}
}
@@ -862,6 +871,7 @@
Sampler::~Sampler() {
+ ASSERT(!data_->signal_sender_launched_);
delete data_;
}
diff --git a/src/preparser.h b/src/preparser.h
index 697ef6e..44c55cf 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -31,7 +31,6 @@
#include "unicode.h"
namespace v8 {
-namespace internal {
namespace preparser {
// Preparsing checks a JavaScript program and emits preparse-data that helps
@@ -47,6 +46,8 @@
// That means that contextual checks (like a label being declared where
// it is used) are generally omitted.
+namespace i = v8::internal;
+
enum StatementType {
kUnknownStatement
};
@@ -92,7 +93,7 @@
log_ = log;
Scope top_scope(&scope_, kTopLevelScope);
bool ok = true;
- ParseSourceElements(Token::EOS, &ok);
+ ParseSourceElements(i::Token::EOS, &ok);
bool stack_overflow = scanner_->stack_overflow();
if (!ok && !stack_overflow) {
ReportUnexpectedToken(scanner_->current_token());
@@ -144,7 +145,7 @@
// simple this-property assignments.
// Report syntax error
- void ReportUnexpectedToken(Token::Value token);
+ void ReportUnexpectedToken(i::Token::Value token);
void ReportMessageAt(int start_pos,
int end_pos,
const char* type,
@@ -186,8 +187,7 @@
Expression ParseLeftHandSideExpression(bool* ok);
Expression ParseNewExpression(bool* ok);
Expression ParseMemberExpression(bool* ok);
- Expression ParseNewPrefix(int* new_count, bool* ok);
- Expression ParseMemberWithNewPrefixesExpression(int* new_count, bool* ok);
+ Expression ParseMemberWithNewPrefixesExpression(unsigned new_count, bool* ok);
Expression ParsePrimaryExpression(bool* ok);
Expression ParseArrayLiteral(bool* ok);
Expression ParseObjectLiteral(bool* ok);
@@ -206,24 +206,24 @@
Expression GetStringSymbol();
- Token::Value peek() { return scanner_->peek(); }
- Token::Value Next() {
- Token::Value next = scanner_->Next();
+ i::Token::Value peek() { return scanner_->peek(); }
+ i::Token::Value Next() {
+ i::Token::Value next = scanner_->Next();
return next;
}
- void Consume(Token::Value token) {
+ void Consume(i::Token::Value token) {
Next();
}
- void Expect(Token::Value token, bool* ok) {
+ void Expect(i::Token::Value token, bool* ok) {
if (Next() != token) {
*ok = false;
}
}
- bool Check(Token::Value token) {
- Token::Value next = peek();
+ bool Check(i::Token::Value token) {
+ i::Token::Value next = peek();
if (next == token) {
Consume(next);
return true;
@@ -232,7 +232,7 @@
}
void ExpectSemicolon(bool* ok);
- static int Precedence(Token::Value tok, bool accept_IN);
+ static int Precedence(i::Token::Value tok, bool accept_IN);
Scanner* scanner_;
PreParserLog* log_;
@@ -249,31 +249,31 @@
template <typename Scanner, typename Log>
-void PreParser<Scanner, Log>::ReportUnexpectedToken(Token::Value token) {
+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 == Token::ILLEGAL && scanner_->stack_overflow()) {
+ 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 Token::EOS:
+ case i::Token::EOS:
return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
"unexpected_eos", NULL);
- case Token::NUMBER:
+ case i::Token::NUMBER:
return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
"unexpected_token_number", NULL);
- case Token::STRING:
+ case i::Token::STRING:
return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
"unexpected_token_string", NULL);
- case Token::IDENTIFIER:
+ case i::Token::IDENTIFIER:
return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
"unexpected_token_identifier", NULL);
default:
- const char* name = Token::String(token);
+ const char* name = i::Token::String(token);
ReportMessageAt(source_location.beg_pos, source_location.end_pos,
"unexpected_token", name);
}
@@ -321,57 +321,57 @@
// Keep the source position of the statement
switch (peek()) {
- case Token::LBRACE:
+ case i::Token::LBRACE:
return ParseBlock(ok);
- case Token::CONST:
- case Token::VAR:
+ case i::Token::CONST:
+ case i::Token::VAR:
return ParseVariableStatement(ok);
- case Token::SEMICOLON:
+ case i::Token::SEMICOLON:
Next();
return kUnknownStatement;
- case Token::IF:
+ case i::Token::IF:
return ParseIfStatement(ok);
- case Token::DO:
+ case i::Token::DO:
return ParseDoWhileStatement(ok);
- case Token::WHILE:
+ case i::Token::WHILE:
return ParseWhileStatement(ok);
- case Token::FOR:
+ case i::Token::FOR:
return ParseForStatement(ok);
- case Token::CONTINUE:
+ case i::Token::CONTINUE:
return ParseContinueStatement(ok);
- case Token::BREAK:
+ case i::Token::BREAK:
return ParseBreakStatement(ok);
- case Token::RETURN:
+ case i::Token::RETURN:
return ParseReturnStatement(ok);
- case Token::WITH:
+ case i::Token::WITH:
return ParseWithStatement(ok);
- case Token::SWITCH:
+ case i::Token::SWITCH:
return ParseSwitchStatement(ok);
- case Token::THROW:
+ case i::Token::THROW:
return ParseThrowStatement(ok);
- case Token::TRY:
+ case i::Token::TRY:
return ParseTryStatement(ok);
- case Token::FUNCTION:
+ case i::Token::FUNCTION:
return ParseFunctionDeclaration(ok);
- case Token::NATIVE:
+ case i::Token::NATIVE:
return ParseNativeDeclaration(ok);
- case Token::DEBUGGER:
+ case i::Token::DEBUGGER:
return ParseDebuggerStatement(ok);
default:
@@ -384,7 +384,7 @@
Statement PreParser<Scanner, Log>::ParseFunctionDeclaration(bool* ok) {
// FunctionDeclaration ::
// 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
- Expect(Token::FUNCTION, CHECK_OK);
+ Expect(i::Token::FUNCTION, CHECK_OK);
ParseIdentifier(CHECK_OK);
ParseFunctionLiteral(CHECK_OK);
return kUnknownStatement;
@@ -397,20 +397,20 @@
// callback provided by the extension.
template <typename Scanner, typename Log>
Statement PreParser<Scanner, Log>::ParseNativeDeclaration(bool* ok) {
- Expect(Token::NATIVE, CHECK_OK);
- Expect(Token::FUNCTION, CHECK_OK);
+ Expect(i::Token::NATIVE, CHECK_OK);
+ Expect(i::Token::FUNCTION, CHECK_OK);
ParseIdentifier(CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
- bool done = (peek() == Token::RPAREN);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ bool done = (peek() == i::Token::RPAREN);
while (!done) {
ParseIdentifier(CHECK_OK);
- done = (peek() == Token::RPAREN);
+ done = (peek() == i::Token::RPAREN);
if (!done) {
- Expect(Token::COMMA, CHECK_OK);
+ Expect(i::Token::COMMA, CHECK_OK);
}
}
- Expect(Token::RPAREN, CHECK_OK);
- Expect(Token::SEMICOLON, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
+ Expect(i::Token::SEMICOLON, CHECK_OK);
return kUnknownStatement;
}
@@ -423,11 +423,11 @@
// Note that a Block does not introduce a new execution scope!
// (ECMA-262, 3rd, 12.2)
//
- Expect(Token::LBRACE, CHECK_OK);
- while (peek() != Token::RBRACE) {
+ Expect(i::Token::LBRACE, CHECK_OK);
+ while (peek() != i::Token::RBRACE) {
ParseStatement(CHECK_OK);
}
- Expect(Token::RBRACE, CHECK_OK);
+ Expect(i::Token::RBRACE, CHECK_OK);
return kUnknownStatement;
}
@@ -455,10 +455,10 @@
// VariableDeclarations ::
// ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
- if (peek() == Token::VAR) {
- Consume(Token::VAR);
- } else if (peek() == Token::CONST) {
- Consume(Token::CONST);
+ if (peek() == i::Token::VAR) {
+ Consume(i::Token::VAR);
+ } else if (peek() == i::Token::CONST) {
+ Consume(i::Token::CONST);
} else {
*ok = false;
return 0;
@@ -469,14 +469,14 @@
int nvars = 0; // the number of variables declared
do {
// Parse variable name.
- if (nvars > 0) Consume(Token::COMMA);
+ if (nvars > 0) Consume(i::Token::COMMA);
ParseIdentifier(CHECK_OK);
nvars++;
- if (peek() == Token::ASSIGN) {
- Expect(Token::ASSIGN, CHECK_OK);
+ if (peek() == i::Token::ASSIGN) {
+ Expect(i::Token::ASSIGN, CHECK_OK);
ParseAssignmentExpression(accept_IN, CHECK_OK);
}
- } while (peek() == Token::COMMA);
+ } while (peek() == i::Token::COMMA);
if (num_decl != NULL) *num_decl = nvars;
return kUnknownStatement;
@@ -491,8 +491,8 @@
// Identifier ':' Statement
Expression expr = ParseExpression(true, CHECK_OK);
- if (peek() == Token::COLON && expr == kIdentifierExpression) {
- Consume(Token::COLON);
+ if (peek() == i::Token::COLON && expr == kIdentifierExpression) {
+ Consume(i::Token::COLON);
return ParseStatement(ok);
}
// Parsed expression statement.
@@ -506,12 +506,12 @@
// IfStatement ::
// 'if' '(' Expression ')' Statement ('else' Statement)?
- Expect(Token::IF, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
+ Expect(i::Token::IF, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK);
- if (peek() == Token::ELSE) {
+ if (peek() == i::Token::ELSE) {
Next();
ParseStatement(CHECK_OK);
}
@@ -524,12 +524,12 @@
// ContinueStatement ::
// 'continue' [no line terminator] Identifier? ';'
- Expect(Token::CONTINUE, CHECK_OK);
- Token::Value tok = peek();
+ Expect(i::Token::CONTINUE, CHECK_OK);
+ i::Token::Value tok = peek();
if (!scanner_->has_line_terminator_before_next() &&
- tok != Token::SEMICOLON &&
- tok != Token::RBRACE &&
- tok != Token::EOS) {
+ tok != i::Token::SEMICOLON &&
+ tok != i::Token::RBRACE &&
+ tok != i::Token::EOS) {
ParseIdentifier(CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
@@ -542,12 +542,12 @@
// BreakStatement ::
// 'break' [no line terminator] Identifier? ';'
- Expect(Token::BREAK, CHECK_OK);
- Token::Value tok = peek();
+ Expect(i::Token::BREAK, CHECK_OK);
+ i::Token::Value tok = peek();
if (!scanner_->has_line_terminator_before_next() &&
- tok != Token::SEMICOLON &&
- tok != Token::RBRACE &&
- tok != Token::EOS) {
+ tok != i::Token::SEMICOLON &&
+ tok != i::Token::RBRACE &&
+ tok != i::Token::EOS) {
ParseIdentifier(CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
@@ -563,18 +563,18 @@
// 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(Token::RETURN, CHECK_OK);
+ 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.
- Token::Value tok = peek();
+ i::Token::Value tok = peek();
if (!scanner_->has_line_terminator_before_next() &&
- tok != Token::SEMICOLON &&
- tok != Token::RBRACE &&
- tok != Token::EOS) {
+ tok != i::Token::SEMICOLON &&
+ tok != i::Token::RBRACE &&
+ tok != i::Token::EOS) {
ParseExpression(true, CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
@@ -586,10 +586,10 @@
Statement PreParser<Scanner, Log>::ParseWithStatement(bool* ok) {
// WithStatement ::
// 'with' '(' Expression ')' Statement
- Expect(Token::WITH, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
+ Expect(i::Token::WITH, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
scope_->EnterWith();
ParseStatement(CHECK_OK);
@@ -603,27 +603,27 @@
// SwitchStatement ::
// 'switch' '(' Expression ')' '{' CaseClause* '}'
- Expect(Token::SWITCH, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
+ Expect(i::Token::SWITCH, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
- Expect(Token::LBRACE, CHECK_OK);
- Token::Value token = peek();
- while (token != Token::RBRACE) {
- if (token == Token::CASE) {
- Expect(Token::CASE, 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(Token::COLON, CHECK_OK);
- } else if (token == Token::DEFAULT) {
- Expect(Token::DEFAULT, CHECK_OK);
- Expect(Token::COLON, 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(Token::RBRACE, CHECK_OK);
+ Expect(i::Token::RBRACE, CHECK_OK);
return kUnknownStatement;
}
@@ -634,12 +634,12 @@
// DoStatement ::
// 'do' Statement 'while' '(' Expression ')' ';'
- Expect(Token::DO, CHECK_OK);
+ Expect(i::Token::DO, CHECK_OK);
ParseStatement(CHECK_OK);
- Expect(Token::WHILE, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
+ Expect(i::Token::WHILE, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
return kUnknownStatement;
}
@@ -649,10 +649,10 @@
// WhileStatement ::
// 'while' '(' Expression ')' Statement
- Expect(Token::WHILE, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
+ Expect(i::Token::WHILE, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK);
return kUnknownStatement;
}
@@ -663,26 +663,26 @@
// ForStatement ::
// 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
- Expect(Token::FOR, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
- if (peek() != Token::SEMICOLON) {
- if (peek() == Token::VAR || peek() == Token::CONST) {
+ 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() == Token::IN && decl_count == 1) {
- Expect(Token::IN, CHECK_OK);
+ if (peek() == i::Token::IN && decl_count == 1) {
+ Expect(i::Token::IN, CHECK_OK);
ParseExpression(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK);
return kUnknownStatement;
}
} else {
ParseExpression(false, CHECK_OK);
- if (peek() == Token::IN) {
- Expect(Token::IN, CHECK_OK);
+ if (peek() == i::Token::IN) {
+ Expect(i::Token::IN, CHECK_OK);
ParseExpression(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK);
return kUnknownStatement;
@@ -691,17 +691,17 @@
}
// Parsed initializer at this point.
- Expect(Token::SEMICOLON, CHECK_OK);
+ Expect(i::Token::SEMICOLON, CHECK_OK);
- if (peek() != Token::SEMICOLON) {
+ if (peek() != i::Token::SEMICOLON) {
ParseExpression(true, CHECK_OK);
}
- Expect(Token::SEMICOLON, CHECK_OK);
+ Expect(i::Token::SEMICOLON, CHECK_OK);
- if (peek() != Token::RPAREN) {
+ if (peek() != i::Token::RPAREN) {
ParseExpression(true, CHECK_OK);
}
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
ParseStatement(CHECK_OK);
return kUnknownStatement;
@@ -713,7 +713,7 @@
// ThrowStatement ::
// 'throw' [no line terminator] Expression ';'
- Expect(Token::THROW, CHECK_OK);
+ 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,
@@ -744,21 +744,21 @@
// In preparsing, allow any number of catch/finally blocks, including zero
// of both.
- Expect(Token::TRY, CHECK_OK);
+ Expect(i::Token::TRY, CHECK_OK);
ParseBlock(CHECK_OK);
bool catch_or_finally_seen = false;
- if (peek() == Token::CATCH) {
- Expect(Token::CATCH, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
+ if (peek() == i::Token::CATCH) {
+ Expect(i::Token::CATCH, CHECK_OK);
+ Expect(i::Token::LPAREN, CHECK_OK);
ParseIdentifier(CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
ParseBlock(CHECK_OK);
catch_or_finally_seen = true;
}
- if (peek() == Token::FINALLY) {
- Expect(Token::FINALLY, CHECK_OK);
+ if (peek() == i::Token::FINALLY) {
+ Expect(i::Token::FINALLY, CHECK_OK);
ParseBlock(CHECK_OK);
catch_or_finally_seen = true;
}
@@ -777,7 +777,7 @@
// DebuggerStatement ::
// 'debugger' ';'
- Expect(Token::DEBUGGER, CHECK_OK);
+ Expect(i::Token::DEBUGGER, CHECK_OK);
ExpectSemicolon(CHECK_OK);
return kUnknownStatement;
}
@@ -791,8 +791,8 @@
// Expression ',' AssignmentExpression
Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK);
- while (peek() == Token::COMMA) {
- Expect(Token::COMMA, CHECK_OK);
+ while (peek() == i::Token::COMMA) {
+ Expect(i::Token::COMMA, CHECK_OK);
ParseAssignmentExpression(accept_IN, CHECK_OK);
result = kUnknownExpression;
}
@@ -810,15 +810,15 @@
Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
- if (!Token::IsAssignmentOp(peek())) {
+ if (!i::Token::IsAssignmentOp(peek())) {
// Parsed conditional expression only (no assignment).
return expression;
}
- Token::Value op = Next(); // Get assignment operator.
+ i::Token::Value op = Next(); // Get assignment operator.
ParseAssignmentExpression(accept_IN, CHECK_OK);
- if ((op == Token::ASSIGN) && (expression == kThisPropertyExpression)) {
+ if ((op == i::Token::ASSIGN) && (expression == kThisPropertyExpression)) {
scope_->AddProperty();
}
@@ -836,24 +836,24 @@
// We start using the binary expression parser for prec >= 4 only!
Expression expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
- if (peek() != Token::CONDITIONAL) return expression;
- Consume(Token::CONDITIONAL);
+ 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(Token::COLON, 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(Token::Value tok, bool accept_IN) {
- if (tok == Token::IN && !accept_IN)
+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 Token::Precedence(tok);
+ return i::Token::Precedence(tok);
}
@@ -889,8 +889,8 @@
// '~' UnaryExpression
// '!' UnaryExpression
- Token::Value op = peek();
- if (Token::IsUnaryOp(op) || Token::IsCountOp(op)) {
+ i::Token::Value op = peek();
+ if (i::Token::IsUnaryOp(op) || i::Token::IsCountOp(op)) {
op = Next();
ParseUnaryExpression(ok);
return kUnknownExpression;
@@ -907,7 +907,7 @@
Expression expression = ParseLeftHandSideExpression(CHECK_OK);
if (!scanner_->has_line_terminator_before_next() &&
- Token::IsCountOp(peek())) {
+ i::Token::IsCountOp(peek())) {
Next();
return kUnknownExpression;
}
@@ -921,7 +921,7 @@
// (NewExpression | MemberExpression) ...
Expression result;
- if (peek() == Token::NEW) {
+ if (peek() == i::Token::NEW) {
result = ParseNewExpression(CHECK_OK);
} else {
result = ParseMemberExpression(CHECK_OK);
@@ -929,10 +929,10 @@
while (true) {
switch (peek()) {
- case Token::LBRACK: {
- Consume(Token::LBRACK);
+ case i::Token::LBRACK: {
+ Consume(i::Token::LBRACK);
ParseExpression(true, CHECK_OK);
- Expect(Token::RBRACK, CHECK_OK);
+ Expect(i::Token::RBRACK, CHECK_OK);
if (result == kThisExpression) {
result = kThisPropertyExpression;
} else {
@@ -941,14 +941,14 @@
break;
}
- case Token::LPAREN: {
+ case i::Token::LPAREN: {
ParseArguments(CHECK_OK);
result = kUnknownExpression;
break;
}
- case Token::PERIOD: {
- Consume(Token::PERIOD);
+ case i::Token::PERIOD: {
+ Consume(i::Token::PERIOD);
ParseIdentifierName(CHECK_OK);
if (result == kThisExpression) {
result = kThisPropertyExpression;
@@ -965,9 +965,8 @@
}
-
template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseNewPrefix(int* new_count, bool* ok) {
+Expression PreParser<Scanner, Log>::ParseNewExpression(bool* ok) {
// NewExpression ::
// ('new')+ MemberExpression
@@ -979,47 +978,34 @@
// 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
- Expect(Token::NEW, CHECK_OK);
- *new_count++;
+ unsigned new_count = 0;
+ do {
+ Consume(i::Token::NEW);
+ new_count++;
+ } while (peek() == i::Token::NEW);
- if (peek() == Token::NEW) {
- ParseNewPrefix(new_count, CHECK_OK);
- } else {
- ParseMemberWithNewPrefixesExpression(new_count, CHECK_OK);
- }
-
- if (*new_count > 0) {
- *new_count--;
- }
- return kUnknownExpression;
-}
-
-
-template <typename Scanner, typename Log>
-Expression PreParser<Scanner, Log>::ParseNewExpression(bool* ok) {
- int new_count = 0;
- return ParseNewPrefix(&new_count, ok);
+ return ParseMemberWithNewPrefixesExpression(new_count, ok);
}
template <typename Scanner, typename Log>
Expression PreParser<Scanner, Log>::ParseMemberExpression(bool* ok) {
- return ParseMemberWithNewPrefixesExpression(NULL, ok);
+ return ParseMemberWithNewPrefixesExpression(0, ok);
}
template <typename Scanner, typename Log>
Expression PreParser<Scanner, Log>::ParseMemberWithNewPrefixesExpression(
- int* new_count, bool* ok) {
+ unsigned new_count, bool* ok) {
// MemberExpression ::
// (PrimaryExpression | FunctionLiteral)
// ('[' Expression ']' | '.' Identifier | Arguments)*
// Parse the initial primary or function expression.
Expression result = NULL;
- if (peek() == Token::FUNCTION) {
- Consume(Token::FUNCTION);
- if (peek() == Token::IDENTIFIER) {
+ if (peek() == i::Token::FUNCTION) {
+ Consume(i::Token::FUNCTION);
+ if (peek() == i::Token::IDENTIFIER) {
ParseIdentifier(CHECK_OK);
}
result = ParseFunctionLiteral(CHECK_OK);
@@ -1029,10 +1015,10 @@
while (true) {
switch (peek()) {
- case Token::LBRACK: {
- Consume(Token::LBRACK);
+ case i::Token::LBRACK: {
+ Consume(i::Token::LBRACK);
ParseExpression(true, CHECK_OK);
- Expect(Token::RBRACK, CHECK_OK);
+ Expect(i::Token::RBRACK, CHECK_OK);
if (result == kThisExpression) {
result = kThisPropertyExpression;
} else {
@@ -1040,8 +1026,8 @@
}
break;
}
- case Token::PERIOD: {
- Consume(Token::PERIOD);
+ case i::Token::PERIOD: {
+ Consume(i::Token::PERIOD);
ParseIdentifierName(CHECK_OK);
if (result == kThisExpression) {
result = kThisPropertyExpression;
@@ -1050,11 +1036,11 @@
}
break;
}
- case Token::LPAREN: {
- if ((new_count == NULL) || *new_count == 0) return result;
+ case i::Token::LPAREN: {
+ if (new_count == 0) return result;
// Consume one of the new prefixes (already parsed).
ParseArguments(CHECK_OK);
- *new_count--;
+ new_count--;
result = kUnknownExpression;
break;
}
@@ -1082,55 +1068,55 @@
Expression result = kUnknownExpression;
switch (peek()) {
- case Token::THIS: {
+ case i::Token::THIS: {
Next();
result = kThisExpression;
break;
}
- case Token::IDENTIFIER: {
+ case i::Token::IDENTIFIER: {
ParseIdentifier(CHECK_OK);
result = kIdentifierExpression;
break;
}
- case Token::NULL_LITERAL:
- case Token::TRUE_LITERAL:
- case Token::FALSE_LITERAL:
- case Token::NUMBER: {
+ case i::Token::NULL_LITERAL:
+ case i::Token::TRUE_LITERAL:
+ case i::Token::FALSE_LITERAL:
+ case i::Token::NUMBER: {
Next();
break;
}
- case Token::STRING: {
+ case i::Token::STRING: {
Next();
result = GetStringSymbol();
break;
}
- case Token::ASSIGN_DIV:
+ case i::Token::ASSIGN_DIV:
result = ParseRegExpLiteral(true, CHECK_OK);
break;
- case Token::DIV:
+ case i::Token::DIV:
result = ParseRegExpLiteral(false, CHECK_OK);
break;
- case Token::LBRACK:
+ case i::Token::LBRACK:
result = ParseArrayLiteral(CHECK_OK);
break;
- case Token::LBRACE:
+ case i::Token::LBRACE:
result = ParseObjectLiteral(CHECK_OK);
break;
- case Token::LPAREN:
- Consume(Token::LPAREN);
+ case i::Token::LPAREN:
+ Consume(i::Token::LPAREN);
result = ParseExpression(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
if (result == kIdentifierExpression) result = kUnknownExpression;
break;
- case Token::MOD:
+ case i::Token::MOD:
result = ParseV8Intrinsic(CHECK_OK);
break;
@@ -1149,16 +1135,16 @@
Expression PreParser<Scanner, Log>::ParseArrayLiteral(bool* ok) {
// ArrayLiteral ::
// '[' Expression? (',' Expression?)* ']'
- Expect(Token::LBRACK, CHECK_OK);
- while (peek() != Token::RBRACK) {
- if (peek() != Token::COMMA) {
+ Expect(i::Token::LBRACK, CHECK_OK);
+ while (peek() != i::Token::RBRACK) {
+ if (peek() != i::Token::COMMA) {
ParseAssignmentExpression(true, CHECK_OK);
}
- if (peek() != Token::RBRACK) {
- Expect(Token::COMMA, CHECK_OK);
+ if (peek() != i::Token::RBRACK) {
+ Expect(i::Token::COMMA, CHECK_OK);
}
}
- Expect(Token::RBRACK, CHECK_OK);
+ Expect(i::Token::RBRACK, CHECK_OK);
scope_->NextMaterializedLiteralIndex();
return kUnknownExpression;
@@ -1173,40 +1159,40 @@
// | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
// )*[','] '}'
- Expect(Token::LBRACE, CHECK_OK);
- while (peek() != Token::RBRACE) {
- Token::Value next = peek();
+ Expect(i::Token::LBRACE, CHECK_OK);
+ while (peek() != i::Token::RBRACE) {
+ i::Token::Value next = peek();
switch (next) {
- case Token::IDENTIFIER: {
+ 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() != Token::COLON) {
- Token::Value name = Next();
- if (name != Token::IDENTIFIER &&
- name != Token::NUMBER &&
- name != Token::STRING &&
- !Token::IsKeyword(name)) {
+ 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() != Token::RBRACE) {
- Expect(Token::COMMA, CHECK_OK);
+ if (peek() != i::Token::RBRACE) {
+ Expect(i::Token::COMMA, CHECK_OK);
}
continue; // restart the while
}
break;
}
- case Token::STRING:
+ case i::Token::STRING:
Consume(next);
GetStringSymbol();
break;
- case Token::NUMBER:
+ case i::Token::NUMBER:
Consume(next);
break;
default:
- if (Token::IsKeyword(next)) {
+ if (i::Token::IsKeyword(next)) {
Consume(next);
} else {
// Unexpected token.
@@ -1215,13 +1201,13 @@
}
}
- Expect(Token::COLON, CHECK_OK);
+ Expect(i::Token::COLON, CHECK_OK);
ParseAssignmentExpression(true, CHECK_OK);
// TODO(1240767): Consider allowing trailing comma.
- if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK);
+ if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK);
}
- Expect(Token::RBRACE, CHECK_OK);
+ Expect(i::Token::RBRACE, CHECK_OK);
scope_->NextMaterializedLiteralIndex();
return kUnknownExpression;
@@ -1260,16 +1246,16 @@
// Arguments ::
// '(' (AssignmentExpression)*[','] ')'
- Expect(Token::LPAREN, CHECK_OK);
- bool done = (peek() == Token::RPAREN);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ bool done = (peek() == i::Token::RPAREN);
int argc = 0;
while (!done) {
ParseAssignmentExpression(true, CHECK_OK);
argc++;
- done = (peek() == Token::RPAREN);
- if (!done) Expect(Token::COMMA, CHECK_OK);
+ done = (peek() == i::Token::RPAREN);
+ if (!done) Expect(i::Token::COMMA, CHECK_OK);
}
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
return argc;
}
@@ -1286,18 +1272,18 @@
// FormalParameterList ::
// '(' (Identifier)*[','] ')'
- Expect(Token::LPAREN, CHECK_OK);
- bool done = (peek() == Token::RPAREN);
+ Expect(i::Token::LPAREN, CHECK_OK);
+ bool done = (peek() == i::Token::RPAREN);
while (!done) {
ParseIdentifier(CHECK_OK);
- done = (peek() == Token::RPAREN);
+ done = (peek() == i::Token::RPAREN);
if (!done) {
- Expect(Token::COMMA, CHECK_OK);
+ Expect(i::Token::COMMA, CHECK_OK);
}
}
- Expect(Token::RPAREN, CHECK_OK);
+ Expect(i::Token::RPAREN, CHECK_OK);
- Expect(Token::LBRACE, CHECK_OK);
+ Expect(i::Token::LBRACE, CHECK_OK);
int function_block_pos = scanner_->location().beg_pos;
// Determine if the function will be lazily compiled.
@@ -1308,19 +1294,19 @@
if (is_lazily_compiled) {
log_->PauseRecording();
- ParseSourceElements(Token::RBRACE, ok);
+ ParseSourceElements(i::Token::RBRACE, ok);
log_->ResumeRecording();
if (!*ok) return kUnknownExpression;
- Expect(Token::RBRACE, CHECK_OK);
+ 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(Token::RBRACE, CHECK_OK);
- Expect(Token::RBRACE, CHECK_OK);
+ ParseSourceElements(i::Token::RBRACE, CHECK_OK);
+ Expect(i::Token::RBRACE, CHECK_OK);
}
return kUnknownExpression;
}
@@ -1331,7 +1317,7 @@
// CallRuntime ::
// '%' Identifier Arguments
- Expect(Token::MOD, CHECK_OK);
+ Expect(i::Token::MOD, CHECK_OK);
ParseIdentifier(CHECK_OK);
ParseArguments(CHECK_OK);
@@ -1343,17 +1329,17 @@
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.
- Token::Value tok = peek();
- if (tok == Token::SEMICOLON) {
+ i::Token::Value tok = peek();
+ if (tok == i::Token::SEMICOLON) {
Next();
return;
}
if (scanner_->has_line_terminator_before_next() ||
- tok == Token::RBRACE ||
- tok == Token::EOS) {
+ tok == i::Token::RBRACE ||
+ tok == i::Token::EOS) {
return;
}
- Expect(Token::SEMICOLON, ok);
+ Expect(i::Token::SEMICOLON, ok);
}
@@ -1383,21 +1369,21 @@
template <typename Scanner, typename Log>
Identifier PreParser<Scanner, Log>::ParseIdentifier(bool* ok) {
- Expect(Token::IDENTIFIER, ok);
+ Expect(i::Token::IDENTIFIER, ok);
return GetIdentifierSymbol();
}
template <typename Scanner, typename Log>
Identifier PreParser<Scanner, Log>::ParseIdentifierName(bool* ok) {
- Token::Value next = Next();
- if (Token::IsKeyword(next)) {
+ i::Token::Value next = Next();
+ if (i::Token::IsKeyword(next)) {
int pos = scanner_->location().beg_pos;
- const char* keyword = Token::String(next);
+ const char* keyword = i::Token::String(next);
log_->LogSymbol(pos, keyword, strlen(keyword));
return kUnknownExpression;
}
- if (next == Token::IDENTIFIER) {
+ if (next == i::Token::IDENTIFIER) {
return GetIdentifierSymbol();
}
*ok = false;
@@ -1413,7 +1399,7 @@
Identifier PreParser<Scanner, Log>::ParseIdentifierOrGetOrSet(bool* is_get,
bool* is_set,
bool* ok) {
- Expect(Token::IDENTIFIER, CHECK_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;
@@ -1423,6 +1409,6 @@
}
#undef CHECK_OK
-} } } // v8::internal::preparser
+} } // v8::preparser
#endif // V8_PREPARSER_H
diff --git a/src/regexp.js b/src/regexp.js
index 6a69cf6..9e708fd 100644
--- a/src/regexp.js
+++ b/src/regexp.js
@@ -237,7 +237,6 @@
} else {
s = ToString(string);
}
- var length = s.length;
var lastIndex = this.lastIndex;
@@ -247,7 +246,7 @@
var global = this.global;
if (global) {
- if (i < 0 || i > length) {
+ if (i < 0 || i > s.length) {
this.lastIndex = 0;
return false;
}
@@ -271,13 +270,6 @@
if (!regexp_val.test(s)) return false;
}
- var length = s.length;
-
- if (i < 0 || i > length) {
- this.lastIndex = 0;
- return false;
- }
-
%_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
// matchIndices is either null or the lastMatchInfo array.
var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
diff --git a/src/scanner-base.cc b/src/scanner-base.cc
new file mode 100644
index 0000000..6e9d40e
--- /dev/null
+++ b/src/scanner-base.cc
@@ -0,0 +1,167 @@
+// 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.
+
+// Features shared by parsing and pre-parsing scanners.
+
+#include "scanner-base.h"
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// Keyword Matcher
+
+KeywordMatcher::FirstState KeywordMatcher::first_states_[] = {
+ { "break", KEYWORD_PREFIX, Token::BREAK },
+ { NULL, C, Token::ILLEGAL },
+ { NULL, D, Token::ILLEGAL },
+ { "else", KEYWORD_PREFIX, Token::ELSE },
+ { NULL, F, Token::ILLEGAL },
+ { NULL, UNMATCHABLE, Token::ILLEGAL },
+ { NULL, UNMATCHABLE, Token::ILLEGAL },
+ { NULL, I, Token::ILLEGAL },
+ { NULL, UNMATCHABLE, Token::ILLEGAL },
+ { NULL, UNMATCHABLE, Token::ILLEGAL },
+ { NULL, UNMATCHABLE, Token::ILLEGAL },
+ { NULL, UNMATCHABLE, Token::ILLEGAL },
+ { NULL, N, Token::ILLEGAL },
+ { NULL, UNMATCHABLE, Token::ILLEGAL },
+ { NULL, UNMATCHABLE, Token::ILLEGAL },
+ { NULL, UNMATCHABLE, Token::ILLEGAL },
+ { "return", KEYWORD_PREFIX, Token::RETURN },
+ { "switch", KEYWORD_PREFIX, Token::SWITCH },
+ { NULL, T, Token::ILLEGAL },
+ { NULL, UNMATCHABLE, Token::ILLEGAL },
+ { NULL, V, Token::ILLEGAL },
+ { NULL, W, Token::ILLEGAL }
+};
+
+
+void KeywordMatcher::Step(unibrow::uchar input) {
+ switch (state_) {
+ case INITIAL: {
+ // matching the first character is the only state with significant fanout.
+ // Match only lower-case letters in range 'b'..'w'.
+ unsigned int offset = input - kFirstCharRangeMin;
+ if (offset < kFirstCharRangeLength) {
+ state_ = first_states_[offset].state;
+ if (state_ == KEYWORD_PREFIX) {
+ keyword_ = first_states_[offset].keyword;
+ counter_ = 1;
+ keyword_token_ = first_states_[offset].token;
+ }
+ return;
+ }
+ break;
+ }
+ case KEYWORD_PREFIX:
+ if (static_cast<unibrow::uchar>(keyword_[counter_]) == input) {
+ counter_++;
+ if (keyword_[counter_] == '\0') {
+ state_ = KEYWORD_MATCHED;
+ token_ = keyword_token_;
+ }
+ return;
+ }
+ break;
+ case KEYWORD_MATCHED:
+ token_ = Token::IDENTIFIER;
+ break;
+ case C:
+ if (MatchState(input, 'a', CA)) return;
+ if (MatchState(input, 'o', CO)) return;
+ break;
+ case CA:
+ if (MatchKeywordStart(input, "case", 2, Token::CASE)) return;
+ if (MatchKeywordStart(input, "catch", 2, Token::CATCH)) return;
+ break;
+ case CO:
+ if (MatchState(input, 'n', CON)) return;
+ break;
+ case CON:
+ if (MatchKeywordStart(input, "const", 3, Token::CONST)) return;
+ if (MatchKeywordStart(input, "continue", 3, Token::CONTINUE)) return;
+ break;
+ case D:
+ if (MatchState(input, 'e', DE)) return;
+ if (MatchKeyword(input, 'o', KEYWORD_MATCHED, Token::DO)) return;
+ break;
+ case DE:
+ if (MatchKeywordStart(input, "debugger", 2, Token::DEBUGGER)) return;
+ if (MatchKeywordStart(input, "default", 2, Token::DEFAULT)) return;
+ if (MatchKeywordStart(input, "delete", 2, Token::DELETE)) return;
+ break;
+ case F:
+ if (MatchKeywordStart(input, "false", 1, Token::FALSE_LITERAL)) return;
+ if (MatchKeywordStart(input, "finally", 1, Token::FINALLY)) return;
+ if (MatchKeywordStart(input, "for", 1, Token::FOR)) return;
+ if (MatchKeywordStart(input, "function", 1, Token::FUNCTION)) return;
+ break;
+ case I:
+ if (MatchKeyword(input, 'f', KEYWORD_MATCHED, Token::IF)) return;
+ if (MatchKeyword(input, 'n', IN, Token::IN)) return;
+ break;
+ case IN:
+ token_ = Token::IDENTIFIER;
+ if (MatchKeywordStart(input, "instanceof", 2, Token::INSTANCEOF)) {
+ return;
+ }
+ break;
+ case N:
+ if (MatchKeywordStart(input, "native", 1, Token::NATIVE)) return;
+ if (MatchKeywordStart(input, "new", 1, Token::NEW)) return;
+ if (MatchKeywordStart(input, "null", 1, Token::NULL_LITERAL)) return;
+ break;
+ case T:
+ if (MatchState(input, 'h', TH)) return;
+ if (MatchState(input, 'r', TR)) return;
+ if (MatchKeywordStart(input, "typeof", 1, Token::TYPEOF)) return;
+ break;
+ case TH:
+ if (MatchKeywordStart(input, "this", 2, Token::THIS)) return;
+ if (MatchKeywordStart(input, "throw", 2, Token::THROW)) return;
+ break;
+ case TR:
+ if (MatchKeywordStart(input, "true", 2, Token::TRUE_LITERAL)) return;
+ if (MatchKeyword(input, 'y', KEYWORD_MATCHED, Token::TRY)) return;
+ break;
+ case V:
+ if (MatchKeywordStart(input, "var", 1, Token::VAR)) return;
+ if (MatchKeywordStart(input, "void", 1, Token::VOID)) return;
+ break;
+ case W:
+ if (MatchKeywordStart(input, "while", 1, Token::WHILE)) return;
+ if (MatchKeywordStart(input, "with", 1, Token::WITH)) return;
+ break;
+ case UNMATCHABLE:
+ break;
+ }
+ // On fallthrough, it's a failure.
+ state_ = UNMATCHABLE;
+}
+
+} } // namespace v8::internal
diff --git a/src/scanner-base.h b/src/scanner-base.h
new file mode 100644
index 0000000..500870b
--- /dev/null
+++ b/src/scanner-base.h
@@ -0,0 +1,165 @@
+// 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.
+
+// Features shared by parsing and pre-parsing scanners.
+
+#ifndef V8_SCANNER_BASE_H_
+#define V8_SCANNER_BASE_H_
+
+#include "token.h"
+#include "unicode.h"
+
+namespace v8 {
+namespace internal {
+
+class KeywordMatcher {
+// Incrementally recognize keywords.
+//
+// Recognized keywords:
+// break case catch const* continue debugger* default delete do else
+// finally false for function if in instanceof native* new null
+// return switch this throw true try typeof var void while with
+//
+// *: Actually "future reserved keywords". These are the only ones we
+// recognized, the remaining are allowed as identifiers.
+ public:
+ KeywordMatcher()
+ : state_(INITIAL),
+ token_(Token::IDENTIFIER),
+ keyword_(NULL),
+ counter_(0),
+ keyword_token_(Token::ILLEGAL) {}
+
+ Token::Value token() { return token_; }
+
+ inline void AddChar(unibrow::uchar input) {
+ if (state_ != UNMATCHABLE) {
+ Step(input);
+ }
+ }
+
+ void Fail() {
+ token_ = Token::IDENTIFIER;
+ state_ = UNMATCHABLE;
+ }
+
+ private:
+ enum State {
+ UNMATCHABLE,
+ INITIAL,
+ KEYWORD_PREFIX,
+ KEYWORD_MATCHED,
+ C,
+ CA,
+ CO,
+ CON,
+ D,
+ DE,
+ F,
+ I,
+ IN,
+ N,
+ T,
+ TH,
+ TR,
+ V,
+ W
+ };
+
+ struct FirstState {
+ const char* keyword;
+ State state;
+ Token::Value token;
+ };
+
+ // Range of possible first characters of a keyword.
+ static const unsigned int kFirstCharRangeMin = 'b';
+ static const unsigned int kFirstCharRangeMax = 'w';
+ static const unsigned int kFirstCharRangeLength =
+ kFirstCharRangeMax - kFirstCharRangeMin + 1;
+ // State map for first keyword character range.
+ static FirstState first_states_[kFirstCharRangeLength];
+
+ // If input equals keyword's character at position, continue matching keyword
+ // from that position.
+ inline bool MatchKeywordStart(unibrow::uchar input,
+ const char* keyword,
+ int position,
+ Token::Value token_if_match) {
+ if (input == static_cast<unibrow::uchar>(keyword[position])) {
+ state_ = KEYWORD_PREFIX;
+ this->keyword_ = keyword;
+ this->counter_ = position + 1;
+ this->keyword_token_ = token_if_match;
+ return true;
+ }
+ return false;
+ }
+
+ // If input equals match character, transition to new state and return true.
+ inline bool MatchState(unibrow::uchar input, char match, State new_state) {
+ if (input == static_cast<unibrow::uchar>(match)) {
+ state_ = new_state;
+ return true;
+ }
+ return false;
+ }
+
+ inline bool MatchKeyword(unibrow::uchar input,
+ char match,
+ State new_state,
+ Token::Value keyword_token) {
+ if (input != static_cast<unibrow::uchar>(match)) {
+ return false;
+ }
+ state_ = new_state;
+ token_ = keyword_token;
+ return true;
+ }
+
+ void Step(unibrow::uchar input);
+
+ // Current state.
+ State state_;
+ // Token for currently added characters.
+ Token::Value token_;
+
+ // Matching a specific keyword string (there is only one possible valid
+ // keyword with the current prefix).
+ const char* keyword_;
+ int counter_;
+ Token::Value keyword_token_;
+};
+
+
+
+
+
+
+} } // namespace v8::internal
+
+#endif // V8_SCANNER_BASE_H_
diff --git a/src/scanner.cc b/src/scanner.cc
index 79d63f1..a24952a 100755
--- a/src/scanner.cc
+++ b/src/scanner.cc
@@ -184,142 +184,6 @@
pos_ = pos;
}
-
-// ----------------------------------------------------------------------------
-// Keyword Matcher
-
-KeywordMatcher::FirstState KeywordMatcher::first_states_[] = {
- { "break", KEYWORD_PREFIX, Token::BREAK },
- { NULL, C, Token::ILLEGAL },
- { NULL, D, Token::ILLEGAL },
- { "else", KEYWORD_PREFIX, Token::ELSE },
- { NULL, F, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, I, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, N, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { "return", KEYWORD_PREFIX, Token::RETURN },
- { "switch", KEYWORD_PREFIX, Token::SWITCH },
- { NULL, T, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, V, Token::ILLEGAL },
- { NULL, W, Token::ILLEGAL }
-};
-
-
-void KeywordMatcher::Step(uc32 input) {
- switch (state_) {
- case INITIAL: {
- // matching the first character is the only state with significant fanout.
- // Match only lower-case letters in range 'b'..'w'.
- unsigned int offset = input - kFirstCharRangeMin;
- if (offset < kFirstCharRangeLength) {
- state_ = first_states_[offset].state;
- if (state_ == KEYWORD_PREFIX) {
- keyword_ = first_states_[offset].keyword;
- counter_ = 1;
- keyword_token_ = first_states_[offset].token;
- }
- return;
- }
- break;
- }
- case KEYWORD_PREFIX:
- if (keyword_[counter_] == input) {
- ASSERT_NE(input, '\0');
- counter_++;
- if (keyword_[counter_] == '\0') {
- state_ = KEYWORD_MATCHED;
- token_ = keyword_token_;
- }
- return;
- }
- break;
- case KEYWORD_MATCHED:
- token_ = Token::IDENTIFIER;
- break;
- case C:
- if (MatchState(input, 'a', CA)) return;
- if (MatchState(input, 'o', CO)) return;
- break;
- case CA:
- if (MatchKeywordStart(input, "case", 2, Token::CASE)) return;
- if (MatchKeywordStart(input, "catch", 2, Token::CATCH)) return;
- break;
- case CO:
- if (MatchState(input, 'n', CON)) return;
- break;
- case CON:
- if (MatchKeywordStart(input, "const", 3, Token::CONST)) return;
- if (MatchKeywordStart(input, "continue", 3, Token::CONTINUE)) return;
- break;
- case D:
- if (MatchState(input, 'e', DE)) return;
- if (MatchKeyword(input, 'o', KEYWORD_MATCHED, Token::DO)) return;
- break;
- case DE:
- if (MatchKeywordStart(input, "debugger", 2, Token::DEBUGGER)) return;
- if (MatchKeywordStart(input, "default", 2, Token::DEFAULT)) return;
- if (MatchKeywordStart(input, "delete", 2, Token::DELETE)) return;
- break;
- case F:
- if (MatchKeywordStart(input, "false", 1, Token::FALSE_LITERAL)) return;
- if (MatchKeywordStart(input, "finally", 1, Token::FINALLY)) return;
- if (MatchKeywordStart(input, "for", 1, Token::FOR)) return;
- if (MatchKeywordStart(input, "function", 1, Token::FUNCTION)) return;
- break;
- case I:
- if (MatchKeyword(input, 'f', KEYWORD_MATCHED, Token::IF)) return;
- if (MatchKeyword(input, 'n', IN, Token::IN)) return;
- break;
- case IN:
- token_ = Token::IDENTIFIER;
- if (MatchKeywordStart(input, "instanceof", 2, Token::INSTANCEOF)) {
- return;
- }
- break;
- case N:
- if (MatchKeywordStart(input, "native", 1, Token::NATIVE)) return;
- if (MatchKeywordStart(input, "new", 1, Token::NEW)) return;
- if (MatchKeywordStart(input, "null", 1, Token::NULL_LITERAL)) return;
- break;
- case T:
- if (MatchState(input, 'h', TH)) return;
- if (MatchState(input, 'r', TR)) return;
- if (MatchKeywordStart(input, "typeof", 1, Token::TYPEOF)) return;
- break;
- case TH:
- if (MatchKeywordStart(input, "this", 2, Token::THIS)) return;
- if (MatchKeywordStart(input, "throw", 2, Token::THROW)) return;
- break;
- case TR:
- if (MatchKeywordStart(input, "true", 2, Token::TRUE_LITERAL)) return;
- if (MatchKeyword(input, 'y', KEYWORD_MATCHED, Token::TRY)) return;
- break;
- case V:
- if (MatchKeywordStart(input, "var", 1, Token::VAR)) return;
- if (MatchKeywordStart(input, "void", 1, Token::VOID)) return;
- break;
- case W:
- if (MatchKeywordStart(input, "while", 1, Token::WHILE)) return;
- if (MatchKeywordStart(input, "with", 1, Token::WITH)) return;
- break;
- default:
- UNREACHABLE();
- }
- // On fallthrough, it's a failure.
- state_ = UNMATCHABLE;
-}
-
-
-
// ----------------------------------------------------------------------------
// Scanner::LiteralScope
diff --git a/src/scanner.h b/src/scanner.h
index 8c575df..1f49fd0 100644
--- a/src/scanner.h
+++ b/src/scanner.h
@@ -30,6 +30,7 @@
#include "token.h"
#include "char-predicates-inl.h"
+#include "scanner-base.h"
namespace v8 {
namespace internal {
@@ -142,126 +143,6 @@
};
-class KeywordMatcher {
-// Incrementally recognize keywords.
-//
-// Recognized keywords:
-// break case catch const* continue debugger* default delete do else
-// finally false for function if in instanceof native* new null
-// return switch this throw true try typeof var void while with
-//
-// *: Actually "future reserved keywords". These are the only ones we
-// recognized, the remaining are allowed as identifiers.
- public:
- KeywordMatcher()
- : state_(INITIAL),
- token_(Token::IDENTIFIER),
- keyword_(NULL),
- counter_(0),
- keyword_token_(Token::ILLEGAL) {}
-
- Token::Value token() { return token_; }
-
- inline void AddChar(uc32 input) {
- if (state_ != UNMATCHABLE) {
- Step(input);
- }
- }
-
- void Fail() {
- token_ = Token::IDENTIFIER;
- state_ = UNMATCHABLE;
- }
-
- private:
- enum State {
- UNMATCHABLE,
- INITIAL,
- KEYWORD_PREFIX,
- KEYWORD_MATCHED,
- C,
- CA,
- CO,
- CON,
- D,
- DE,
- F,
- I,
- IN,
- N,
- T,
- TH,
- TR,
- V,
- W
- };
-
- struct FirstState {
- const char* keyword;
- State state;
- Token::Value token;
- };
-
- // Range of possible first characters of a keyword.
- static const unsigned int kFirstCharRangeMin = 'b';
- static const unsigned int kFirstCharRangeMax = 'w';
- static const unsigned int kFirstCharRangeLength =
- kFirstCharRangeMax - kFirstCharRangeMin + 1;
- // State map for first keyword character range.
- static FirstState first_states_[kFirstCharRangeLength];
-
- // If input equals keyword's character at position, continue matching keyword
- // from that position.
- inline bool MatchKeywordStart(uc32 input,
- const char* keyword,
- int position,
- Token::Value token_if_match) {
- if (input == keyword[position]) {
- state_ = KEYWORD_PREFIX;
- this->keyword_ = keyword;
- this->counter_ = position + 1;
- this->keyword_token_ = token_if_match;
- return true;
- }
- return false;
- }
-
- // If input equals match character, transition to new state and return true.
- inline bool MatchState(uc32 input, char match, State new_state) {
- if (input == match) {
- state_ = new_state;
- return true;
- }
- return false;
- }
-
- inline bool MatchKeyword(uc32 input,
- char match,
- State new_state,
- Token::Value keyword_token) {
- if (input != match) {
- return false;
- }
- state_ = new_state;
- token_ = keyword_token;
- return true;
- }
-
- void Step(uc32 input);
-
- // Current state.
- State state_;
- // Token for currently added characters.
- Token::Value token_;
-
- // Matching a specific keyword string (there is only one possible valid
- // keyword with the current prefix).
- const char* keyword_;
- int counter_;
- Token::Value keyword_token_;
-};
-
-
enum ParserLanguage { JAVASCRIPT, JSON };
diff --git a/src/string.js b/src/string.js
index a75ccf0..d82ce05 100644
--- a/src/string.js
+++ b/src/string.js
@@ -162,9 +162,6 @@
var subject = TO_STRING_INLINE(this);
if (IS_REGEXP(regexp)) {
if (!regexp.global) return regexp.exec(subject);
-
- var saveAnswer = false;
-
%_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
// lastMatchInfo is defined in regexp.js.
return %StringMatch(subject, regexp, lastMatchInfo);
@@ -562,12 +559,10 @@
return result;
}
- var saveAnswer = false;
-
%_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
if (length === 0) {
- if (splitMatch(separator, subject, 0, 0) != null) {
+ if (DoRegExpExec(separator, subject, 0, 0) != null) {
return [];
}
return [subject];
diff --git a/src/token.h b/src/token.h
index ebc7fea..74d9539 100644
--- a/src/token.h
+++ b/src/token.h
@@ -28,6 +28,8 @@
#ifndef V8_TOKEN_H_
#define V8_TOKEN_H_
+#include "checks.h"
+
namespace v8 {
namespace internal {
diff --git a/src/utils.cc b/src/utils.cc
index 45a4cd6..7096ba3 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -37,34 +37,6 @@
namespace internal {
-// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
-// figure 3-3, page 48, where the function is called clp2.
-uint32_t RoundUpToPowerOf2(uint32_t x) {
- ASSERT(x <= 0x80000000u);
- x = x - 1;
- x = x | (x >> 1);
- x = x | (x >> 2);
- x = x | (x >> 4);
- x = x | (x >> 8);
- x = x | (x >> 16);
- return x + 1;
-}
-
-
-// Thomas Wang, Integer Hash Functions.
-// http://www.concentric.net/~Ttwang/tech/inthash.htm
-uint32_t ComputeIntegerHash(uint32_t key) {
- uint32_t hash = key;
- hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1;
- hash = hash ^ (hash >> 12);
- hash = hash + (hash << 2);
- hash = hash ^ (hash >> 4);
- hash = hash * 2057; // hash = (hash + (hash << 3)) + (hash << 11);
- hash = hash ^ (hash >> 16);
- return hash;
-}
-
-
void PrintF(const char* format, ...) {
va_list arguments;
va_start(arguments, format);
@@ -274,12 +246,4 @@
}
-int TenToThe(int exponent) {
- ASSERT(exponent <= 9);
- ASSERT(exponent >= 1);
- int answer = 10;
- for (int i = 1; i < exponent; i++) answer *= 10;
- return answer;
-}
-
} } // namespace v8::internal
diff --git a/src/utils.h b/src/utils.h
index ffdb639..069be4f 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -31,6 +31,8 @@
#include <stdlib.h>
#include <string.h>
+#include "checks.h"
+
namespace v8 {
namespace internal {
@@ -142,7 +144,19 @@
// Returns the smallest power of two which is >= x. If you pass in a
// number that is already a power of two, it is returned as is.
-uint32_t RoundUpToPowerOf2(uint32_t x);
+// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.,
+// figure 3-3, page 48, where the function is called clp2.
+static inline uint32_t RoundUpToPowerOf2(uint32_t x) {
+ ASSERT(x <= 0x80000000u);
+ x = x - 1;
+ x = x | (x >> 1);
+ x = x | (x >> 2);
+ x = x | (x >> 4);
+ x = x | (x >> 8);
+ x = x | (x >> 16);
+ return x + 1;
+}
+
template <typename T>
@@ -216,65 +230,18 @@
// ----------------------------------------------------------------------------
// Hash function.
-uint32_t ComputeIntegerHash(uint32_t key);
-
-
-// ----------------------------------------------------------------------------
-// I/O support.
-
-#if __GNUC__ >= 4
-// On gcc we can ask the compiler to check the types of %d-style format
-// specifiers and their associated arguments. TODO(erikcorry) fix this
-// so it works on MacOSX.
-#if defined(__MACH__) && defined(__APPLE__)
-#define PRINTF_CHECKING
-#else // MacOsX.
-#define PRINTF_CHECKING __attribute__ ((format (printf, 1, 2)))
-#endif
-#else
-#define PRINTF_CHECKING
-#endif
-
-// Our version of printf().
-void PRINTF_CHECKING PrintF(const char* format, ...);
-
-// Our version of fflush.
-void Flush();
-
-
-// Read a line of characters after printing the prompt to stdout. The resulting
-// char* needs to be disposed off with DeleteArray by the caller.
-char* ReadLine(const char* prompt);
-
-
-// Read and return the raw bytes in a file. the size of the buffer is returned
-// in size.
-// The returned buffer must be freed by the caller.
-byte* ReadBytes(const char* filename, int* size, bool verbose = true);
-
-
-// Write size chars from str to the file given by filename.
-// The file is overwritten. Returns the number of chars written.
-int WriteChars(const char* filename,
- const char* str,
- int size,
- bool verbose = true);
-
-
-// Write size bytes to the file given by filename.
-// The file is overwritten. Returns the number of bytes written.
-int WriteBytes(const char* filename,
- const byte* bytes,
- int size,
- bool verbose = true);
-
-
-// Write the C code
-// const char* <varname> = "<str>";
-// const int <varname>_len = <len>;
-// to the file given by filename. Only the first len chars are written.
-int WriteAsCFile(const char* filename, const char* varname,
- const char* str, int size, bool verbose = true);
+// Thomas Wang, Integer Hash Functions.
+// http://www.concentric.net/~Ttwang/tech/inthash.htm
+static inline uint32_t ComputeIntegerHash(uint32_t key) {
+ uint32_t hash = key;
+ hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1;
+ hash = hash ^ (hash >> 12);
+ hash = hash + (hash << 2);
+ hash = hash ^ (hash >> 4);
+ hash = hash * 2057; // hash = (hash + (hash << 3)) + (hash << 11);
+ hash = hash ^ (hash >> 16);
+ return hash;
+}
// ----------------------------------------------------------------------------
@@ -416,23 +383,6 @@
};
-// A temporary assignment sets a (non-local) variable to a value on
-// construction and resets it the value on destruction.
-template <typename T>
-class TempAssign {
- public:
- TempAssign(T* var, T value): var_(var), old_value_(*var) {
- *var = value;
- }
-
- ~TempAssign() { *var_ = old_value_; }
-
- private:
- T* var_;
- T old_value_;
-};
-
-
template <typename T, int kSize>
class EmbeddedVector : public Vector<T> {
public:
@@ -484,13 +434,6 @@
return Vector<char>(data, (length < max) ? length : max);
}
-template <typename T>
-inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms,
- int length) {
- return Vector< Handle<Object> >(
- reinterpret_cast<v8::internal::Handle<Object>*>(elms), length);
-}
-
/*
* A class that collects values into a backing store.
@@ -699,156 +642,6 @@
};
-// Simple support to read a file into a 0-terminated C-string.
-// The returned buffer must be freed by the caller.
-// On return, *exits tells whether the file existed.
-Vector<const char> ReadFile(const char* filename,
- bool* exists,
- bool verbose = true);
-
-
-// Simple wrapper that allows an ExternalString to refer to a
-// Vector<const char>. Doesn't assume ownership of the data.
-class AsciiStringAdapter: public v8::String::ExternalAsciiStringResource {
- public:
- explicit AsciiStringAdapter(Vector<const char> data) : data_(data) {}
-
- virtual const char* data() const { return data_.start(); }
-
- virtual size_t length() const { return data_.length(); }
-
- private:
- Vector<const char> data_;
-};
-
-
-// Helper class for building result strings in a character buffer. The
-// purpose of the class is to use safe operations that checks the
-// buffer bounds on all operations in debug mode.
-class StringBuilder {
- public:
- // Create a string builder with a buffer of the given size. The
- // buffer is allocated through NewArray<char> and must be
- // deallocated by the caller of Finalize().
- explicit StringBuilder(int size);
-
- StringBuilder(char* buffer, int size)
- : buffer_(buffer, size), position_(0) { }
-
- ~StringBuilder() { if (!is_finalized()) Finalize(); }
-
- int size() const { return buffer_.length(); }
-
- // Get the current position in the builder.
- int position() const {
- ASSERT(!is_finalized());
- return position_;
- }
-
- // Reset the position.
- void Reset() { position_ = 0; }
-
- // Add a single character to the builder. It is not allowed to add
- // 0-characters; use the Finalize() method to terminate the string
- // instead.
- void AddCharacter(char c) {
- ASSERT(c != '\0');
- ASSERT(!is_finalized() && position_ < buffer_.length());
- buffer_[position_++] = c;
- }
-
- // Add an entire string to the builder. Uses strlen() internally to
- // compute the length of the input string.
- void AddString(const char* s);
-
- // Add the first 'n' characters of the given string 's' to the
- // builder. The input string must have enough characters.
- void AddSubstring(const char* s, int n);
-
- // Add formatted contents to the builder just like printf().
- void AddFormatted(const char* format, ...);
-
- // Add character padding to the builder. If count is non-positive,
- // nothing is added to the builder.
- void AddPadding(char c, int count);
-
- // Finalize the string by 0-terminating it and returning the buffer.
- char* Finalize();
-
- private:
- Vector<char> buffer_;
- int position_;
-
- bool is_finalized() const { return position_ < 0; }
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
-};
-
-
-// Custom memcpy implementation for platforms where the standard version
-// may not be good enough.
-// TODO(lrn): Check whether some IA32 platforms should be excluded.
-#if defined(V8_TARGET_ARCH_IA32)
-
-// TODO(lrn): Extend to other platforms as needed.
-
-typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size);
-
-// Implemented in codegen-<arch>.cc.
-MemCopyFunction CreateMemCopyFunction();
-
-// Copy memory area to disjoint memory area.
-static inline void MemCopy(void* dest, const void* src, size_t size) {
- static MemCopyFunction memcopy = CreateMemCopyFunction();
- (*memcopy)(dest, src, size);
-#ifdef DEBUG
- CHECK_EQ(0, memcmp(dest, src, size));
-#endif
-}
-
-
-// Limit below which the extra overhead of the MemCopy function is likely
-// to outweigh the benefits of faster copying.
-// TODO(lrn): Try to find a more precise value.
-static const int kMinComplexMemCopy = 64;
-
-#else // V8_TARGET_ARCH_IA32
-
-static inline void MemCopy(void* dest, const void* src, size_t size) {
- memcpy(dest, src, size);
-}
-
-static const int kMinComplexMemCopy = 256;
-
-#endif // V8_TARGET_ARCH_IA32
-
-
-// Copy from ASCII/16bit chars to ASCII/16bit chars.
-template <typename sourcechar, typename sinkchar>
-static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
- sinkchar* limit = dest + chars;
-#ifdef V8_HOST_CAN_READ_UNALIGNED
- if (sizeof(*dest) == sizeof(*src)) {
- if (chars >= static_cast<int>(kMinComplexMemCopy / sizeof(*dest))) {
- MemCopy(dest, src, chars * sizeof(*dest));
- return;
- }
- // Number of characters in a uintptr_t.
- static const int kStepSize = sizeof(uintptr_t) / sizeof(*dest); // NOLINT
- while (dest <= limit - kStepSize) {
- *reinterpret_cast<uintptr_t*>(dest) =
- *reinterpret_cast<const uintptr_t*>(src);
- dest += kStepSize;
- src += kStepSize;
- }
- }
-#endif
- while (dest < limit) {
- *dest++ = static_cast<sinkchar>(*src++);
- }
-}
-
-
// Compare ASCII/16bit chars to ASCII/16bit chars.
template <typename lchar, typename rchar>
static inline int CompareChars(const lchar* lhs, const rchar* rhs, int chars) {
@@ -877,54 +670,14 @@
}
-template <typename T>
-static inline void MemsetPointer(T** dest, T* value, int counter) {
-#if defined(V8_HOST_ARCH_IA32)
-#define STOS "stosl"
-#elif defined(V8_HOST_ARCH_X64)
-#define STOS "stosq"
-#endif
-
-#if defined(__GNUC__) && defined(STOS)
- asm volatile(
- "cld;"
- "rep ; " STOS
- : "+&c" (counter), "+&D" (dest)
- : "a" (value)
- : "memory", "cc");
-#else
- for (int i = 0; i < counter; i++) {
- dest[i] = value;
- }
-#endif
-
-#undef STOS
-}
-
-
-// Copies data from |src| to |dst|. The data spans MUST not overlap.
-inline void CopyWords(Object** dst, Object** src, int num_words) {
- ASSERT(Min(dst, src) + num_words <= Max(dst, src));
- ASSERT(num_words > 0);
-
- // Use block copying memcpy if the segment we're copying is
- // enough to justify the extra call/setup overhead.
- static const int kBlockCopyLimit = 16;
-
- if (num_words >= kBlockCopyLimit) {
- memcpy(dst, src, num_words * kPointerSize);
- } else {
- int remaining = num_words;
- do {
- remaining--;
- *dst++ = *src++;
- } while (remaining > 0);
- }
-}
-
-
// Calculate 10^exponent.
-int TenToThe(int exponent);
+static inline int TenToThe(int exponent) {
+ ASSERT(exponent <= 9);
+ ASSERT(exponent >= 1);
+ int answer = 10;
+ for (int i = 1; i < exponent; i++) answer *= 10;
+ return answer;
+}
// The type-based aliasing rule allows the compiler to assume that pointers of
diff --git a/src/v8.h b/src/v8.h
index 9dbdf4c..1cb8d2f 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -56,7 +56,7 @@
#include "globals.h"
#include "checks.h"
#include "allocation.h"
-#include "utils.h"
+#include "v8utils.h"
#include "flags.h"
// Objects & heap
diff --git a/src/v8utils.h b/src/v8utils.h
new file mode 100644
index 0000000..a907c9f
--- /dev/null
+++ b/src/v8utils.h
@@ -0,0 +1,301 @@
+// 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_V8UTILS_H_
+#define V8_V8UTILS_H_
+
+#include "utils.h"
+
+namespace v8 {
+namespace internal {
+
+// ----------------------------------------------------------------------------
+// I/O support.
+
+#if __GNUC__ >= 4
+// On gcc we can ask the compiler to check the types of %d-style format
+// specifiers and their associated arguments. TODO(erikcorry) fix this
+// so it works on MacOSX.
+#if defined(__MACH__) && defined(__APPLE__)
+#define PRINTF_CHECKING
+#else // MacOsX.
+#define PRINTF_CHECKING __attribute__ ((format (printf, 1, 2)))
+#endif
+#else
+#define PRINTF_CHECKING
+#endif
+
+// Our version of printf().
+void PRINTF_CHECKING PrintF(const char* format, ...);
+
+// Our version of fflush.
+void Flush();
+
+
+// Read a line of characters after printing the prompt to stdout. The resulting
+// char* needs to be disposed off with DeleteArray by the caller.
+char* ReadLine(const char* prompt);
+
+
+// Read and return the raw bytes in a file. the size of the buffer is returned
+// in size.
+// The returned buffer must be freed by the caller.
+byte* ReadBytes(const char* filename, int* size, bool verbose = true);
+
+
+// Write size chars from str to the file given by filename.
+// The file is overwritten. Returns the number of chars written.
+int WriteChars(const char* filename,
+ const char* str,
+ int size,
+ bool verbose = true);
+
+
+// Write size bytes to the file given by filename.
+// The file is overwritten. Returns the number of bytes written.
+int WriteBytes(const char* filename,
+ const byte* bytes,
+ int size,
+ bool verbose = true);
+
+
+// Write the C code
+// const char* <varname> = "<str>";
+// const int <varname>_len = <len>;
+// to the file given by filename. Only the first len chars are written.
+int WriteAsCFile(const char* filename, const char* varname,
+ const char* str, int size, bool verbose = true);
+
+
+// Data structures
+
+template <typename T>
+inline Vector< Handle<Object> > HandleVector(v8::internal::Handle<T>* elms,
+ int length) {
+ return Vector< Handle<Object> >(
+ reinterpret_cast<v8::internal::Handle<Object>*>(elms), length);
+}
+
+// Memory
+
+// Copies data from |src| to |dst|. The data spans MUST not overlap.
+inline void CopyWords(Object** dst, Object** src, int num_words) {
+ ASSERT(Min(dst, src) + num_words <= Max(dst, src));
+ ASSERT(num_words > 0);
+
+ // Use block copying memcpy if the segment we're copying is
+ // enough to justify the extra call/setup overhead.
+ static const int kBlockCopyLimit = 16;
+
+ if (num_words >= kBlockCopyLimit) {
+ memcpy(dst, src, num_words * kPointerSize);
+ } else {
+ int remaining = num_words;
+ do {
+ remaining--;
+ *dst++ = *src++;
+ } while (remaining > 0);
+ }
+}
+
+
+template <typename T>
+static inline void MemsetPointer(T** dest, T* value, int counter) {
+#if defined(V8_HOST_ARCH_IA32)
+#define STOS "stosl"
+#elif defined(V8_HOST_ARCH_X64)
+#define STOS "stosq"
+#endif
+
+#if defined(__GNUC__) && defined(STOS)
+ asm volatile(
+ "cld;"
+ "rep ; " STOS
+ : "+&c" (counter), "+&D" (dest)
+ : "a" (value)
+ : "memory", "cc");
+#else
+ for (int i = 0; i < counter; i++) {
+ dest[i] = value;
+ }
+#endif
+
+#undef STOS
+}
+
+
+// Simple wrapper that allows an ExternalString to refer to a
+// Vector<const char>. Doesn't assume ownership of the data.
+class AsciiStringAdapter: public v8::String::ExternalAsciiStringResource {
+ public:
+ explicit AsciiStringAdapter(Vector<const char> data) : data_(data) {}
+
+ virtual const char* data() const { return data_.start(); }
+
+ virtual size_t length() const { return data_.length(); }
+
+ private:
+ Vector<const char> data_;
+};
+
+
+// Simple support to read a file into a 0-terminated C-string.
+// The returned buffer must be freed by the caller.
+// On return, *exits tells whether the file existed.
+Vector<const char> ReadFile(const char* filename,
+ bool* exists,
+ bool verbose = true);
+
+
+// Helper class for building result strings in a character buffer. The
+// purpose of the class is to use safe operations that checks the
+// buffer bounds on all operations in debug mode.
+class StringBuilder {
+ public:
+ // Create a string builder with a buffer of the given size. The
+ // buffer is allocated through NewArray<char> and must be
+ // deallocated by the caller of Finalize().
+ explicit StringBuilder(int size);
+
+ StringBuilder(char* buffer, int size)
+ : buffer_(buffer, size), position_(0) { }
+
+ ~StringBuilder() { if (!is_finalized()) Finalize(); }
+
+ int size() const { return buffer_.length(); }
+
+ // Get the current position in the builder.
+ int position() const {
+ ASSERT(!is_finalized());
+ return position_;
+ }
+
+ // Reset the position.
+ void Reset() { position_ = 0; }
+
+ // Add a single character to the builder. It is not allowed to add
+ // 0-characters; use the Finalize() method to terminate the string
+ // instead.
+ void AddCharacter(char c) {
+ ASSERT(c != '\0');
+ ASSERT(!is_finalized() && position_ < buffer_.length());
+ buffer_[position_++] = c;
+ }
+
+ // Add an entire string to the builder. Uses strlen() internally to
+ // compute the length of the input string.
+ void AddString(const char* s);
+
+ // Add the first 'n' characters of the given string 's' to the
+ // builder. The input string must have enough characters.
+ void AddSubstring(const char* s, int n);
+
+ // Add formatted contents to the builder just like printf().
+ void AddFormatted(const char* format, ...);
+
+ // Add character padding to the builder. If count is non-positive,
+ // nothing is added to the builder.
+ void AddPadding(char c, int count);
+
+ // Finalize the string by 0-terminating it and returning the buffer.
+ char* Finalize();
+
+ private:
+ Vector<char> buffer_;
+ int position_;
+
+ bool is_finalized() const { return position_ < 0; }
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
+};
+
+
+// Custom memcpy implementation for platforms where the standard version
+// may not be good enough.
+#if defined(V8_TARGET_ARCH_IA32)
+
+// The default memcpy on ia32 architectures is generally not as efficient
+// as possible. (If any further ia32 platforms are introduced where the
+// memcpy function is efficient, exclude them from this branch).
+
+typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size);
+
+// Implemented in codegen-<arch>.cc.
+MemCopyFunction CreateMemCopyFunction();
+
+// Copy memory area to disjoint memory area.
+static inline void MemCopy(void* dest, const void* src, size_t size) {
+ static MemCopyFunction memcopy = CreateMemCopyFunction();
+ (*memcopy)(dest, src, size);
+#ifdef DEBUG
+ CHECK_EQ(0, memcmp(dest, src, size));
+#endif
+}
+
+// Limit below which the extra overhead of the MemCopy function is likely
+// to outweigh the benefits of faster copying.
+static const int kMinComplexMemCopy = 64;
+
+#else // V8_TARGET_ARCH_IA32
+
+static inline void MemCopy(void* dest, const void* src, size_t size) {
+ memcpy(dest, src, size);
+}
+
+static const int kMinComplexMemCopy = 256;
+
+#endif // V8_TARGET_ARCH_IA32
+
+
+// Copy from ASCII/16bit chars to ASCII/16bit chars.
+template <typename sourcechar, typename sinkchar>
+static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
+ sinkchar* limit = dest + chars;
+#ifdef V8_HOST_CAN_READ_UNALIGNED
+ if (sizeof(*dest) == sizeof(*src)) {
+ if (chars >= static_cast<int>(kMinComplexMemCopy / sizeof(*dest))) {
+ MemCopy(dest, src, chars * sizeof(*dest));
+ return;
+ }
+ // Number of characters in a uintptr_t.
+ static const int kStepSize = sizeof(uintptr_t) / sizeof(*dest); // NOLINT
+ while (dest <= limit - kStepSize) {
+ *reinterpret_cast<uintptr_t*>(dest) =
+ *reinterpret_cast<const uintptr_t*>(src);
+ dest += kStepSize;
+ src += kStepSize;
+ }
+ }
+#endif
+ while (dest < limit) {
+ *dest++ = static_cast<sinkchar>(*src++);
+ }
+}
+
+} } // namespace v8::internal
+
+#endif // V8_V8UTILS_H_
diff --git a/src/version.cc b/src/version.cc
index 8432750..5ef2a65 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 2
#define MINOR_VERSION 5
-#define BUILD_NUMBER 4
+#define BUILD_NUMBER 5
#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc
index bf5ee5b..caed7c8 100644
--- a/src/x64/assembler-x64.cc
+++ b/src/x64/assembler-x64.cc
@@ -296,7 +296,7 @@
byte* Assembler::spare_buffer_ = NULL;
Assembler::Assembler(void* buffer, int buffer_size)
- : code_targets_(100) {
+ : code_targets_(100), positions_recorder_(this) {
if (buffer == NULL) {
// Do our own buffer management.
if (buffer_size <= kMinimalBufferSize) {
@@ -337,10 +337,7 @@
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
last_pc_ = NULL;
- current_statement_position_ = RelocInfo::kNoPosition;
- current_position_ = RelocInfo::kNoPosition;
- written_statement_position_ = current_statement_position_;
- written_position_ = current_position_;
+
#ifdef GENERATED_CODE_COVERAGE
InitCoverageLog();
#endif
@@ -845,7 +842,7 @@
void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
last_pc_ = pc_;
// 1110 1000 #32-bit disp.
@@ -2935,14 +2932,14 @@
}
void Assembler::RecordJSReturn() {
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::JS_RETURN);
}
void Assembler::RecordDebugBreakSlot() {
- WriteRecordedPositions();
+ positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
}
@@ -2956,47 +2953,6 @@
}
-void Assembler::RecordPosition(int pos) {
- ASSERT(pos != RelocInfo::kNoPosition);
- ASSERT(pos >= 0);
- current_position_ = pos;
-}
-
-
-void Assembler::RecordStatementPosition(int pos) {
- ASSERT(pos != RelocInfo::kNoPosition);
- ASSERT(pos >= 0);
- current_statement_position_ = pos;
-}
-
-
-bool Assembler::WriteRecordedPositions() {
- bool written = false;
-
- // Write the statement position if it is different from what was written last
- // time.
- if (current_statement_position_ != written_statement_position_) {
- EnsureSpace ensure_space(this);
- RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
- written_statement_position_ = current_statement_position_;
- written = true;
- }
-
- // Write the position if it is different from what was written last time and
- // also different from the written statement position.
- if (current_position_ != written_position_ &&
- current_position_ != written_statement_position_) {
- EnsureSpace ensure_space(this);
- RecordRelocInfo(RelocInfo::POSITION, current_position_);
- written_position_ = current_position_;
- written = true;
- }
-
- // Return whether something was written.
- return written;
-}
-
-
const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
1 << RelocInfo::INTERNAL_REFERENCE;
diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h
index bbc1010..c7f7632 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -1174,13 +1174,9 @@
// Use --debug_code to enable.
void RecordComment(const char* msg);
- void RecordPosition(int pos);
- void RecordStatementPosition(int pos);
- bool WriteRecordedPositions();
-
int pc_offset() const { return static_cast<int>(pc_ - buffer_); }
- int current_statement_position() const { return current_statement_position_; }
- int current_position() const { return current_position_; }
+
+ PositionsRecorder* positions_recorder() { return &positions_recorder_; }
// Check if there is less than kGap bytes available in the buffer.
// If this is the case, we need to grow the buffer before emitting
@@ -1404,11 +1400,8 @@
// push-pop elimination
byte* last_pc_;
- // source position information
- int current_statement_position_;
- int current_position_;
- int written_statement_position_;
- int written_position_;
+ PositionsRecorder positions_recorder_;
+ friend class PositionsRecorder;
};
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index c1a23fc..e0e4095 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -2956,7 +2956,7 @@
CodeForStatementPosition(node);
Load(node->expression());
Result return_value = frame_->Pop();
- masm()->WriteRecordedPositions();
+ masm()->positions_recorder()->WriteRecordedPositions();
if (function_return_is_shadowed_) {
function_return_.Jump(&return_value);
} else {
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 4e0f6d4..00ea684 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -1717,12 +1717,14 @@
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- for (int i = 0; i < arg_count; i++) {
- VisitForStackValue(args->at(i));
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i));
+ }
+ __ Move(rcx, name);
}
- __ Move(rcx, name);
// Record source position for debugger.
- SetSourcePosition(expr->position());
+ SetSourcePosition(expr->position(), FORCED_POSITION);
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
@@ -1740,13 +1742,15 @@
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- for (int i = 0; i < arg_count; i++) {
- VisitForStackValue(args->at(i));
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i));
+ }
+ VisitForAccumulatorValue(key);
+ __ movq(rcx, rax);
}
- VisitForAccumulatorValue(key);
- __ movq(rcx, rax);
// Record source position for debugger.
- SetSourcePosition(expr->position());
+ SetSourcePosition(expr->position(), FORCED_POSITION);
// Call the IC initialization code.
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
@@ -1762,11 +1766,13 @@
// Code common for calls using the call stub.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- for (int i = 0; i < arg_count; i++) {
- VisitForStackValue(args->at(i));
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i));
+ }
}
// Record source position for debugger.
- SetSourcePosition(expr->position());
+ SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@@ -1787,37 +1793,38 @@
// resolve the function we need to call and the receiver of the
// call. The we call the resolved function using the given
// arguments.
- VisitForStackValue(fun);
- __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
-
- // Push the arguments.
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
- for (int i = 0; i < arg_count; i++) {
- VisitForStackValue(args->at(i));
- }
+ { PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
+ VisitForStackValue(fun);
+ __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
- // Push copy of the function - found below the arguments.
- __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
+ // Push the arguments.
+ for (int i = 0; i < arg_count; i++) {
+ VisitForStackValue(args->at(i));
+ }
- // Push copy of the first argument or undefined if it doesn't exist.
- if (arg_count > 0) {
- __ push(Operand(rsp, arg_count * kPointerSize));
- } else {
+ // Push copy of the function - found below the arguments.
+ __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
+
+ // Push copy of the first argument or undefined if it doesn't exist.
+ if (arg_count > 0) {
+ __ push(Operand(rsp, arg_count * kPointerSize));
+ } else {
__ PushRoot(Heap::kUndefinedValueRootIndex);
+ }
+
+ // Push the receiver of the enclosing function and do runtime call.
+ __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+
+ // The runtime call returns a pair of values in rax (function) and
+ // rdx (receiver). Touch up the stack with the right values.
+ __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
+ __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
}
-
- // Push the receiver of the enclosing function and do runtime call.
- __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
-
- // The runtime call returns a pair of values in rax (function) and
- // rdx (receiver). Touch up the stack with the right values.
- __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
- __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
-
// Record source position for debugger.
- SetSourcePosition(expr->position());
+ SetSourcePosition(expr->position(), FORCED_POSITION);
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
__ CallStub(&stub);
@@ -1834,35 +1841,37 @@
// Call to a lookup slot (dynamically introduced variable).
Label slow, done;
- // Generate code for loading from variables potentially shadowed
- // by eval-introduced variables.
- EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
- NOT_INSIDE_TYPEOF,
- &slow,
- &done);
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ // Generate code for loading from variables potentially shadowed
+ // by eval-introduced variables.
+ EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
+ NOT_INSIDE_TYPEOF,
+ &slow,
+ &done);
- __ bind(&slow);
- // Call the runtime to find the function to call (returned in rax)
- // and the object holding it (returned in rdx).
- __ push(context_register());
- __ Push(var->name());
- __ CallRuntime(Runtime::kLoadContextSlot, 2);
- __ push(rax); // Function.
- __ push(rdx); // Receiver.
+ __ bind(&slow);
+ // Call the runtime to find the function to call (returned in rax)
+ // and the object holding it (returned in rdx).
+ __ push(context_register());
+ __ Push(var->name());
+ __ CallRuntime(Runtime::kLoadContextSlot, 2);
+ __ push(rax); // Function.
+ __ push(rdx); // Receiver.
- // If fast case code has been generated, emit code to push the
- // function and receiver and have the slow path jump around this
- // code.
- if (done.is_linked()) {
- NearLabel call;
- __ jmp(&call);
- __ bind(&done);
- // Push function.
- __ push(rax);
- // Push global receiver.
- __ movq(rbx, CodeGenerator::GlobalObject());
- __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
- __ bind(&call);
+ // If fast case code has been generated, emit code to push the
+ // function and receiver and have the slow path jump around this
+ // code.
+ if (done.is_linked()) {
+ NearLabel call;
+ __ jmp(&call);
+ __ bind(&done);
+ // Push function.
+ __ push(rax);
+ // Push global receiver.
+ __ movq(rbx, CodeGenerator::GlobalObject());
+ __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
+ __ bind(&call);
+ }
}
EmitCallWithStub(expr);
@@ -1873,18 +1882,24 @@
Literal* key = prop->key()->AsLiteral();
if (key != NULL && key->handle()->IsSymbol()) {
// Call to a named property, use call IC.
- VisitForStackValue(prop->obj());
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(prop->obj());
+ }
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else {
// Call to a keyed property.
// For a synthetic property use keyed load IC followed by function call,
// for a regular property use KeyedCallIC.
- VisitForStackValue(prop->obj());
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(prop->obj());
+ }
if (prop->is_synthetic()) {
- VisitForAccumulatorValue(prop->key());
- __ movq(rdx, Operand(rsp, 0));
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ VisitForAccumulatorValue(prop->key());
+ __ movq(rdx, Operand(rsp, 0));
+ }
// Record source code position for IC call.
- SetSourcePosition(prop->position());
+ SetSourcePosition(prop->position(), FORCED_POSITION);
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET);
// Pop receiver.
@@ -1909,7 +1924,9 @@
loop_depth() == 0) {
lit->set_try_full_codegen(true);
}
- VisitForStackValue(fun);
+ { PreserveStatementPositionScope scope(masm()->positions_recorder());
+ VisitForStackValue(fun);
+ }
// Load global receiver object.
__ movq(rbx, CodeGenerator::GlobalObject());
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc
index 1d95b7f..9ec7814 100644
--- a/src/x64/ic-x64.cc
+++ b/src/x64/ic-x64.cc
@@ -33,7 +33,6 @@
#include "ic-inl.h"
#include "runtime.h"
#include "stub-cache.h"
-#include "utils.h"
namespace v8 {
namespace internal {
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index d59e2f5..748e3e8 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -902,6 +902,7 @@
// Debug event handler which re-issues a debug break until a limit has been
// reached.
int max_break_point_hit_count = 0;
+bool terminate_after_max_break_point_hit = false;
static void DebugEventBreakMax(v8::DebugEvent event,
v8::Handle<v8::Object> exec_state,
v8::Handle<v8::Object> event_data,
@@ -909,12 +910,17 @@
// When hitting a debug event listener there must be a break set.
CHECK_NE(v8::internal::Debug::break_id(), 0);
- if (event == v8::Break && break_point_hit_count < max_break_point_hit_count) {
- // Count the number of breaks.
- break_point_hit_count++;
+ if (event == v8::Break) {
+ if (break_point_hit_count < max_break_point_hit_count) {
+ // Count the number of breaks.
+ break_point_hit_count++;
- // Set the break flag again to come back here as soon as possible.
- v8::Debug::DebugBreak();
+ // Set the break flag again to come back here as soon as possible.
+ v8::Debug::DebugBreak();
+ } else if (terminate_after_max_break_point_hit) {
+ // Terminate execution after the last break if requested.
+ v8::V8::TerminateExecution();
+ }
}
}
@@ -6892,4 +6898,33 @@
CheckDebuggerUnloaded();
}
+
+// Test that setting the terminate execution flag during debug break processing.
+TEST(DebugBreakLoop) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+
+ // Receive 100 breaks and terminate.
+ max_break_point_hit_count = 100;
+ terminate_after_max_break_point_hit = true;
+
+ // Register a debug event listener which sets the break flag and counts.
+ v8::Debug::SetDebugEventListener(DebugEventBreakMax);
+
+ // Function with infinite loop.
+ CompileRun("function f() { while (true) { } }");
+
+ // Set the debug break to enter the debugger as soon as possible.
+ v8::Debug::DebugBreak();
+
+ // Call function with infinite loop.
+ CompileRun("f();");
+ CHECK_EQ(100, break_point_hit_count);
+
+ // Get rid of the debug event listener.
+ v8::Debug::SetDebugEventListener(NULL);
+ CheckDebuggerUnloaded();
+}
+
+
#endif // ENABLE_DEBUGGER_SUPPORT
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 3134b12..7ae8dcf 100755
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -253,6 +253,7 @@
"var x = 42;",
"function foo(x, y) { return x + y; }",
"native function foo(); return %ArgleBargle(glop);",
+ "var x = new new Function('this.x = 42');",
NULL
};
@@ -262,7 +263,7 @@
i::CompleteParserRecorder log;
i::Scanner scanner;
scanner.Initialize(i::Handle<i::String>::null(), &stream, i::JAVASCRIPT);
- i::preparser::PreParser<i::Scanner, i::CompleteParserRecorder> preparser;
+ v8::preparser::PreParser<i::Scanner, i::CompleteParserRecorder> preparser;
bool result = preparser.PreParseProgram(&scanner, &log, true);
CHECK(result);
i::ScriptDataImpl data(log.ExtractData());
diff --git a/test/mjsunit/regress/regress-conditional-position.js b/test/mjsunit/regress/regress-conditional-position.js
new file mode 100644
index 0000000..cd8f7bd
--- /dev/null
+++ b/test/mjsunit/regress/regress-conditional-position.js
@@ -0,0 +1,95 @@
+// 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.
+
+// Flags: --always-full-compiler
+
+var functionToCatch;
+var lineNumber;
+
+function catchLineNumber () {
+ var x = {};
+
+ Error.prepareStackTrace = function (error, stackTrace) {
+ stackTrace.some(function (frame) {
+ if (frame.getFunction() == functionToCatch) {
+ lineNumber = frame.getLineNumber();
+ return true;
+ }
+ return false;
+ });
+ return lineNumber;
+ };
+
+ Error.captureStackTrace(x);
+ return x.stack;
+}
+
+function log() {
+ catchLineNumber();
+}
+
+function foo() {}
+
+function test1() {
+ log(foo() == foo()
+ ? 'a'
+ : 'b');
+}
+
+function test2() {
+ var o = { foo: function () {}}
+ log(o.foo() == o.foo()
+ ? 'a'
+ : 'b');
+}
+
+function test3() {
+ var o = { log: log, foo: function() { } };
+ o.log(o.foo() == o.foo()
+ ? 'a'
+ : 'b');
+
+}
+
+function test(f, expectedLineNumber) {
+ functionToCatch = f;
+ f();
+
+ assertEquals(expectedLineNumber, lineNumber);
+}
+
+test(test1, 58);
+test(test2, 65);
+test(test3, 72);
+
+eval(test1.toString() + "//@ sourceUrl=foo");
+eval(test2.toString() + "//@ sourceUrl=foo");
+eval(test3.toString() + "//@ sourceUrl=foo");
+
+test(test1, 2);
+test(test2, 3);
+test(test3, 3);
diff --git a/test/mjsunit/string-split.js b/test/mjsunit/string-split.js
index 59d3ad3..c741f6a 100644
--- a/test/mjsunit/string-split.js
+++ b/test/mjsunit/string-split.js
@@ -27,76 +27,45 @@
expected = ["A", undefined, "B", "bold", "/", "B", "and", undefined, "CODE", "coded", "/", "CODE", ""];
result = "A<B>bold</B>and<CODE>coded</CODE>".split(/<(\/)?([^<>]+)>/);
-assertArrayEquals(expected, result, 1);
+assertArrayEquals(expected, result);
-expected = ["a", "b"];
-result = "ab".split(/a*?/);
-assertArrayEquals(expected, result, 2);
-expected = ["", "b"];
-result = "ab".split(/a*/);
-assertArrayEquals(expected, result, 3);
+assertArrayEquals(["a", "b"], "ab".split(/a*?/));
-expected = ["a"];
-result = "ab".split(/a*?/, 1);
-assertArrayEquals(expected, result, 4);
+assertArrayEquals(["", "b"], "ab".split(/a*/));
-expected = [""];
-result = "ab".split(/a*/, 1);
-assertArrayEquals(expected, result, 5);
+assertArrayEquals(["a"], "ab".split(/a*?/, 1));
-expected = ["as","fas","fas","f"];
-result = "asdfasdfasdf".split("d");
-assertArrayEquals(expected, result, 6);
+assertArrayEquals([""], "ab".split(/a*/, 1));
-expected = ["as","fas","fas","f"];
-result = "asdfasdfasdf".split("d", -1);
-assertArrayEquals(expected, result, 7);
+assertArrayEquals(["as","fas","fas","f"], "asdfasdfasdf".split("d"));
-expected = ["as", "fas"];
-result = "asdfasdfasdf".split("d", 2);
-assertArrayEquals(expected, result, 8);
+assertArrayEquals(["as","fas","fas","f"], "asdfasdfasdf".split("d", -1));
-expected = [];
-result = "asdfasdfasdf".split("d", 0);
-assertArrayEquals(expected, result, 9);
+assertArrayEquals(["as", "fas"], "asdfasdfasdf".split("d", 2));
-expected = ["as","fas","fas",""];
-result = "asdfasdfasd".split("d");
-assertArrayEquals(expected, result, 10);
+assertArrayEquals([], "asdfasdfasdf".split("d", 0));
-expected = [];
-result = "".split("");
-assertArrayEquals(expected, result, 11);
+assertArrayEquals(["as","fas","fas",""], "asdfasdfasd".split("d"));
-expected = [""]
-result = "".split("a");
-assertArrayEquals(expected, result, 12);
+assertArrayEquals([], "".split(""));
-expected = ["a","b"]
-result = "axxb".split(/x*/);
-assertArrayEquals(expected, result, 13);
+assertArrayEquals([""], "".split("a"));
-expected = ["a","b"]
-result = "axxb".split(/x+/);
-assertArrayEquals(expected, result, 14);
+assertArrayEquals(["a","b"], "axxb".split(/x*/));
-expected = ["a","","b"]
-result = "axxb".split(/x/);
-assertArrayEquals(expected, result, 15);
+assertArrayEquals(["a","b"], "axxb".split(/x+/));
+
+assertArrayEquals(["a","","b"], "axxb".split(/x/));
// This was http://b/issue?id=1151354
-expected = ["div", "#id", ".class"]
-result = "div#id.class".split(/(?=[#.])/);
-assertArrayEquals(expected, result, 16);
+assertArrayEquals(["div", "#id", ".class"], "div#id.class".split(/(?=[#.])/));
-expected = ["div", "#i", "d", ".class"]
-result = "div#id.class".split(/(?=[d#.])/);
-assertArrayEquals(expected, result, 17);
-expected = ["a", "b", "c"]
-result = "abc".split(/(?=.)/);
-assertArrayEquals(expected, result, 18);
+assertArrayEquals(["div", "#i", "d", ".class"], "div#id.class".split(/(?=[d#.])/));
+
+assertArrayEquals(["a", "b", "c"], "abc".split(/(?=.)/));
+
/* "ab".split(/((?=.))/)
*
@@ -108,19 +77,23 @@
*
* Opera seems to have this right. The others make no sense.
*/
-expected = ["a", "", "b"]
-result = "ab".split(/((?=.))/);
-assertArrayEquals(expected, result, 19);
+assertArrayEquals(["a", "", "b"], "ab".split(/((?=.))/));
/* "ab".split(/(?=)/)
*
* KJS: a,b
* SM: ab
* IE: a,b
- * Opera: a,b
+ * Opera: a,bb
* V8: a,b
*/
-expected = ["a", "b"]
-result = "ab".split(/(?=)/);
-assertArrayEquals(expected, result, 20);
+assertArrayEquals(["a", "b"], "ab".split(/(?=)/));
+
+// For issue http://code.google.com/p/v8/issues/detail?id=924
+// Splitting the empty string is a special case.
+assertEquals([""], ''.split());
+assertEquals([""], ''.split(/./));
+assertEquals([], ''.split(/.?/));
+assertEquals([], ''.split(/.??/));
+assertEquals([], ''.split(/()()/));
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 17d556f..3e40fcc 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -426,6 +426,8 @@
'../../src/rewriter.h',
'../../src/runtime.cc',
'../../src/runtime.h',
+ '../../src/scanner-base.cc',
+ '../../src/scanner-base.h',
'../../src/scanner.cc',
'../../src/scanner.h',
'../../src/scopeinfo.cc',
diff --git a/tools/presubmit.py b/tools/presubmit.py
index e69c9a8..ebf8bd8 100755
--- a/tools/presubmit.py
+++ b/tools/presubmit.py
@@ -195,7 +195,7 @@
or (name in CppLintProcessor.IGNORE_LINT))
def GetPathsToSearch(self):
- return ['src', 'public', 'samples', join('test', 'cctest')]
+ return ['src', 'include', 'samples', join('test', 'cctest')]
def ProcessFiles(self, files, path):
good_files_cache = FileContentsCache('.cpplint-cache')
diff --git a/tools/v8.xcodeproj/project.pbxproj b/tools/v8.xcodeproj/project.pbxproj
index 08558cc..5f93c78 100644
--- a/tools/v8.xcodeproj/project.pbxproj
+++ b/tools/v8.xcodeproj/project.pbxproj
@@ -115,6 +115,7 @@
89A88E180E71A6960043BA31 /* property.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16D0E719B8F00D62E90 /* property.cc */; };
89A88E190E71A6970043BA31 /* rewriter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16F0E719B8F00D62E90 /* rewriter.cc */; };
89A88E1A0E71A69B0043BA31 /* runtime.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1710E719B8F00D62E90 /* runtime.cc */; };
+ 89A88E1B0E71A69D0043BA31 /* scanner-base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1730E719B8F00D62E90 /* scanner-base.cc */; };
89A88E1B0E71A69D0043BA31 /* scanner.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1730E719B8F00D62E90 /* scanner.cc */; };
89A88E1C0E71A69E0043BA31 /* scopeinfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1760E719B8F00D62E90 /* scopeinfo.cc */; };
89A88E1D0E71A6A00043BA31 /* scopes.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1780E719B8F00D62E90 /* scopes.cc */; };
@@ -177,6 +178,7 @@
89F23C6C0E78D5B2006B2466 /* property.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16D0E719B8F00D62E90 /* property.cc */; };
89F23C6D0E78D5B2006B2466 /* rewriter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF16F0E719B8F00D62E90 /* rewriter.cc */; };
89F23C6E0E78D5B2006B2466 /* runtime.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1710E719B8F00D62E90 /* runtime.cc */; };
+ 89F23C6F0E78D5B2006B2466 /* scanner-base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1730E719B8F00D62E90 /* scanner-base.cc */; };
89F23C6F0E78D5B2006B2466 /* scanner.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1730E719B8F00D62E90 /* scanner.cc */; };
89F23C700E78D5B2006B2466 /* scopeinfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1760E719B8F00D62E90 /* scopeinfo.cc */; };
89F23C710E78D5B2006B2466 /* scopes.cc in Sources */ = {isa = PBXBuildFile; fileRef = 897FF1780E719B8F00D62E90 /* scopes.cc */; };
@@ -481,6 +483,8 @@
897FF1700E719B8F00D62E90 /* rewriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rewriter.h; sourceTree = "<group>"; };
897FF1710E719B8F00D62E90 /* runtime.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = runtime.cc; sourceTree = "<group>"; };
897FF1720E719B8F00D62E90 /* runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = runtime.h; sourceTree = "<group>"; };
+ 897FF1730E719B8F00D62E90 /* scanner-base.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scanner-base.cc; sourceTree = "<group>"; };
+ 897FF1740E719B8F00D62E90 /* scanner-base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scanner-base.h; sourceTree = "<group>"; };
897FF1730E719B8F00D62E90 /* scanner.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scanner.cc; sourceTree = "<group>"; };
897FF1740E719B8F00D62E90 /* scanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scanner.h; sourceTree = "<group>"; };
897FF1750E719B8F00D62E90 /* SConscript */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SConscript; sourceTree = "<group>"; };
@@ -943,6 +947,8 @@
897FF1700E719B8F00D62E90 /* rewriter.h */,
897FF1710E719B8F00D62E90 /* runtime.cc */,
897FF1720E719B8F00D62E90 /* runtime.h */,
+ 897FF1730E719B8F00D62E90 /* scanner-base.cc */,
+ 897FF1740E719B8F00D62E90 /* scanner-base.h */,
897FF1730E719B8F00D62E90 /* scanner.cc */,
897FF1740E719B8F00D62E90 /* scanner.h */,
897FF1760E719B8F00D62E90 /* scopeinfo.cc */,
@@ -1348,6 +1354,7 @@
58950D630F5551AF00F3E8BA /* register-allocator.cc in Sources */,
89A88E190E71A6970043BA31 /* rewriter.cc in Sources */,
89A88E1A0E71A69B0043BA31 /* runtime.cc in Sources */,
+ 89A88E1B0E71A69D0043BA31 /* scanner-base.cc in Sources */,
89A88E1B0E71A69D0043BA31 /* scanner.cc in Sources */,
89A88E1C0E71A69E0043BA31 /* scopeinfo.cc in Sources */,
89A88E1D0E71A6A00043BA31 /* scopes.cc in Sources */,
@@ -1472,6 +1479,7 @@
58950D640F5551B500F3E8BA /* register-allocator.cc in Sources */,
89F23C6D0E78D5B2006B2466 /* rewriter.cc in Sources */,
89F23C6E0E78D5B2006B2466 /* runtime.cc in Sources */,
+ 89F23C6F0E78D5B2006B2466 /* scanner-base.cc in Sources */,
89F23C6F0E78D5B2006B2466 /* scanner.cc in Sources */,
89F23C700E78D5B2006B2466 /* scopeinfo.cc in Sources */,
89F23C710E78D5B2006B2466 /* scopes.cc in Sources */,
diff --git a/tools/visual_studio/v8_base.vcproj b/tools/visual_studio/v8_base.vcproj
index 62d4501..bddf38e 100644
--- a/tools/visual_studio/v8_base.vcproj
+++ b/tools/visual_studio/v8_base.vcproj
@@ -882,6 +882,14 @@
>
</File>
<File
+ RelativePath="..\..\src\scanner-base.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\src\scanner-base.h"
+ >
+ </File>
+ <File
RelativePath="..\..\src\scanner.cc"
>
</File>