Browse Source

Upgrade V8 to 2.2.16

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
cd232a9cce
  1. 12
      deps/v8/ChangeLog
  2. 68
      deps/v8/include/v8.h
  3. 14
      deps/v8/src/api.cc
  4. 19
      deps/v8/src/arm/assembler-arm-inl.h
  5. 21
      deps/v8/src/arm/assembler-arm.cc
  6. 28
      deps/v8/src/arm/assembler-arm.h
  7. 6
      deps/v8/src/arm/codegen-arm.cc
  8. 4
      deps/v8/src/arm/codegen-arm.h
  9. 71
      deps/v8/src/arm/debug-arm.cc
  10. 6
      deps/v8/src/arm/full-codegen-arm.cc
  11. 6
      deps/v8/src/assembler.cc
  12. 14
      deps/v8/src/assembler.h
  13. 13
      deps/v8/src/ast.h
  14. 7
      deps/v8/src/builtins.cc
  15. 1
      deps/v8/src/builtins.h
  16. 2
      deps/v8/src/checks.h
  17. 19
      deps/v8/src/codegen.cc
  18. 28
      deps/v8/src/compilation-cache.cc
  19. 3
      deps/v8/src/compilation-cache.h
  20. 1
      deps/v8/src/compiler.cc
  21. 8
      deps/v8/src/cpu-profiler.cc
  22. 3
      deps/v8/src/d8.cc
  23. 67
      deps/v8/src/debug.cc
  24. 19
      deps/v8/src/debug.h
  25. 2
      deps/v8/src/flag-definitions.h
  26. 296
      deps/v8/src/full-codegen.cc
  27. 26
      deps/v8/src/full-codegen.h
  28. 8
      deps/v8/src/heap-inl.h
  29. 99
      deps/v8/src/heap.cc
  30. 12
      deps/v8/src/heap.h
  31. 22
      deps/v8/src/ia32/assembler-ia32-inl.h
  32. 17
      deps/v8/src/ia32/assembler-ia32.cc
  33. 14
      deps/v8/src/ia32/assembler-ia32.h
  34. 4
      deps/v8/src/ia32/codegen-ia32.h
  35. 42
      deps/v8/src/ia32/debug-ia32.cc
  36. 14
      deps/v8/src/ia32/disasm-ia32.cc
  37. 18
      deps/v8/src/mark-compact.cc
  38. 9
      deps/v8/src/mips/assembler-mips.cc
  39. 5
      deps/v8/src/mips/assembler-mips.h
  40. 4
      deps/v8/src/objects-inl.h
  41. 7
      deps/v8/src/objects.cc
  42. 7
      deps/v8/src/objects.h
  43. 5
      deps/v8/src/parser.cc
  44. 96
      deps/v8/src/profile-generator.cc
  45. 39
      deps/v8/src/profile-generator.h
  46. 4
      deps/v8/src/serialize.cc
  47. 2
      deps/v8/src/version.cc
  48. 15
      deps/v8/src/x64/assembler-x64-inl.h
  49. 16
      deps/v8/src/x64/assembler-x64.cc
  50. 16
      deps/v8/src/x64/assembler-x64.h
  51. 4
      deps/v8/src/x64/codegen-x64.h
  52. 43
      deps/v8/src/x64/debug-x64.cc
  53. 71
      deps/v8/test/cctest/test-api.cc
  54. 5
      deps/v8/test/cctest/test-cpu-profiler.cc
  55. 417
      deps/v8/test/cctest/test-debug.cc
  56. 3
      deps/v8/test/cctest/test-disasm-ia32.cc
  57. 39
      deps/v8/test/cctest/test-heap.cc
  58. 78
      deps/v8/test/cctest/test-profile-generator.cc
  59. 2
      deps/v8/test/mjsunit/const-eval-init.js
  60. 12
      deps/v8/test/mjsunit/debug-conditional-breakpoints.js
  61. 7
      deps/v8/test/mjsunit/debug-step.js

12
deps/v8/ChangeLog

@ -1,3 +1,15 @@
2010-06-07: Version 2.2.16
Remove the SetExternalStringDiposeCallback API. Changed the
disposal of external string resources to call a virtual Dispose
method on the resource.
Added support for more precise break points when debugging and
stepping.
Memory usage improvements on all platforms.
2010-06-07: Version 2.2.15
Add an API to control the disposal of external string resources.

68
deps/v8/include/v8.h

@ -134,6 +134,7 @@ namespace internal {
class Arguments;
class Object;
class Heap;
class Top;
}
@ -513,6 +514,7 @@ class V8EXPORT Data {
class V8EXPORT ScriptData { // NOLINT
public:
virtual ~ScriptData() { }
/**
* Pre-compiles the specified script (context-independent).
*
@ -521,6 +523,16 @@ class V8EXPORT ScriptData { // NOLINT
*/
static ScriptData* PreCompile(const char* input, int length);
/**
* Pre-compiles the specified script (context-independent).
*
* NOTE: Pre-compilation using this method cannot happen on another thread
* without using Lockers.
*
* \param source Script source code.
*/
static ScriptData* PreCompile(Handle<String> source);
/**
* Load previous pre-compilation data.
*
@ -1026,12 +1038,24 @@ class V8EXPORT String : public Primitive {
class V8EXPORT ExternalStringResourceBase {
public:
virtual ~ExternalStringResourceBase() {}
protected:
ExternalStringResourceBase() {}
/**
* Internally V8 will call this Dispose method when the external string
* resource is no longer needed. The default implementation will use the
* delete operator. This method can be overridden in subclasses to
* control how allocated external string resources are disposed.
*/
virtual void Dispose() { delete this; }
private:
// Disallow copying and assigning.
ExternalStringResourceBase(const ExternalStringResourceBase&);
void operator=(const ExternalStringResourceBase&);
friend class v8::internal::Heap;
};
/**
@ -1048,10 +1072,17 @@ class V8EXPORT String : public Primitive {
* buffer.
*/
virtual ~ExternalStringResource() {}
/** The string data from the underlying buffer.*/
/**
* The string data from the underlying buffer.
*/
virtual const uint16_t* data() const = 0;
/** The length of the string. That is, the number of two-byte characters.*/
/**
* The length of the string. That is, the number of two-byte characters.
*/
virtual size_t length() const = 0;
protected:
ExternalStringResource() {}
};
@ -1123,12 +1154,10 @@ class V8EXPORT String : public Primitive {
/**
* Creates a new external string using the data defined in the given
* resource. When the external string is no longer live on V8's heap the
* resource will be disposed. If a disposal callback has been set using
* SetExternalStringDiposeCallback this callback will be called to dispose
* the resource. Otherwise, V8 will dispose the resource using the C++ delete
* operator. The caller of this function should not otherwise delete or
* modify the resource. Neither should the underlying buffer be deallocated
* or modified except through the destructor of the external string resource.
* resource will be disposed by calling its Dispose method. The caller of
* this function should not otherwise delete or modify the resource. Neither
* should the underlying buffer be deallocated or modified except through the
* destructor of the external string resource.
*/
static Local<String> NewExternal(ExternalStringResource* resource);
@ -1146,12 +1175,10 @@ class V8EXPORT String : public Primitive {
/**
* Creates a new external string using the ascii data defined in the given
* resource. When the external string is no longer live on V8's heap the
* resource will be disposed. If a disposal callback has been set using
* SetExternalStringDiposeCallback this callback will be called to dispose
* the resource. Otherwise, V8 will dispose the resource using the C++ delete
* operator. The caller of this function should not otherwise delete or
* modify the resource. Neither should the underlying buffer be deallocated
* or modified except through the destructor of the external string resource.
* resource will be disposed by calling its Dispose method. The caller of
* this function should not otherwise delete or modify the resource. Neither
* should the underlying buffer be deallocated or modified except through the
* destructor of the external string resource.
*/
static Local<String> NewExternal(ExternalAsciiStringResource* resource);
@ -1251,10 +1278,6 @@ class V8EXPORT String : public Primitive {
};
typedef void (*ExternalStringDiposeCallback)
(String::ExternalStringResourceBase* resource);
/**
* A JavaScript number value (ECMA-262, 4.3.20)
*/
@ -2471,15 +2494,6 @@ class V8EXPORT V8 {
*/
static void RemoveMessageListeners(MessageCallback that);
/**
* Set a callback to be called when an external string is no longer live on
* V8's heap. The resource will no longer be needed by V8 and the embedder
* can dispose of if. If this callback is not set V8 will free the resource
* using the C++ delete operator.
*/
static void SetExternalStringDiposeCallback(
ExternalStringDiposeCallback that);
/**
* Sets V8 flags from a string.
*/

14
deps/v8/src/api.cc

@ -1120,6 +1120,12 @@ ScriptData* ScriptData::PreCompile(const char* input, int length) {
}
ScriptData* ScriptData::PreCompile(v8::Handle<String> source) {
i::Handle<i::String> str = Utils::OpenHandle(*source);
return i::PreParse(str, NULL, NULL);
}
ScriptData* ScriptData::New(const char* data, int length) {
// Return an empty ScriptData if the length is obviously invalid.
if (length % sizeof(unsigned) != 0) {
@ -3692,14 +3698,6 @@ void V8::RemoveMessageListeners(MessageCallback that) {
}
void V8::SetExternalStringDiposeCallback(
ExternalStringDiposeCallback callback) {
if (IsDeadCheck("v8::V8::SetExternalStringDiposeCallback()"))
return;
i::Heap::SetExternalStringDiposeCallback(callback);
}
void V8::SetCounterFunction(CounterLookupCallback callback) {
if (IsDeadCheck("v8::V8::SetCounterFunction()")) return;
i::StatsTable::SetCounterFunction(callback);

19
deps/v8/src/arm/assembler-arm-inl.h

@ -116,9 +116,10 @@ Address* RelocInfo::target_reference_address() {
Address RelocInfo::call_address() {
ASSERT(IsPatchedReturnSequence());
// The 2 instructions offset assumes patched return sequence.
ASSERT(IsJSReturn(rmode()));
// The 2 instructions offset assumes patched debug break slot or return
// sequence.
ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
return Memory::Address_at(pc_ + 2 * Assembler::kInstrSize);
}
@ -168,6 +169,12 @@ bool RelocInfo::IsPatchedReturnSequence() {
}
bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
Instr current_instr = Assembler::instr_at(pc_);
return !Assembler::IsNop(current_instr, 2);
}
void RelocInfo::Visit(ObjectVisitor* visitor) {
RelocInfo::Mode mode = rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
@ -178,8 +185,10 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
visitor->VisitExternalReference(target_reference_address());
#ifdef ENABLE_DEBUGGER_SUPPORT
} else if (Debug::has_break_points() &&
RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) {
((RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(mode) &&
IsPatchedDebugBreakSlotSequence()))) {
visitor->VisitDebugTarget(this);
#endif
} else if (mode == RelocInfo::RUNTIME_ENTRY) {

21
deps/v8/src/arm/assembler-arm.cc

@ -2040,6 +2040,13 @@ void Assembler::RecordJSReturn() {
}
void Assembler::RecordDebugBreakSlot() {
WriteRecordedPositions();
CheckBuffer();
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
}
void Assembler::RecordComment(const char* msg) {
if (FLAG_debug_code) {
CheckBuffer();
@ -2062,13 +2069,16 @@ void Assembler::RecordStatementPosition(int pos) {
}
void Assembler::WriteRecordedPositions() {
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
@ -2078,7 +2088,11 @@ void Assembler::WriteRecordedPositions() {
CheckBuffer();
RecordRelocInfo(RelocInfo::POSITION, current_position_);
written_position_ = current_position_;
written = true;
}
// Return whether something was written.
return written;
}
@ -2135,9 +2149,10 @@ void Assembler::GrowBuffer() {
void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
RelocInfo rinfo(pc_, rmode, data); // we do not try to reuse pool constants
if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::STATEMENT_POSITION) {
if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) {
// Adjust code for new modes.
ASSERT(RelocInfo::IsJSReturn(rmode)
ASSERT(RelocInfo::IsDebugBreakSlot(rmode)
|| RelocInfo::IsJSReturn(rmode)
|| RelocInfo::IsComment(rmode)
|| RelocInfo::IsPosition(rmode));
// These modes do not need an entry in the constant pool.

28
deps/v8/src/arm/assembler-arm.h

@ -629,22 +629,39 @@ class Assembler : public Malloced {
// Distance between start of patched return sequence and the emitted address
// to jump to.
#ifdef USE_BLX
// Return sequence is:
// Patched return sequence is:
// ldr ip, [pc, #0] @ emited address and start
// blx ip
static const int kPatchReturnSequenceAddressOffset = 0 * kInstrSize;
#else
// Return sequence is:
// Patched return sequence is:
// mov lr, pc @ start of sequence
// ldr pc, [pc, #-4] @ emited address
static const int kPatchReturnSequenceAddressOffset = kInstrSize;
#endif
// Distance between start of patched debug break slot and the emitted address
// to jump to.
#ifdef USE_BLX
// Patched debug break slot code is:
// ldr ip, [pc, #0] @ emited address and start
// blx ip
static const int kPatchDebugBreakSlotAddressOffset = 0 * kInstrSize;
#else
// Patched debug break slot code is:
// mov lr, pc @ start of sequence
// ldr pc, [pc, #-4] @ emited address
static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
#endif
// Difference between address of current opcode and value read from pc
// register.
static const int kPcLoadDelta = 8;
static const int kJSReturnSequenceLength = 4;
static const int kJSReturnSequenceInstructions = 4;
static const int kDebugBreakSlotInstructions = 3;
static const int kDebugBreakSlotLength =
kDebugBreakSlotInstructions * kInstrSize;
// ---------------------------------------------------------------------------
// Code generation
@ -981,13 +998,16 @@ class Assembler : public Malloced {
// Mark address of the ExitJSFrame code.
void RecordJSReturn();
// Mark address of a debug break slot.
void RecordDebugBreakSlot();
// Record a comment relocation entry that can be used by a disassembler.
// Use --debug_code to enable.
void RecordComment(const char* msg);
void RecordPosition(int pos);
void RecordStatementPosition(int pos);
void WriteRecordedPositions();
bool WriteRecordedPositions();
int pc_offset() const { return pc_ - buffer_; }
int current_position() const { return current_position_; }

6
deps/v8/src/arm/codegen-arm.cc

@ -386,8 +386,10 @@ void CodeGenerator::Generate(CompilationInfo* info) {
// the add instruction the add will generate two instructions.
int return_sequence_length =
masm_->InstructionsGeneratedSince(&check_exit_codesize);
CHECK(return_sequence_length == Assembler::kJSReturnSequenceLength ||
return_sequence_length == Assembler::kJSReturnSequenceLength + 1);
CHECK(return_sequence_length ==
Assembler::kJSReturnSequenceInstructions ||
return_sequence_length ==
Assembler::kJSReturnSequenceInstructions + 1);
#endif
}
}

4
deps/v8/src/arm/codegen-arm.h

@ -226,7 +226,9 @@ class CodeGenerator: public AstVisitor {
bool is_toplevel,
Handle<Script> script);
static void RecordPositions(MacroAssembler* masm, int pos);
static bool RecordPositions(MacroAssembler* masm,
int pos,
bool right_here = false);
// Accessors
MacroAssembler* masm() { return masm_; }

71
deps/v8/src/arm/debug-arm.cc

@ -57,7 +57,7 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
// #endif
// <debug break return code entry point address>
// bktp 0
CodePatcher patcher(rinfo()->pc(), 4);
CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
#ifdef USE_BLX
patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0));
patcher.masm()->blx(v8::internal::ip);
@ -73,17 +73,59 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
// Restore the JS frame exit code.
void BreakLocationIterator::ClearDebugBreakAtReturn() {
rinfo()->PatchCode(original_rinfo()->pc(),
Assembler::kJSReturnSequenceLength);
Assembler::kJSReturnSequenceInstructions);
}
// A debug break in the exit code is identified by a call.
// A debug break in the frame exit code is identified by the JS frame exit code
// having been patched with a call instruction.
bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
return rinfo->IsPatchedReturnSequence();
}
bool BreakLocationIterator::IsDebugBreakAtSlot() {
ASSERT(IsDebugBreakSlot());
// Check whether the debug break slot instructions have been patched.
return rinfo()->IsPatchedDebugBreakSlotSequence();
}
void BreakLocationIterator::SetDebugBreakAtSlot() {
ASSERT(IsDebugBreakSlot());
// Patch the code changing the debug break slot code from
// mov r2, r2
// mov r2, r2
// mov r2, r2
// to a call to the debug break slot code.
// #if USE_BLX
// ldr ip, [pc, #0]
// blx ip
// #else
// mov lr, pc
// ldr pc, [pc, #-4]
// #endif
// <debug break slot code entry point address>
CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
#ifdef USE_BLX
patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0));
patcher.masm()->blx(v8::internal::ip);
#else
patcher.masm()->mov(v8::internal::lr, v8::internal::pc);
patcher.masm()->ldr(v8::internal::pc, MemOperand(v8::internal::pc, -4));
#endif
patcher.Emit(Debug::debug_break_return()->entry());
}
void BreakLocationIterator::ClearDebugBreakAtSlot() {
ASSERT(IsDebugBreakSlot());
rinfo()->PatchCode(original_rinfo()->pc(),
Assembler::kDebugBreakSlotInstructions);
}
#define __ ACCESS_MASM(masm)
@ -220,10 +262,33 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
}
void Debug::GenerateSlot(MacroAssembler* masm) {
// Generate enough nop's to make space for a call instruction. Avoid emitting
// the constant pool in the debug break slot code.
Assembler::BlockConstPoolScope block_const_pool(masm);
Label check_codesize;
__ bind(&check_codesize);
__ RecordDebugBreakSlot();
for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
__ nop(2);
}
ASSERT_EQ(Assembler::kDebugBreakSlotInstructions,
masm->InstructionsGeneratedSince(&check_codesize));
}
void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
// In the places where a debug break slot is inserted no registers can contain
// object pointers.
Generate_DebugBreakCallHelper(masm, 0);
}
void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
masm->Abort("LiveEdit frame dropping is not supported on arm");
}
void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
masm->Abort("LiveEdit frame dropping is not supported on arm");
}

6
deps/v8/src/arm/full-codegen-arm.cc

@ -238,8 +238,10 @@ void FullCodeGenerator::EmitReturnSequence(int position) {
// add instruction the add will generate two instructions.
int return_sequence_length =
masm_->InstructionsGeneratedSince(&check_exit_codesize);
CHECK(return_sequence_length == Assembler::kJSReturnSequenceLength ||
return_sequence_length == Assembler::kJSReturnSequenceLength + 1);
CHECK(return_sequence_length ==
Assembler::kJSReturnSequenceInstructions ||
return_sequence_length ==
Assembler::kJSReturnSequenceInstructions + 1);
#endif
}
}

6
deps/v8/src/assembler.cc

@ -449,6 +449,11 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
return "external reference";
case RelocInfo::INTERNAL_REFERENCE:
return "internal reference";
case RelocInfo::DEBUG_BREAK_SLOT:
#ifndef ENABLE_DEBUGGER_SUPPORT
UNREACHABLE();
#endif
return "debug break slot";
case RelocInfo::NUMBER_OF_MODES:
UNREACHABLE();
return "number_of_modes";
@ -513,6 +518,7 @@ void RelocInfo::Verify() {
case STATEMENT_POSITION:
case EXTERNAL_REFERENCE:
case INTERNAL_REFERENCE:
case DEBUG_BREAK_SLOT:
case NONE:
break;
case NUMBER_OF_MODES:

14
deps/v8/src/assembler.h

@ -118,9 +118,9 @@ class RelocInfo BASE_EMBEDDED {
enum Mode {
// Please note the order is important (see IsCodeTarget, IsGCRelocMode).
CONSTRUCT_CALL, // code target that is a call to a JavaScript constructor.
CODE_TARGET_CONTEXT, // code target used for contextual loads.
DEBUG_BREAK,
CODE_TARGET, // code target which is not any of the above.
CODE_TARGET_CONTEXT, // Code target used for contextual loads.
DEBUG_BREAK, // Code target for the debugger statement.
CODE_TARGET, // Code target which is not any of the above.
EMBEDDED_OBJECT,
// Everything after runtime_entry (inclusive) is not GC'ed.
@ -129,6 +129,7 @@ class RelocInfo BASE_EMBEDDED {
COMMENT,
POSITION, // See comment for kNoPosition above.
STATEMENT_POSITION, // See comment for kNoPosition above.
DEBUG_BREAK_SLOT, // Additional code inserted for debug break slot.
EXTERNAL_REFERENCE, // The address of an external C++ function.
INTERNAL_REFERENCE, // An address inside the same function.
@ -174,6 +175,9 @@ class RelocInfo BASE_EMBEDDED {
static inline bool IsInternalReference(Mode mode) {
return mode == INTERNAL_REFERENCE;
}
static inline bool IsDebugBreakSlot(Mode mode) {
return mode == DEBUG_BREAK_SLOT;
}
static inline int ModeMask(Mode mode) { return 1 << mode; }
// Accessors
@ -243,6 +247,10 @@ class RelocInfo BASE_EMBEDDED {
// with a call to the debugger.
INLINE(bool IsPatchedReturnSequence());
// Check whether this debug break slot has been patched with a call to the
// debugger.
INLINE(bool IsPatchedDebugBreakSlotSequence());
#ifdef ENABLE_DISASSEMBLER
// Printing
static const char* RelocModeName(Mode rmode);

13
deps/v8/src/ast.h

@ -1469,10 +1469,14 @@ class Conditional: public Expression {
public:
Conditional(Expression* condition,
Expression* then_expression,
Expression* else_expression)
Expression* else_expression,
int then_expression_position,
int else_expression_position)
: condition_(condition),
then_expression_(then_expression),
else_expression_(else_expression) { }
else_expression_(else_expression),
then_expression_position_(then_expression_position),
else_expression_position_(else_expression_position) { }
virtual void Accept(AstVisitor* v);
@ -1482,10 +1486,15 @@ class Conditional: public Expression {
Expression* then_expression() const { return then_expression_; }
Expression* else_expression() const { return else_expression_; }
int then_expression_position() { return then_expression_position_; }
int else_expression_position() { return else_expression_position_; }
private:
Expression* condition_;
Expression* then_expression_;
Expression* else_expression_;
int then_expression_position_;
int else_expression_position_;
};

7
deps/v8/src/builtins.cc

@ -1360,10 +1360,17 @@ static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
Debug::GenerateStubNoRegistersDebugBreak(masm);
}
static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
Debug::GenerateSlotDebugBreak(masm);
}
static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
Debug::GeneratePlainReturnLiveEdit(masm);
}
static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
Debug::GenerateFrameDropperLiveEdit(masm);
}

1
deps/v8/src/builtins.h

@ -127,6 +127,7 @@ enum BuiltinExtraArguments {
V(KeyedLoadIC_DebugBreak, KEYED_LOAD_IC, DEBUG_BREAK) \
V(StoreIC_DebugBreak, STORE_IC, DEBUG_BREAK) \
V(KeyedStoreIC_DebugBreak, KEYED_STORE_IC, DEBUG_BREAK) \
V(Slot_DebugBreak, BUILTIN, DEBUG_BREAK) \
V(PlainReturn_LiveEdit, BUILTIN, DEBUG_BREAK) \
V(FrameDropper_LiveEdit, BUILTIN, DEBUG_BREAK)
#else

2
deps/v8/src/checks.h

@ -286,6 +286,7 @@ template <int> class StaticAssertionHelper { };
#define ASSERT(condition) CHECK(condition)
#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 STATIC_ASSERT(test) STATIC_CHECK(test)
#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition)
#else
@ -293,6 +294,7 @@ template <int> class StaticAssertionHelper { };
#define ASSERT(condition) ((void) 0)
#define ASSERT_EQ(v1, v2) ((void) 0)
#define ASSERT_NE(v1, v2) ((void) 0)
#define ASSERT_GE(v1, v2) ((void) 0)
#define STATIC_ASSERT(test) ((void) 0)
#define SLOW_ASSERT(condition) ((void) 0)
#endif

19
deps/v8/src/codegen.cc

@ -415,32 +415,41 @@ CodeGenerator::ConditionAnalysis CodeGenerator::AnalyzeCondition(
}
void CodeGenerator::RecordPositions(MacroAssembler* masm, int pos) {
bool CodeGenerator::RecordPositions(MacroAssembler* masm,
int pos,
bool right_here) {
if (pos != RelocInfo::kNoPosition) {
masm->RecordStatementPosition(pos);
masm->RecordPosition(pos);
if (right_here) {
return masm->WriteRecordedPositions();
}
}
return false;
}
void CodeGenerator::CodeForFunctionPosition(FunctionLiteral* fun) {
if (FLAG_debug_info) RecordPositions(masm(), fun->start_position());
if (FLAG_debug_info) RecordPositions(masm(), fun->start_position(), false);
}
void CodeGenerator::CodeForReturnPosition(FunctionLiteral* fun) {
if (FLAG_debug_info) RecordPositions(masm(), fun->end_position());
if (FLAG_debug_info) RecordPositions(masm(), fun->end_position(), false);
}
void CodeGenerator::CodeForStatementPosition(Statement* stmt) {
if (FLAG_debug_info) RecordPositions(masm(), stmt->statement_pos());
if (FLAG_debug_info) RecordPositions(masm(), stmt->statement_pos(), false);
}
void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) {
if (FLAG_debug_info) RecordPositions(masm(), stmt->condition_position());
if (FLAG_debug_info)
RecordPositions(masm(), stmt->condition_position(), false);
}
void CodeGenerator::CodeForSourcePosition(int pos) {
if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
masm()->RecordPosition(pos);

28
deps/v8/src/compilation-cache.cc

@ -79,6 +79,8 @@ class CompilationSubCache {
// young generation.
void Age();
bool HasFunction(SharedFunctionInfo* function_info);
// GC support.
void Iterate(ObjectVisitor* v);
@ -204,6 +206,27 @@ Handle<CompilationCacheTable> CompilationSubCache::GetTable(int generation) {
}
bool CompilationSubCache::HasFunction(SharedFunctionInfo* function_info) {
if (function_info->script()->IsUndefined() ||
Script::cast(function_info->script())->source()->IsUndefined()) {
return false;
}
String* source =
String::cast(Script::cast(function_info->script())->source());
// Check all generations.
for (int generation = 0; generation < generations(); generation++) {
if (tables_[generation]->IsUndefined()) continue;
CompilationCacheTable* table =
CompilationCacheTable::cast(tables_[generation]);
Object* object = table->Lookup(source);
if (object->IsSharedFunctionInfo()) return true;
}
return false;
}
void CompilationSubCache::Age() {
// Age the generations implicitly killing off the oldest.
for (int i = generations_ - 1; i > 0; i--) {
@ -506,6 +529,11 @@ void CompilationCache::Clear() {
}
bool CompilationCache::HasFunction(SharedFunctionInfo* function_info) {
return script.HasFunction(function_info);
}
void CompilationCache::Iterate(ObjectVisitor* v) {
for (int i = 0; i < kSubCacheCount; i++) {
subcaches[i]->Iterate(v);

3
deps/v8/src/compilation-cache.h

@ -79,6 +79,9 @@ class CompilationCache {
// Clear the cache - also used to initialize the cache at startup.
static void Clear();
static bool HasFunction(SharedFunctionInfo* function_info);
// GC support.
static void Iterate(ObjectVisitor* v);

1
deps/v8/src/compiler.cc

@ -601,6 +601,7 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
lit->has_only_simple_this_property_assignments(),
*lit->this_property_assignments());
function_info->set_try_full_codegen(lit->try_full_codegen());
function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
}

8
deps/v8/src/cpu-profiler.cc

@ -294,7 +294,8 @@ CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) {
int CpuProfiler::GetProfilesCount() {
ASSERT(singleton_ != NULL);
// The count of profiles doesn't depend on a security token.
return singleton_->profiles_->Profiles(CodeEntry::kNoSecurityToken)->length();
return singleton_->profiles_->Profiles(
TokenEnumerator::kNoSecurityToken)->length();
}
@ -380,7 +381,7 @@ void CpuProfiler::CodeDeleteEvent(Address from) {
void CpuProfiler::FunctionCreateEvent(JSFunction* function) {
int security_token_id = CodeEntry::kNoSecurityToken;
int security_token_id = TokenEnumerator::kNoSecurityToken;
if (function->unchecked_context()->IsContext()) {
security_token_id = singleton_->token_enumerator_->GetTokenId(
function->context()->global_context()->security_token());
@ -476,7 +477,8 @@ void CpuProfiler::StartProcessorIfNotStarted() {
CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) {
const double actual_sampling_rate = generator_->actual_sampling_rate();
StopProcessorIfLastProfile();
CpuProfile* result = profiles_->StopProfiling(CodeEntry::kNoSecurityToken,
CpuProfile* result =
profiles_->StopProfiling(TokenEnumerator::kNoSecurityToken,
title,
actual_sampling_rate);
if (result != NULL) {

3
deps/v8/src/d8.cc

@ -576,6 +576,9 @@ Handle<String> Shell::ReadFile(const char* name) {
void Shell::RunShell() {
LineEditor* editor = LineEditor::Get();
printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
if (i::FLAG_debugger) {
printf("JavaScript debugger enabled\n");
}
editor->Open();
while (true) {
Locker locker;

67
deps/v8/src/debug.cc

@ -129,10 +129,14 @@ void BreakLocationIterator::Next() {
ASSERT(statement_position_ >= 0);
}
if (IsDebugBreakSlot()) {
// There is always a possible break point at a debug break slot.
break_point_++;
return;
} else if (RelocInfo::IsCodeTarget(rmode())) {
// Check for breakable code target. Look in the original code as setting
// break points can cause the code targets in the running (debugged) code to
// be of a different kind than in the original code.
if (RelocInfo::IsCodeTarget(rmode())) {
// break points can cause the code targets in the running (debugged) code
// to be of a different kind than in the original code.
Address target = original_rinfo()->target_address();
Code* code = Code::GetCodeFromTargetAddress(target);
if ((code->is_inline_cache_stub() &&
@ -329,6 +333,9 @@ void BreakLocationIterator::SetDebugBreak() {
if (RelocInfo::IsJSReturn(rmode())) {
// Patch the frame exit code with a break point.
SetDebugBreakAtReturn();
} else if (IsDebugBreakSlot()) {
// Patch the code in the break slot.
SetDebugBreakAtSlot();
} else {
// Patch the IC call.
SetDebugBreakAtIC();
@ -346,6 +353,9 @@ void BreakLocationIterator::ClearDebugBreak() {
if (RelocInfo::IsJSReturn(rmode())) {
// Restore the frame exit code.
ClearDebugBreakAtReturn();
} else if (IsDebugBreakSlot()) {
// Restore the code in the break slot.
ClearDebugBreakAtSlot();
} else {
// Patch the IC call.
ClearDebugBreakAtIC();
@ -417,6 +427,8 @@ bool BreakLocationIterator::HasBreakPoint() {
bool BreakLocationIterator::IsDebugBreak() {
if (RelocInfo::IsJSReturn(rmode())) {
return IsDebugBreakAtReturn();
} else if (IsDebugBreakSlot()) {
return IsDebugBreakAtSlot();
} else {
return Debug::IsDebugBreak(rinfo()->target_address());
}
@ -478,6 +490,11 @@ bool BreakLocationIterator::IsDebuggerStatement() {
}
bool BreakLocationIterator::IsDebugBreakSlot() {
return RelocInfo::DEBUG_BREAK_SLOT == rmode();
}
Object* BreakLocationIterator::BreakPointObjects() {
return debug_info_->GetBreakPointObjects(code_position());
}
@ -573,6 +590,7 @@ bool Debug::break_on_uncaught_exception_ = true;
Handle<Context> Debug::debug_context_ = Handle<Context>();
Code* Debug::debug_break_return_ = NULL;
Code* Debug::debug_break_slot_ = NULL;
void ScriptCache::Add(Handle<Script> script) {
@ -656,6 +674,10 @@ void Debug::Setup(bool create_heap_objects) {
debug_break_return_ =
Builtins::builtin(Builtins::Return_DebugBreak);
ASSERT(debug_break_return_->IsCode());
// Get code to handle debug break in debug break slots.
debug_break_slot_ =
Builtins::builtin(Builtins::Slot_DebugBreak);
ASSERT(debug_break_slot_->IsCode());
}
}
@ -824,6 +846,7 @@ void Debug::PreemptionWhileInDebugger() {
void Debug::Iterate(ObjectVisitor* v) {
v->VisitPointer(BitCast<Object**, Code**>(&(debug_break_return_)));
v->VisitPointer(BitCast<Object**, Code**>(&(debug_break_slot_)));
}
@ -1631,16 +1654,21 @@ void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
// break point is still active after processing the break point.
Address addr = frame->pc() - Assembler::kCallTargetAddressOffset;
// Check if the location is at JS exit.
// Check if the location is at JS exit or debug break slot.
bool at_js_return = false;
bool break_at_js_return_active = false;
bool at_debug_break_slot = false;
RelocIterator it(debug_info->code());
while (!it.done()) {
while (!it.done() && !at_js_return && !at_debug_break_slot) {
if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
at_js_return = (it.rinfo()->pc() ==
addr - Assembler::kPatchReturnSequenceAddressOffset);
break_at_js_return_active = it.rinfo()->IsPatchedReturnSequence();
}
if (RelocInfo::IsDebugBreakSlot(it.rinfo()->rmode())) {
at_debug_break_slot = (it.rinfo()->pc() ==
addr - Assembler::kPatchDebugBreakSlotAddressOffset);
}
it.next();
}
@ -1657,25 +1685,30 @@ void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
// Move back to where the call instruction sequence started.
thread_local_.after_break_target_ =
addr - Assembler::kPatchReturnSequenceAddressOffset;
} else {
// Check if there still is a debug break call at the target address. If the
// break point has been removed it will have disappeared. If it have
// disappeared don't try to look in the original code as the running code
// will have the right address. This takes care of the case where the last
// break point is removed from the function and therefore no "original code"
// is available. If the debug break call is still there find the address in
// the original code.
if (IsDebugBreak(Assembler::target_address_at(addr))) {
// If the break point is still there find the call address which was
// overwritten in the original code by the call to DebugBreakXXX.
} else if (at_debug_break_slot) {
// Address of where the debug break slot starts.
addr = addr - Assembler::kPatchDebugBreakSlotAddressOffset;
// Continue just after the slot.
thread_local_.after_break_target_ = addr + Assembler::kDebugBreakSlotLength;
} else if (IsDebugBreak(Assembler::target_address_at(addr))) {
// We now know that there is still a debug break call at the target address,
// so the break point is still there and the original code will hold the
// address to jump to in order to complete the call which is replaced by a
// call to DebugBreakXXX.
// Find the corresponding address in the original code.
addr += original_code->instruction_start() - code->instruction_start();
}
// Install jump to the call address in the original code. This will be the
// call which was overwritten by the call to DebugBreakXXX.
thread_local_.after_break_target_ = Assembler::target_address_at(addr);
} else {
// There is no longer a break point present. Don't try to look in the
// original code as the running code will have the right address. This takes
// care of the case where the last break point is removed from the function
// and therefore no "original code" is available.
thread_local_.after_break_target_ = Assembler::target_address_at(addr);
}
}

19
deps/v8/src/debug.h

@ -146,6 +146,11 @@ class BreakLocationIterator {
void SetDebugBreakAtReturn();
void ClearDebugBreakAtReturn();
bool IsDebugBreakSlot();
bool IsDebugBreakAtSlot();
void SetDebugBreakAtSlot();
void ClearDebugBreakAtSlot();
DISALLOW_COPY_AND_ASSIGN(BreakLocationIterator);
};
@ -323,6 +328,7 @@ class Debug {
enum AddressId {
k_after_break_target_address,
k_debug_break_return_address,
k_debug_break_slot_address,
k_register_address
};
@ -342,6 +348,12 @@ class Debug {
return &debug_break_return_;
}
// Access to the debug break in debug break slot code.
static Code* debug_break_slot() { return debug_break_slot_; }
static Code** debug_break_slot_address() {
return &debug_break_slot_;
}
static const int kEstimatedNofDebugInfoEntries = 16;
static const int kEstimatedNofBreakPointsInFunction = 16;
@ -370,6 +382,7 @@ class Debug {
static void AfterGarbageCollection();
// Code generator routines.
static void GenerateSlot(MacroAssembler* masm);
static void GenerateLoadICDebugBreak(MacroAssembler* masm);
static void GenerateStoreICDebugBreak(MacroAssembler* masm);
static void GenerateKeyedLoadICDebugBreak(MacroAssembler* masm);
@ -377,6 +390,7 @@ class Debug {
static void GenerateConstructCallDebugBreak(MacroAssembler* masm);
static void GenerateReturnDebugBreak(MacroAssembler* masm);
static void GenerateStubNoRegistersDebugBreak(MacroAssembler* masm);
static void GenerateSlotDebugBreak(MacroAssembler* masm);
static void GeneratePlainReturnLiveEdit(MacroAssembler* masm);
static void GenerateFrameDropperLiveEdit(MacroAssembler* masm);
@ -472,6 +486,9 @@ class Debug {
// Code to call for handling debug break on return.
static Code* debug_break_return_;
// Code to call for handling debug break in debug break slots.
static Code* debug_break_slot_;
DISALLOW_COPY_AND_ASSIGN(Debug);
};
@ -895,6 +912,8 @@ class Debug_Address {
return reinterpret_cast<Address>(Debug::after_break_target_address());
case Debug::k_debug_break_return_address:
return reinterpret_cast<Address>(Debug::debug_break_return_address());
case Debug::k_debug_break_slot_address:
return reinterpret_cast<Address>(Debug::debug_break_slot_address());
case Debug::k_register_address:
return reinterpret_cast<Address>(Debug::register_address(reg_));
default:

2
deps/v8/src/flag-definitions.h

@ -277,7 +277,7 @@ DEFINE_string(testing_serialization_file, "/tmp/serdes",
DEFINE_bool(help, false, "Print usage message, including flags, on console")
DEFINE_bool(dump_counters, false, "Dump counters on exit")
DEFINE_bool(debugger, true, "Enable JavaScript debugger")
DEFINE_bool(debugger, false, "Enable JavaScript debugger")
DEFINE_bool(remote_debugger, false, "Connect JavaScript debugger to the "
"debugger agent in another process")
DEFINE_bool(debugger_agent, false, "Enable debugger agent")

296
deps/v8/src/full-codegen.cc

@ -439,6 +439,231 @@ void FullCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) {
#undef CHECK_BAILOUT
void BreakableStatementChecker::Check(Statement* stmt) {
Visit(stmt);
}
void BreakableStatementChecker::Check(Expression* expr) {
Visit(expr);
}
void BreakableStatementChecker::VisitDeclaration(Declaration* decl) {
}
void BreakableStatementChecker::VisitBlock(Block* stmt) {
}
void BreakableStatementChecker::VisitExpressionStatement(
ExpressionStatement* stmt) {
// Check if expression is breakable.
Visit(stmt->expression());
}
void BreakableStatementChecker::VisitEmptyStatement(EmptyStatement* stmt) {
}
void BreakableStatementChecker::VisitIfStatement(IfStatement* stmt) {
// If the condition is breakable the if statement is breakable.
Visit(stmt->condition());
}
void BreakableStatementChecker::VisitContinueStatement(
ContinueStatement* stmt) {
}
void BreakableStatementChecker::VisitBreakStatement(BreakStatement* stmt) {
}
void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) {
// Return is breakable if the expression is.
Visit(stmt->expression());
}
void BreakableStatementChecker::VisitWithEnterStatement(
WithEnterStatement* stmt) {
Visit(stmt->expression());
}
void BreakableStatementChecker::VisitWithExitStatement(
WithExitStatement* stmt) {
}
void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) {
// Switch statements breakable if the tag expression is.
Visit(stmt->tag());
}
void BreakableStatementChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
// Mark do while as breakable to avoid adding a break slot in front of it.
is_breakable_ = true;
}
void BreakableStatementChecker::VisitWhileStatement(WhileStatement* stmt) {
// Mark while statements breakable if the condition expression is.
Visit(stmt->cond());
}
void BreakableStatementChecker::VisitForStatement(ForStatement* stmt) {
// Mark for statements breakable if the condition expression is.
if (stmt->cond() != NULL) {
Visit(stmt->cond());
}
}
void BreakableStatementChecker::VisitForInStatement(ForInStatement* stmt) {
// Mark for in statements breakable if the enumerable expression is.
Visit(stmt->enumerable());
}
void BreakableStatementChecker::VisitTryCatchStatement(
TryCatchStatement* stmt) {
// Mark try catch as breakable to avoid adding a break slot in front of it.
is_breakable_ = true;
}
void BreakableStatementChecker::VisitTryFinallyStatement(
TryFinallyStatement* stmt) {
// Mark try finally as breakable to avoid adding a break slot in front of it.
is_breakable_ = true;
}
void BreakableStatementChecker::VisitDebuggerStatement(
DebuggerStatement* stmt) {
// The debugger statement is breakable.
is_breakable_ = true;
}
void BreakableStatementChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
}
void BreakableStatementChecker::VisitSharedFunctionInfoLiteral(
SharedFunctionInfoLiteral* expr) {
}
void BreakableStatementChecker::VisitConditional(Conditional* expr) {
}
void BreakableStatementChecker::VisitSlot(Slot* expr) {
}
void BreakableStatementChecker::VisitVariableProxy(VariableProxy* expr) {
}
void BreakableStatementChecker::VisitLiteral(Literal* expr) {
}
void BreakableStatementChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
}
void BreakableStatementChecker::VisitObjectLiteral(ObjectLiteral* expr) {
}
void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) {
}
void BreakableStatementChecker::VisitCatchExtensionObject(
CatchExtensionObject* expr) {
}
void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
// If assigning to a property (including a global property) the assignment is
// breakable.
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
Property* prop = expr->target()->AsProperty();
if (prop != NULL || (var != NULL && var->is_global())) {
is_breakable_ = true;
return;
}
// Otherwise the assignment is breakable if the assigned value is.
Visit(expr->value());
}
void BreakableStatementChecker::VisitThrow(Throw* expr) {
// Throw is breakable if the expression is.
Visit(expr->exception());
}
void BreakableStatementChecker::VisitProperty(Property* expr) {
// Property load is breakable.
is_breakable_ = true;
}
void BreakableStatementChecker::VisitCall(Call* expr) {
// Function calls both through IC and call stub are breakable.
is_breakable_ = true;
}
void BreakableStatementChecker::VisitCallNew(CallNew* expr) {
// Function calls through new are breakable.
is_breakable_ = true;
}
void BreakableStatementChecker::VisitCallRuntime(CallRuntime* expr) {
}
void BreakableStatementChecker::VisitUnaryOperation(UnaryOperation* expr) {
Visit(expr->expression());
}
void BreakableStatementChecker::VisitCountOperation(CountOperation* expr) {
Visit(expr->expression());
}
void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) {
Visit(expr->left());
Visit(expr->right());
}
void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) {
Visit(expr->left());
Visit(expr->right());
}
void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) {
}
#define __ ACCESS_MASM(masm())
Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) {
@ -552,7 +777,60 @@ void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
if (FLAG_debug_info) {
#ifdef ENABLE_DEBUGGER_SUPPORT
if (!Debugger::IsDebuggerActive()) {
CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
} else {
// Check if the statement will be breakable without adding a debug break
// slot.
BreakableStatementChecker checker;
checker.Check(stmt);
// Record the statement position right here if the statement is not
// breakable. For breakable statements the actual recording of the
// position will be postponed to the breakable code (typically an IC).
bool position_recorded = CodeGenerator::RecordPositions(
masm_, stmt->statement_pos(), !checker.is_breakable());
// If the position recording did record a new position generate a debug
// break slot to make the statement breakable.
if (position_recorded) {
Debug::GenerateSlot(masm_);
}
}
#else
CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
#endif
}
}
void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) {
if (FLAG_debug_info) {
#ifdef ENABLE_DEBUGGER_SUPPORT
if (!Debugger::IsDebuggerActive()) {
CodeGenerator::RecordPositions(masm_, pos);
} else {
// Check if the expression will be breakable without adding a debug break
// slot.
BreakableStatementChecker checker;
checker.Check(expr);
// Record a statement position right here if the expression is not
// breakable. For breakable expressions the actual recording of the
// position will be postponed to the breakable code (typically an IC).
// NOTE this will record a statement position for something which might
// not be a statement. As stepping in the debugger will only stop at
// statement positions this is used for e.g. the condition expression of
// a do while loop.
bool position_recorded = CodeGenerator::RecordPositions(
masm_, pos, !checker.is_breakable());
// If the position recording did record a new position generate a debug
// break slot to make the statement breakable.
if (position_recorded) {
Debug::GenerateSlot(masm_);
}
}
#else
CodeGenerator::RecordPositions(masm_, pos);
#endif
}
}
@ -848,7 +1126,11 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
__ bind(&stack_check_success);
__ bind(loop_statement.continue_target());
SetStatementPosition(stmt->condition_position());
// Record the position of the do while condition and make sure it is possible
// to break on the condition.
SetExpressionPosition(stmt->cond(), stmt->condition_position());
VisitForControl(stmt->cond(), &body, loop_statement.break_target());
__ bind(&stack_limit_hit);
@ -864,7 +1146,6 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
Comment cmnt(masm_, "[ WhileStatement");
SetStatementPosition(stmt);
Label body, stack_limit_hit, stack_check_success;
Iteration loop_statement(this, stmt);
@ -877,6 +1158,9 @@ void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
Visit(stmt->body());
__ bind(loop_statement.continue_target());
// Emit the statement position here as this is where the while statement code
// starts.
SetStatementPosition(stmt);
// Check stack before looping.
__ StackLimitCheck(&stack_limit_hit);
@ -896,7 +1180,6 @@ void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
Comment cmnt(masm_, "[ ForStatement");
SetStatementPosition(stmt);
Label test, body, stack_limit_hit, stack_check_success;
Iteration loop_statement(this, stmt);
@ -919,6 +1202,9 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
}
__ bind(&test);
// Emit the statement position here as this is where the for statement code
// starts.
SetStatementPosition(stmt);
// Check stack before looping.
__ StackLimitCheck(&stack_limit_hit);
@ -1064,6 +1350,8 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
VisitForControl(expr->condition(), &true_case, &false_case);
__ bind(&true_case);
SetExpressionPosition(expr->then_expression(),
expr->then_expression_position());
Visit(expr->then_expression());
// If control flow falls through Visit, jump to done.
if (context_ == Expression::kEffect || context_ == Expression::kValue) {
@ -1071,6 +1359,8 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
}
__ bind(&false_case);
SetExpressionPosition(expr->else_expression(),
expr->else_expression_position());
Visit(expr->else_expression());
// If control flow falls through Visit, merge it with true case here.
if (context_ == Expression::kEffect || context_ == Expression::kValue) {

26
deps/v8/src/full-codegen.h

@ -59,6 +59,31 @@ class FullCodeGenSyntaxChecker: public AstVisitor {
};
// AST node visitor which can tell whether a given statement will be breakable
// when the code is compiled by the full compiler in the debugger. This means
// that there will be an IC (load/store/call) in the code generated for the
// debugger to piggybag on.
class BreakableStatementChecker: public AstVisitor {
public:
BreakableStatementChecker() : is_breakable_(false) {}
void Check(Statement* stmt);
void Check(Expression* stmt);
bool is_breakable() { return is_breakable_; }
private:
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
bool is_breakable_;
DISALLOW_COPY_AND_ASSIGN(BreakableStatementChecker);
};
// -----------------------------------------------------------------------------
// Full code generator.
@ -458,6 +483,7 @@ class FullCodeGenerator: public AstVisitor {
void SetFunctionPosition(FunctionLiteral* fun);
void SetReturnPosition(FunctionLiteral* fun);
void SetStatementPosition(Statement* stmt);
void SetExpressionPosition(Expression* expr, int pos);
void SetStatementPosition(int pos);
void SetSourcePosition(int pos);

8
deps/v8/src/heap-inl.h

@ -118,11 +118,9 @@ void Heap::FinalizeExternalString(String* string) {
ExternalString::kResourceOffset -
kHeapObjectTag);
// Dispose of the C++ object.
if (external_string_dispose_callback_ != NULL) {
external_string_dispose_callback_(*resource_addr);
} else {
delete *resource_addr;
// Dispose of the C++ object if it has not already been disposed.
if (*resource_addr != NULL) {
(*resource_addr)->Dispose();
}
// Clear the resource pointer in the string.

99
deps/v8/src/heap.cc

@ -98,8 +98,6 @@ size_t Heap::code_range_size_ = 0;
// set up by ConfigureHeap otherwise.
int Heap::reserved_semispace_size_ = Heap::max_semispace_size_;
ExternalStringDiposeCallback Heap::external_string_dispose_callback_ = NULL;
List<Heap::GCPrologueCallbackPair> Heap::gc_prologue_callbacks_;
List<Heap::GCEpilogueCallbackPair> Heap::gc_epilogue_callbacks_;
@ -607,6 +605,9 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
EnsureFromSpaceIsCommitted();
if (collector == MARK_COMPACTOR) {
// Flush all potentially unused code.
FlushCode();
// Perform mark-sweep with optional compaction.
MarkCompact(tracer);
@ -659,18 +660,19 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
void Heap::MarkCompact(GCTracer* tracer) {
gc_state_ = MARK_COMPACT;
if (MarkCompactCollector::IsCompacting()) {
mc_count_++;
} else {
ms_count_++;
}
tracer->set_full_gc_count(mc_count_);
LOG(ResourceEvent("markcompact", "begin"));
MarkCompactCollector::Prepare(tracer);
bool is_compacting = MarkCompactCollector::IsCompacting();
if (is_compacting) {
mc_count_++;
} else {
ms_count_++;
}
tracer->set_full_gc_count(mc_count_ + ms_count_);
MarkCompactPrologue(is_compacting);
MarkCompactCollector::CollectGarbage();
@ -2185,6 +2187,87 @@ Object* Heap::AllocateExternalArray(int length,
}
// The StackVisitor is used to traverse all the archived threads to see if
// there are activations on any of the stacks corresponding to the code.
class FlushingStackVisitor : public ThreadVisitor {
public:
explicit FlushingStackVisitor(Code* code) : found_(false), code_(code) {}
void VisitThread(ThreadLocalTop* top) {
// If we already found the code in a previous traversed thread we return.
if (found_) return;
for (StackFrameIterator it(top); !it.done(); it.Advance()) {
if (code_->contains(it.frame()->pc())) {
found_ = true;
return;
}
}
}
bool FoundCode() {return found_;}
private:
bool found_;
Code* code_;
};
static void FlushCodeForFunction(SharedFunctionInfo* function_info) {
// The function must be compiled and have the source code available,
// to be able to recompile it in case we need the function again.
if (!(function_info->is_compiled() && function_info->HasSourceCode())) return;
// We never flush code for Api functions.
if (function_info->IsApiFunction()) return;
// Only flush code for functions.
if (!function_info->code()->kind() == Code::FUNCTION) return;
// Function must be lazy compilable.
if (!function_info->allows_lazy_compilation()) return;
// If this is a full script wrapped in a function we do no flush the code.
if (function_info->is_toplevel()) return;
// If this function is in the compilation cache we do not flush the code.
if (CompilationCache::HasFunction(function_info)) return;
// Make sure we are not referencing the code from the stack.
for (StackFrameIterator it; !it.done(); it.Advance()) {
if (function_info->code()->contains(it.frame()->pc())) return;
}
// Iterate the archived stacks in all threads to check if
// the code is referenced.
FlushingStackVisitor threadvisitor(function_info->code());
ThreadManager::IterateArchivedThreads(&threadvisitor);
if (threadvisitor.FoundCode()) return;
HandleScope scope;
// Compute the lazy compilable version of the code.
function_info->set_code(*ComputeLazyCompile(function_info->length()));
}
void Heap::FlushCode() {
#ifdef ENABLE_DEBUGGER_SUPPORT
// Do not flush code if the debugger is loaded or there are breakpoints.
if (Debug::IsLoaded() || Debug::has_break_points()) return;
#endif
HeapObjectIterator it(old_pointer_space());
for (HeapObject* obj = it.next(); obj != NULL; obj = it.next()) {
if (obj->IsJSFunction()) {
JSFunction* jsfunction = JSFunction::cast(obj);
// The function must have a valid context and not be a builtin.
if (jsfunction->unchecked_context()->IsContext() &&
!jsfunction->IsBuiltin()) {
FlushCodeForFunction(jsfunction->shared());
}
}
}
}
Object* Heap::CreateCode(const CodeDesc& desc,
ZoneScopeInfo* sinfo,
Code::Flags flags,

12
deps/v8/src/heap.h

@ -690,11 +690,6 @@ class Heap : public AllStatic {
static bool GarbageCollectionGreedyCheck();
#endif
static void SetExternalStringDiposeCallback(
ExternalStringDiposeCallback callback) {
external_string_dispose_callback_ = callback;
}
static void AddGCPrologueCallback(
GCEpilogueCallback callback, GCType gc_type_filter);
static void RemoveGCPrologueCallback(GCEpilogueCallback callback);
@ -1143,9 +1138,6 @@ class Heap : public AllStatic {
// any string when looked up in properties.
static String* hidden_symbol_;
static ExternalStringDiposeCallback
external_string_dispose_callback_;
// GC callback function, called before and after mark-compact GC.
// Allocations in the callback function are disallowed.
struct GCPrologueCallbackPair {
@ -1274,6 +1266,10 @@ class Heap : public AllStatic {
// Flush the number to string cache.
static void FlushNumberStringCache();
// Flush code from functions we do not expect to use again. The code will
// be replaced with a lazy compilable version.
static void FlushCode();
static const int kInitialSymbolTableSize = 2048;
static const int kInitialEvalCacheSize = 64;

22
deps/v8/src/ia32/assembler-ia32-inl.h

@ -52,16 +52,21 @@ Condition NegateCondition(Condition cc) {
void RelocInfo::apply(intptr_t delta) {
if (rmode_ == RUNTIME_ENTRY || IsCodeTarget(rmode_)) {
int32_t* p = reinterpret_cast<int32_t*>(pc_);
*p -= delta; // relocate entry
*p -= delta; // Relocate entry.
} else if (rmode_ == JS_RETURN && IsPatchedReturnSequence()) {
// Special handling of js_return when a break point is set (call
// instruction has been inserted).
int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
*p -= delta; // relocate entry
*p -= delta; // Relocate entry.
} else if (rmode_ == DEBUG_BREAK_SLOT && IsPatchedDebugBreakSlotSequence()) {
// Special handling of a debug break slot when a break point is set (call
// instruction has been inserted).
int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
*p -= delta; // Relocate entry.
} else if (IsInternalReference(rmode_)) {
// absolute code pointer inside code object moves with the code object.
int32_t* p = reinterpret_cast<int32_t*>(pc_);
*p += delta; // relocate entry
*p += delta; // Relocate entry.
}
}
@ -154,6 +159,11 @@ bool RelocInfo::IsPatchedReturnSequence() {
}
bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
return !Assembler::IsNop(pc());
}
void RelocInfo::Visit(ObjectVisitor* visitor) {
RelocInfo::Mode mode = rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
@ -164,8 +174,10 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
visitor->VisitExternalReference(target_reference_address());
#ifdef ENABLE_DEBUGGER_SUPPORT
} else if (Debug::has_break_points() &&
RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) {
((RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(mode) &&
IsPatchedDebugBreakSlotSequence()))) {
visitor->VisitDebugTarget(this);
#endif
} else if (mode == RelocInfo::RUNTIME_ENTRY) {

17
deps/v8/src/ia32/assembler-ia32.cc

@ -206,6 +206,7 @@ void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
// Add the requested number of int3 instructions after the call.
ASSERT_GE(guard_bytes, 0);
for (int i = 0; i < guard_bytes; i++) {
patcher.masm()->int3();
}
@ -2371,6 +2372,13 @@ void Assembler::RecordJSReturn() {
}
void Assembler::RecordDebugBreakSlot() {
WriteRecordedPositions();
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
}
void Assembler::RecordComment(const char* msg) {
if (FLAG_debug_code) {
EnsureSpace ensure_space(this);
@ -2393,13 +2401,16 @@ void Assembler::RecordStatementPosition(int pos) {
}
void Assembler::WriteRecordedPositions() {
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
@ -2409,7 +2420,11 @@ void Assembler::WriteRecordedPositions() {
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::POSITION, current_position_);
written_position_ = current_position_;
written = true;
}
// Return whether something was written.
return written;
}

14
deps/v8/src/ia32/assembler-ia32.h

@ -468,9 +468,16 @@ class Assembler : public Malloced {
// to jump to.
static const int kPatchReturnSequenceAddressOffset = 1; // JMP imm32.
// Distance between start of patched debug break slot and the emitted address
// to jump to.
static const int kPatchDebugBreakSlotAddressOffset = 1; // JMP imm32.
static const int kCallInstructionLength = 5;
static const int kJSReturnSequenceLength = 6;
// The debug break slot must be able to contain a call instruction.
static const int kDebugBreakSlotLength = kCallInstructionLength;
// ---------------------------------------------------------------------------
// Code generation
//
@ -809,13 +816,16 @@ class Assembler : public Malloced {
// Mark address of the ExitJSFrame code.
void RecordJSReturn();
// Mark address of a debug break slot.
void RecordDebugBreakSlot();
// Record a comment relocation entry that can be used by a disassembler.
// Use --debug_code to enable.
void RecordComment(const char* msg);
void RecordPosition(int pos);
void RecordStatementPosition(int pos);
void WriteRecordedPositions();
bool WriteRecordedPositions();
// Writes a single word of data in the code stream.
// Used for inline tables, e.g., jump-tables.
@ -833,6 +843,8 @@ class Assembler : public Malloced {
// Get the number of bytes available in the buffer.
inline int available_space() const { return reloc_info_writer.pos() - pc_; }
static bool IsNop(Address addr) { return *addr == 0x90; }
// Avoid overflows for displacements etc.
static const int kMaximalBufferSize = 512*MB;
static const int kMinimalBufferSize = 4*KB;

4
deps/v8/src/ia32/codegen-ia32.h

@ -316,7 +316,9 @@ class CodeGenerator: public AstVisitor {
static bool ShouldGenerateLog(Expression* type);
#endif
static void RecordPositions(MacroAssembler* masm, int pos);
static bool RecordPositions(MacroAssembler* masm,
int pos,
bool right_here = false);
// Accessors
MacroAssembler* masm() { return masm_; }

42
deps/v8/src/ia32/debug-ia32.cc

@ -69,6 +69,27 @@ bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
}
bool BreakLocationIterator::IsDebugBreakAtSlot() {
ASSERT(IsDebugBreakSlot());
// Check whether the debug break slot instructions have been patched.
return rinfo()->IsPatchedDebugBreakSlotSequence();
}
void BreakLocationIterator::SetDebugBreakAtSlot() {
ASSERT(IsDebugBreakSlot());
rinfo()->PatchCodeWithCall(
Debug::debug_break_slot()->entry(),
Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
}
void BreakLocationIterator::ClearDebugBreakAtSlot() {
ASSERT(IsDebugBreakSlot());
rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
}
#define __ ACCESS_MASM(masm)
@ -208,10 +229,31 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
}
void Debug::GenerateSlot(MacroAssembler* masm) {
// Generate enough nop's to make space for a call instruction.
Label check_codesize;
__ bind(&check_codesize);
__ RecordDebugBreakSlot();
for (int i = 0; i < Assembler::kDebugBreakSlotLength; i++) {
__ nop();
}
ASSERT_EQ(Assembler::kDebugBreakSlotLength,
masm->SizeOfCodeGeneratedSince(&check_codesize));
}
void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
// In the places where a debug break slot is inserted no registers can contain
// object pointers.
Generate_DebugBreakCallHelper(masm, 0, true);
}
void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
masm->ret(0);
}
// FrameDropper is a code replacement for a JavaScript frame with possibly
// several frames above.
// There is no calling conventions here, because it never actually gets called,

14
deps/v8/src/ia32/disasm-ia32.cc

@ -924,14 +924,18 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
break;
case 0xF6:
{ int mod, regop, rm;
get_modrm(*(data+1), &mod, &regop, &rm);
if (mod == 3 && regop == eax) {
AppendToBuffer("test_b %s,%d", NameOfCPURegister(rm), *(data+2));
{ data++;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
if (regop == eax) {
AppendToBuffer("test_b ");
data += PrintRightOperand(data);
int32_t imm = *data;
AppendToBuffer(",0x%x", imm);
data++;
} else {
UnimplementedInstruction();
}
data += 3;
}
break;

18
deps/v8/src/mark-compact.cc

@ -273,8 +273,10 @@ class MarkingVisitor : public ObjectVisitor {
}
void VisitDebugTarget(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) &&
rinfo->IsPatchedReturnSequence());
ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
rinfo->IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
rinfo->IsPatchedDebugBreakSlotSequence()));
HeapObject* code = Code::GetCodeFromTargetAddress(rinfo->call_address());
MarkCompactCollector::MarkObject(code);
}
@ -1106,8 +1108,10 @@ class PointersToNewGenUpdatingVisitor: public ObjectVisitor {
}
void VisitDebugTarget(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) &&
rinfo->IsPatchedReturnSequence());
ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
rinfo->IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
rinfo->IsPatchedDebugBreakSlotSequence()));
Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
VisitPointer(&target);
rinfo->set_call_address(Code::cast(target)->instruction_start());
@ -1856,8 +1860,10 @@ class UpdatingVisitor: public ObjectVisitor {
}
void VisitDebugTarget(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) &&
rinfo->IsPatchedReturnSequence());
ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
rinfo->IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
rinfo->IsPatchedDebugBreakSlotSequence()));
Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
VisitPointer(&target);
rinfo->set_call_address(

9
deps/v8/src/mips/assembler-mips.cc

@ -1046,13 +1046,16 @@ void Assembler::RecordStatementPosition(int pos) {
}
void Assembler::WriteRecordedPositions() {
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
@ -1062,7 +1065,11 @@ void Assembler::WriteRecordedPositions() {
CheckBuffer();
RecordRelocInfo(RelocInfo::POSITION, current_position_);
written_position_ = current_position_;
written = true;
}
// Return whether something was written.
return written;
}

5
deps/v8/src/mips/assembler-mips.h

@ -355,6 +355,9 @@ class Assembler : public Malloced {
// to jump to.
static const int kPatchReturnSequenceAddressOffset = kInstrSize;
// Distance between start of patched debug break slot and the emitted address
// to jump to.
static const int kPatchDebugBreakSlotAddressOffset = kInstrSize;
// ---------------------------------------------------------------------------
// Code generation.
@ -518,7 +521,7 @@ class Assembler : public Malloced {
void RecordPosition(int pos);
void RecordStatementPosition(int pos);
void WriteRecordedPositions();
bool WriteRecordedPositions();
int32_t pc_offset() const { return pc_ - buffer_; }
int32_t current_position() const { return current_position_; }

4
deps/v8/src/objects-inl.h

@ -2468,6 +2468,10 @@ BOOL_ACCESSORS(SharedFunctionInfo,
compiler_hints,
try_full_codegen,
kTryFullCodegen)
BOOL_ACCESSORS(SharedFunctionInfo,
compiler_hints,
allows_lazy_compilation,
kAllowLazyCompilation)
#if V8_HOST_ARCH_32_BIT
SMI_ACCESSORS(SharedFunctionInfo, length, kLengthOffset)

7
deps/v8/src/objects.cc

@ -5264,8 +5264,10 @@ void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()) &&
rinfo->IsPatchedReturnSequence());
ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
rinfo->IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
rinfo->IsPatchedDebugBreakSlotSequence()));
Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
Object* old_target = target;
VisitPointer(&target);
@ -5278,6 +5280,7 @@ void Code::CodeIterateBody(ObjectVisitor* v) {
RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
RelocInfo::ModeMask(RelocInfo::JS_RETURN) |
RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {

7
deps/v8/src/objects.h

@ -3308,6 +3308,12 @@ class SharedFunctionInfo: public HeapObject {
inline bool try_full_codegen();
inline void set_try_full_codegen(bool flag);
// Indicates if this function can be lazy compiled.
// This is used to determine if we can safely flush code from a function
// when doing GC if we expect that the function will no longer be used.
inline bool allows_lazy_compilation();
inline void set_allows_lazy_compilation(bool flag);
// Check whether a inlined constructor can be generated with the given
// prototype.
bool CanGenerateInlineConstructor(Object* prototype);
@ -3433,6 +3439,7 @@ class SharedFunctionInfo: public HeapObject {
// Bit positions in compiler_hints.
static const int kHasOnlySimpleThisPropertyAssignments = 0;
static const int kTryFullCodegen = 1;
static const int kAllowLazyCompilation = 2;
DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
};

5
deps/v8/src/parser.cc

@ -2867,10 +2867,13 @@ Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
// In parsing the first assignment expression in conditional
// expressions we always accept the 'in' keyword; see ECMA-262,
// section 11.12, page 58.
int left_position = scanner().peek_location().beg_pos;
Expression* left = ParseAssignmentExpression(true, CHECK_OK);
Expect(Token::COLON, CHECK_OK);
int right_position = scanner().peek_location().beg_pos;
Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
return NEW(Conditional(expression, left, right));
return NEW(Conditional(expression, left, right,
left_position, right_position));
}

96
deps/v8/src/profile-generator.cc

@ -55,7 +55,7 @@ TokenEnumerator::~TokenEnumerator() {
int TokenEnumerator::GetTokenId(Object* token) {
if (token == NULL) return CodeEntry::kNoSecurityToken;
if (token == NULL) return TokenEnumerator::kNoSecurityToken;
for (int i = 0; i < token_locations_.length(); ++i) {
if (*token_locations_[i] == token && !token_removed_[i]) return i;
}
@ -86,6 +86,37 @@ void TokenEnumerator::TokenRemoved(Object** token_location) {
}
StringsStorage::StringsStorage()
: names_(StringsMatch) {
}
StringsStorage::~StringsStorage() {
for (HashMap::Entry* p = names_.Start();
p != NULL;
p = names_.Next(p)) {
DeleteArray(reinterpret_cast<const char*>(p->value));
}
}
const char* StringsStorage::GetName(String* name) {
if (name->IsString()) {
char* c_name =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach();
HashMap::Entry* cache_entry = names_.Lookup(c_name, name->Hash(), true);
if (cache_entry->value == NULL) {
// New entry added.
cache_entry->value = c_name;
} else {
DeleteArray(c_name);
}
return reinterpret_cast<const char*>(cache_entry->value);
}
return "";
}
const char* CodeEntry::kEmptyNamePrefix = "";
unsigned CodeEntry::next_call_uid_ = 1;
@ -171,7 +202,7 @@ ProfileTree::ProfileTree()
"(root)",
"",
0,
CodeEntry::kNoSecurityToken),
TokenEnumerator::kNoSecurityToken),
root_(new ProfileNode(this, &root_entry_)) {
}
@ -248,11 +279,11 @@ class FilteredCloneCallback {
private:
bool IsTokenAcceptable(int token, int parent_token) {
if (token == CodeEntry::kNoSecurityToken
if (token == TokenEnumerator::kNoSecurityToken
|| token == security_token_id_) return true;
if (token == CodeEntry::kInheritsSecurityToken) {
ASSERT(parent_token != CodeEntry::kInheritsSecurityToken);
return parent_token == CodeEntry::kNoSecurityToken
if (token == TokenEnumerator::kInheritsSecurityToken) {
ASSERT(parent_token != TokenEnumerator::kInheritsSecurityToken);
return parent_token == TokenEnumerator::kNoSecurityToken
|| parent_token == security_token_id_;
}
return false;
@ -373,7 +404,7 @@ void CpuProfile::SetActualSamplingRate(double actual_sampling_rate) {
CpuProfile* CpuProfile::FilteredClone(int security_token_id) {
ASSERT(security_token_id != CodeEntry::kNoSecurityToken);
ASSERT(security_token_id != TokenEnumerator::kNoSecurityToken);
CpuProfile* clone = new CpuProfile(title_, uid_);
clone->top_down_.FilteredClone(&top_down_, security_token_id);
clone->bottom_up_.FilteredClone(&bottom_up_, security_token_id);
@ -438,8 +469,7 @@ void CodeMap::Print() {
CpuProfilesCollection::CpuProfilesCollection()
: function_and_resource_names_(StringsMatch),
profiles_uids_(UidsMatch),
: profiles_uids_(UidsMatch),
current_profiles_semaphore_(OS::CreateSemaphore(1)) {
// Create list of unabridged profiles.
profiles_by_token_.Add(new List<CpuProfile*>());
@ -470,11 +500,6 @@ CpuProfilesCollection::~CpuProfilesCollection() {
profiles_by_token_.Iterate(DeleteProfilesList);
code_entries_.Iterate(DeleteCodeEntry);
args_count_names_.Iterate(DeleteArgsCountName);
for (HashMap::Entry* p = function_and_resource_names_.Start();
p != NULL;
p = function_and_resource_names_.Next(p)) {
DeleteArray(reinterpret_cast<const char*>(p->value));
}
}
@ -517,7 +542,7 @@ CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id,
profile->CalculateTotalTicks();
profile->SetActualSamplingRate(actual_sampling_rate);
List<CpuProfile*>* unabridged_list =
profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)];
profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
unabridged_list->Add(profile);
HashMap::Entry* entry =
profiles_uids_.Lookup(reinterpret_cast<void*>(profile->uid()),
@ -550,8 +575,8 @@ CpuProfile* CpuProfilesCollection::GetProfile(int security_token_id,
return NULL;
}
List<CpuProfile*>* unabridged_list =
profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)];
if (security_token_id == CodeEntry::kNoSecurityToken) {
profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
if (security_token_id == TokenEnumerator::kNoSecurityToken) {
return unabridged_list->at(index);
}
List<CpuProfile*>* list = GetProfilesList(security_token_id);
@ -564,7 +589,7 @@ CpuProfile* CpuProfilesCollection::GetProfile(int security_token_id,
int CpuProfilesCollection::TokenToIndex(int security_token_id) {
ASSERT(CodeEntry::kNoSecurityToken == -1);
ASSERT(TokenEnumerator::kNoSecurityToken == -1);
return security_token_id + 1; // kNoSecurityToken -> 0, 0 -> 1, ...
}
@ -575,7 +600,7 @@ List<CpuProfile*>* CpuProfilesCollection::GetProfilesList(
const int lists_to_add = index - profiles_by_token_.length() + 1;
if (lists_to_add > 0) profiles_by_token_.AddBlock(NULL, lists_to_add);
List<CpuProfile*>* unabridged_list =
profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)];
profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
const int current_count = unabridged_list->length();
if (profiles_by_token_[index] == NULL) {
profiles_by_token_[index] = new List<CpuProfile*>(current_count);
@ -589,8 +614,8 @@ List<CpuProfile*>* CpuProfilesCollection::GetProfilesList(
List<CpuProfile*>* CpuProfilesCollection::Profiles(int security_token_id) {
List<CpuProfile*>* unabridged_list =
profiles_by_token_[TokenToIndex(CodeEntry::kNoSecurityToken)];
if (security_token_id == CodeEntry::kNoSecurityToken) {
profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
if (security_token_id == TokenEnumerator::kNoSecurityToken) {
return unabridged_list;
}
List<CpuProfile*>* list = GetProfilesList(security_token_id);
@ -613,7 +638,7 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
GetFunctionName(name),
GetName(resource_name),
line_number,
CodeEntry::kNoSecurityToken);
TokenEnumerator::kNoSecurityToken);
code_entries_.Add(entry);
return entry;
}
@ -626,7 +651,7 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
GetFunctionName(name),
"",
v8::CpuProfileNode::kNoLineNumberInfo,
CodeEntry::kNoSecurityToken);
TokenEnumerator::kNoSecurityToken);
code_entries_.Add(entry);
return entry;
}
@ -640,7 +665,7 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
GetName(name),
"",
v8::CpuProfileNode::kNoLineNumberInfo,
CodeEntry::kInheritsSecurityToken);
TokenEnumerator::kInheritsSecurityToken);
code_entries_.Add(entry);
return entry;
}
@ -653,7 +678,7 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
GetName(args_count),
"",
v8::CpuProfileNode::kNoLineNumberInfo,
CodeEntry::kInheritsSecurityToken);
TokenEnumerator::kInheritsSecurityToken);
code_entries_.Add(entry);
return entry;
}
@ -666,27 +691,6 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(int security_token_id) {
}
const char* CpuProfilesCollection::GetName(String* name) {
if (name->IsString()) {
char* c_name =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach();
HashMap::Entry* cache_entry =
function_and_resource_names_.Lookup(c_name,
name->Hash(),
true);
if (cache_entry->value == NULL) {
// New entry added.
cache_entry->value = c_name;
} else {
DeleteArray(c_name);
}
return reinterpret_cast<const char*>(cache_entry->value);
} else {
return "";
}
}
const char* CpuProfilesCollection::GetName(int args_count) {
ASSERT(args_count >= 0);
if (args_count_names_.length() <= args_count) {

39
deps/v8/src/profile-generator.h

@ -41,6 +41,9 @@ class TokenEnumerator {
~TokenEnumerator();
int GetTokenId(Object* token);
static const int kNoSecurityToken = -1;
static const int kInheritsSecurityToken = -2;
private:
static void TokenRemovedCallback(v8::Persistent<v8::Value> handle,
void* parameter);
@ -53,6 +56,28 @@ class TokenEnumerator {
};
// Provides a storage of strings allocated in C++ heap, to hold them
// forever, even if they disappear from JS heap or external storage.
class StringsStorage {
public:
StringsStorage();
~StringsStorage();
const char* GetName(String* name);
private:
INLINE(static bool StringsMatch(void* key1, void* key2)) {
return strcmp(reinterpret_cast<char*>(key1),
reinterpret_cast<char*>(key2)) == 0;
}
// String::Hash -> const char*
HashMap names_;
DISALLOW_COPY_AND_ASSIGN(StringsStorage);
};
class CodeEntry {
public:
explicit INLINE(CodeEntry(int security_token_id));
@ -78,8 +103,6 @@ class CodeEntry {
void CopyData(const CodeEntry& source);
static const char* kEmptyNamePrefix;
static const int kNoSecurityToken = -1;
static const int kInheritsSecurityToken = -2;
private:
unsigned call_uid_;
@ -257,10 +280,12 @@ class CpuProfilesCollection {
String* title,
double actual_sampling_rate);
List<CpuProfile*>* Profiles(int security_token_id);
const char* GetName(String* name) {
return function_and_resource_names_.GetName(name);
}
CpuProfile* GetProfile(int security_token_id, unsigned uid);
inline bool is_last_profile();
const char* GetName(String* name);
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
String* name, String* resource_name, int line_number);
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name);
@ -279,17 +304,11 @@ class CpuProfilesCollection {
List<CpuProfile*>* GetProfilesList(int security_token_id);
int TokenToIndex(int security_token_id);
INLINE(static bool StringsMatch(void* key1, void* key2)) {
return strcmp(reinterpret_cast<char*>(key1),
reinterpret_cast<char*>(key2)) == 0;
}
INLINE(static bool UidsMatch(void* key1, void* key2)) {
return key1 == key2;
}
// String::Hash -> const char*
HashMap function_and_resource_names_;
StringsStorage function_and_resource_names_;
// args_count -> char*
List<char*> args_count_names_;
List<CodeEntry*> code_entries_;

4
deps/v8/src/serialize.cc

@ -229,6 +229,10 @@ void ExternalReferenceTable::PopulateTable() {
DEBUG_ADDRESS,
Debug::k_after_break_target_address << kDebugIdShift,
"Debug::after_break_target_address()");
Add(Debug_Address(Debug::k_debug_break_slot_address).address(),
DEBUG_ADDRESS,
Debug::k_debug_break_slot_address << kDebugIdShift,
"Debug::debug_break_slot_address()");
Add(Debug_Address(Debug::k_debug_break_return_address).address(),
DEBUG_ADDRESS,
Debug::k_debug_break_return_address << kDebugIdShift,

2
deps/v8/src/version.cc

@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 2
#define MINOR_VERSION 2
#define BUILD_NUMBER 15
#define BUILD_NUMBER 16
#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false

15
deps/v8/src/x64/assembler-x64-inl.h

@ -210,6 +210,10 @@ void RelocInfo::apply(intptr_t delta) {
// Special handling of js_return when a break point is set (call
// instruction has been inserted).
Memory::int32_at(pc_ + 1) -= static_cast<int32_t>(delta); // relocate entry
} else if (rmode_ == DEBUG_BREAK_SLOT && IsPatchedDebugBreakSlotSequence()) {
// Special handling of debug break slot when a break point is set (call
// instruction has been inserted).
Memory::int32_at(pc_ + 1) -= static_cast<int32_t>(delta); // relocate entry
}
}
@ -298,6 +302,11 @@ bool RelocInfo::IsPatchedReturnSequence() {
}
bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
return !Assembler::IsNop(pc());
}
Address RelocInfo::call_address() {
ASSERT(IsPatchedReturnSequence());
return Memory::Address_at(
@ -341,8 +350,10 @@ void RelocInfo::Visit(ObjectVisitor* visitor) {
visitor->VisitExternalReference(target_reference_address());
#ifdef ENABLE_DEBUGGER_SUPPORT
} else if (Debug::has_break_points() &&
RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) {
((RelocInfo::IsJSReturn(mode) &&
IsPatchedReturnSequence()) ||
(RelocInfo::IsDebugBreakSlot(mode) &&
IsPatchedDebugBreakSlotSequence()))) {
visitor->VisitDebugTarget(this);
#endif
} else if (mode == RelocInfo::RUNTIME_ENTRY) {

16
deps/v8/src/x64/assembler-x64.cc

@ -2800,6 +2800,13 @@ void Assembler::RecordJSReturn() {
}
void Assembler::RecordDebugBreakSlot() {
WriteRecordedPositions();
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
}
void Assembler::RecordComment(const char* msg) {
if (FLAG_debug_code) {
EnsureSpace ensure_space(this);
@ -2822,13 +2829,16 @@ void Assembler::RecordStatementPosition(int pos) {
}
void Assembler::WriteRecordedPositions() {
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
@ -2838,7 +2848,11 @@ void Assembler::WriteRecordedPositions() {
EnsureSpace ensure_space(this);
RecordRelocInfo(RelocInfo::POSITION, current_position_);
written_position_ = current_position_;
written = true;
}
// Return whether something was written.
return written;
}

16
deps/v8/src/x64/assembler-x64.h

@ -455,6 +455,11 @@ class Assembler : public Malloced {
// return address. TODO: Use return sequence length instead.
// Should equal Debug::kX64JSReturnSequenceLength - kCallTargetAddressOffset;
static const int kPatchReturnSequenceAddressOffset = 13 - 4;
// Distance between start of patched debug break slot and where the
// 32-bit displacement of a near call would be, relative to the pushed
// return address. TODO: Use return sequence length instead.
// Should equal Debug::kX64JSReturnSequenceLength - kCallTargetAddressOffset;
static const int kPatchDebugBreakSlotAddressOffset = 13 - 4;
// TODO(X64): Rename this, removing the "Real", after changing the above.
static const int kRealPatchReturnSequenceAddressOffset = 2;
@ -463,6 +468,10 @@ class Assembler : public Malloced {
static const int kCallInstructionLength = 13;
static const int kJSReturnSequenceLength = 13;
// The debug break slot must be able to contain a call instruction.
static const int kDebugBreakSlotLength = kCallInstructionLength;
// ---------------------------------------------------------------------------
// Code generation
//
@ -1135,13 +1144,16 @@ class Assembler : public Malloced {
// Mark address of the ExitJSFrame code.
void RecordJSReturn();
// Mark address of a debug break slot.
void RecordDebugBreakSlot();
// Record a comment relocation entry that can be used by a disassembler.
// Use --debug_code to enable.
void RecordComment(const char* msg);
void RecordPosition(int pos);
void RecordStatementPosition(int pos);
void WriteRecordedPositions();
bool WriteRecordedPositions();
int pc_offset() const { return static_cast<int>(pc_ - buffer_); }
int current_statement_position() const { return current_statement_position_; }
@ -1159,6 +1171,8 @@ class Assembler : public Malloced {
return static_cast<int>(reloc_info_writer.pos() - pc_);
}
static bool IsNop(Address addr) { return *addr == 0x90; }
// Avoid overflows for displacements etc.
static const int kMaximalBufferSize = 512*MB;
static const int kMinimalBufferSize = 4*KB;

4
deps/v8/src/x64/codegen-x64.h

@ -314,7 +314,9 @@ class CodeGenerator: public AstVisitor {
static bool ShouldGenerateLog(Expression* type);
#endif
static void RecordPositions(MacroAssembler* masm, int pos);
static bool RecordPositions(MacroAssembler* masm,
int pos,
bool right_here = false);
// Accessors
MacroAssembler* masm() { return masm_; }

43
deps/v8/src/x64/debug-x64.cc

@ -181,10 +181,31 @@ void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
}
void Debug::GenerateSlot(MacroAssembler* masm) {
// Generate enough nop's to make space for a call instruction.
Label check_codesize;
__ bind(&check_codesize);
__ RecordDebugBreakSlot();
for (int i = 0; i < Assembler::kDebugBreakSlotLength; i++) {
__ nop();
}
ASSERT_EQ(Assembler::kDebugBreakSlotLength,
masm->SizeOfCodeGeneratedSince(&check_codesize));
}
void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
// In the places where a debug break slot is inserted no registers can contain
// object pointers.
Generate_DebugBreakCallHelper(masm, 0, true);
}
void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
masm->Abort("LiveEdit frame dropping is not supported on x64");
}
void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
masm->Abort("LiveEdit frame dropping is not supported on x64");
}
@ -217,6 +238,28 @@ void BreakLocationIterator::SetDebugBreakAtReturn() {
Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
}
bool BreakLocationIterator::IsDebugBreakAtSlot() {
ASSERT(IsDebugBreakSlot());
// Check whether the debug break slot instructions have been patched.
return !Assembler::IsNop(rinfo()->pc());
}
void BreakLocationIterator::SetDebugBreakAtSlot() {
ASSERT(IsDebugBreakSlot());
rinfo()->PatchCodeWithCall(
Debug::debug_break_slot()->entry(),
Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
}
void BreakLocationIterator::ClearDebugBreakAtSlot() {
ASSERT(IsDebugBreakSlot());
rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
}
#endif // ENABLE_DEBUGGER_SUPPORT
} } // namespace v8::internal

71
deps/v8/test/cctest/test-api.cc

@ -612,30 +612,33 @@ THREADED_TEST(ScavengeExternalAsciiString) {
}
static int dispose_count = 0;
static void DisposeExternalStringCount(
String::ExternalStringResourceBase* resource) {
dispose_count++;
}
class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
public:
static int dispose_calls;
TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
: TestAsciiResource(data),
dispose_(dispose) { }
static void DisposeExternalStringDeleteAndCount(
String::ExternalStringResourceBase* resource) {
delete resource;
dispose_count++;
}
void Dispose() {
++dispose_calls;
if (dispose_) delete this;
}
private:
bool dispose_;
};
TEST(ExternalStringWithResourceDisposeCallback) {
const char* c_source = "1 + 2 * 3";
int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
// Set an external string collected callback which does not delete the object.
v8::V8::SetExternalStringDiposeCallback(DisposeExternalStringCount);
TEST(ExternalStringWithDisposeHandling) {
const char* c_source = "1 + 2 * 3";
// Use a stack allocated external string resource allocated object.
dispose_count = 0;
TestAsciiResource::dispose_count = 0;
TestAsciiResource res_stack(i::StrDup(c_source));
TestAsciiResourceWithDisposeControl::dispose_calls = 0;
TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
{
v8::HandleScope scope;
LocalContext env;
@ -649,16 +652,14 @@ TEST(ExternalStringWithResourceDisposeCallback) {
}
v8::internal::CompilationCache::Clear();
v8::internal::Heap::CollectAllGarbage(false);
CHECK_EQ(1, dispose_count);
CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
CHECK_EQ(0, TestAsciiResource::dispose_count);
// Set an external string collected callback which does delete the object.
v8::V8::SetExternalStringDiposeCallback(DisposeExternalStringDeleteAndCount);
// Use a heap allocated external string resource allocated object.
dispose_count = 0;
TestAsciiResource::dispose_count = 0;
TestAsciiResource* res_heap = new TestAsciiResource(i::StrDup(c_source));
TestAsciiResourceWithDisposeControl::dispose_calls = 0;
TestAsciiResource* res_heap =
new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
{
v8::HandleScope scope;
LocalContext env;
@ -672,7 +673,7 @@ TEST(ExternalStringWithResourceDisposeCallback) {
}
v8::internal::CompilationCache::Clear();
v8::internal::Heap::CollectAllGarbage(false);
CHECK_EQ(1, dispose_count);
CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
CHECK_EQ(1, TestAsciiResource::dispose_count);
}
@ -8497,6 +8498,30 @@ TEST(PreCompileDeserializationError) {
}
// Verifies that the Handle<String> and const char* versions of the API produce
// the same results (at least for one trivial case).
TEST(PreCompileAPIVariationsAreSame) {
v8::V8::Initialize();
v8::HandleScope scope;
const char* cstring = "function foo(a) { return a+1; }";
v8::ScriptData* sd_from_cstring =
v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
TestAsciiResource* resource = new TestAsciiResource(cstring);
v8::ScriptData* sd_from_istring = v8::ScriptData::PreCompile(
v8::String::NewExternal(resource));
CHECK_EQ(sd_from_cstring->Length(), sd_from_istring->Length());
CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
sd_from_istring->Data(),
sd_from_cstring->Length()));
delete sd_from_cstring;
delete sd_from_istring;
}
// This tests that we do not allow dictionary load/call inline caches
// to use functions that have not yet been compiled. The potential
// problem of loading a function that has not yet been compiled can

5
deps/v8/test/cctest/test-cpu-profiler.cc

@ -16,6 +16,7 @@ using i::CpuProfilesCollection;
using i::ProfileGenerator;
using i::ProfileNode;
using i::ProfilerEventsProcessor;
using i::TokenEnumerator;
TEST(StartStop) {
@ -115,7 +116,7 @@ TEST(CodeEvents) {
processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
processor.CodeDeleteEvent(ToAddress(0x1600));
processor.FunctionCreateEvent(ToAddress(0x1700), ToAddress(0x1000),
CodeEntry::kNoSecurityToken);
TokenEnumerator::kNoSecurityToken);
// Enqueue a tick event to enable code events processing.
EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
@ -178,7 +179,7 @@ TEST(TickEvents) {
processor.Stop();
processor.Join();
CpuProfile* profile =
profiles.StopProfiling(CodeEntry::kNoSecurityToken, "", 1);
profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
CHECK_NE(NULL, profile);
// Check call trees.

417
deps/v8/test/cctest/test-debug.cc

@ -1231,6 +1231,11 @@ TEST(GCDuringBreakPointProcessing) {
SetBreakPoint(foo, 0);
CallWithBreakPoints(env->Global(), foo, 1, 25);
// Test debug break slot break point with garbage collection.
foo = CompileFunction(&env, "function foo(){var a;}", "foo");
SetBreakPoint(foo, 0);
CallWithBreakPoints(env->Global(), foo, 1, 25);
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
@ -1660,7 +1665,7 @@ TEST(ConditionalScriptBreakPoint) {
f->Call(env->Global(), 0, NULL);
CHECK_EQ(1, break_point_hit_count);
ChangeScriptBreakPointConditionFromJS(sbp1, "a % 2 == 0");
ChangeScriptBreakPointConditionFromJS(sbp1, "x % 2 == 0");
break_point_hit_count = 0;
for (int i = 0; i < 10; i++) {
f->Call(env->Global(), 0, NULL);
@ -2144,17 +2149,19 @@ TEST(DebugEvaluate) {
v8::Local<v8::Function> foo = CompileFunction(&env,
"function foo(x) {"
" var a;"
" y=0; /* To ensure break location.*/"
" y=0;" // To ensure break location 1.
" a=x;"
" y=0;" // To ensure break location 2.
"}",
"foo");
const int foo_break_position = 15;
const int foo_break_position_1 = 15;
const int foo_break_position_2 = 29;
// Arguments with one parameter "Hello, world!"
v8::Handle<v8::Value> argv_foo[1] = { v8::String::New("Hello, world!") };
// Call foo with breakpoint set before a=x and undefined as parameter.
int bp = SetBreakPoint(foo, foo_break_position);
int bp = SetBreakPoint(foo, foo_break_position_1);
checks = checks_uu;
foo->Call(env->Global(), 0, NULL);
@ -2164,7 +2171,7 @@ TEST(DebugEvaluate) {
// Call foo with breakpoint set after a=x and parameter "Hello, world!".
ClearBreakPoint(bp);
SetBreakPoint(foo, foo_break_position + 1);
SetBreakPoint(foo, foo_break_position_2);
checks = checks_hh;
foo->Call(env->Global(), 1, argv_foo);
@ -2426,6 +2433,9 @@ TEST(DebugStepKeyedLoadLoop) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping of keyed load. The statement 'y=1'
// is there to have more than one breakable statement in the loop, TODO(315).
v8::Local<v8::Function> foo = CompileFunction(
@ -2451,9 +2461,6 @@ TEST(DebugStepKeyedLoadLoop) {
v8::Handle<v8::Value> args[kArgc] = { a };
foo->Call(env->Global(), kArgc, args);
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Setup break point and step through the function.
SetBreakPoint(foo, 3);
step_action = StepNext;
@ -2461,7 +2468,7 @@ TEST(DebugStepKeyedLoadLoop) {
foo->Call(env->Global(), kArgc, args);
// With stepping all break locations are hit.
CHECK_EQ(22, break_point_hit_count);
CHECK_EQ(33, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
@ -2473,6 +2480,9 @@ TEST(DebugStepKeyedStoreLoop) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping of keyed store. The statement 'y=1'
// is there to have more than one breakable statement in the loop, TODO(315).
v8::Local<v8::Function> foo = CompileFunction(
@ -2497,9 +2507,6 @@ TEST(DebugStepKeyedStoreLoop) {
v8::Handle<v8::Value> args[kArgc] = { a };
foo->Call(env->Global(), kArgc, args);
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Setup break point and step through the function.
SetBreakPoint(foo, 3);
step_action = StepNext;
@ -2507,7 +2514,7 @@ TEST(DebugStepKeyedStoreLoop) {
foo->Call(env->Global(), kArgc, args);
// With stepping all break locations are hit.
CHECK_EQ(22, break_point_hit_count);
CHECK_EQ(32, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
@ -2519,6 +2526,9 @@ TEST(DebugStepNamedLoadLoop) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping of named load.
v8::Local<v8::Function> foo = CompileFunction(
&env,
@ -2541,9 +2551,6 @@ TEST(DebugStepNamedLoadLoop) {
// Call function without any break points to ensure inlining is in place.
foo->Call(env->Global(), 0, NULL);
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Setup break point and step through the function.
SetBreakPoint(foo, 4);
step_action = StepNext;
@ -2551,7 +2558,7 @@ TEST(DebugStepNamedLoadLoop) {
foo->Call(env->Global(), 0, NULL);
// With stepping all break locations are hit.
CHECK_EQ(41, break_point_hit_count);
CHECK_EQ(53, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
@ -2563,6 +2570,9 @@ TEST(DebugStepLinearMixedICs) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping.
v8::Local<v8::Function> foo = CompileFunction(&env,
"function bar() {};"
@ -2573,15 +2583,12 @@ TEST(DebugStepLinearMixedICs) {
" a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
SetBreakPoint(foo, 0);
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
step_action = StepIn;
break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL);
// With stepping all break locations are hit.
CHECK_EQ(8, break_point_hit_count);
CHECK_EQ(11, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
@ -2601,6 +2608,66 @@ TEST(DebugStepLinearMixedICs) {
}
TEST(DebugStepDeclarations) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping.
const char* src = "function foo() { "
" var a;"
" var b = 1;"
" var c = foo;"
" var d = Math.floor;"
" var e = b + d(1.2);"
"}";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 0);
// Stepping through the declarations.
step_action = StepIn;
break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(6, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
TEST(DebugStepLocals) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping.
const char* src = "function foo() { "
" var a,b;"
" a = 1;"
" b = a + 2;"
" b = 1 + 2 + 3;"
" a = Math.floor(b);"
"}";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 0);
// Stepping through the declarations.
step_action = StepIn;
break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(6, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
TEST(DebugStepIf) {
v8::HandleScope scope;
DebugLocalContext env;
@ -2627,14 +2694,14 @@ TEST(DebugStepIf) {
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
foo->Call(env->Global(), argc, argv_true);
CHECK_EQ(3, break_point_hit_count);
CHECK_EQ(4, break_point_hit_count);
// Stepping through the false part.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_false[argc] = { v8::False() };
foo->Call(env->Global(), argc, argv_false);
CHECK_EQ(4, break_point_hit_count);
CHECK_EQ(5, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
@ -2662,6 +2729,7 @@ TEST(DebugStepSwitch) {
" case 3:"
" d = 1;"
" e = 1;"
" f = 1;"
" break;"
" }"
"}";
@ -2673,21 +2741,97 @@ TEST(DebugStepSwitch) {
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_1[argc] = { v8::Number::New(1) };
foo->Call(env->Global(), argc, argv_1);
CHECK_EQ(4, break_point_hit_count);
CHECK_EQ(6, break_point_hit_count);
// Another case.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_2[argc] = { v8::Number::New(2) };
foo->Call(env->Global(), argc, argv_2);
CHECK_EQ(3, break_point_hit_count);
CHECK_EQ(5, break_point_hit_count);
// Last case.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_3[argc] = { v8::Number::New(3) };
foo->Call(env->Global(), argc, argv_3);
CHECK_EQ(4, break_point_hit_count);
CHECK_EQ(7, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
TEST(DebugStepWhile) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping.
const int argc = 1;
const char* src = "function foo(x) { "
" var a = 0;"
" while (a < x) {"
" a++;"
" }"
"}";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 8); // "var a = 0;"
// Looping 10 times.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
foo->Call(env->Global(), argc, argv_10);
CHECK_EQ(23, break_point_hit_count);
// Looping 100 times.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
foo->Call(env->Global(), argc, argv_100);
CHECK_EQ(203, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
TEST(DebugStepDoWhile) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping.
const int argc = 1;
const char* src = "function foo(x) { "
" var a = 0;"
" do {"
" a++;"
" } while (a < x)"
"}";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 8); // "var a = 0;"
// Looping 10 times.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
foo->Call(env->Global(), argc, argv_10);
CHECK_EQ(22, break_point_hit_count);
// Looping 100 times.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
foo->Call(env->Global(), argc, argv_100);
CHECK_EQ(202, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
@ -2733,6 +2877,210 @@ TEST(DebugStepFor) {
}
TEST(DebugStepForContinue) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping.
const int argc = 1;
const char* src = "function foo(x) { "
" var a = 0;"
" var b = 0;"
" var c = 0;"
" for (var i = 0; i < x; i++) {"
" a++;"
" if (a % 2 == 0) continue;"
" b++;"
" c++;"
" }"
" return b;"
"}";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
v8::Handle<v8::Value> result;
SetBreakPoint(foo, 8); // "var a = 0;"
// Each loop generates 4 or 5 steps depending on whether a is equal.
// Looping 10 times.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
result = foo->Call(env->Global(), argc, argv_10);
CHECK_EQ(5, result->Int32Value());
CHECK_EQ(50, break_point_hit_count);
// Looping 100 times.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
result = foo->Call(env->Global(), argc, argv_100);
CHECK_EQ(50, result->Int32Value());
CHECK_EQ(455, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
TEST(DebugStepForBreak) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping.
const int argc = 1;
const char* src = "function foo(x) { "
" var a = 0;"
" var b = 0;"
" var c = 0;"
" for (var i = 0; i < 1000; i++) {"
" a++;"
" if (a == x) break;"
" b++;"
" c++;"
" }"
" return b;"
"}";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
v8::Handle<v8::Value> result;
SetBreakPoint(foo, 8); // "var a = 0;"
// Each loop generates 5 steps except for the last (when break is executed)
// which only generates 4.
// Looping 10 times.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
result = foo->Call(env->Global(), argc, argv_10);
CHECK_EQ(9, result->Int32Value());
CHECK_EQ(53, break_point_hit_count);
// Looping 100 times.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
result = foo->Call(env->Global(), argc, argv_100);
CHECK_EQ(99, result->Int32Value());
CHECK_EQ(503, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
TEST(DebugStepForIn) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
v8::Local<v8::Function> foo;
const char* src_1 = "function foo() { "
" var a = [1, 2];"
" for (x in a) {"
" b = 0;"
" }"
"}";
foo = CompileFunction(&env, src_1, "foo");
SetBreakPoint(foo, 0); // "var a = ..."
step_action = StepIn;
break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(6, break_point_hit_count);
const char* src_2 = "function foo() { "
" var a = {a:[1, 2, 3]};"
" for (x in a.a) {"
" b = 0;"
" }"
"}";
foo = CompileFunction(&env, src_2, "foo");
SetBreakPoint(foo, 0); // "var a = ..."
step_action = StepIn;
break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(8, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
TEST(DebugStepWith) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping.
const char* src = "function foo(x) { "
" var a = {};"
" with (a) {}"
" with (b) {}"
"}";
env->Global()->Set(v8::String::New("b"), v8::Object::New());
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
v8::Handle<v8::Value> result;
SetBreakPoint(foo, 8); // "var a = {};"
step_action = StepIn;
break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(4, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
TEST(DebugConditional) {
v8::HandleScope scope;
DebugLocalContext env;
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping.
const char* src = "function foo(x) { "
" var a;"
" a = x ? 1 : 2;"
" return a;"
"}";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 0); // "var a;"
step_action = StepIn;
break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(5, break_point_hit_count);
step_action = StepIn;
break_point_hit_count = 0;
const int argc = 1;
v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
foo->Call(env->Global(), argc, argv_true);
CHECK_EQ(5, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
}
TEST(StepInOutSimple) {
v8::HandleScope scope;
DebugLocalContext env;
@ -2854,7 +3202,7 @@ TEST(StepInOutBranch) {
// Step through invocation of a.
step_action = StepIn;
break_point_hit_count = 0;
expected_step_sequence = "abaca";
expected_step_sequence = "abbaca";
a->Call(env->Global(), 0, NULL);
CHECK_EQ(StrLength(expected_step_sequence),
break_point_hit_count);
@ -2923,7 +3271,7 @@ TEST(DebugStepFunctionApply) {
foo->Call(env->Global(), 0, NULL);
// With stepping all break locations are hit.
CHECK_EQ(6, break_point_hit_count);
CHECK_EQ(7, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
@ -2967,14 +3315,14 @@ TEST(DebugStepFunctionCall) {
// Check stepping where the if condition in bar is false.
break_point_hit_count = 0;
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(4, break_point_hit_count);
CHECK_EQ(6, break_point_hit_count);
// Check stepping where the if condition in bar is true.
break_point_hit_count = 0;
const int argc = 1;
v8::Handle<v8::Value> argv[argc] = { v8::True() };
foo->Call(env->Global(), argc, argv);
CHECK_EQ(6, break_point_hit_count);
CHECK_EQ(8, break_point_hit_count);
v8::Debug::SetDebugEventListener(NULL);
CheckDebuggerUnloaded();
@ -3267,14 +3615,13 @@ TEST(StepWithException) {
b->Call(env->Global(), 0, NULL);
CHECK_EQ(StrLength(expected_step_sequence),
break_point_hit_count);
// Step through invocation of d + e.
v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
SetBreakPoint(d, 0);
ChangeBreakOnException(false, true);
step_action = StepIn;
break_point_hit_count = 0;
expected_step_sequence = "dded";
expected_step_sequence = "ddedd";
d->Call(env->Global(), 0, NULL);
CHECK_EQ(StrLength(expected_step_sequence),
break_point_hit_count);
@ -3283,7 +3630,7 @@ TEST(StepWithException) {
ChangeBreakOnException(true, true);
step_action = StepIn;
break_point_hit_count = 0;
expected_step_sequence = "ddeed";
expected_step_sequence = "ddeedd";
d->Call(env->Global(), 0, NULL);
CHECK_EQ(StrLength(expected_step_sequence),
break_point_hit_count);
@ -3294,7 +3641,7 @@ TEST(StepWithException) {
ChangeBreakOnException(false, true);
step_action = StepIn;
break_point_hit_count = 0;
expected_step_sequence = "ffghf";
expected_step_sequence = "ffghhff";
f->Call(env->Global(), 0, NULL);
CHECK_EQ(StrLength(expected_step_sequence),
break_point_hit_count);
@ -3303,7 +3650,7 @@ TEST(StepWithException) {
ChangeBreakOnException(true, true);
step_action = StepIn;
break_point_hit_count = 0;
expected_step_sequence = "ffghhf";
expected_step_sequence = "ffghhhff";
f->Call(env->Global(), 0, NULL);
CHECK_EQ(StrLength(expected_step_sequence),
break_point_hit_count);

3
deps/v8/test/cctest/test-disasm-ia32.cc

@ -244,6 +244,9 @@ TEST(DisasmIa320) {
__ test(edx, Immediate(12345));
__ test(edx, Operand(ebx, ecx, times_8, 10000));
__ test(Operand(esi, edi, times_1, -20000000), Immediate(300000000));
__ test_b(edx, Operand(ecx, ebx, times_2, 1000));
__ test_b(Operand(eax, -20), 0x9A);
__ nop();
__ xor_(edx, 12345);

39
deps/v8/test/cctest/test-heap.cc

@ -957,3 +957,42 @@ TEST(Regression39128) {
// Check that region covering inobject property 1 is marked dirty.
CHECK(page->IsRegionDirty(clone_addr + (object_size - kPointerSize)));
}
TEST(TestCodeFlushing) {
i::FLAG_allow_natives_syntax = true;
InitializeVM();
v8::HandleScope scope;
const char* source = "function foo() {"
" var x = 42;"
" var y = 42;"
" var z = x + y;"
"};"
"foo()";
Handle<String> foo_name = Factory::LookupAsciiSymbol("foo");
// This compile will add the code to the compilation cache.
CompileRun(source);
// Check function is compiled.
Object* func_value = Top::context()->global()->GetProperty(*foo_name);
CHECK(func_value->IsJSFunction());
Handle<JSFunction> function(JSFunction::cast(func_value));
CHECK(function->shared()->is_compiled());
Heap::CollectAllGarbage(true);
Heap::CollectAllGarbage(true);
// foo should still be in the compilation cache and therefore not
// have been removed.
CHECK(function->shared()->is_compiled());
Heap::CollectAllGarbage(true);
Heap::CollectAllGarbage(true);
Heap::CollectAllGarbage(true);
Heap::CollectAllGarbage(true);
// foo should no longer be in the compilation cache
CHECK(!function->shared()->is_compiled());
// Call foo to get it recompiled.
CompileRun("foo()");
CHECK(function->shared()->is_compiled());
}

78
deps/v8/test/cctest/test-profile-generator.cc

@ -39,7 +39,7 @@ class TokenEnumeratorTester {
TEST(TokenEnumerator) {
TokenEnumerator te;
CHECK_EQ(CodeEntry::kNoSecurityToken, te.GetTokenId(NULL));
CHECK_EQ(TokenEnumerator::kNoSecurityToken, te.GetTokenId(NULL));
v8::HandleScope hs;
v8::Local<v8::String> token1(v8::String::New("1"));
CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
@ -65,20 +65,20 @@ TEST(TokenEnumerator) {
TEST(ProfileNodeFindOrAddChild) {
ProfileNode node(NULL, NULL);
CodeEntry entry1(
i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
TokenEnumerator::kNoSecurityToken);
ProfileNode* childNode1 = node.FindOrAddChild(&entry1);
CHECK_NE(NULL, childNode1);
CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
CodeEntry entry2(
i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
TokenEnumerator::kNoSecurityToken);
ProfileNode* childNode2 = node.FindOrAddChild(&entry2);
CHECK_NE(NULL, childNode2);
CHECK_NE(childNode1, childNode2);
CHECK_EQ(childNode1, node.FindOrAddChild(&entry1));
CHECK_EQ(childNode2, node.FindOrAddChild(&entry2));
CodeEntry entry3(
i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
TokenEnumerator::kNoSecurityToken);
ProfileNode* childNode3 = node.FindOrAddChild(&entry3);
CHECK_NE(NULL, childNode3);
CHECK_NE(childNode1, childNode3);
@ -119,12 +119,12 @@ class ProfileTreeTestHelper {
} // namespace
TEST(ProfileTreeAddPathFromStart) {
CodeEntry entry1(
i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry2(
i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry3(
i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
TokenEnumerator::kNoSecurityToken);
CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
TokenEnumerator::kNoSecurityToken);
CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
TokenEnumerator::kNoSecurityToken);
ProfileTree tree;
ProfileTreeTestHelper helper(&tree);
CHECK_EQ(NULL, helper.Walk(&entry1));
@ -189,12 +189,12 @@ TEST(ProfileTreeAddPathFromStart) {
TEST(ProfileTreeAddPathFromEnd) {
CodeEntry entry1(
i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry2(
i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry3(
i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
TokenEnumerator::kNoSecurityToken);
CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
TokenEnumerator::kNoSecurityToken);
CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
TokenEnumerator::kNoSecurityToken);
ProfileTree tree;
ProfileTreeTestHelper helper(&tree);
CHECK_EQ(NULL, helper.Walk(&entry1));
@ -272,8 +272,8 @@ TEST(ProfileTreeCalculateTotalTicks) {
CHECK_EQ(1, empty_tree.root()->total_ticks());
CHECK_EQ(1, empty_tree.root()->self_ticks());
CodeEntry entry1(
i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
TokenEnumerator::kNoSecurityToken);
CodeEntry* e1_path[] = {&entry1};
Vector<CodeEntry*> e1_path_vec(
e1_path, sizeof(e1_path) / sizeof(e1_path[0]));
@ -294,8 +294,8 @@ TEST(ProfileTreeCalculateTotalTicks) {
CHECK_EQ(1, node1->total_ticks());
CHECK_EQ(1, node1->self_ticks());
CodeEntry entry2(
i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
TokenEnumerator::kNoSecurityToken);
CodeEntry* e1_e2_path[] = {&entry1, &entry2};
Vector<CodeEntry*> e1_e2_path_vec(
e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
@ -330,8 +330,8 @@ TEST(ProfileTreeCalculateTotalTicks) {
CodeEntry* e2_path[] = {&entry2};
Vector<CodeEntry*> e2_path_vec(
e2_path, sizeof(e2_path) / sizeof(e2_path[0]));
CodeEntry entry3(
i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
TokenEnumerator::kNoSecurityToken);
CodeEntry* e3_path[] = {&entry3};
Vector<CodeEntry*> e3_path_vec(
e3_path, sizeof(e3_path) / sizeof(e3_path[0]));
@ -394,7 +394,7 @@ TEST(ProfileTreeFilteredClone) {
CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0, token0);
CodeEntry entry4(
i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
CodeEntry::kInheritsSecurityToken);
TokenEnumerator::kInheritsSecurityToken);
{
CodeEntry* e1_e2_path[] = {&entry1, &entry2};
@ -491,14 +491,14 @@ static inline i::Address ToAddress(int n) {
TEST(CodeMapAddCode) {
CodeMap code_map;
CodeEntry entry1(
i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry2(
i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry3(
i::Logger::FUNCTION_TAG, "", "ccc", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry4(
i::Logger::FUNCTION_TAG, "", "ddd", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
TokenEnumerator::kNoSecurityToken);
CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
TokenEnumerator::kNoSecurityToken);
CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
TokenEnumerator::kNoSecurityToken);
CodeEntry entry4(i::Logger::FUNCTION_TAG, "", "ddd", "", 0,
TokenEnumerator::kNoSecurityToken);
code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
code_map.AddCode(ToAddress(0x1900), &entry3, 0x50);
@ -525,10 +525,10 @@ TEST(CodeMapAddCode) {
TEST(CodeMapMoveAndDeleteCode) {
CodeMap code_map;
CodeEntry entry1(
i::Logger::FUNCTION_TAG, "", "aaa", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry2(
i::Logger::FUNCTION_TAG, "", "bbb", "", 0, CodeEntry::kNoSecurityToken);
CodeEntry entry1(i::Logger::FUNCTION_TAG, "", "aaa", "", 0,
TokenEnumerator::kNoSecurityToken);
CodeEntry entry2(i::Logger::FUNCTION_TAG, "", "bbb", "", 0,
TokenEnumerator::kNoSecurityToken);
code_map.AddCode(ToAddress(0x1500), &entry1, 0x200);
code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
@ -601,7 +601,7 @@ TEST(RecordTickSample) {
generator.RecordTickSample(sample3);
CpuProfile* profile =
profiles.StopProfiling(CodeEntry::kNoSecurityToken, "", 1);
profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
CHECK_NE(NULL, profile);
ProfileTreeTestHelper top_down_test_helper(profile->top_down());
CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));

2
deps/v8/test/mjsunit/const-eval-init.js

@ -91,7 +91,7 @@ function testInitSlowCaseExtension() {
var source = "";
// Introduce 100 properties on the context extension object to force
// it in slow case.
for (var i = 0; i < 100; i++) source += ("var a" + i + " = i;");
for (var i = 0; i < 100; i++) source += ("var a" + i + " = " + i + ";");
source += "const x = 10; assertEquals(10, x); x = 11; assertEquals(10, x)";
eval(source);
}

12
deps/v8/test/mjsunit/debug-conditional-breakpoints.js

@ -45,7 +45,7 @@ Debug.setListener(listener);
count = 0;
function f() {};
function g() {h(count++)};
function h(x) {var a=x;};
function h(x) {var a=x; return a};
// Conditional breakpoint which syntax error.
@ -136,7 +136,7 @@ Debug.clearBreakPoint(bp);
// Conditional breakpoint which checks a local variable.
break_point_hit_count = 0;
bp = Debug.setBreakPoint(h, 0, 0, 'a % 2 == 0');
bp = Debug.setBreakPoint(h, 0, 23, 'a % 2 == 0');
for (var i = 0; i < 10; i++) {
g();
}
@ -146,8 +146,8 @@ Debug.clearBreakPoint(bp);
// Multiple conditional breakpoint which the same condition.
break_point_hit_count = 0;
bp1 = Debug.setBreakPoint(h, 0, 0, 'a % 2 == 0');
bp2 = Debug.setBreakPoint(h, 0, 0, 'a % 2 == 0');
bp1 = Debug.setBreakPoint(h, 0, 23, 'a % 2 == 0');
bp2 = Debug.setBreakPoint(h, 0, 23, 'a % 2 == 0');
for (var i = 0; i < 10; i++) {
g();
}
@ -159,8 +159,8 @@ Debug.clearBreakPoint(bp2);
// Multiple conditional breakpoint which different conditions.
break_point_hit_count = 0;
bp1 = Debug.setBreakPoint(h, 0, 0, 'a % 2 == 0');
bp2 = Debug.setBreakPoint(h, 0, 0, '(a + 1) % 2 == 0');
bp1 = Debug.setBreakPoint(h, 0, 23, 'a % 2 == 0');
bp2 = Debug.setBreakPoint(h, 0, 23, '(a + 1) % 2 == 0');
for (var i = 0; i < 10; i++) {
g();
}

7
deps/v8/test/mjsunit/debug-step.js

@ -55,8 +55,9 @@ Debug.setListener(listener);
// Test debug event for break point.
function f() {
for (i = 0; i < 1000; i++) { // Line 1.
x = 1; // Line 2.
var i; // Line 1.
for (i = 0; i < 1000; i++) { // Line 2.
x = 1; // Line 3.
}
};
@ -74,7 +75,7 @@ assertEquals(499, result);
// multiple steps have been requested.
state = 0;
result = -1;
bp2 = Debug.setBreakPoint(f, 2);
bp2 = Debug.setBreakPoint(f, 3);
f();
assertEquals(0, result);

Loading…
Cancel
Save