Browse Source

Upgrade V8 to 3.0.1

v0.7.4-release
Ryan Dahl 14 years ago
parent
commit
1d78159e8f
  1. 25
      deps/v8/ChangeLog
  2. 7
      deps/v8/include/v8-preparser.h
  3. 4
      deps/v8/include/v8-profiler.h
  4. 18
      deps/v8/include/v8.h
  5. 26
      deps/v8/preparser/preparser-process.cc
  6. 6
      deps/v8/samples/shell.cc
  7. 20
      deps/v8/src/api.cc
  8. 30
      deps/v8/src/arm/full-codegen-arm.cc
  9. 23
      deps/v8/src/arm/lithium-arm.cc
  10. 11
      deps/v8/src/arm/lithium-arm.h
  11. 7
      deps/v8/src/arm/lithium-codegen-arm.cc
  12. 5
      deps/v8/src/arm/macro-assembler-arm.cc
  13. 13
      deps/v8/src/array.js
  14. 52
      deps/v8/src/assembler.cc
  15. 8
      deps/v8/src/assembler.h
  16. 3
      deps/v8/src/ast-inl.h
  17. 11
      deps/v8/src/ast.cc
  18. 22
      deps/v8/src/ast.h
  19. 2
      deps/v8/src/checks.h
  20. 34
      deps/v8/src/compiler.cc
  21. 263
      deps/v8/src/extensions/experimental/i18n-extension.cc
  22. 64
      deps/v8/src/extensions/experimental/i18n-extension.h
  23. 3
      deps/v8/src/flag-definitions.h
  24. 2
      deps/v8/src/full-codegen.h
  25. 33
      deps/v8/src/heap-profiler.cc
  26. 16
      deps/v8/src/heap-profiler.h
  27. 18
      deps/v8/src/heap.cc
  28. 4
      deps/v8/src/heap.h
  29. 20
      deps/v8/src/hydrogen-instructions.h
  30. 1005
      deps/v8/src/hydrogen.cc
  31. 81
      deps/v8/src/hydrogen.h
  32. 1
      deps/v8/src/ia32/builtins-ia32.cc
  33. 27
      deps/v8/src/ia32/full-codegen-ia32.cc
  34. 64
      deps/v8/src/ia32/lithium-codegen-ia32.cc
  35. 1
      deps/v8/src/ia32/lithium-codegen-ia32.h
  36. 24
      deps/v8/src/ia32/lithium-ia32.cc
  37. 13
      deps/v8/src/ia32/lithium-ia32.h
  38. 24
      deps/v8/src/ia32/macro-assembler-ia32.cc
  39. 22
      deps/v8/src/json.js
  40. 356
      deps/v8/src/lithium-allocator.cc
  41. 83
      deps/v8/src/lithium-allocator.h
  42. 181
      deps/v8/src/log-utils.cc
  43. 64
      deps/v8/src/log-utils.h
  44. 176
      deps/v8/src/log.cc
  45. 103
      deps/v8/src/log.h
  46. 1
      deps/v8/src/math.js
  47. 12
      deps/v8/src/objects.h
  48. 173
      deps/v8/src/parser.cc
  49. 33
      deps/v8/src/parser.h
  50. 29
      deps/v8/src/platform-linux.cc
  51. 109
      deps/v8/src/preparser-api.cc
  52. 1
      deps/v8/src/preparser.cc
  53. 14
      deps/v8/src/profile-generator-inl.h
  54. 373
      deps/v8/src/profile-generator.cc
  55. 41
      deps/v8/src/profile-generator.h
  56. 66
      deps/v8/src/regexp.js
  57. 101
      deps/v8/src/runtime-profiler.cc
  58. 76
      deps/v8/src/runtime.cc
  59. 32
      deps/v8/src/scanner-base.cc
  60. 80
      deps/v8/src/scanner-base.h
  61. 367
      deps/v8/src/scanner.cc
  62. 201
      deps/v8/src/scanner.h
  63. 12
      deps/v8/src/serialize.cc
  64. 2
      deps/v8/src/spaces.cc
  65. 93
      deps/v8/src/string.js
  66. 8
      deps/v8/src/v8natives.js
  67. 39
      deps/v8/src/v8preparserdll-main.cc
  68. 4
      deps/v8/src/version.cc
  69. 2220
      deps/v8/src/x64/builtins-x64.cc
  70. 16
      deps/v8/src/x64/full-codegen-x64.cc
  71. 5
      deps/v8/src/x64/lithium-x64.h
  72. 25
      deps/v8/src/x64/macro-assembler-x64.cc
  73. 7
      deps/v8/src/x64/macro-assembler-x64.h
  74. 3
      deps/v8/test/cctest/cctest.status
  75. 47
      deps/v8/test/cctest/test-heap-profiler.cc
  76. 170
      deps/v8/test/cctest/test-log-utils.cc
  77. 303
      deps/v8/test/cctest/test-parsing.cc
  78. 11
      deps/v8/test/cctest/test-profile-generator.cc
  79. 3
      deps/v8/test/cctest/test-regexp.cc
  80. 5
      deps/v8/test/mjsunit/mjsunit.status
  81. 32
      deps/v8/test/mjsunit/object-define-property.js
  82. 92
      deps/v8/test/mjsunit/regexp.js
  83. 53
      deps/v8/test/mjsunit/regress/regress-962.js
  84. 127
      deps/v8/test/mjsunit/regress/regress-969.js
  85. 24
      deps/v8/test/mjsunit/third_party/regexp-pcre.js
  86. 82
      deps/v8/test/mjsunit/tools/logreader.js
  87. 7
      deps/v8/test/mozilla/mozilla.status
  88. 2
      deps/v8/test/sputnik/README
  89. 32
      deps/v8/tools/gyp/v8.gyp
  90. 149
      deps/v8/tools/logreader.js
  91. 14
      deps/v8/tools/test.py
  92. 62
      deps/v8/tools/tickprocessor.js
  93. 2504
      deps/v8/tools/visual_studio/v8_base.vcproj
  94. 2398
      deps/v8/tools/visual_studio/v8_base_arm.vcproj
  95. 2344
      deps/v8/tools/visual_studio/v8_base_x64.vcproj
  96. 2
      deps/v8/tools/visual_studio/v8_shell_sample.vcproj
  97. 2
      deps/v8/tools/visual_studio/v8_shell_sample_arm.vcproj
  98. 4
      deps/v8/tools/visual_studio/v8_shell_sample_x64.vcproj

25
deps/v8/ChangeLog

@ -1,3 +1,26 @@
2010-12-13: Version 3.0.1
Added support for an experimental internationalization API as an
extension. This extension is disabled by default but can be enabled
when building V8. The ECMAScript internationalization strawman is
at http://wiki.ecmascript.org/doku.php?id=strawman:i18n_api.
Made RegExp character class parsing stricter. This mirrors a change
to RegExp parsing in WebKit.
Fixed a bug in Object.defineProperty when used to change attributes
of an existing property. It incorrectly set the property value to
undefined (issue 965).
Fixed several different compilation failures on various platforms
caused by the 3.0.0 release.
Optimized Math.pow so it can work on unboxed doubles.
Sped up quoting of JSON strings by removing one traversal of the
string.
2010-12-07: Version 3.0.0 2010-12-07: Version 3.0.0
Improved performance by (partially) addressing issue 957 on Improved performance by (partially) addressing issue 957 on
@ -132,7 +155,7 @@
Added USE_SIMULATOR macro that explicitly indicates that we wish to use Added USE_SIMULATOR macro that explicitly indicates that we wish to use
the simulator as the execution engine (by Mark Lam <mark.lam@palm.com> the simulator as the execution engine (by Mark Lam <mark.lam@palm.com>
from Hewlett-Packard Development Company, LP). from Hewlett-Packard Development Company, LP).
Fixed compilation error on ARM with gcc 4.4 (issue 894). Fixed compilation error on ARM with gcc 4.4 (issue 894).

7
deps/v8/include/v8-preparser.h

@ -99,13 +99,6 @@ class UnicodeInputStream {
// Returns the next Unicode code-point in the input, or a negative value when // Returns the next Unicode code-point in the input, or a negative value when
// there is no more input in the stream. // there is no more input in the stream.
virtual int32_t Next() = 0; virtual int32_t Next() = 0;
// Pushes a read character back into the stream, so that it will be the next
// to be read by Advance(). The character pushed back must be the most
// recently read character that hasn't already been pushed back (i.e., if
// pushing back more than one character, they must occur in the opposite order
// of the one they were read in).
virtual void PushBack(int32_t ch) = 0;
}; };

4
deps/v8/include/v8-profiler.h

@ -245,7 +245,6 @@ class V8EXPORT HeapGraphPath {
class V8EXPORT HeapGraphNode { class V8EXPORT HeapGraphNode {
public: public:
enum Type { enum Type {
kInternal = 0, // For compatibility, will be removed.
kHidden = 0, // Hidden node, may be filtered when shown to user. kHidden = 0, // Hidden node, may be filtered when shown to user.
kArray = 1, // An array of elements. kArray = 1, // An array of elements.
kString = 2, // A string. kString = 2, // A string.
@ -413,7 +412,8 @@ class V8EXPORT HeapProfiler {
*/ */
static const HeapSnapshot* TakeSnapshot( static const HeapSnapshot* TakeSnapshot(
Handle<String> title, Handle<String> title,
HeapSnapshot::Type type = HeapSnapshot::kFull); HeapSnapshot::Type type = HeapSnapshot::kFull,
ActivityControl* control = NULL);
}; };

18
deps/v8/include/v8.h

@ -3281,6 +3281,24 @@ class V8EXPORT OutputStream { // NOLINT
}; };
/**
* An interface for reporting progress and controlling long-running
* activities.
*/
class V8EXPORT ActivityControl { // NOLINT
public:
enum ControlOption {
kContinue = 0,
kAbort = 1
};
virtual ~ActivityControl() {}
/**
* Notify about current progress. The activity can be stopped by
* returning kAbort as the callback result.
*/
virtual ControlOption ReportProgressValue(int done, int total) = 0;
};
// --- I m p l e m e n t a t i o n --- // --- I m p l e m e n t a t i o n ---

26
deps/v8/preparser/preparser-process.cc

@ -127,7 +127,7 @@ uint32_t ReadUInt32(FILE* source, bool* ok) {
bool ReadBuffer(FILE* source, void* buffer, size_t length) { bool ReadBuffer(FILE* source, void* buffer, size_t length) {
size_t actually_read = fread(buffer, 1, length, stdin); size_t actually_read = fread(buffer, 1, length, source);
return (actually_read == length); return (actually_read == length);
} }
@ -150,22 +150,25 @@ class ScopedPointer {
}; };
// Preparse stdin and output result on stdout. // Preparse input and output result on stdout.
int PreParseIO() { int PreParseIO(FILE* input) {
fprintf(stderr, "LOG: Enter parsing loop\n"); fprintf(stderr, "LOG: Enter parsing loop\n");
bool ok = true; bool ok = true;
uint32_t length = ReadUInt32(stdin, &ok); uint32_t length = ReadUInt32(input, &ok);
fprintf(stderr, "LOG: Input length: %d\n", length);
if (!ok) return kErrorReading; if (!ok) return kErrorReading;
ScopedPointer<uint8_t> buffer(new uint8_t[length]); ScopedPointer<uint8_t> buffer(new uint8_t[length]);
if (!ReadBuffer(stdin, *buffer, length)) { if (!ReadBuffer(input, *buffer, length)) {
return kErrorReading; return kErrorReading;
} }
UTF8InputStream input_buffer(*buffer, static_cast<size_t>(length)); UTF8InputStream input_buffer(*buffer, static_cast<size_t>(length));
v8::PreParserData data = v8::PreParserData data =
v8::Preparse(&input_buffer, 64 * sizeof(void*)); // NOLINT v8::Preparse(&input_buffer, 64 * 1024 * sizeof(void*)); // NOLINT
if (data.stack_overflow()) { if (data.stack_overflow()) {
fprintf(stderr, "LOG: Stack overflow\n");
fflush(stderr);
// Report stack overflow error/no-preparser-data. // Report stack overflow error/no-preparser-data.
WriteUInt32(stdout, 0, &ok); WriteUInt32(stdout, 0, &ok);
if (!ok) return kErrorWriting; if (!ok) return kErrorWriting;
@ -173,6 +176,8 @@ int PreParseIO() {
} }
uint32_t size = data.size(); uint32_t size = data.size();
fprintf(stderr, "LOG: Success, data size: %u\n", size);
fflush(stderr);
WriteUInt32(stdout, size, &ok); WriteUInt32(stdout, size, &ok);
if (!ok) return kErrorWriting; if (!ok) return kErrorWriting;
if (!WriteBuffer(stdout, data.data(), size)) { if (!WriteBuffer(stdout, data.data(), size)) {
@ -185,10 +190,17 @@ int PreParseIO() {
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
FILE* input = stdin;
if (argc > 1) {
char* arg = argv[1];
input = fopen(arg, "rb");
if (input == NULL) return EXIT_FAILURE;
}
int status = 0; int status = 0;
do { do {
status = v8::internal::PreParseIO(); status = v8::internal::PreParseIO(input);
} while (status == 0); } while (status == 0);
fprintf(stderr, "EXIT: Failure %d\n", status); fprintf(stderr, "EXIT: Failure %d\n", status);
fflush(stderr);
return EXIT_FAILURE; return EXIT_FAILURE;
} }

6
deps/v8/samples/shell.cc

@ -45,7 +45,6 @@ v8::Handle<v8::Value> Quit(const v8::Arguments& args);
v8::Handle<v8::Value> Version(const v8::Arguments& args); v8::Handle<v8::Value> Version(const v8::Arguments& args);
v8::Handle<v8::String> ReadFile(const char* name); v8::Handle<v8::String> ReadFile(const char* name);
void ReportException(v8::TryCatch* handler); void ReportException(v8::TryCatch* handler);
void SetFlagsFromString(const char* flags);
int RunMain(int argc, char* argv[]) { int RunMain(int argc, char* argv[]) {
@ -345,8 +344,3 @@ void ReportException(v8::TryCatch* try_catch) {
} }
} }
} }
void SetFlagsFromString(const char* flags) {
v8::V8::SetFlagsFromString(flags, strlen(flags));
}

20
deps/v8/src/api.cc

@ -1165,14 +1165,22 @@ void ObjectTemplate::SetInternalFieldCount(int value) {
ScriptData* ScriptData::PreCompile(const char* input, int length) { ScriptData* ScriptData::PreCompile(const char* input, int length) {
unibrow::Utf8InputBuffer<> buf(input, length); i::Utf8ToUC16CharacterStream stream(
return i::ParserApi::PreParse(i::Handle<i::String>(), &buf, NULL); reinterpret_cast<const unsigned char*>(input), length);
return i::ParserApi::PreParse(&stream, NULL);
} }
ScriptData* ScriptData::PreCompile(v8::Handle<String> source) { ScriptData* ScriptData::PreCompile(v8::Handle<String> source) {
i::Handle<i::String> str = Utils::OpenHandle(*source); i::Handle<i::String> str = Utils::OpenHandle(*source);
return i::ParserApi::PreParse(str, NULL, NULL); if (str->IsExternalTwoByteString()) {
i::ExternalTwoByteStringUC16CharacterStream stream(
i::Handle<i::ExternalTwoByteString>::cast(str), 0, str->length());
return i::ParserApi::PreParse(&stream, NULL);
} else {
i::GenericStringUC16CharacterStream stream(str, 0, str->length());
return i::ParserApi::PreParse(&stream, NULL);
}
} }
@ -4939,7 +4947,8 @@ const HeapSnapshot* HeapProfiler::FindSnapshot(unsigned uid) {
const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle<String> title, const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle<String> title,
HeapSnapshot::Type type) { HeapSnapshot::Type type,
ActivityControl* control) {
IsDeadCheck("v8::HeapProfiler::TakeSnapshot"); IsDeadCheck("v8::HeapProfiler::TakeSnapshot");
i::HeapSnapshot::Type internal_type = i::HeapSnapshot::kFull; i::HeapSnapshot::Type internal_type = i::HeapSnapshot::kFull;
switch (type) { switch (type) {
@ -4953,7 +4962,8 @@ const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle<String> title,
UNREACHABLE(); UNREACHABLE();
} }
return reinterpret_cast<const HeapSnapshot*>( return reinterpret_cast<const HeapSnapshot*>(
i::HeapProfiler::TakeSnapshot(*Utils::OpenHandle(*title), internal_type)); i::HeapProfiler::TakeSnapshot(
*Utils::OpenHandle(*title), internal_type, control));
} }
#endif // ENABLE_LOGGING_AND_PROFILING #endif // ENABLE_LOGGING_AND_PROFILING

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

@ -890,7 +890,9 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ bind(&update_each); __ bind(&update_each);
__ mov(result_register(), r3); __ mov(result_register(), r3);
// Perform the assignment as if via '='. // Perform the assignment as if via '='.
EmitAssignment(stmt->each()); { EffectContext context(this);
EmitAssignment(stmt->each(), stmt->AssignmentId());
}
// Generate code for the body of the loop. // Generate code for the body of the loop.
Visit(stmt->body()); Visit(stmt->body());
@ -1444,7 +1446,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// For property compound assignments we need another deoptimization // For property compound assignments we need another deoptimization
// point after the property load. // point after the property load.
if (property != NULL) { if (property != NULL) {
PrepareForBailoutForId(expr->compound_bailout_id(), TOS_REG); PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
} }
Token::Value op = expr->binary_op(); Token::Value op = expr->binary_op();
@ -1536,7 +1538,7 @@ void FullCodeGenerator::EmitBinaryOp(Token::Value op,
} }
void FullCodeGenerator::EmitAssignment(Expression* expr) { void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
// Invalid left-hand sides are rewritten to have a 'throw // Invalid left-hand sides are rewritten to have a 'throw
// ReferenceError' on the left-hand side. // ReferenceError' on the left-hand side.
if (!expr->IsValidLeftHandSide()) { if (!expr->IsValidLeftHandSide()) {
@ -1584,6 +1586,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
break; break;
} }
} }
PrepareForBailoutForId(bailout_ast_id, TOS_REG);
context()->Plug(r0);
} }
@ -1657,8 +1661,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
} }
__ bind(&done); __ bind(&done);
} }
context()->Plug(result_register());
} }
@ -1701,10 +1703,10 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
__ push(ip); __ push(ip);
__ CallRuntime(Runtime::kToFastProperties, 1); __ CallRuntime(Runtime::kToFastProperties, 1);
__ pop(r0); __ pop(r0);
context()->DropAndPlug(1, r0); __ Drop(1);
} else {
context()->Plug(r0);
} }
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(r0);
} }
@ -1745,10 +1747,10 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
__ push(ip); __ push(ip);
__ CallRuntime(Runtime::kToFastProperties, 1); __ CallRuntime(Runtime::kToFastProperties, 1);
__ pop(r0); __ pop(r0);
context()->DropAndPlug(1, r0); __ Drop(1);
} else {
context()->Plug(r0);
} }
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(r0);
} }
@ -3200,6 +3202,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
{ EffectContext context(this); { EffectContext context(this);
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Token::ASSIGN); Token::ASSIGN);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context.Plug(r0);
} }
// For all contexts except EffectConstant We have the result on // For all contexts except EffectConstant We have the result on
// top of the stack. // top of the stack.
@ -3209,6 +3213,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
} else { } else {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Token::ASSIGN); Token::ASSIGN);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(r0);
} }
break; break;
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
@ -3216,6 +3222,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
__ pop(r1); __ pop(r1);
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET); EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) { if (expr->is_postfix()) {
if (!context()->IsEffect()) { if (!context()->IsEffect()) {
context()->PlugTOS(); context()->PlugTOS();
@ -3230,6 +3237,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
__ pop(r2); // Receiver. __ pop(r2); // Receiver.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET); EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) { if (expr->is_postfix()) {
if (!context()->IsEffect()) { if (!context()->IsEffect()) {
context()->PlugTOS(); context()->PlugTOS();

23
deps/v8/src/arm/lithium-arm.cc

@ -460,12 +460,6 @@ int LChunk::NearestGapPos(int index) const {
} }
int LChunk::NearestNextGapPos(int index) const {
while (!IsGapAt(index)) index++;
return index;
}
void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) { void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to); GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
} }
@ -1357,6 +1351,9 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
return AssignEnvironment(DefineAsRegister(result)); return AssignEnvironment(DefineAsRegister(result));
case kMathSqrt: case kMathSqrt:
return DefineSameAsFirst(result); return DefineSameAsFirst(result);
case kMathPowHalf:
Abort("MathPowHalf LUnaryMathOperation not implemented");
return NULL;
default: default:
UNREACHABLE(); UNREACHABLE();
return NULL; return NULL;
@ -1554,6 +1551,12 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
} }
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
Abort("LPower instruction not implemented on ARM");
return NULL;
}
LInstruction* LChunkBuilder::DoCompare(HCompare* instr) { LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
Token::Value op = instr->token(); Token::Value op = instr->token();
if (instr->left()->representation().IsInteger32()) { if (instr->left()->representation().IsInteger32()) {
@ -1688,11 +1691,13 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
} else if (from.IsDouble()) { } else if (from.IsDouble()) {
if (to.IsTagged()) { if (to.IsTagged()) {
LOperand* value = UseRegister(instr->value()); LOperand* value = UseRegister(instr->value());
LOperand* temp = TempRegister(); LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
// Make sure that temp and result_temp are different registers. // Make sure that the temp and result_temp registers are
// different.
LUnallocated* result_temp = TempRegister(); LUnallocated* result_temp = TempRegister();
LInstruction* result = new LNumberTagD(value, temp); LInstruction* result = new LNumberTagD(value, temp1, temp2);
Define(result, result_temp); Define(result, result_temp);
return AssignPointerMap(result); return AssignPointerMap(result);
} else { } else {

11
deps/v8/src/arm/lithium-arm.h

@ -1395,15 +1395,17 @@ class LNumberTagI: public LUnaryOperation {
class LNumberTagD: public LUnaryOperation { class LNumberTagD: public LUnaryOperation {
public: public:
explicit LNumberTagD(LOperand* value, LOperand* temp) LNumberTagD(LOperand* value, LOperand* temp1, LOperand* temp2)
: LUnaryOperation(value), temp_(temp) { } : LUnaryOperation(value), temp1_(temp1), temp2_(temp2) { }
DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d") DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d")
LOperand* temp() const { return temp_; } LOperand* temp1() const { return temp1_; }
LOperand* temp2() const { return temp2_; }
private: private:
LOperand* temp_; LOperand* temp1_;
LOperand* temp2_;
}; };
@ -1887,7 +1889,6 @@ class LChunk: public ZoneObject {
LGap* GetGapAt(int index) const; LGap* GetGapAt(int index) const;
bool IsGapAt(int index) const; bool IsGapAt(int index) const;
int NearestGapPos(int index) const; int NearestGapPos(int index) const;
int NearestNextGapPos(int index) const;
void MarkEmptyBlocks(); void MarkEmptyBlocks();
const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; } const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; }
LLabel* GetLabel(int block_id) const { LLabel* GetLabel(int block_id) const {

7
deps/v8/src/arm/lithium-codegen-arm.cc

@ -136,7 +136,7 @@ bool LCodeGen::GeneratePrologue() {
Label loop; Label loop;
__ bind(&loop); __ bind(&loop);
__ push(r2); __ push(r2);
__ sub(r0, r0, Operand(1)); __ sub(r0, r0, Operand(1), SetCC);
__ b(ne, &loop); __ b(ne, &loop);
} else { } else {
__ sub(sp, sp, Operand(slots * kPointerSize)); __ sub(sp, sp, Operand(slots * kPointerSize));
@ -1733,13 +1733,14 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
DoubleRegister input_reg = ToDoubleRegister(instr->input()); DoubleRegister input_reg = ToDoubleRegister(instr->input());
Register reg = ToRegister(instr->result()); Register reg = ToRegister(instr->result());
Register tmp = ToRegister(instr->temp()); Register temp1 = ToRegister(instr->temp1());
Register temp2 = ToRegister(instr->temp2());
Register scratch = r9; Register scratch = r9;
DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
if (FLAG_inline_new) { if (FLAG_inline_new) {
__ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex); __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex);
__ AllocateHeapNumber(reg, tmp, ip, scratch, deferred->entry()); __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry());
} else { } else {
__ jmp(deferred->entry()); __ jmp(deferred->entry());
} }

5
deps/v8/src/arm/macro-assembler-arm.cc

@ -1060,9 +1060,14 @@ void MacroAssembler::AllocateInNewSpace(Register object_size,
return; return;
} }
// Assert that the register arguments are different and that none of
// them are ip. ip is used explicitly in the code generated below.
ASSERT(!result.is(scratch1)); ASSERT(!result.is(scratch1));
ASSERT(!result.is(scratch2)); ASSERT(!result.is(scratch2));
ASSERT(!scratch1.is(scratch2)); ASSERT(!scratch1.is(scratch2));
ASSERT(!result.is(ip));
ASSERT(!scratch1.is(ip));
ASSERT(!scratch2.is(ip));
// Check relative positions of allocation top and limit addresses. // Check relative positions of allocation top and limit addresses.
// The values must be adjacent in memory to allow the use of LDM. // The values must be adjacent in memory to allow the use of LDM.

13
deps/v8/src/array.js

@ -159,9 +159,11 @@ function Join(array, length, separator, convert) {
} }
function ConvertToString(e) { function ConvertToString(x) {
if (e == null) return ''; if (IS_STRING(x)) return x;
else return ToString(e); if (IS_NUMBER(x)) return %_NumberToString(x);
if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
return (IS_NULL_OR_UNDEFINED(x)) ? '' : %ToString(%DefaultString(x));
} }
@ -365,14 +367,13 @@ function ArrayJoin(separator) {
if (IS_UNDEFINED(separator)) { if (IS_UNDEFINED(separator)) {
separator = ','; separator = ',';
} else if (!IS_STRING(separator)) { } else if (!IS_STRING(separator)) {
separator = ToString(separator); separator = NonStringToString(separator);
} }
var result = %_FastAsciiArrayJoin(this, separator); var result = %_FastAsciiArrayJoin(this, separator);
if (!IS_UNDEFINED(result)) return result; if (!IS_UNDEFINED(result)) return result;
var length = TO_UINT32(this.length); return Join(this, TO_UINT32(this.length), separator, ConvertToString);
return Join(this, length, separator, ConvertToString);
} }

52
deps/v8/src/assembler.cc

@ -66,6 +66,7 @@ namespace internal {
const double DoubleConstant::min_int = kMinInt; const double DoubleConstant::min_int = kMinInt;
const double DoubleConstant::one_half = 0.5; const double DoubleConstant::one_half = 0.5;
const double DoubleConstant::negative_infinity = -V8_INFINITY;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -722,6 +723,12 @@ ExternalReference ExternalReference::address_of_one_half() {
} }
ExternalReference ExternalReference::address_of_negative_infinity() {
return ExternalReference(reinterpret_cast<void*>(
const_cast<double*>(&DoubleConstant::negative_infinity)));
}
#ifndef V8_INTERPRETED_REGEXP #ifndef V8_INTERPRETED_REGEXP
ExternalReference ExternalReference::re_check_stack_guard_state() { ExternalReference ExternalReference::re_check_stack_guard_state() {
@ -793,6 +800,51 @@ static double mod_two_doubles(double x, double y) {
} }
// Helper function to compute x^y, where y is known to be an
// integer. Uses binary decomposition to limit the number of
// multiplications; see the discussion in "Hacker's Delight" by Henry
// S. Warren, Jr., figure 11-6, page 213.
double power_double_int(double x, int y) {
double m = (y < 0) ? 1 / x : x;
unsigned n = (y < 0) ? -y : y;
double p = 1;
while (n != 0) {
if ((n & 1) != 0) p *= m;
m *= m;
if ((n & 2) != 0) p *= m;
m *= m;
n >>= 2;
}
return p;
}
double power_double_double(double x, double y) {
int y_int = static_cast<int>(y);
if (y == y_int) {
return power_double_int(x, y_int); // Returns 1.0 for exponent 0.
}
if (!isinf(x)) {
if (y == 0.5) return sqrt(x);
if (y == -0.5) return 1.0 / sqrt(x);
}
if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
return OS::nan_value();
}
return pow(x, y);
}
ExternalReference ExternalReference::power_double_double_function() {
return ExternalReference(Redirect(FUNCTION_ADDR(power_double_double)));
}
ExternalReference ExternalReference::power_double_int_function() {
return ExternalReference(Redirect(FUNCTION_ADDR(power_double_int)));
}
static int native_compare_doubles(double y, double x) { static int native_compare_doubles(double y, double x) {
if (x == y) return EQUAL; if (x == y) return EQUAL;
return x < y ? LESS : GREATER; return x < y ? LESS : GREATER;

8
deps/v8/src/assembler.h

@ -50,6 +50,7 @@ class DoubleConstant: public AllStatic {
public: public:
static const double min_int; static const double min_int;
static const double one_half; static const double one_half;
static const double negative_infinity;
}; };
@ -539,6 +540,8 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference double_fp_operation(Token::Value operation); static ExternalReference double_fp_operation(Token::Value operation);
static ExternalReference compare_doubles(); static ExternalReference compare_doubles();
static ExternalReference power_double_double_function();
static ExternalReference power_double_int_function();
static ExternalReference handle_scope_next_address(); static ExternalReference handle_scope_next_address();
static ExternalReference handle_scope_limit_address(); static ExternalReference handle_scope_limit_address();
@ -549,6 +552,7 @@ class ExternalReference BASE_EMBEDDED {
// Static variables containing common double constants. // Static variables containing common double constants.
static ExternalReference address_of_min_int(); static ExternalReference address_of_min_int();
static ExternalReference address_of_one_half(); static ExternalReference address_of_one_half();
static ExternalReference address_of_negative_infinity();
Address address() const {return reinterpret_cast<Address>(address_);} Address address() const {return reinterpret_cast<Address>(address_);}
@ -710,6 +714,10 @@ static inline int NumberOfBitsSet(uint32_t x) {
return num_bits_set; return num_bits_set;
} }
// Computes pow(x, y) with the special cases in the spec for Math.pow.
double power_double_int(double x, int y);
double power_double_double(double x, double y);
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_ASSEMBLER_H_ #endif // V8_ASSEMBLER_H_

3
deps/v8/src/ast-inl.h

@ -94,7 +94,8 @@ ForStatement::ForStatement(ZoneStringList* labels)
ForInStatement::ForInStatement(ZoneStringList* labels) ForInStatement::ForInStatement(ZoneStringList* labels)
: IterationStatement(labels), each_(NULL), enumerable_(NULL) { : IterationStatement(labels), each_(NULL), enumerable_(NULL),
assignment_id_(GetNextId()) {
} }

11
deps/v8/src/ast.cc

@ -125,17 +125,18 @@ Assignment::Assignment(Token::Value op,
target_(target), target_(target),
value_(value), value_(value),
pos_(pos), pos_(pos),
compound_bailout_id_(kNoNumber), binary_operation_(NULL),
compound_load_id_(kNoNumber),
assignment_id_(GetNextId()),
block_start_(false), block_start_(false),
block_end_(false), block_end_(false),
is_monomorphic_(false), is_monomorphic_(false),
receiver_types_(NULL) { receiver_types_(NULL) {
ASSERT(Token::IsAssignmentOp(op)); ASSERT(Token::IsAssignmentOp(op));
binary_operation_ = is_compound()
? new BinaryOperation(binary_op(), target, value, pos + 1)
: NULL;
if (is_compound()) { if (is_compound()) {
compound_bailout_id_ = GetNextId(); binary_operation_ =
new BinaryOperation(binary_op(), target, value, pos + 1);
compound_load_id_ = GetNextId();
} }
} }

22
deps/v8/src/ast.h

@ -435,7 +435,6 @@ class IterationStatement: public BreakableStatement {
virtual IterationStatement* AsIterationStatement() { return this; } virtual IterationStatement* AsIterationStatement() { return this; }
Statement* body() const { return body_; } Statement* body() const { return body_; }
void set_body(Statement* stmt) { body_ = stmt; }
// Bailout support. // Bailout support.
int OsrEntryId() const { return osr_entry_id_; } int OsrEntryId() const { return osr_entry_id_; }
@ -532,11 +531,8 @@ class ForStatement: public IterationStatement {
} }
Statement* init() const { return init_; } Statement* init() const { return init_; }
void set_init(Statement* stmt) { init_ = stmt; }
Expression* cond() const { return cond_; } Expression* cond() const { return cond_; }
void set_cond(Expression* expr) { cond_ = expr; }
Statement* next() const { return next_; } Statement* next() const { return next_; }
void set_next(Statement* stmt) { next_ = stmt; }
bool may_have_function_literal() const { bool may_have_function_literal() const {
return may_have_function_literal_; return may_have_function_literal_;
@ -579,11 +575,13 @@ class ForInStatement: public IterationStatement {
Expression* enumerable() const { return enumerable_; } Expression* enumerable() const { return enumerable_; }
// Bailout support. // Bailout support.
int AssignmentId() const { return assignment_id_; }
virtual int ContinueId() const { return EntryId(); } virtual int ContinueId() const { return EntryId(); }
private: private:
Expression* each_; Expression* each_;
Expression* enumerable_; Expression* enumerable_;
int assignment_id_;
}; };
@ -748,9 +746,7 @@ class IfStatement: public Statement {
Expression* condition() const { return condition_; } Expression* condition() const { return condition_; }
Statement* then_statement() const { return then_statement_; } Statement* then_statement() const { return then_statement_; }
void set_then_statement(Statement* stmt) { then_statement_ = stmt; }
Statement* else_statement() const { return else_statement_; } Statement* else_statement() const { return else_statement_; }
void set_else_statement(Statement* stmt) { else_statement_ = stmt; }
private: private:
Expression* condition_; Expression* condition_;
@ -1432,7 +1428,9 @@ class IncrementOperation: public Expression {
class CountOperation: public Expression { class CountOperation: public Expression {
public: public:
CountOperation(bool is_prefix, IncrementOperation* increment, int pos) CountOperation(bool is_prefix, IncrementOperation* increment, int pos)
: is_prefix_(is_prefix), increment_(increment), pos_(pos) { } : is_prefix_(is_prefix), increment_(increment), pos_(pos),
assignment_id_(GetNextId()) {
}
DECLARE_NODE_TYPE(CountOperation) DECLARE_NODE_TYPE(CountOperation)
@ -1452,10 +1450,14 @@ class CountOperation: public Expression {
virtual bool IsInlineable() const; virtual bool IsInlineable() const;
// Bailout support.
int AssignmentId() const { return assignment_id_; }
private: private:
bool is_prefix_; bool is_prefix_;
IncrementOperation* increment_; IncrementOperation* increment_;
int pos_; int pos_;
int assignment_id_;
}; };
@ -1585,7 +1587,8 @@ class Assignment: public Expression {
} }
// Bailout support. // Bailout support.
int compound_bailout_id() const { return compound_bailout_id_; } int CompoundLoadId() const { return compound_load_id_; }
int AssignmentId() const { return assignment_id_; }
private: private:
Token::Value op_; Token::Value op_;
@ -1593,7 +1596,8 @@ class Assignment: public Expression {
Expression* value_; Expression* value_;
int pos_; int pos_;
BinaryOperation* binary_operation_; BinaryOperation* binary_operation_;
int compound_bailout_id_; int compound_load_id_;
int assignment_id_;
bool block_start_; bool block_start_;
bool block_end_; bool block_end_;

2
deps/v8/src/checks.h

@ -231,6 +231,8 @@ static inline void CheckNonEqualsHelper(const char* file,
#define CHECK_GT(a, b) CHECK((a) > (b)) #define CHECK_GT(a, b) CHECK((a) > (b))
#define CHECK_GE(a, b) CHECK((a) >= (b)) #define CHECK_GE(a, b) CHECK((a) >= (b))
#define CHECK_LT(a, b) CHECK((a) < (b))
#define CHECK_LE(a, b) CHECK((a) <= (b))
// This is inspired by the static assertion facility in boost. This // This is inspired by the static assertion facility in boost. This

34
deps/v8/src/compiler.cc

@ -116,13 +116,26 @@ static bool AlwaysFullCompiler() {
static void FinishOptimization(Handle<JSFunction> function, int64_t start) { static void FinishOptimization(Handle<JSFunction> function, int64_t start) {
int opt_count = function->shared()->opt_count(); int opt_count = function->shared()->opt_count();
function->shared()->set_opt_count(opt_count + 1); function->shared()->set_opt_count(opt_count + 1);
if (!FLAG_trace_opt) return;
double ms = static_cast<double>(OS::Ticks() - start) / 1000; double ms = static_cast<double>(OS::Ticks() - start) / 1000;
PrintF("[optimizing: "); if (FLAG_trace_opt) {
function->PrintName(); PrintF("[optimizing: ");
PrintF(" / %" V8PRIxPTR, reinterpret_cast<intptr_t>(*function)); function->PrintName();
PrintF(" - took %0.3f ms]\n", ms); PrintF(" / %" V8PRIxPTR, reinterpret_cast<intptr_t>(*function));
PrintF(" - took %0.3f ms]\n", ms);
}
if (FLAG_trace_opt_stats) {
static double compilation_time = 0.0;
static int compiled_functions = 0;
static int code_size = 0;
compilation_time += ms;
compiled_functions++;
code_size += function->shared()->SourceSize();
PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
compiled_functions,
code_size,
compilation_time);
}
} }
@ -461,7 +474,14 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
ScriptDataImpl* pre_data = input_pre_data; ScriptDataImpl* pre_data = input_pre_data;
if (pre_data == NULL if (pre_data == NULL
&& source_length >= FLAG_min_preparse_length) { && source_length >= FLAG_min_preparse_length) {
pre_data = ParserApi::PartialPreParse(source, NULL, extension); if (source->IsExternalTwoByteString()) {
ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length());
pre_data = ParserApi::PartialPreParse(&stream, extension);
} else {
GenericStringUC16CharacterStream stream(source, 0, source->length());
pre_data = ParserApi::PartialPreParse(&stream, extension);
}
} }
// Create a script object describing the script to be compiled. // Create a script object describing the script to be compiled.

263
deps/v8/src/extensions/experimental/i18n-extension.cc

@ -0,0 +1,263 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "i18n-extension.h"
#include <algorithm>
#include <string>
#include "unicode/locid.h"
#include "unicode/uloc.h"
namespace v8 {
namespace internal {
I18NExtension* I18NExtension::extension_ = NULL;
// TODO(cira): maybe move JS code to a .js file and generata cc files from it?
const char* const I18NExtension::kSource =
"Locale = function(optLocale) {"
" native function NativeJSLocale();"
" var properties = NativeJSLocale(optLocale);"
" this.locale = properties.locale;"
" this.language = properties.language;"
" this.script = properties.script;"
" this.region = properties.region;"
"};"
"Locale.availableLocales = function() {"
" native function NativeJSAvailableLocales();"
" return NativeJSAvailableLocales();"
"};"
"Locale.prototype.maximizedLocale = function() {"
" native function NativeJSMaximizedLocale();"
" return new Locale(NativeJSMaximizedLocale(this.locale));"
"};"
"Locale.prototype.minimizedLocale = function() {"
" native function NativeJSMinimizedLocale();"
" return new Locale(NativeJSMinimizedLocale(this.locale));"
"};"
"Locale.prototype.displayLocale_ = function(displayLocale) {"
" var result = this.locale;"
" if (displayLocale !== undefined) {"
" result = displayLocale.locale;"
" }"
" return result;"
"};"
"Locale.prototype.displayLanguage = function(optDisplayLocale) {"
" var displayLocale = this.displayLocale_(optDisplayLocale);"
" native function NativeJSDisplayLanguage();"
" return NativeJSDisplayLanguage(this.locale, displayLocale);"
"};"
"Locale.prototype.displayScript = function(optDisplayLocale) {"
" var displayLocale = this.displayLocale_(optDisplayLocale);"
" native function NativeJSDisplayScript();"
" return NativeJSDisplayScript(this.locale, displayLocale);"
"};"
"Locale.prototype.displayRegion = function(optDisplayLocale) {"
" var displayLocale = this.displayLocale_(optDisplayLocale);"
" native function NativeJSDisplayRegion();"
" return NativeJSDisplayRegion(this.locale, displayLocale);"
"};"
"Locale.prototype.displayName = function(optDisplayLocale) {"
" var displayLocale = this.displayLocale_(optDisplayLocale);"
" native function NativeJSDisplayName();"
" return NativeJSDisplayName(this.locale, displayLocale);"
"};";
v8::Handle<v8::FunctionTemplate> I18NExtension::GetNativeFunction(
v8::Handle<v8::String> name) {
if (name->Equals(v8::String::New("NativeJSLocale"))) {
return v8::FunctionTemplate::New(JSLocale);
} else if (name->Equals(v8::String::New("NativeJSAvailableLocales"))) {
return v8::FunctionTemplate::New(JSAvailableLocales);
} else if (name->Equals(v8::String::New("NativeJSMaximizedLocale"))) {
return v8::FunctionTemplate::New(JSMaximizedLocale);
} else if (name->Equals(v8::String::New("NativeJSMinimizedLocale"))) {
return v8::FunctionTemplate::New(JSMinimizedLocale);
} else if (name->Equals(v8::String::New("NativeJSDisplayLanguage"))) {
return v8::FunctionTemplate::New(JSDisplayLanguage);
} else if (name->Equals(v8::String::New("NativeJSDisplayScript"))) {
return v8::FunctionTemplate::New(JSDisplayScript);
} else if (name->Equals(v8::String::New("NativeJSDisplayRegion"))) {
return v8::FunctionTemplate::New(JSDisplayRegion);
} else if (name->Equals(v8::String::New("NativeJSDisplayName"))) {
return v8::FunctionTemplate::New(JSDisplayName);
}
return v8::Handle<v8::FunctionTemplate>();
}
v8::Handle<v8::Value> I18NExtension::JSLocale(const v8::Arguments& args) {
// TODO(cira): Fetch browser locale. Accept en-US as good default for now.
// We could possibly pass browser locale as a parameter in the constructor.
std::string locale_name("en-US");
if (args.Length() == 1 && args[0]->IsString()) {
locale_name = *v8::String::Utf8Value(args[0]->ToString());
}
v8::Local<v8::Object> locale = v8::Object::New();
locale->Set(v8::String::New("locale"), v8::String::New(locale_name.c_str()));
icu::Locale icu_locale(locale_name.c_str());
const char* language = icu_locale.getLanguage();
locale->Set(v8::String::New("language"), v8::String::New(language));
const char* script = icu_locale.getScript();
if (strlen(script)) {
locale->Set(v8::String::New("script"), v8::String::New(script));
}
const char* region = icu_locale.getCountry();
if (strlen(region)) {
locale->Set(v8::String::New("region"), v8::String::New(region));
}
return locale;
}
// TODO(cira): Filter out locales that Chrome doesn't support.
v8::Handle<v8::Value> I18NExtension::JSAvailableLocales(
const v8::Arguments& args) {
v8::Local<v8::Array> all_locales = v8::Array::New();
int count = 0;
const Locale* icu_locales = icu::Locale::getAvailableLocales(count);
for (int i = 0; i < count; ++i) {
all_locales->Set(i, v8::String::New(icu_locales[i].getName()));
}
return all_locales;
}
// Use - as tag separator, not _ that ICU uses.
static std::string NormalizeLocale(const std::string& locale) {
std::string result(locale);
// TODO(cira): remove STL dependency.
std::replace(result.begin(), result.end(), '_', '-');
return result;
}
v8::Handle<v8::Value> I18NExtension::JSMaximizedLocale(
const v8::Arguments& args) {
if (!args.Length() || !args[0]->IsString()) {
return v8::Undefined();
}
UErrorCode status = U_ZERO_ERROR;
std::string locale_name = *v8::String::Utf8Value(args[0]->ToString());
char max_locale[ULOC_FULLNAME_CAPACITY];
uloc_addLikelySubtags(locale_name.c_str(), max_locale,
sizeof(max_locale), &status);
if (U_FAILURE(status)) {
return v8::Undefined();
}
return v8::String::New(NormalizeLocale(max_locale).c_str());
}
v8::Handle<v8::Value> I18NExtension::JSMinimizedLocale(
const v8::Arguments& args) {
if (!args.Length() || !args[0]->IsString()) {
return v8::Undefined();
}
UErrorCode status = U_ZERO_ERROR;
std::string locale_name = *v8::String::Utf8Value(args[0]->ToString());
char min_locale[ULOC_FULLNAME_CAPACITY];
uloc_minimizeSubtags(locale_name.c_str(), min_locale,
sizeof(min_locale), &status);
if (U_FAILURE(status)) {
return v8::Undefined();
}
return v8::String::New(NormalizeLocale(min_locale).c_str());
}
// Common code for JSDisplayXXX methods.
static v8::Handle<v8::Value> GetDisplayItem(const v8::Arguments& args,
const std::string& item) {
if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) {
return v8::Undefined();
}
std::string base_locale = *v8::String::Utf8Value(args[0]->ToString());
icu::Locale icu_locale(base_locale.c_str());
icu::Locale display_locale =
icu::Locale(*v8::String::Utf8Value(args[1]->ToString()));
UnicodeString result;
if (item == "language") {
icu_locale.getDisplayLanguage(display_locale, result);
} else if (item == "script") {
icu_locale.getDisplayScript(display_locale, result);
} else if (item == "region") {
icu_locale.getDisplayCountry(display_locale, result);
} else if (item == "name") {
icu_locale.getDisplayName(display_locale, result);
} else {
return v8::Undefined();
}
if (result.length()) {
return v8::String::New(
reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length());
}
return v8::Undefined();
}
v8::Handle<v8::Value> I18NExtension::JSDisplayLanguage(
const v8::Arguments& args) {
return GetDisplayItem(args, "language");
}
v8::Handle<v8::Value> I18NExtension::JSDisplayScript(
const v8::Arguments& args) {
return GetDisplayItem(args, "script");
}
v8::Handle<v8::Value> I18NExtension::JSDisplayRegion(
const v8::Arguments& args) {
return GetDisplayItem(args, "region");
}
v8::Handle<v8::Value> I18NExtension::JSDisplayName(const v8::Arguments& args) {
return GetDisplayItem(args, "name");
}
I18NExtension* I18NExtension::get() {
if (!extension_) {
extension_ = new I18NExtension();
}
return extension_;
}
void I18NExtension::Register() {
static v8::DeclareExtension i18n_extension_declaration(I18NExtension::get());
}
} } // namespace v8::internal

64
deps/v8/src/extensions/experimental/i18n-extension.h

@ -0,0 +1,64 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_EXTENSIONS_EXPERIMENTAL_I18N_EXTENSION_H_
#define V8_EXTENSIONS_EXPERIMENTAL_I18N_EXTENSION_H_
#include <v8.h>
namespace v8 {
namespace internal {
class I18NExtension : public v8::Extension {
public:
I18NExtension() : v8::Extension("v8/i18n", kSource) {}
virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
v8::Handle<v8::String> name);
// Implementations of window.Locale methods.
static v8::Handle<v8::Value> JSLocale(const v8::Arguments& args);
static v8::Handle<v8::Value> JSAvailableLocales(const v8::Arguments& args);
static v8::Handle<v8::Value> JSMaximizedLocale(const v8::Arguments& args);
static v8::Handle<v8::Value> JSMinimizedLocale(const v8::Arguments& args);
static v8::Handle<v8::Value> JSDisplayLanguage(const v8::Arguments& args);
static v8::Handle<v8::Value> JSDisplayScript(const v8::Arguments& args);
static v8::Handle<v8::Value> JSDisplayRegion(const v8::Arguments& args);
static v8::Handle<v8::Value> JSDisplayName(const v8::Arguments& args);
// V8 code prefers Register, while Chrome and WebKit use get kind of methods.
static void Register();
static I18NExtension* get();
private:
static const char* const kSource;
static I18NExtension* extension_;
};
} } // namespace v8::internal
#endif // V8_EXTENSIONS_EXPERIMENTAL_I18N_EXTENSION_H_

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

@ -194,6 +194,7 @@ DEFINE_bool(mask_constants_with_cookie,
// codegen.cc // codegen.cc
DEFINE_bool(lazy, true, "use lazy compilation") DEFINE_bool(lazy, true, "use lazy compilation")
DEFINE_bool(trace_opt, false, "trace lazy optimization") DEFINE_bool(trace_opt, false, "trace lazy optimization")
DEFINE_bool(trace_opt_stats, false, "trace lazy optimization statistics")
DEFINE_bool(opt, true, "use adaptive optimizations") DEFINE_bool(opt, true, "use adaptive optimizations")
DEFINE_bool(opt_eagerly, false, "be more eager when adaptively optimizing") DEFINE_bool(opt_eagerly, false, "be more eager when adaptively optimizing")
DEFINE_bool(always_opt, false, "always try to optimize functions") DEFINE_bool(always_opt, false, "always try to optimize functions")
@ -456,8 +457,6 @@ DEFINE_bool(log_snapshot_positions, false,
"log positions of (de)serialized objects in the snapshot.") "log positions of (de)serialized objects in the snapshot.")
DEFINE_bool(log_suspect, false, "Log suspect operations.") DEFINE_bool(log_suspect, false, "Log suspect operations.")
DEFINE_bool(log_producers, false, "Log stack traces of JS objects allocations.") DEFINE_bool(log_producers, false, "Log stack traces of JS objects allocations.")
DEFINE_bool(compress_log, false,
"Compress log to save space (makes log less human-readable).")
DEFINE_bool(prof, false, DEFINE_bool(prof, false,
"Log statistical profiling information (implies --log-code).") "Log statistical profiling information (implies --log-code).")
DEFINE_bool(prof_auto, true, DEFINE_bool(prof_auto, true,

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

@ -481,7 +481,7 @@ class FullCodeGenerator: public AstVisitor {
// Assign to the given expression as if via '='. The right-hand-side value // Assign to the given expression as if via '='. The right-hand-side value
// is expected in the accumulator. // is expected in the accumulator.
void EmitAssignment(Expression* expr); void EmitAssignment(Expression* expr, int bailout_ast_id);
// Complete a variable assignment. The right-hand-side value is expected // Complete a variable assignment. The right-hand-side value is expected
// in the accumulator. // in the accumulator.

33
deps/v8/src/heap-profiler.cc

@ -348,27 +348,34 @@ void HeapProfiler::TearDown() {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
HeapSnapshot* HeapProfiler::TakeSnapshot(const char* name, int type) { HeapSnapshot* HeapProfiler::TakeSnapshot(const char* name,
int type,
v8::ActivityControl* control) {
ASSERT(singleton_ != NULL); ASSERT(singleton_ != NULL);
return singleton_->TakeSnapshotImpl(name, type); return singleton_->TakeSnapshotImpl(name, type, control);
} }
HeapSnapshot* HeapProfiler::TakeSnapshot(String* name, int type) { HeapSnapshot* HeapProfiler::TakeSnapshot(String* name,
int type,
v8::ActivityControl* control) {
ASSERT(singleton_ != NULL); ASSERT(singleton_ != NULL);
return singleton_->TakeSnapshotImpl(name, type); return singleton_->TakeSnapshotImpl(name, type, control);
} }
HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name, int type) { HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name,
int type,
v8::ActivityControl* control) {
Heap::CollectAllGarbage(true); Heap::CollectAllGarbage(true);
HeapSnapshot::Type s_type = static_cast<HeapSnapshot::Type>(type); HeapSnapshot::Type s_type = static_cast<HeapSnapshot::Type>(type);
HeapSnapshot* result = HeapSnapshot* result =
snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++); snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++);
bool generation_completed = true;
switch (s_type) { switch (s_type) {
case HeapSnapshot::kFull: { case HeapSnapshot::kFull: {
HeapSnapshotGenerator generator(result); HeapSnapshotGenerator generator(result, control);
generator.GenerateSnapshot(); generation_completed = generator.GenerateSnapshot();
break; break;
} }
case HeapSnapshot::kAggregated: { case HeapSnapshot::kAggregated: {
@ -381,13 +388,19 @@ HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name, int type) {
default: default:
UNREACHABLE(); UNREACHABLE();
} }
snapshots_->SnapshotGenerationFinished(); if (!generation_completed) {
delete result;
result = NULL;
}
snapshots_->SnapshotGenerationFinished(result);
return result; return result;
} }
HeapSnapshot* HeapProfiler::TakeSnapshotImpl(String* name, int type) { HeapSnapshot* HeapProfiler::TakeSnapshotImpl(String* name,
return TakeSnapshotImpl(snapshots_->GetName(name), type); int type,
v8::ActivityControl* control) {
return TakeSnapshotImpl(snapshots_->GetName(name), type, control);
} }

16
deps/v8/src/heap-profiler.h

@ -56,8 +56,12 @@ class HeapProfiler {
static void TearDown(); static void TearDown();
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
static HeapSnapshot* TakeSnapshot(const char* name, int type); static HeapSnapshot* TakeSnapshot(const char* name,
static HeapSnapshot* TakeSnapshot(String* name, int type); int type,
v8::ActivityControl* control);
static HeapSnapshot* TakeSnapshot(String* name,
int type,
v8::ActivityControl* control);
static int GetSnapshotsCount(); static int GetSnapshotsCount();
static HeapSnapshot* GetSnapshot(int index); static HeapSnapshot* GetSnapshot(int index);
static HeapSnapshot* FindSnapshot(unsigned uid); static HeapSnapshot* FindSnapshot(unsigned uid);
@ -75,8 +79,12 @@ class HeapProfiler {
private: private:
HeapProfiler(); HeapProfiler();
~HeapProfiler(); ~HeapProfiler();
HeapSnapshot* TakeSnapshotImpl(const char* name, int type); HeapSnapshot* TakeSnapshotImpl(const char* name,
HeapSnapshot* TakeSnapshotImpl(String* name, int type); int type,
v8::ActivityControl* control);
HeapSnapshot* TakeSnapshotImpl(String* name,
int type,
v8::ActivityControl* control);
HeapSnapshotsCollection* snapshots_; HeapSnapshotsCollection* snapshots_;
unsigned next_snapshot_uid_; unsigned next_snapshot_uid_;

18
deps/v8/src/heap.cc

@ -3757,14 +3757,21 @@ bool Heap::IdleNotification() {
static const int kIdlesBeforeScavenge = 4; static const int kIdlesBeforeScavenge = 4;
static const int kIdlesBeforeMarkSweep = 7; static const int kIdlesBeforeMarkSweep = 7;
static const int kIdlesBeforeMarkCompact = 8; static const int kIdlesBeforeMarkCompact = 8;
static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1;
static const int kGCsBetweenCleanup = 4;
static int number_idle_notifications = 0; static int number_idle_notifications = 0;
static int last_gc_count = gc_count_; static int last_gc_count = gc_count_;
bool uncommit = true; bool uncommit = true;
bool finished = false; bool finished = false;
if (last_gc_count == gc_count_) { // Reset the number of idle notifications received when a number of
number_idle_notifications++; // GCs have taken place. This allows another round of cleanup based
// on idle notifications if enough work has been carried out to
// provoke a number of garbage collections.
if (gc_count_ < last_gc_count + kGCsBetweenCleanup) {
number_idle_notifications =
Min(number_idle_notifications + 1, kMaxIdleCount);
} else { } else {
number_idle_notifications = 0; number_idle_notifications = 0;
last_gc_count = gc_count_; last_gc_count = gc_count_;
@ -3779,7 +3786,6 @@ bool Heap::IdleNotification() {
} }
new_space_.Shrink(); new_space_.Shrink();
last_gc_count = gc_count_; last_gc_count = gc_count_;
} else if (number_idle_notifications == kIdlesBeforeMarkSweep) { } else if (number_idle_notifications == kIdlesBeforeMarkSweep) {
// Before doing the mark-sweep collections we clear the // Before doing the mark-sweep collections we clear the
// compilation cache to avoid hanging on to source code and // compilation cache to avoid hanging on to source code and
@ -3794,7 +3800,6 @@ bool Heap::IdleNotification() {
CollectAllGarbage(true); CollectAllGarbage(true);
new_space_.Shrink(); new_space_.Shrink();
last_gc_count = gc_count_; last_gc_count = gc_count_;
number_idle_notifications = 0;
finished = true; finished = true;
} else if (contexts_disposed_ > 0) { } else if (contexts_disposed_ > 0) {
@ -3813,6 +3818,11 @@ bool Heap::IdleNotification() {
number_idle_notifications = 0; number_idle_notifications = 0;
uncommit = false; uncommit = false;
} }
} else if (number_idle_notifications > kIdlesBeforeMarkCompact) {
// If we have received more than kIdlesBeforeMarkCompact idle
// notifications we do not perform any cleanup because we don't
// expect to gain much by doing so.
finished = true;
} }
// Make sure that we have no pending context disposals and // Make sure that we have no pending context disposals and

4
deps/v8/src/heap.h

@ -1119,9 +1119,9 @@ class Heap : public AllStatic {
static int contexts_disposed_; static int contexts_disposed_;
#if defined(V8_TARGET_ARCH_X64) #if defined(V8_TARGET_ARCH_X64)
static const int kMaxObjectSizeInNewSpace = 512*KB; static const int kMaxObjectSizeInNewSpace = 1024*KB;
#else #else
static const int kMaxObjectSizeInNewSpace = 256*KB; static const int kMaxObjectSizeInNewSpace = 512*KB;
#endif #endif
static NewSpace new_space_; static NewSpace new_space_;

20
deps/v8/src/hydrogen-instructions.h

@ -77,6 +77,7 @@ class LChunkBuilder;
// HLoadKeyedFastElement // HLoadKeyedFastElement
// HLoadKeyedGeneric // HLoadKeyedGeneric
// HLoadNamedGeneric // HLoadNamedGeneric
// HPower
// HStoreNamed // HStoreNamed
// HStoreNamedField // HStoreNamedField
// HStoreNamedGeneric // HStoreNamedGeneric
@ -223,6 +224,7 @@ class LChunkBuilder;
V(ObjectLiteral) \ V(ObjectLiteral) \
V(OsrEntry) \ V(OsrEntry) \
V(Parameter) \ V(Parameter) \
V(Power) \
V(PushArgument) \ V(PushArgument) \
V(RegExpLiteral) \ V(RegExpLiteral) \
V(Return) \ V(Return) \
@ -1377,6 +1379,7 @@ class HUnaryMathOperation: public HUnaryOperation {
SetFlag(kFlexibleRepresentation); SetFlag(kFlexibleRepresentation);
break; break;
case kMathSqrt: case kMathSqrt:
case kMathPowHalf:
default: default:
set_representation(Representation::Double()); set_representation(Representation::Double());
} }
@ -1395,6 +1398,7 @@ class HUnaryMathOperation: public HUnaryOperation {
case kMathRound: case kMathRound:
case kMathCeil: case kMathCeil:
case kMathSqrt: case kMathSqrt:
case kMathPowHalf:
return Representation::Double(); return Representation::Double();
break; break;
case kMathAbs: case kMathAbs:
@ -2184,6 +2188,22 @@ class HInstanceOf: public HBinaryOperation {
}; };
class HPower: public HBinaryOperation {
public:
HPower(HValue* left, HValue* right)
: HBinaryOperation(left, right) {
set_representation(Representation::Double());
SetFlag(kUseGVN);
}
virtual Representation RequiredInputRepresentation(int index) const {
return (index == 1) ? Representation::None() : Representation::Double();
}
DECLARE_CONCRETE_INSTRUCTION(Power, "power")
};
class HAdd: public HArithmeticBinaryOperation { class HAdd: public HArithmeticBinaryOperation {
public: public:
HAdd(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) { HAdd(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) {

1005
deps/v8/src/hydrogen.cc

File diff suppressed because it is too large

81
deps/v8/src/hydrogen.h

@ -557,10 +557,29 @@ class AstContext {
bool IsValue() const { return kind_ == Expression::kValue; } bool IsValue() const { return kind_ == Expression::kValue; }
bool IsTest() const { return kind_ == Expression::kTest; } bool IsTest() const { return kind_ == Expression::kTest; }
// 'Fill' this context with a hydrogen value. The value is assumed to
// have already been inserted in the instruction stream (or not need to
// be, e.g., HPhi). Call this function in tail position in the Visit
// functions for expressions.
virtual void ReturnValue(HValue* value) = 0;
// Add a hydrogen instruction to the instruction stream (recording an
// environment simulation if necessary) and then fill this context with
// the instruction as value.
virtual void ReturnInstruction(HInstruction* instr, int ast_id) = 0;
protected: protected:
AstContext(HGraphBuilder* owner, Expression::Context kind); AstContext(HGraphBuilder* owner, Expression::Context kind);
virtual ~AstContext(); virtual ~AstContext();
HGraphBuilder* owner() const { return owner_; }
// We want to be able to assert, in a context-specific way, that the stack
// height makes sense when the context is filled.
#ifdef DEBUG
int original_count_;
#endif
private: private:
HGraphBuilder* owner_; HGraphBuilder* owner_;
Expression::Context kind_; Expression::Context kind_;
@ -573,6 +592,10 @@ class EffectContext: public AstContext {
explicit EffectContext(HGraphBuilder* owner) explicit EffectContext(HGraphBuilder* owner)
: AstContext(owner, Expression::kEffect) { : AstContext(owner, Expression::kEffect) {
} }
virtual ~EffectContext();
virtual void ReturnValue(HValue* value);
virtual void ReturnInstruction(HInstruction* instr, int ast_id);
}; };
@ -581,6 +604,10 @@ class ValueContext: public AstContext {
explicit ValueContext(HGraphBuilder* owner) explicit ValueContext(HGraphBuilder* owner)
: AstContext(owner, Expression::kValue) { : AstContext(owner, Expression::kValue) {
} }
virtual ~ValueContext();
virtual void ReturnValue(HValue* value);
virtual void ReturnInstruction(HInstruction* instr, int ast_id);
}; };
@ -598,6 +625,9 @@ class TestContext: public AstContext {
invert_false_(invert_false) { invert_false_(invert_false) {
} }
virtual void ReturnValue(HValue* value);
virtual void ReturnInstruction(HInstruction* instr, int ast_id);
static TestContext* cast(AstContext* context) { static TestContext* cast(AstContext* context) {
ASSERT(context->IsTest()); ASSERT(context->IsTest());
return reinterpret_cast<TestContext*>(context); return reinterpret_cast<TestContext*>(context);
@ -610,6 +640,10 @@ class TestContext: public AstContext {
bool invert_false() { return invert_false_; } bool invert_false() { return invert_false_; }
private: private:
// Build the shared core part of the translation unpacking a value into
// control flow.
void BuildBranch(HValue* value);
HBasicBlock* if_true_; HBasicBlock* if_true_;
HBasicBlock* if_false_; HBasicBlock* if_false_;
bool invert_true_; bool invert_true_;
@ -631,9 +665,25 @@ class HGraphBuilder: public AstVisitor {
HGraph* CreateGraph(CompilationInfo* info); HGraph* CreateGraph(CompilationInfo* info);
// Simple accessors.
HGraph* graph() const { return graph_; }
HSubgraph* subgraph() const { return current_subgraph_; }
HEnvironment* environment() const { return subgraph()->environment(); }
HBasicBlock* CurrentBlock() const { return subgraph()->exit_block(); }
// Adding instructions.
HInstruction* AddInstruction(HInstruction* instr);
void AddSimulate(int id);
// Bailout environment manipulation.
void Push(HValue* value) { environment()->Push(value); }
HValue* Pop() { return environment()->Pop(); }
private: private:
// Type of a member function that generates inline code for a native function. // Type of a member function that generates inline code for a native function.
typedef void (HGraphBuilder::*InlineFunctionGenerator)(int argument_count); typedef void (HGraphBuilder::*InlineFunctionGenerator)(int argument_count,
int ast_id);
// Forward declarations for inner scope classes. // Forward declarations for inner scope classes.
class SubgraphScope; class SubgraphScope;
@ -650,19 +700,14 @@ class HGraphBuilder: public AstVisitor {
// Simple accessors. // Simple accessors.
TypeFeedbackOracle* oracle() const { return oracle_; } TypeFeedbackOracle* oracle() const { return oracle_; }
HGraph* graph() const { return graph_; }
HSubgraph* subgraph() const { return current_subgraph_; }
AstContext* ast_context() const { return ast_context_; } AstContext* ast_context() const { return ast_context_; }
void set_ast_context(AstContext* context) { ast_context_ = context; } void set_ast_context(AstContext* context) { ast_context_ = context; }
AstContext* call_context() const { return call_context_; } AstContext* call_context() const { return call_context_; }
HBasicBlock* function_return() const { return function_return_; } HBasicBlock* function_return() const { return function_return_; }
HEnvironment* environment() const { return subgraph()->environment(); }
HBasicBlock* CurrentBlock() const { return subgraph()->exit_block(); }
// Generators for inline runtime functions. // Generators for inline runtime functions.
#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \ #define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \
void Generate##Name(int argument_count); void Generate##Name(int argument_count, int ast_id);
INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION)
@ -683,8 +728,6 @@ class HGraphBuilder: public AstVisitor {
HSubgraph* true_graph, HSubgraph* true_graph,
HSubgraph* false_graph); HSubgraph* false_graph);
void Push(HValue* value) { environment()->Push(value); }
HValue* Pop() { return environment()->Pop(); }
HValue* Top() const { return environment()->Top(); } HValue* Top() const { return environment()->Top(); }
void Drop(int n) { environment()->Drop(n); } void Drop(int n) { environment()->Drop(n); }
void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); } void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); }
@ -708,18 +751,15 @@ class HGraphBuilder: public AstVisitor {
HValue* VisitArgument(Expression* expr); HValue* VisitArgument(Expression* expr);
void VisitArgumentList(ZoneList<Expression*>* arguments); void VisitArgumentList(ZoneList<Expression*>* arguments);
HInstruction* AddInstruction(HInstruction* instr);
void AddSimulate(int id);
void AddPhi(HPhi* phi); void AddPhi(HPhi* phi);
void PushAndAdd(HInstruction* instr); void PushAndAdd(HInstruction* instr);
void PushAndAdd(HInstruction* instr, int position);
void PushArgumentsForStubCall(int argument_count); void PushArgumentsForStubCall(int argument_count);
// Initialize the arguments to the call based on then environment, add it // Remove the arguments from the bailout environment and emit instructions
// to the graph, and drop the arguments from the environment. // to push them as outgoing parameters.
void ProcessCall(HCall* call, int source_position); void ProcessCall(HCall* call);
void AssumeRepresentation(HValue* value, Representation r); void AssumeRepresentation(HValue* value, Representation r);
static Representation ToRepresentation(TypeInfo info); static Representation ToRepresentation(TypeInfo info);
@ -743,7 +783,7 @@ class HGraphBuilder: public AstVisitor {
FunctionLiteral* function); FunctionLiteral* function);
// Helpers for flow graph construction. // Helpers for flow graph construction.
void LookupGlobalPropertyCell(VariableProxy* expr, void LookupGlobalPropertyCell(Variable* var,
LookupResult* lookup, LookupResult* lookup,
bool is_store); bool is_store);
@ -753,10 +793,11 @@ class HGraphBuilder: public AstVisitor {
bool TryMathFunctionInline(Call* expr); bool TryMathFunctionInline(Call* expr);
void TraceInline(Handle<JSFunction> target, bool result); void TraceInline(Handle<JSFunction> target, bool result);
void HandleGlobalVariableAssignment(VariableProxy* proxy, void HandleGlobalVariableAssignment(Variable* var,
HValue* value, HValue* value,
int position); int position,
void HandleGlobalVariableLoad(VariableProxy* expr); int ast_id);
void HandlePropertyAssignment(Assignment* expr); void HandlePropertyAssignment(Assignment* expr);
void HandleCompoundAssignment(Assignment* expr); void HandleCompoundAssignment(Assignment* expr);
void HandlePolymorphicLoadNamedField(Property* expr, void HandlePolymorphicLoadNamedField(Property* expr,

1
deps/v8/src/ia32/builtins-ia32.cc

@ -29,7 +29,6 @@
#if defined(V8_TARGET_ARCH_IA32) #if defined(V8_TARGET_ARCH_IA32)
#include "code-stubs.h"
#include "codegen-inl.h" #include "codegen-inl.h"
#include "deoptimizer.h" #include "deoptimizer.h"
#include "full-codegen.h" #include "full-codegen.h"

27
deps/v8/src/ia32/full-codegen-ia32.cc

@ -911,7 +911,9 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ bind(&update_each); __ bind(&update_each);
__ mov(result_register(), ebx); __ mov(result_register(), ebx);
// Perform the assignment as if via '='. // Perform the assignment as if via '='.
EmitAssignment(stmt->each()); { EffectContext context(this);
EmitAssignment(stmt->each(), stmt->AssignmentId());
}
// Generate code for the body of the loop. // Generate code for the body of the loop.
Visit(stmt->body()); Visit(stmt->body());
@ -1478,7 +1480,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// For property compound assignments we need another deoptimization // For property compound assignments we need another deoptimization
// point after the property load. // point after the property load.
if (property != NULL) { if (property != NULL) {
PrepareForBailoutForId(expr->compound_bailout_id(), TOS_REG); PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
} }
Token::Value op = expr->binary_op(); Token::Value op = expr->binary_op();
@ -1521,6 +1523,8 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
case VARIABLE: case VARIABLE:
EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
expr->op()); expr->op());
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(eax);
break; break;
case NAMED_PROPERTY: case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr); EmitNamedPropertyAssignment(expr);
@ -1849,7 +1853,7 @@ void FullCodeGenerator::EmitBinaryOp(Token::Value op,
} }
void FullCodeGenerator::EmitAssignment(Expression* expr) { void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
// Invalid left-hand sides are rewritten to have a 'throw // Invalid left-hand sides are rewritten to have a 'throw
// ReferenceError' on the left-hand side. // ReferenceError' on the left-hand side.
if (!expr->IsValidLeftHandSide()) { if (!expr->IsValidLeftHandSide()) {
@ -1897,6 +1901,8 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
break; break;
} }
} }
PrepareForBailoutForId(bailout_ast_id, TOS_REG);
context()->Plug(eax);
} }
@ -1969,8 +1975,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
} }
__ bind(&done); __ bind(&done);
} }
context()->Plug(eax);
} }
@ -2007,10 +2011,10 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
__ push(Operand(esp, kPointerSize)); // Receiver is under value. __ push(Operand(esp, kPointerSize)); // Receiver is under value.
__ CallRuntime(Runtime::kToFastProperties, 1); __ CallRuntime(Runtime::kToFastProperties, 1);
__ pop(eax); __ pop(eax);
context()->DropAndPlug(1, eax); __ Drop(1);
} else {
context()->Plug(eax);
} }
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(eax);
} }
@ -2048,6 +2052,7 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
__ pop(eax); __ pop(eax);
} }
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(eax); context()->Plug(eax);
} }
@ -3749,6 +3754,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
{ EffectContext context(this); { EffectContext context(this);
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Token::ASSIGN); Token::ASSIGN);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context.Plug(eax);
} }
// For all contexts except EffectContext We have the result on // For all contexts except EffectContext We have the result on
// top of the stack. // top of the stack.
@ -3759,6 +3766,8 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
// Perform the assignment as if via '='. // Perform the assignment as if via '='.
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Token::ASSIGN); Token::ASSIGN);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
context()->Plug(eax);
} }
break; break;
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
@ -3766,6 +3775,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
__ pop(edx); __ pop(edx);
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET); EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) { if (expr->is_postfix()) {
if (!context()->IsEffect()) { if (!context()->IsEffect()) {
context()->PlugTOS(); context()->PlugTOS();
@ -3780,6 +3790,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
__ pop(edx); __ pop(edx);
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
EmitCallIC(ic, RelocInfo::CODE_TARGET); EmitCallIC(ic, RelocInfo::CODE_TARGET);
PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
if (expr->is_postfix()) { if (expr->is_postfix()) {
// Result is on the stack // Result is on the stack
if (!context()->IsEffect()) { if (!context()->IsEffect()) {

64
deps/v8/src/ia32/lithium-codegen-ia32.cc

@ -2174,6 +2174,67 @@ void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
} }
void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
XMMRegister xmm_scratch = xmm0;
XMMRegister input_reg = ToDoubleRegister(instr->input());
ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ExternalReference negative_infinity =
ExternalReference::address_of_negative_infinity();
__ movdbl(xmm_scratch, Operand::StaticVariable(negative_infinity));
__ ucomisd(xmm_scratch, input_reg);
DeoptimizeIf(equal, instr->environment());
__ sqrtsd(input_reg, input_reg);
}
void LCodeGen::DoPower(LPower* instr) {
LOperand* left = instr->left();
LOperand* right = instr->right();
Representation exponent_type = instr->hydrogen()->right()->representation();
if (exponent_type.IsDouble()) {
// Pass two doubles as arguments on the stack.
__ PrepareCallCFunction(4, eax);
__ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
__ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
__ CallCFunction(ExternalReference::power_double_double_function(), 4);
} else if (exponent_type.IsInteger32()) {
__ PrepareCallCFunction(4, ebx);
__ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
__ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
__ CallCFunction(ExternalReference::power_double_int_function(), 4);
} else {
ASSERT(exponent_type.IsTagged());
__ PrepareCallCFunction(4, ebx);
__ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
Register right_reg = ToRegister(right);
Label non_smi;
Label done;
__ test(right_reg, Immediate(kSmiTagMask));
__ j(not_zero, &non_smi);
__ SmiUntag(right_reg);
__ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
__ CallCFunction(ExternalReference::power_double_int_function(), 4);
__ jmp(&done);
__ bind(&non_smi);
__ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx);
DeoptimizeIf(not_equal, instr->environment());
__ movdbl(xmm1, FieldOperand(right_reg, HeapNumber::kValueOffset));
__ movdbl(Operand(esp, 1 * kDoubleSize), xmm1);
__ CallCFunction(ExternalReference::power_double_double_function(), 4);
__ bind(&done);
}
// Return value is in st(0) on ia32.
// Store it into the (fixed) result register.
__ sub(Operand(esp), Immediate(kDoubleSize));
__ fstp_d(Operand(esp, 0));
__ movdbl(ToDoubleRegister(instr->result()), Operand(esp, 0));
__ add(Operand(esp), Immediate(kDoubleSize));
}
void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
switch (instr->op()) { switch (instr->op()) {
case kMathAbs: case kMathAbs:
@ -2188,6 +2249,9 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
case kMathSqrt: case kMathSqrt:
DoMathSqrt(instr); DoMathSqrt(instr);
break; break;
case kMathPowHalf:
DoMathPowHalf(instr);
break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }

1
deps/v8/src/ia32/lithium-codegen-ia32.h

@ -175,6 +175,7 @@ class LCodeGen BASE_EMBEDDED {
void DoMathFloor(LUnaryMathOperation* instr); void DoMathFloor(LUnaryMathOperation* instr);
void DoMathRound(LUnaryMathOperation* instr); void DoMathRound(LUnaryMathOperation* instr);
void DoMathSqrt(LUnaryMathOperation* instr); void DoMathSqrt(LUnaryMathOperation* instr);
void DoMathPowHalf(LUnaryMathOperation* instr);
// Support for recording safepoint and position information. // Support for recording safepoint and position information.
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);

24
deps/v8/src/ia32/lithium-ia32.cc

@ -460,12 +460,6 @@ int LChunk::NearestGapPos(int index) const {
} }
int LChunk::NearestNextGapPos(int index) const {
while (!IsGapAt(index)) index++;
return index;
}
void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) { void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) {
GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to); GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to);
} }
@ -1372,6 +1366,8 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
return AssignEnvironment(DefineAsRegister(result)); return AssignEnvironment(DefineAsRegister(result));
case kMathSqrt: case kMathSqrt:
return DefineSameAsFirst(result); return DefineSameAsFirst(result);
case kMathPowHalf:
return AssignEnvironment(DefineSameAsFirst(result));
default: default:
UNREACHABLE(); UNREACHABLE();
return NULL; return NULL;
@ -1572,6 +1568,22 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
} }
LInstruction* LChunkBuilder::DoPower(HPower* instr) {
ASSERT(instr->representation().IsDouble());
// We call a C function for double power. It can't trigger a GC.
// We need to use fixed result register for the call.
Representation exponent_type = instr->right()->representation();
ASSERT(instr->left()->representation().IsDouble());
LOperand* left = UseFixedDouble(instr->left(), xmm1);
LOperand* right = exponent_type.IsDouble() ?
UseFixedDouble(instr->right(), xmm2) :
UseFixed(instr->right(), eax);
LPower* result = new LPower(left, right);
return MarkAsCall(DefineFixedDouble(result, xmm1), instr,
CAN_DEOPTIMIZE_EAGERLY);
}
LInstruction* LChunkBuilder::DoCompare(HCompare* instr) { LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
Token::Value op = instr->token(); Token::Value op = instr->token();
if (instr->left()->representation().IsInteger32()) { if (instr->left()->representation().IsInteger32()) {

13
deps/v8/src/ia32/lithium-ia32.h

@ -67,6 +67,7 @@ class LGapNode;
// LLoadKeyedGeneric // LLoadKeyedGeneric
// LModI // LModI
// LMulI // LMulI
// LPower
// LShiftI // LShiftI
// LSubI // LSubI
// LCallConstantFunction // LCallConstantFunction
@ -229,6 +230,7 @@ class LGapNode;
V(ObjectLiteral) \ V(ObjectLiteral) \
V(OsrEntry) \ V(OsrEntry) \
V(Parameter) \ V(Parameter) \
V(Power) \
V(PushArgument) \ V(PushArgument) \
V(RegExpLiteral) \ V(RegExpLiteral) \
V(Return) \ V(Return) \
@ -1154,6 +1156,16 @@ class LAddI: public LBinaryOperation {
}; };
class LPower: public LBinaryOperation {
public:
LPower(LOperand* left, LOperand* right)
: LBinaryOperation(left, right) { }
DECLARE_CONCRETE_INSTRUCTION(Power, "power")
DECLARE_HYDROGEN_ACCESSOR(Power)
};
class LArithmeticD: public LBinaryOperation { class LArithmeticD: public LBinaryOperation {
public: public:
LArithmeticD(Token::Value op, LOperand* left, LOperand* right) LArithmeticD(Token::Value op, LOperand* left, LOperand* right)
@ -1890,7 +1902,6 @@ class LChunk: public ZoneObject {
LGap* GetGapAt(int index) const; LGap* GetGapAt(int index) const;
bool IsGapAt(int index) const; bool IsGapAt(int index) const;
int NearestGapPos(int index) const; int NearestGapPos(int index) const;
int NearestNextGapPos(int index) const;
void MarkEmptyBlocks(); void MarkEmptyBlocks();
const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; } const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; }
LLabel* GetLabel(int block_id) const { LLabel* GetLabel(int block_id) const {

24
deps/v8/src/ia32/macro-assembler-ia32.cc

@ -1216,25 +1216,29 @@ MaybeObject* MacroAssembler::TryTailCallRuntime(Runtime::FunctionId fid,
} }
// If true, a Handle<T> passed by value is passed and returned by // If true, a Handle<T> returned by value from a function with cdecl calling
// using the location_ field directly. If false, it is passed and // convention will be returned directly as a value of location_ field in a
// returned as a pointer to a handle. // register eax.
#ifdef USING_BSD_ABI // If false, it is returned as a pointer to a preallocated by caller memory
static const bool kPassHandlesDirectly = true; // region. Pointer to this region should be passed to a function as an
// implicit first argument.
#if defined(USING_BSD_ABI) || defined(__MINGW32__)
static const bool kReturnHandlesDirectly = true;
#else #else
static const bool kPassHandlesDirectly = false; static const bool kReturnHandlesDirectly = false;
#endif #endif
Operand ApiParameterOperand(int index) { Operand ApiParameterOperand(int index) {
return Operand(esp, (index + (kPassHandlesDirectly ? 0 : 1)) * kPointerSize); return Operand(
esp, (index + (kReturnHandlesDirectly ? 0 : 1)) * kPointerSize);
} }
void MacroAssembler::PrepareCallApiFunction(int argc, Register scratch) { void MacroAssembler::PrepareCallApiFunction(int argc, Register scratch) {
if (kPassHandlesDirectly) { if (kReturnHandlesDirectly) {
EnterApiExitFrame(argc); EnterApiExitFrame(argc);
// When handles as passed directly we don't have to allocate extra // When handles are returned directly we don't have to allocate extra
// space for and pass an out parameter. // space for and pass an out parameter.
} else { } else {
// We allocate two additional slots: return value and pointer to it. // We allocate two additional slots: return value and pointer to it.
@ -1279,7 +1283,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function,
// Call the api function! // Call the api function!
call(function->address(), RelocInfo::RUNTIME_ENTRY); call(function->address(), RelocInfo::RUNTIME_ENTRY);
if (!kPassHandlesDirectly) { if (!kReturnHandlesDirectly) {
// The returned value is a pointer to the handle holding the result. // The returned value is a pointer to the handle holding the result.
// Dereference this to get to the location. // Dereference this to get to the location.
mov(eax, Operand(eax, 0)); mov(eax, Operand(eax, 0));

22
deps/v8/src/json.js

@ -66,21 +66,10 @@ function JSONParse(text, reviver) {
} }
} }
function StackContains(stack, val) {
var length = stack.length;
for (var i = 0; i < length; i++) {
if (stack[i] === val) {
return true;
}
}
return false;
}
function SerializeArray(value, replacer, stack, indent, gap) { function SerializeArray(value, replacer, stack, indent, gap) {
if (StackContains(stack, value)) { if (!%PushIfAbsent(stack, value)) {
throw MakeTypeError('circular_structure', []); throw MakeTypeError('circular_structure', []);
} }
stack.push(value);
var stepback = indent; var stepback = indent;
indent += gap; indent += gap;
var partial = []; var partial = [];
@ -108,10 +97,9 @@ function SerializeArray(value, replacer, stack, indent, gap) {
} }
function SerializeObject(value, replacer, stack, indent, gap) { function SerializeObject(value, replacer, stack, indent, gap) {
if (StackContains(stack, value)) { if (!%PushIfAbsent(stack, value)) {
throw MakeTypeError('circular_structure', []); throw MakeTypeError('circular_structure', []);
} }
stack.push(value);
var stepback = indent; var stepback = indent;
indent += gap; indent += gap;
var partial = []; var partial = [];
@ -197,10 +185,9 @@ function JSONSerialize(key, holder, replacer, stack, indent, gap) {
function BasicSerializeArray(value, stack, builder) { function BasicSerializeArray(value, stack, builder) {
if (StackContains(stack, value)) { if (!%PushIfAbsent(stack, value)) {
throw MakeTypeError('circular_structure', []); throw MakeTypeError('circular_structure', []);
} }
stack.push(value);
builder.push("["); builder.push("[");
var len = value.length; var len = value.length;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
@ -220,10 +207,9 @@ function BasicSerializeArray(value, stack, builder) {
function BasicSerializeObject(value, stack, builder) { function BasicSerializeObject(value, stack, builder) {
if (StackContains(stack, value)) { if (!%PushIfAbsent(stack, value)) {
throw MakeTypeError('circular_structure', []); throw MakeTypeError('circular_structure', []);
} }
stack.push(value);
builder.push("{"); builder.push("{");
for (var p in value) { for (var p in value) {
if (%HasLocalProperty(value, p)) { if (%HasLocalProperty(value, p)) {

356
deps/v8/src/lithium-allocator.cc

@ -247,7 +247,7 @@ LOperand* LiveRange::CreateAssignedOperand() {
LOperand* op = NULL; LOperand* op = NULL;
if (HasRegisterAssigned()) { if (HasRegisterAssigned()) {
ASSERT(!IsSpilled()); ASSERT(!IsSpilled());
if (assigned_double_) { if (IsDouble()) {
op = LDoubleRegister::Create(assigned_register()); op = LDoubleRegister::Create(assigned_register());
} else { } else {
op = LRegister::Create(assigned_register()); op = LRegister::Create(assigned_register());
@ -290,7 +290,7 @@ void LiveRange::AdvanceLastProcessedMarker(
void LiveRange::SplitAt(LifetimePosition position, LiveRange* result) { void LiveRange::SplitAt(LifetimePosition position, LiveRange* result) {
ASSERT(Start().Value() <= position.Value()); ASSERT(Start().Value() < position.Value());
ASSERT(result->IsEmpty()); ASSERT(result->IsEmpty());
// Find the last interval that ends before the position. If the // Find the last interval that ends before the position. If the
// position is contained in one of the intervals in the chain, we // position is contained in one of the intervals in the chain, we
@ -625,7 +625,7 @@ LiveRange* LAllocator::FixedLiveRangeFor(int index) {
if (result == NULL) { if (result == NULL) {
result = new LiveRange(FixedLiveRangeID(index)); result = new LiveRange(FixedLiveRangeID(index));
ASSERT(result->IsFixed()); ASSERT(result->IsFixed());
result->set_assigned_register(index, false); result->set_assigned_register(index, GENERAL_REGISTERS);
fixed_live_ranges_[index] = result; fixed_live_ranges_[index] = result;
} }
return result; return result;
@ -642,7 +642,7 @@ LiveRange* LAllocator::FixedDoubleLiveRangeFor(int index) {
if (result == NULL) { if (result == NULL) {
result = new LiveRange(FixedDoubleLiveRangeID(index)); result = new LiveRange(FixedDoubleLiveRangeID(index));
ASSERT(result->IsFixed()); ASSERT(result->IsFixed());
result->set_assigned_register(index, true); result->set_assigned_register(index, DOUBLE_REGISTERS);
fixed_double_live_ranges_[index] = result; fixed_double_live_ranges_[index] = result;
} }
return result; return result;
@ -1258,14 +1258,6 @@ void LAllocator::BuildLiveRanges() {
} }
void LAllocator::AllocateGeneralRegisters() {
HPhase phase("Allocate general registers", this);
num_registers_ = Register::kNumAllocatableRegisters;
mode_ = CPU_REGISTERS;
AllocateRegisters();
}
bool LAllocator::SafePointsAreInOrder() const { bool LAllocator::SafePointsAreInOrder() const {
const ZoneList<LPointerMap*>* pointer_maps = chunk_->pointer_maps(); const ZoneList<LPointerMap*>* pointer_maps = chunk_->pointer_maps();
int safe_point = 0; int safe_point = 0;
@ -1397,10 +1389,18 @@ void LAllocator::ProcessOsrEntry() {
} }
void LAllocator::AllocateGeneralRegisters() {
HPhase phase("Allocate general registers", this);
num_registers_ = Register::kNumAllocatableRegisters;
mode_ = GENERAL_REGISTERS;
AllocateRegisters();
}
void LAllocator::AllocateDoubleRegisters() { void LAllocator::AllocateDoubleRegisters() {
HPhase phase("Allocate double registers", this); HPhase phase("Allocate double registers", this);
num_registers_ = DoubleRegister::kNumAllocatableRegisters; num_registers_ = DoubleRegister::kNumAllocatableRegisters;
mode_ = XMM_REGISTERS; mode_ = DOUBLE_REGISTERS;
AllocateRegisters(); AllocateRegisters();
} }
@ -1411,7 +1411,7 @@ void LAllocator::AllocateRegisters() {
for (int i = 0; i < live_ranges_.length(); ++i) { for (int i = 0; i < live_ranges_.length(); ++i) {
if (live_ranges_[i] != NULL) { if (live_ranges_[i] != NULL) {
if (HasDoubleValue(live_ranges_[i]->id()) == (mode_ == XMM_REGISTERS)) { if (RequiredRegisterKind(live_ranges_[i]->id()) == mode_) {
AddToUnhandledUnsorted(live_ranges_[i]); AddToUnhandledUnsorted(live_ranges_[i]);
} }
} }
@ -1422,7 +1422,7 @@ void LAllocator::AllocateRegisters() {
ASSERT(active_live_ranges_.is_empty()); ASSERT(active_live_ranges_.is_empty());
ASSERT(inactive_live_ranges_.is_empty()); ASSERT(inactive_live_ranges_.is_empty());
if (mode_ == XMM_REGISTERS) { if (mode_ == DOUBLE_REGISTERS) {
for (int i = 0; i < fixed_double_live_ranges_.length(); ++i) { for (int i = 0; i < fixed_double_live_ranges_.length(); ++i) {
LiveRange* current = fixed_double_live_ranges_.at(i); LiveRange* current = fixed_double_live_ranges_.at(i);
if (current != NULL) { if (current != NULL) {
@ -1463,11 +1463,7 @@ void LAllocator::AllocateRegisters() {
current->Start().NextInstruction().Value()) { current->Start().NextInstruction().Value()) {
// Do not spill live range eagerly if use position that can benefit from // Do not spill live range eagerly if use position that can benefit from
// the register is too close to the start of live range. // the register is too close to the start of live range.
LiveRange* part = Split(current, SpillBetween(current, current->Start(), pos->pos());
current->Start().NextInstruction(),
pos->pos());
Spill(current);
AddToUnhandledSorted(part);
ASSERT(UnhandledIsSorted()); ASSERT(UnhandledIsSorted());
continue; continue;
} }
@ -1521,6 +1517,16 @@ void LAllocator::Setup() {
} }
const char* LAllocator::RegisterName(int allocation_index) {
ASSERT(mode_ != NONE);
if (mode_ == GENERAL_REGISTERS) {
return Register::AllocationIndexToString(allocation_index);
} else {
return DoubleRegister::AllocationIndexToString(allocation_index);
}
}
void LAllocator::TraceAlloc(const char* msg, ...) { void LAllocator::TraceAlloc(const char* msg, ...) {
if (FLAG_trace_alloc) { if (FLAG_trace_alloc) {
va_list arguments; va_list arguments;
@ -1544,10 +1550,12 @@ bool LAllocator::HasTaggedValue(int virtual_register) const {
} }
bool LAllocator::HasDoubleValue(int virtual_register) const { RegisterKind LAllocator::RequiredRegisterKind(int virtual_register) const {
HValue* value = graph()->LookupValue(virtual_register); HValue* value = graph()->LookupValue(virtual_register);
if (value == NULL) return false; if (value != NULL && value->representation().IsDouble()) {
return value->representation().IsDouble(); return DOUBLE_REGISTERS;
}
return GENERAL_REGISTERS;
} }
@ -1728,16 +1736,22 @@ void LAllocator::InactiveToActive(LiveRange* range) {
} }
// TryAllocateFreeReg and AllocateBlockedReg assume this
// when allocating local arrays.
STATIC_ASSERT(DoubleRegister::kNumAllocatableRegisters >=
Register::kNumAllocatableRegisters);
bool LAllocator::TryAllocateFreeReg(LiveRange* current) { bool LAllocator::TryAllocateFreeReg(LiveRange* current) {
LifetimePosition max_pos = LifetimePosition::FromInstructionIndex( LifetimePosition free_until_pos[DoubleRegister::kNumAllocatableRegisters];
chunk_->instructions()->length() + 1);
ASSERT(DoubleRegister::kNumAllocatableRegisters >= for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; i++) {
Register::kNumAllocatableRegisters); free_until_pos[i] = LifetimePosition::MaxPosition();
EmbeddedVector<LifetimePosition, DoubleRegister::kNumAllocatableRegisters> }
free_pos(max_pos);
for (int i = 0; i < active_live_ranges_.length(); ++i) { for (int i = 0; i < active_live_ranges_.length(); ++i) {
LiveRange* cur_active = active_live_ranges_.at(i); LiveRange* cur_active = active_live_ranges_.at(i);
free_pos[cur_active->assigned_register()] = free_until_pos[cur_active->assigned_register()] =
LifetimePosition::FromInstructionIndex(0); LifetimePosition::FromInstructionIndex(0);
} }
@ -1748,67 +1762,83 @@ bool LAllocator::TryAllocateFreeReg(LiveRange* current) {
cur_inactive->FirstIntersection(current); cur_inactive->FirstIntersection(current);
if (!next_intersection.IsValid()) continue; if (!next_intersection.IsValid()) continue;
int cur_reg = cur_inactive->assigned_register(); int cur_reg = cur_inactive->assigned_register();
free_pos[cur_reg] = Min(free_pos[cur_reg], next_intersection); free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection);
} }
UsePosition* pos = current->FirstPosWithHint(); UsePosition* hinted_use = current->FirstPosWithHint();
if (pos != NULL) { if (hinted_use != NULL) {
LOperand* hint = pos->hint(); LOperand* hint = hinted_use->hint();
if (hint->IsRegister() || hint->IsDoubleRegister()) { if (hint->IsRegister() || hint->IsDoubleRegister()) {
int register_index = hint->index(); int register_index = hint->index();
TraceAlloc("Found reg hint %d for live range %d (free [%d, end %d[)\n", TraceAlloc(
register_index, "Found reg hint %s (free until [%d) for live range %d (end %d[).\n",
current->id(), RegisterName(register_index),
free_pos[register_index].Value(), free_until_pos[register_index].Value(),
current->End().Value()); current->id(),
if (free_pos[register_index].Value() >= current->End().Value()) { current->End().Value());
TraceAlloc("Assigning preferred reg %d to live range %d\n",
register_index, // The desired register is free until the end of the current live range.
if (free_until_pos[register_index].Value() >= current->End().Value()) {
TraceAlloc("Assigning preferred reg %s to live range %d\n",
RegisterName(register_index),
current->id()); current->id());
current->set_assigned_register(register_index, mode_ == XMM_REGISTERS); current->set_assigned_register(register_index, mode_);
return true; return true;
} }
} }
} }
int max_reg = 0; // Find the register which stays free for the longest time.
int reg = 0;
for (int i = 1; i < RegisterCount(); ++i) { for (int i = 1; i < RegisterCount(); ++i) {
if (free_pos[i].Value() > free_pos[max_reg].Value()) { if (free_until_pos[i].Value() > free_until_pos[reg].Value()) {
max_reg = i; reg = i;
} }
} }
if (free_pos[max_reg].InstructionIndex() == 0) { LifetimePosition pos = free_until_pos[reg];
if (pos.Value() <= current->Start().Value()) {
// All registers are blocked.
return false; return false;
} else if (free_pos[max_reg].Value() >= current->End().Value()) {
TraceAlloc("Assigning reg %d to live range %d\n", max_reg, current->id());
current->set_assigned_register(max_reg, mode_ == XMM_REGISTERS);
} else {
// Split the interval at the nearest gap and never split an interval at its
// start position.
LifetimePosition pos =
LifetimePosition::FromInstructionIndex(
chunk_->NearestGapPos(free_pos[max_reg].InstructionIndex()));
if (pos.Value() <= current->Start().Value()) return false;
LiveRange* second_range = Split(current, pos);
AddToUnhandledSorted(second_range);
current->set_assigned_register(max_reg, mode_ == XMM_REGISTERS);
} }
if (pos.Value() < current->End().Value()) {
// Register reg is available at the range start but becomes blocked before
// the range end. Split current at position where it becomes blocked.
LiveRange* tail = SplitAt(current, pos);
AddToUnhandledSorted(tail);
}
// Register reg is available at the range start and is free until
// the range end.
ASSERT(pos.Value() >= current->End().Value());
TraceAlloc("Assigning reg %s to live range %d\n",
RegisterName(reg),
current->id());
current->set_assigned_register(reg, mode_);
return true; return true;
} }
void LAllocator::AllocateBlockedReg(LiveRange* current) { void LAllocator::AllocateBlockedReg(LiveRange* current) {
LifetimePosition max_pos = UsePosition* register_use = current->NextRegisterPosition(current->Start());
LifetimePosition::FromInstructionIndex( if (register_use == NULL) {
chunk_->instructions()->length() + 1); // There is no use in the current live range that requires a register.
ASSERT(DoubleRegister::kNumAllocatableRegisters >= // We can just spill it.
Register::kNumAllocatableRegisters); Spill(current);
EmbeddedVector<LifetimePosition, DoubleRegister::kNumAllocatableRegisters> return;
use_pos(max_pos); }
EmbeddedVector<LifetimePosition, DoubleRegister::kNumAllocatableRegisters>
block_pos(max_pos);
LifetimePosition use_pos[DoubleRegister::kNumAllocatableRegisters];
LifetimePosition block_pos[DoubleRegister::kNumAllocatableRegisters];
for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; i++) {
use_pos[i] = block_pos[i] = LifetimePosition::MaxPosition();
}
for (int i = 0; i < active_live_ranges_.length(); ++i) { for (int i = 0; i < active_live_ranges_.length(); ++i) {
LiveRange* range = active_live_ranges_[i]; LiveRange* range = active_live_ranges_[i];
@ -1841,47 +1871,63 @@ void LAllocator::AllocateBlockedReg(LiveRange* current) {
} }
} }
int max_reg = 0; int reg = 0;
for (int i = 1; i < RegisterCount(); ++i) { for (int i = 1; i < RegisterCount(); ++i) {
if (use_pos[i].Value() > use_pos[max_reg].Value()) { if (use_pos[i].Value() > use_pos[reg].Value()) {
max_reg = i; reg = i;
} }
} }
UsePosition* first_usage = current->NextRegisterPosition(current->Start()); LifetimePosition pos = use_pos[reg];
if (first_usage == NULL) {
Spill(current); if (pos.Value() < register_use->pos().Value()) {
} else if (use_pos[max_reg].Value() < first_usage->pos().Value()) { // All registers are blocked before the first use that requires a register.
SplitAndSpill(current, current->Start(), first_usage->pos()); // Spill starting part of live range up to that use.
} else { //
if (block_pos[max_reg].Value() < current->End().Value()) { // Corner case: the first use position is equal to the start of the range.
// Split current before blocked position. // In this case we have nothing to spill and SpillBetween will just return
LiveRange* second_range = Split(current, // this range to the list of unhandled ones. This will lead to the infinite
current->Start(), // loop.
block_pos[max_reg]); ASSERT(current->Start().Value() < register_use->pos().Value());
AddToUnhandledSorted(second_range); SpillBetween(current, current->Start(), register_use->pos());
} return;
}
current->set_assigned_register(max_reg, mode_ == XMM_REGISTERS); if (block_pos[reg].Value() < current->End().Value()) {
SplitAndSpillIntersecting(current); // Register becomes blocked before the current range end. Split before that
// position.
LiveRange* tail = SplitBetween(current,
current->Start(),
block_pos[reg].InstructionStart());
AddToUnhandledSorted(tail);
} }
// Register reg is not blocked for the whole range.
ASSERT(block_pos[reg].Value() >= current->End().Value());
TraceAlloc("Assigning reg %s to live range %d\n",
RegisterName(reg),
current->id());
current->set_assigned_register(reg, mode_);
// This register was not free. Thus we need to find and spill
// parts of active and inactive live regions that use the same register
// at the same lifetime positions as current.
SplitAndSpillIntersecting(current);
} }
void LAllocator::SplitAndSpillIntersecting(LiveRange* current) { void LAllocator::SplitAndSpillIntersecting(LiveRange* current) {
ASSERT(current->HasRegisterAssigned()); ASSERT(current->HasRegisterAssigned());
int reg = current->assigned_register(); int reg = current->assigned_register();
LifetimePosition split_pos = LifetimePosition split_pos = current->Start();
LifetimePosition::FromInstructionIndex(
chunk_->NearestGapPos(current->Start().InstructionIndex()));
for (int i = 0; i < active_live_ranges_.length(); ++i) { for (int i = 0; i < active_live_ranges_.length(); ++i) {
LiveRange* range = active_live_ranges_[i]; LiveRange* range = active_live_ranges_[i];
if (range->assigned_register() == reg) { if (range->assigned_register() == reg) {
UsePosition* next_pos = range->NextRegisterPosition(current->Start()); UsePosition* next_pos = range->NextRegisterPosition(current->Start());
if (next_pos == NULL) { if (next_pos == NULL) {
SplitAndSpill(range, split_pos); SpillAfter(range, split_pos);
} else { } else {
SplitAndSpill(range, split_pos, next_pos->pos()); SpillBetween(range, split_pos, next_pos->pos());
} }
ActiveToHandled(range); ActiveToHandled(range);
--i; --i;
@ -1896,10 +1942,10 @@ void LAllocator::SplitAndSpillIntersecting(LiveRange* current) {
if (next_intersection.IsValid()) { if (next_intersection.IsValid()) {
UsePosition* next_pos = range->NextRegisterPosition(current->Start()); UsePosition* next_pos = range->NextRegisterPosition(current->Start());
if (next_pos == NULL) { if (next_pos == NULL) {
SplitAndSpill(range, split_pos); SpillAfter(range, split_pos);
} else { } else {
next_intersection = Min(next_intersection, next_pos->pos()); next_intersection = Min(next_intersection, next_pos->pos());
SplitAndSpill(range, split_pos, next_intersection); SpillBetween(range, split_pos, next_intersection);
} }
InactiveToHandled(range); InactiveToHandled(range);
--i; --i;
@ -1909,19 +1955,50 @@ void LAllocator::SplitAndSpillIntersecting(LiveRange* current) {
} }
LiveRange* LAllocator::Split(LiveRange* range, bool LAllocator::IsBlockBoundary(LifetimePosition pos) {
LifetimePosition start, return pos.IsInstructionStart() &&
LifetimePosition end) { chunk_->instructions()->at(pos.InstructionIndex())->IsLabel();
}
void LAllocator::AddGapMove(int pos, LiveRange* prev, LiveRange* next) {
UsePosition* prev_pos = prev->AddUsePosition(
LifetimePosition::FromInstructionIndex(pos));
UsePosition* next_pos = next->AddUsePosition(
LifetimePosition::FromInstructionIndex(pos));
LOperand* prev_operand = prev_pos->operand();
LOperand* next_operand = next_pos->operand();
LGap* gap = chunk_->GetGapAt(pos);
gap->GetOrCreateParallelMove(LGap::START)->
AddMove(prev_operand, next_operand);
next_pos->set_hint(prev_operand);
}
LiveRange* LAllocator::SplitAt(LiveRange* range, LifetimePosition pos) {
ASSERT(!range->IsFixed());
TraceAlloc("Splitting live range %d at %d\n", range->id(), pos.Value());
if (pos.Value() <= range->Start().Value()) return range;
LiveRange* result = LiveRangeFor(next_virtual_register_++);
range->SplitAt(pos, result);
return result;
}
LiveRange* LAllocator::SplitBetween(LiveRange* range,
LifetimePosition start,
LifetimePosition end) {
ASSERT(!range->IsFixed()); ASSERT(!range->IsFixed());
TraceAlloc("Splitting live range %d in position between [%d, %d[\n", TraceAlloc("Splitting live range %d in position between [%d, %d]\n",
range->id(), range->id(),
start.Value(), start.Value(),
end.Value()); end.Value());
LifetimePosition split_pos = FindOptimalSplitPos( LifetimePosition split_pos = FindOptimalSplitPos(start, end);
start, end.PrevInstruction().InstructionEnd());
ASSERT(split_pos.Value() >= start.Value()); ASSERT(split_pos.Value() >= start.Value());
return Split(range, split_pos); return SplitAt(range, split_pos);
} }
@ -1944,81 +2021,52 @@ LifetimePosition LAllocator::FindOptimalSplitPos(LifetimePosition start,
} }
HBasicBlock* block = end_block; HBasicBlock* block = end_block;
// Move to the most outside loop header. // Find header of outermost loop.
while (block->parent_loop_header() != NULL && while (block->parent_loop_header() != NULL &&
block->parent_loop_header()->block_id() > start_block->block_id()) { block->parent_loop_header()->block_id() > start_block->block_id()) {
block = block->parent_loop_header(); block = block->parent_loop_header();
} }
if (block == end_block) { if (block == end_block) return end;
return end;
}
return LifetimePosition::FromInstructionIndex( return LifetimePosition::FromInstructionIndex(
block->first_instruction_index()); block->first_instruction_index());
} }
bool LAllocator::IsBlockBoundary(LifetimePosition pos) { void LAllocator::SpillAfter(LiveRange* range, LifetimePosition pos) {
return pos.IsInstructionStart() && LiveRange* second_part = SplitAt(range, pos);
chunk_->instructions()->at(pos.InstructionIndex())->IsLabel(); Spill(second_part);
} }
void LAllocator::AddGapMove(int pos, LiveRange* prev, LiveRange* next) { void LAllocator::SpillBetween(LiveRange* range,
UsePosition* prev_pos = prev->AddUsePosition( LifetimePosition start,
LifetimePosition::FromInstructionIndex(pos)); LifetimePosition end) {
UsePosition* next_pos = next->AddUsePosition( ASSERT(start.Value() < end.Value());
LifetimePosition::FromInstructionIndex(pos)); LiveRange* second_part = SplitAt(range, start);
LOperand* prev_operand = prev_pos->operand();
LOperand* next_operand = next_pos->operand();
LGap* gap = chunk_->GetGapAt(pos);
gap->GetOrCreateParallelMove(LGap::START)->
AddMove(prev_operand, next_operand);
next_pos->set_hint(prev_operand);
}
LiveRange* LAllocator::Split(LiveRange* range, LifetimePosition pos) { if (second_part->Start().Value() < end.Value()) {
ASSERT(!range->IsFixed()); // The split result intersects with [start, end[.
TraceAlloc("Splitting live range %d at %d\n", range->id(), pos.Value()); // Split it at position between ]start+1, end[, spill the middle part
if (pos.Value() <= range->Start().Value()) { // and put the rest to unhandled.
return range; LiveRange* third_part = SplitBetween(
} second_part,
LiveRange* result = LiveRangeFor(next_virtual_register_++); second_part->Start().InstructionEnd(),
range->SplitAt(pos, result); end.PrevInstruction().InstructionEnd());
return result;
}
ASSERT(third_part != second_part);
void LAllocator::SplitAndSpill(LiveRange* range, Spill(second_part);
LifetimePosition start,
LifetimePosition end) {
// We have an interval range and want to make sure that it is
// spilled at start and at most spilled until end.
ASSERT(start.Value() < end.Value());
LiveRange* tail_part = Split(range, start);
if (tail_part->Start().Value() < end.Value()) {
LiveRange* third_part = Split(tail_part,
tail_part->Start().NextInstruction(),
end);
Spill(tail_part);
ASSERT(third_part != tail_part);
AddToUnhandledSorted(third_part); AddToUnhandledSorted(third_part);
} else { } else {
AddToUnhandledSorted(tail_part); // The split result does not intersect with [start, end[.
// Nothing to spill. Just put it to unhandled as whole.
AddToUnhandledSorted(second_part);
} }
} }
void LAllocator::SplitAndSpill(LiveRange* range, LifetimePosition at) {
at = LifetimePosition::FromInstructionIndex(
chunk_->NearestGapPos(at.InstructionIndex()));
LiveRange* second_part = Split(range, at);
Spill(second_part);
}
void LAllocator::Spill(LiveRange* range) { void LAllocator::Spill(LiveRange* range) {
ASSERT(!range->IsSpilled()); ASSERT(!range->IsSpilled());
TraceAlloc("Spilling live range %d\n", range->id()); TraceAlloc("Spilling live range %d\n", range->id());
@ -2026,7 +2074,7 @@ void LAllocator::Spill(LiveRange* range) {
if (!first->HasAllocatedSpillOperand()) { if (!first->HasAllocatedSpillOperand()) {
LOperand* op = TryReuseSpillSlot(range); LOperand* op = TryReuseSpillSlot(range);
if (op == NULL) op = chunk_->GetNextSpillSlot(mode_ == XMM_REGISTERS); if (op == NULL) op = chunk_->GetNextSpillSlot(mode_ == DOUBLE_REGISTERS);
first->SetSpillOperand(op); first->SetSpillOperand(op);
} }
range->MakeSpilled(); range->MakeSpilled();

83
deps/v8/src/lithium-allocator.h

@ -55,6 +55,7 @@ class LPointerMap;
class LStackSlot; class LStackSlot;
class LRegister; class LRegister;
// This class represents a single point of a LOperand's lifetime. // This class represents a single point of a LOperand's lifetime.
// For each lithium instruction there are exactly two lifetime positions: // For each lithium instruction there are exactly two lifetime positions:
// the beginning and the end of the instruction. Lifetime positions for // the beginning and the end of the instruction. Lifetime positions for
@ -121,7 +122,13 @@ class LifetimePosition {
// instruction. // instruction.
bool IsValid() const { return value_ != -1; } bool IsValid() const { return value_ != -1; }
static LifetimePosition Invalid() { return LifetimePosition(); } static inline LifetimePosition Invalid() { return LifetimePosition(); }
static inline LifetimePosition MaxPosition() {
// We have to use this kind of getter instead of static member due to
// crash bug in GDB.
return LifetimePosition(kMaxInt);
}
private: private:
static const int kStep = 2; static const int kStep = 2;
@ -135,6 +142,13 @@ class LifetimePosition {
}; };
enum RegisterKind {
NONE,
GENERAL_REGISTERS,
DOUBLE_REGISTERS
};
class LOperand: public ZoneObject { class LOperand: public ZoneObject {
public: public:
enum Kind { enum Kind {
@ -594,8 +608,8 @@ class LiveRange: public ZoneObject {
explicit LiveRange(int id) explicit LiveRange(int id)
: id_(id), : id_(id),
spilled_(false), spilled_(false),
assigned_double_(false),
assigned_register_(kInvalidAssignment), assigned_register_(kInvalidAssignment),
assigned_register_kind_(NONE),
last_interval_(NULL), last_interval_(NULL),
first_interval_(NULL), first_interval_(NULL),
first_pos_(NULL), first_pos_(NULL),
@ -620,10 +634,10 @@ class LiveRange: public ZoneObject {
LOperand* CreateAssignedOperand(); LOperand* CreateAssignedOperand();
int assigned_register() const { return assigned_register_; } int assigned_register() const { return assigned_register_; }
int spill_start_index() const { return spill_start_index_; } int spill_start_index() const { return spill_start_index_; }
void set_assigned_register(int reg, bool double_reg) { void set_assigned_register(int reg, RegisterKind register_kind) {
ASSERT(!HasRegisterAssigned() && !IsSpilled()); ASSERT(!HasRegisterAssigned() && !IsSpilled());
assigned_register_ = reg; assigned_register_ = reg;
assigned_double_ = double_reg; assigned_register_kind_ = register_kind;
ConvertOperands(); ConvertOperands();
} }
void MakeSpilled() { void MakeSpilled() {
@ -652,9 +666,13 @@ class LiveRange: public ZoneObject {
// Can this live range be spilled at this position. // Can this live range be spilled at this position.
bool CanBeSpilled(LifetimePosition pos); bool CanBeSpilled(LifetimePosition pos);
// Split this live range at the given position which must follow the start of
// the range.
// All uses following the given position will be moved from this
// live range to the result live range.
void SplitAt(LifetimePosition position, LiveRange* result); void SplitAt(LifetimePosition position, LiveRange* result);
bool IsDouble() const { return assigned_double_; } bool IsDouble() const { return assigned_register_kind_ == DOUBLE_REGISTERS; }
bool HasRegisterAssigned() const { bool HasRegisterAssigned() const {
return assigned_register_ != kInvalidAssignment; return assigned_register_ != kInvalidAssignment;
} }
@ -721,8 +739,8 @@ class LiveRange: public ZoneObject {
int id_; int id_;
bool spilled_; bool spilled_;
bool assigned_double_;
int assigned_register_; int assigned_register_;
RegisterKind assigned_register_kind_;
UseInterval* last_interval_; UseInterval* last_interval_;
UseInterval* first_interval_; UseInterval* first_interval_;
UsePosition* first_pos_; UsePosition* first_pos_;
@ -774,8 +792,8 @@ class LAllocator BASE_EMBEDDED {
// Checks whether the value of a given virtual register is tagged. // Checks whether the value of a given virtual register is tagged.
bool HasTaggedValue(int virtual_register) const; bool HasTaggedValue(int virtual_register) const;
// Checks whether the value of a given virtual register is a double. // Returns the register kind required by the given virtual register.
bool HasDoubleValue(int virtual_register) const; RegisterKind RequiredRegisterKind(int virtual_register) const;
// Begin a new instruction. // Begin a new instruction.
void BeginInstruction(); void BeginInstruction();
@ -814,12 +832,6 @@ class LAllocator BASE_EMBEDDED {
#endif #endif
private: private:
enum OperationMode {
NONE,
CPU_REGISTERS,
XMM_REGISTERS
};
void MeetRegisterConstraints(); void MeetRegisterConstraints();
void ResolvePhis(); void ResolvePhis();
void BuildLiveRanges(); void BuildLiveRanges();
@ -871,17 +883,38 @@ class LAllocator BASE_EMBEDDED {
// Helper methods for allocating registers. // Helper methods for allocating registers.
bool TryAllocateFreeReg(LiveRange* range); bool TryAllocateFreeReg(LiveRange* range);
void AllocateBlockedReg(LiveRange* range); void AllocateBlockedReg(LiveRange* range);
void SplitAndSpillIntersecting(LiveRange* range);
// Live range splitting helpers.
// Split the given range at the given position.
// If range starts at or after the given position then the
// original range is returned.
// Otherwise returns the live range that starts at pos and contains
// all uses from the original range that follow pos. Uses at pos will
// still be owned by the original range after splitting.
LiveRange* SplitAt(LiveRange* range, LifetimePosition pos);
// Split the given range in a position from the interval [start, end].
LiveRange* SplitBetween(LiveRange* range,
LifetimePosition start,
LifetimePosition end);
// Find a lifetime position in the interval [start, end] which
// is optimal for splitting: it is either header of the outermost
// loop covered by this interval or the latest possible position.
LifetimePosition FindOptimalSplitPos(LifetimePosition start, LifetimePosition FindOptimalSplitPos(LifetimePosition start,
LifetimePosition end); LifetimePosition end);
LiveRange* Split(LiveRange* range,
LifetimePosition start, // Spill the given life range after position pos.
LifetimePosition end); void SpillAfter(LiveRange* range, LifetimePosition pos);
LiveRange* Split(LiveRange* range, LifetimePosition split_pos);
void SplitAndSpill(LiveRange* range, // Spill the given life range after position start and up to position end.
LifetimePosition start, void SpillBetween(LiveRange* range,
LifetimePosition end); LifetimePosition start,
void SplitAndSpill(LiveRange* range, LifetimePosition at); LifetimePosition end);
void SplitAndSpillIntersecting(LiveRange* range);
void Spill(LiveRange* range); void Spill(LiveRange* range);
bool IsBlockBoundary(LifetimePosition pos); bool IsBlockBoundary(LifetimePosition pos);
void AddGapMove(int pos, LiveRange* prev, LiveRange* next); void AddGapMove(int pos, LiveRange* prev, LiveRange* next);
@ -914,6 +947,8 @@ class LAllocator BASE_EMBEDDED {
HPhi* LookupPhi(LOperand* operand) const; HPhi* LookupPhi(LOperand* operand) const;
LGap* GetLastGap(HBasicBlock* block) const; LGap* GetLastGap(HBasicBlock* block) const;
const char* RegisterName(int allocation_index);
LChunk* chunk_; LChunk* chunk_;
ZoneList<InstructionSummary*> summaries_; ZoneList<InstructionSummary*> summaries_;
InstructionSummary* next_summary_; InstructionSummary* next_summary_;
@ -938,7 +973,7 @@ class LAllocator BASE_EMBEDDED {
// Next virtual register number to be assigned to temporaries. // Next virtual register number to be assigned to temporaries.
int next_virtual_register_; int next_virtual_register_;
OperationMode mode_; RegisterKind mode_;
int num_registers_; int num_registers_;
HGraph* graph_; HGraph* graph_;

181
deps/v8/src/log-utils.cc

@ -273,29 +273,7 @@ void LogMessageBuilder::Append(String* str) {
void LogMessageBuilder::AppendAddress(Address addr) { void LogMessageBuilder::AppendAddress(Address addr) {
static Address last_address_ = NULL; Append("0x%" V8PRIxPTR, addr);
AppendAddress(addr, last_address_);
last_address_ = addr;
}
void LogMessageBuilder::AppendAddress(Address addr, Address bias) {
if (!FLAG_compress_log) {
Append("0x%" V8PRIxPTR, addr);
} else if (bias == NULL) {
Append("%" V8PRIxPTR, addr);
} else {
uintptr_t delta;
char sign;
if (addr >= bias) {
delta = addr - bias;
sign = '+';
} else {
delta = bias - addr;
sign = '-';
}
Append("%c%" V8PRIxPTR, sign, delta);
}
} }
@ -343,24 +321,6 @@ void LogMessageBuilder::AppendStringPart(const char* str, int len) {
} }
bool LogMessageBuilder::StoreInCompressor(LogRecordCompressor* compressor) {
return compressor->Store(Vector<const char>(Log::message_buffer_, pos_));
}
bool LogMessageBuilder::RetrieveCompressedPrevious(
LogRecordCompressor* compressor, const char* prefix) {
pos_ = 0;
if (prefix[0] != '\0') Append(prefix);
Vector<char> prev_record(Log::message_buffer_ + pos_,
Log::kMessageBufferSize - pos_);
const bool has_prev = compressor->RetrievePreviousCompressed(&prev_record);
if (!has_prev) return false;
pos_ += prev_record.length();
return true;
}
void LogMessageBuilder::WriteToLogFile() { void LogMessageBuilder::WriteToLogFile() {
ASSERT(pos_ <= Log::kMessageBufferSize); ASSERT(pos_ <= Log::kMessageBufferSize);
const int written = Log::Write(Log::message_buffer_, pos_); const int written = Log::Write(Log::message_buffer_, pos_);
@ -369,145 +329,6 @@ void LogMessageBuilder::WriteToLogFile() {
} }
} }
// Formatting string for back references to the whole line. E.g. "#2" means
// "the second line above".
const char* LogRecordCompressor::kLineBackwardReferenceFormat = "#%d";
// Formatting string for back references. E.g. "#2:10" means
// "the second line above, start from char 10 (0-based)".
const char* LogRecordCompressor::kBackwardReferenceFormat = "#%d:%d";
LogRecordCompressor::~LogRecordCompressor() {
for (int i = 0; i < buffer_.length(); ++i) {
buffer_[i].Dispose();
}
}
static int GetNumberLength(int number) {
ASSERT(number >= 0);
ASSERT(number < 10000);
if (number < 10) return 1;
if (number < 100) return 2;
if (number < 1000) return 3;
return 4;
}
int LogRecordCompressor::GetBackwardReferenceSize(int distance, int pos) {
// See kLineBackwardReferenceFormat and kBackwardReferenceFormat.
return pos == 0 ? GetNumberLength(distance) + 1
: GetNumberLength(distance) + GetNumberLength(pos) + 2;
}
void LogRecordCompressor::PrintBackwardReference(Vector<char> dest,
int distance,
int pos) {
if (pos == 0) {
OS::SNPrintF(dest, kLineBackwardReferenceFormat, distance);
} else {
OS::SNPrintF(dest, kBackwardReferenceFormat, distance, pos);
}
}
bool LogRecordCompressor::Store(const Vector<const char>& record) {
// Check if the record is the same as the last stored one.
if (curr_ != -1) {
Vector<const char>& curr = buffer_[curr_];
if (record.length() == curr.length()
&& strncmp(record.start(), curr.start(), record.length()) == 0) {
return false;
}
}
// buffer_ is circular.
prev_ = curr_++;
curr_ %= buffer_.length();
Vector<char> record_copy = Vector<char>::New(record.length());
memcpy(record_copy.start(), record.start(), record.length());
buffer_[curr_].Dispose();
buffer_[curr_] =
Vector<const char>(record_copy.start(), record_copy.length());
return true;
}
bool LogRecordCompressor::RetrievePreviousCompressed(
Vector<char>* prev_record) {
if (prev_ == -1) return false;
int index = prev_;
// Distance from prev_.
int distance = 0;
// Best compression result among records in the buffer.
struct {
intptr_t truncated_len;
int distance;
int copy_from_pos;
int backref_size;
} best = {-1, 0, 0, 0};
Vector<const char>& prev = buffer_[prev_];
const char* const prev_start = prev.start();
const char* const prev_end = prev.start() + prev.length();
do {
// We're moving backwards until we reach the current record.
// Remember that buffer_ is circular.
if (--index == -1) index = buffer_.length() - 1;
++distance;
if (index == curr_) break;
Vector<const char>& data = buffer_[index];
if (data.start() == NULL) break;
const char* const data_end = data.start() + data.length();
const char* prev_ptr = prev_end;
const char* data_ptr = data_end;
// Compare strings backwards, stop on the last matching character.
while (prev_ptr != prev_start && data_ptr != data.start()
&& *(prev_ptr - 1) == *(data_ptr - 1)) {
--prev_ptr;
--data_ptr;
}
const intptr_t truncated_len = prev_end - prev_ptr;
const int copy_from_pos = static_cast<int>(data_ptr - data.start());
// Check if the length of compressed tail is enough.
if (truncated_len <= kMaxBackwardReferenceSize
&& truncated_len <= GetBackwardReferenceSize(distance, copy_from_pos)) {
continue;
}
// Record compression results.
if (truncated_len > best.truncated_len) {
best.truncated_len = truncated_len;
best.distance = distance;
best.copy_from_pos = copy_from_pos;
best.backref_size = GetBackwardReferenceSize(distance, copy_from_pos);
}
} while (true);
if (best.distance == 0) {
// Can't compress the previous record. Return as is.
ASSERT(prev_record->length() >= prev.length());
memcpy(prev_record->start(), prev.start(), prev.length());
prev_record->Truncate(prev.length());
} else {
// Copy the uncompressible part unchanged.
const intptr_t unchanged_len = prev.length() - best.truncated_len;
// + 1 for '\0'.
ASSERT(prev_record->length() >= unchanged_len + best.backref_size + 1);
memcpy(prev_record->start(), prev.start(), unchanged_len);
// Append the backward reference.
Vector<char> backref(
prev_record->start() + unchanged_len, best.backref_size + 1);
PrintBackwardReference(backref, best.distance, best.copy_from_pos);
ASSERT(strlen(backref.start()) - best.backref_size == 0);
prev_record->Truncate(static_cast<int>(unchanged_len + best.backref_size));
}
return true;
}
#endif // ENABLE_LOGGING_AND_PROFILING #endif // ENABLE_LOGGING_AND_PROFILING
} } // namespace v8::internal } } // namespace v8::internal

64
deps/v8/src/log-utils.h

@ -176,50 +176,6 @@ class Log : public AllStatic {
friend class Logger; friend class Logger;
friend class LogMessageBuilder; friend class LogMessageBuilder;
friend class LogRecordCompressor;
};
// An utility class for performing backward reference compression
// of string ends. It operates using a window of previous strings.
class LogRecordCompressor {
public:
// 'window_size' is the size of backward lookup window.
explicit LogRecordCompressor(int window_size)
: buffer_(window_size + kNoCompressionWindowSize),
kMaxBackwardReferenceSize(
GetBackwardReferenceSize(window_size, Log::kMessageBufferSize)),
curr_(-1), prev_(-1) {
}
~LogRecordCompressor();
// Fills vector with a compressed version of the previous record.
// Returns false if there is no previous record.
bool RetrievePreviousCompressed(Vector<char>* prev_record);
// Stores a record if it differs from a previous one (or there's no previous).
// Returns true, if the record has been stored.
bool Store(const Vector<const char>& record);
private:
// The minimum size of a buffer: a place needed for the current and
// the previous record. Since there is no place for precedessors of a previous
// record, it can't be compressed at all.
static const int kNoCompressionWindowSize = 2;
// Formatting strings for back references.
static const char* kLineBackwardReferenceFormat;
static const char* kBackwardReferenceFormat;
static int GetBackwardReferenceSize(int distance, int pos);
static void PrintBackwardReference(Vector<char> dest, int distance, int pos);
ScopedVector< Vector<const char> > buffer_;
const int kMaxBackwardReferenceSize;
int curr_;
int prev_;
}; };
@ -244,32 +200,14 @@ class LogMessageBuilder BASE_EMBEDDED {
// Append a heap string. // Append a heap string.
void Append(String* str); void Append(String* str);
// Appends an address, compressing it if needed by offsetting // Appends an address.
// from Logger::last_address_.
void AppendAddress(Address addr); void AppendAddress(Address addr);
// Appends an address, compressing it if needed.
void AppendAddress(Address addr, Address bias);
void AppendDetailed(String* str, bool show_impl_info); void AppendDetailed(String* str, bool show_impl_info);
// Append a portion of a string. // Append a portion of a string.
void AppendStringPart(const char* str, int len); void AppendStringPart(const char* str, int len);
// Stores log message into compressor, returns true if the message
// was stored (i.e. doesn't repeat the previous one).
bool StoreInCompressor(LogRecordCompressor* compressor);
// Sets log message to a previous version of compressed message.
// Returns false, if there is no previous message.
bool RetrieveCompressedPrevious(LogRecordCompressor* compressor) {
return RetrieveCompressedPrevious(compressor, "");
}
// Does the same at the version without arguments, and sets a prefix.
bool RetrieveCompressedPrevious(LogRecordCompressor* compressor,
const char* prefix);
// Write the log message to the log file currently opened. // Write the log message to the log file currently opened.
void WriteToLogFile(); void WriteToLogFile();

176
deps/v8/src/log.cc

@ -303,7 +303,6 @@ void Profiler::Engage() {
Logger::ticker_->SetProfiler(this); Logger::ticker_->SetProfiler(this);
Logger::ProfilerBeginEvent(); Logger::ProfilerBeginEvent();
Logger::LogAliases();
} }
@ -343,43 +342,21 @@ void Profiler::Run() {
Ticker* Logger::ticker_ = NULL; Ticker* Logger::ticker_ = NULL;
Profiler* Logger::profiler_ = NULL; Profiler* Logger::profiler_ = NULL;
SlidingStateWindow* Logger::sliding_state_window_ = NULL; SlidingStateWindow* Logger::sliding_state_window_ = NULL;
const char** Logger::log_events_ = NULL;
CompressionHelper* Logger::compression_helper_ = NULL;
int Logger::logging_nesting_ = 0; int Logger::logging_nesting_ = 0;
int Logger::cpu_profiler_nesting_ = 0; int Logger::cpu_profiler_nesting_ = 0;
int Logger::heap_profiler_nesting_ = 0; int Logger::heap_profiler_nesting_ = 0;
#define DECLARE_LONG_EVENT(ignore1, long_name, ignore2) long_name, #define DECLARE_EVENT(ignore1, name) name,
const char* kLongLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = { const char* kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
LOG_EVENTS_AND_TAGS_LIST(DECLARE_LONG_EVENT) LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT)
}; };
#undef DECLARE_LONG_EVENT #undef DECLARE_EVENT
#define DECLARE_SHORT_EVENT(ignore1, ignore2, short_name) short_name,
const char* kCompressedLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = {
LOG_EVENTS_AND_TAGS_LIST(DECLARE_SHORT_EVENT)
};
#undef DECLARE_SHORT_EVENT
void Logger::ProfilerBeginEvent() { void Logger::ProfilerBeginEvent() {
if (!Log::IsEnabled()) return; if (!Log::IsEnabled()) return;
LogMessageBuilder msg; LogMessageBuilder msg;
msg.Append("profiler,\"begin\",%d\n", kSamplingIntervalMs); msg.Append("profiler,\"begin\",%d\n", kSamplingIntervalMs);
if (FLAG_compress_log) {
msg.Append("profiler,\"compression\",%d\n", kCompressionWindowSize);
}
msg.WriteToLogFile();
}
void Logger::LogAliases() {
if (!Log::IsEnabled() || !FLAG_compress_log) return;
LogMessageBuilder msg;
for (int i = 0; i < NUMBER_OF_LOG_EVENTS; ++i) {
msg.Append("alias,%s,%s\n",
kCompressedLogEventsNames[i], kLongLogEventsNames[i]);
}
msg.WriteToLogFile(); msg.WriteToLogFile();
} }
@ -686,55 +663,16 @@ void Logger::DeleteEvent(const char* name, void* object) {
} }
#ifdef ENABLE_LOGGING_AND_PROFILING
// A class that contains all common code dealing with record compression.
class CompressionHelper {
public:
explicit CompressionHelper(int window_size)
: compressor_(window_size), repeat_count_(0) { }
// Handles storing message in compressor, retrieving the previous one and
// prefixing it with repeat count, if needed.
// Returns true if message needs to be written to log.
bool HandleMessage(LogMessageBuilder* msg) {
if (!msg->StoreInCompressor(&compressor_)) {
// Current message repeats the previous one, don't write it.
++repeat_count_;
return false;
}
if (repeat_count_ == 0) {
return msg->RetrieveCompressedPrevious(&compressor_);
}
OS::SNPrintF(prefix_, "%s,%d,",
Logger::log_events_[Logger::REPEAT_META_EVENT],
repeat_count_ + 1);
repeat_count_ = 0;
return msg->RetrieveCompressedPrevious(&compressor_, prefix_.start());
}
private:
LogRecordCompressor compressor_;
int repeat_count_;
EmbeddedVector<char, 20> prefix_;
};
#endif // ENABLE_LOGGING_AND_PROFILING
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::CallbackEventInternal(const char* prefix, const char* name, void Logger::CallbackEventInternal(const char* prefix, const char* name,
Address entry_point) { Address entry_point) {
if (!Log::IsEnabled() || !FLAG_log_code) return; if (!Log::IsEnabled() || !FLAG_log_code) return;
LogMessageBuilder msg; LogMessageBuilder msg;
msg.Append("%s,%s,", msg.Append("%s,%s,",
log_events_[CODE_CREATION_EVENT], log_events_[CALLBACK_TAG]); kLogEventsNames[CODE_CREATION_EVENT],
kLogEventsNames[CALLBACK_TAG]);
msg.AppendAddress(entry_point); msg.AppendAddress(entry_point);
msg.Append(",1,\"%s%s\"", prefix, name); msg.Append(",1,\"%s%s\"", prefix, name);
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
msg.Append('\n'); msg.Append('\n');
msg.WriteToLogFile(); msg.WriteToLogFile();
} }
@ -786,7 +724,9 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_code) return; if (!Log::IsEnabled() || !FLAG_log_code) return;
LogMessageBuilder msg; LogMessageBuilder msg;
msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.Append("%s,%s,",
kLogEventsNames[CODE_CREATION_EVENT],
kLogEventsNames[tag]);
msg.AppendAddress(code->address()); msg.AppendAddress(code->address());
msg.Append(",%d,\"%s", code->ExecutableSize(), ComputeMarker(code)); msg.Append(",%d,\"%s", code->ExecutableSize(), ComputeMarker(code));
for (const char* p = comment; *p != '\0'; p++) { for (const char* p = comment; *p != '\0'; p++) {
@ -797,10 +737,6 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
} }
msg.Append('"'); msg.Append('"');
LowLevelCodeCreateEvent(code, &msg); LowLevelCodeCreateEvent(code, &msg);
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
msg.Append('\n'); msg.Append('\n');
msg.WriteToLogFile(); msg.WriteToLogFile();
#endif #endif
@ -813,14 +749,12 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, String* name) {
LogMessageBuilder msg; LogMessageBuilder msg;
SmartPointer<char> str = SmartPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.Append("%s,%s,",
kLogEventsNames[CODE_CREATION_EVENT],
kLogEventsNames[tag]);
msg.AppendAddress(code->address()); msg.AppendAddress(code->address());
msg.Append(",%d,\"%s%s\"", code->ExecutableSize(), ComputeMarker(code), *str); msg.Append(",%d,\"%s%s\"", code->ExecutableSize(), ComputeMarker(code), *str);
LowLevelCodeCreateEvent(code, &msg); LowLevelCodeCreateEvent(code, &msg);
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
msg.Append('\n'); msg.Append('\n');
msg.WriteToLogFile(); msg.WriteToLogFile();
#endif #endif
@ -837,7 +771,9 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
SmartPointer<char> sourcestr = SmartPointer<char> sourcestr =
source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.Append("%s,%s,",
kLogEventsNames[CODE_CREATION_EVENT],
kLogEventsNames[tag]);
msg.AppendAddress(code->address()); msg.AppendAddress(code->address());
msg.Append(",%d,\"%s%s %s:%d\"", msg.Append(",%d,\"%s%s %s:%d\"",
code->ExecutableSize(), code->ExecutableSize(),
@ -846,10 +782,6 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag,
*sourcestr, *sourcestr,
line); line);
LowLevelCodeCreateEvent(code, &msg); LowLevelCodeCreateEvent(code, &msg);
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
msg.Append('\n'); msg.Append('\n');
msg.WriteToLogFile(); msg.WriteToLogFile();
#endif #endif
@ -860,14 +792,12 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_code) return; if (!Log::IsEnabled() || !FLAG_log_code) return;
LogMessageBuilder msg; LogMessageBuilder msg;
msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.Append("%s,%s,",
kLogEventsNames[CODE_CREATION_EVENT],
kLogEventsNames[tag]);
msg.AppendAddress(code->address()); msg.AppendAddress(code->address());
msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count); msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count);
LowLevelCodeCreateEvent(code, &msg); LowLevelCodeCreateEvent(code, &msg);
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
msg.Append('\n'); msg.Append('\n');
msg.WriteToLogFile(); msg.WriteToLogFile();
#endif #endif
@ -878,7 +808,7 @@ void Logger::CodeMovingGCEvent() {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return; if (!Log::IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return;
LogMessageBuilder msg; LogMessageBuilder msg;
msg.Append("%s\n", log_events_[CODE_MOVING_GC]); msg.Append("%s\n", kLogEventsNames[CODE_MOVING_GC]);
msg.WriteToLogFile(); msg.WriteToLogFile();
OS::SignalCodeMovingGC(); OS::SignalCodeMovingGC();
#endif #endif
@ -890,16 +820,13 @@ void Logger::RegExpCodeCreateEvent(Code* code, String* source) {
if (!Log::IsEnabled() || !FLAG_log_code) return; if (!Log::IsEnabled() || !FLAG_log_code) return;
LogMessageBuilder msg; LogMessageBuilder msg;
msg.Append("%s,%s,", msg.Append("%s,%s,",
log_events_[CODE_CREATION_EVENT], log_events_[REG_EXP_TAG]); kLogEventsNames[CODE_CREATION_EVENT],
kLogEventsNames[REG_EXP_TAG]);
msg.AppendAddress(code->address()); msg.AppendAddress(code->address());
msg.Append(",%d,\"", code->ExecutableSize()); msg.Append(",%d,\"", code->ExecutableSize());
msg.AppendDetailed(source, false); msg.AppendDetailed(source, false);
msg.Append('\"'); msg.Append('\"');
LowLevelCodeCreateEvent(code, &msg); LowLevelCodeCreateEvent(code, &msg);
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
msg.Append('\n'); msg.Append('\n');
msg.WriteToLogFile(); msg.WriteToLogFile();
#endif #endif
@ -924,13 +851,9 @@ void Logger::SnapshotPositionEvent(Address addr, int pos) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
if (!Log::IsEnabled() || !FLAG_log_snapshot_positions) return; if (!Log::IsEnabled() || !FLAG_log_snapshot_positions) return;
LogMessageBuilder msg; LogMessageBuilder msg;
msg.Append("%s,", log_events_[SNAPSHOT_POSITION_EVENT]); msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]);
msg.AppendAddress(addr); msg.AppendAddress(addr);
msg.Append(",%d", pos); msg.Append(",%d", pos);
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
msg.Append('\n'); msg.Append('\n');
msg.WriteToLogFile(); msg.WriteToLogFile();
#endif #endif
@ -942,18 +865,12 @@ void Logger::FunctionCreateEvent(JSFunction* function) {
// This function can be called from GC iterators (during Scavenge, // This function can be called from GC iterators (during Scavenge,
// MC, and MS), so marking bits can be set on objects. That's // MC, and MS), so marking bits can be set on objects. That's
// why unchecked accessors are used here. // why unchecked accessors are used here.
static Address prev_code = NULL;
if (!Log::IsEnabled() || !FLAG_log_code) return; if (!Log::IsEnabled() || !FLAG_log_code) return;
LogMessageBuilder msg; LogMessageBuilder msg;
msg.Append("%s,", log_events_[FUNCTION_CREATION_EVENT]); msg.Append("%s,", kLogEventsNames[FUNCTION_CREATION_EVENT]);
msg.AppendAddress(function->address()); msg.AppendAddress(function->address());
msg.Append(','); msg.Append(',');
msg.AppendAddress(function->unchecked_code()->address(), prev_code); msg.AppendAddress(function->unchecked_code()->address());
prev_code = function->unchecked_code()->address();
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
msg.Append('\n'); msg.Append('\n');
msg.WriteToLogFile(); msg.WriteToLogFile();
#endif #endif
@ -987,18 +904,12 @@ void Logger::FunctionDeleteEvent(Address from) {
void Logger::MoveEventInternal(LogEventsAndTags event, void Logger::MoveEventInternal(LogEventsAndTags event,
Address from, Address from,
Address to) { Address to) {
static Address prev_to_ = NULL;
if (!Log::IsEnabled() || !FLAG_log_code) return; if (!Log::IsEnabled() || !FLAG_log_code) return;
LogMessageBuilder msg; LogMessageBuilder msg;
msg.Append("%s,", log_events_[event]); msg.Append("%s,", kLogEventsNames[event]);
msg.AppendAddress(from); msg.AppendAddress(from);
msg.Append(','); msg.Append(',');
msg.AppendAddress(to, prev_to_); msg.AppendAddress(to);
prev_to_ = to;
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
msg.Append('\n'); msg.Append('\n');
msg.WriteToLogFile(); msg.WriteToLogFile();
} }
@ -1009,12 +920,8 @@ void Logger::MoveEventInternal(LogEventsAndTags event,
void Logger::DeleteEventInternal(LogEventsAndTags event, Address from) { void Logger::DeleteEventInternal(LogEventsAndTags event, Address from) {
if (!Log::IsEnabled() || !FLAG_log_code) return; if (!Log::IsEnabled() || !FLAG_log_code) return;
LogMessageBuilder msg; LogMessageBuilder msg;
msg.Append("%s,", log_events_[event]); msg.Append("%s,", kLogEventsNames[event]);
msg.AppendAddress(from); msg.AppendAddress(from);
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
}
msg.Append('\n'); msg.Append('\n');
msg.WriteToLogFile(); msg.WriteToLogFile();
} }
@ -1202,30 +1109,20 @@ void Logger::DebugEvent(const char* event_type, Vector<uint16_t> parameter) {
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
void Logger::TickEvent(TickSample* sample, bool overflow) { void Logger::TickEvent(TickSample* sample, bool overflow) {
if (!Log::IsEnabled() || !FLAG_prof) return; if (!Log::IsEnabled() || !FLAG_prof) return;
static Address prev_sp = NULL;
static Address prev_function = NULL;
LogMessageBuilder msg; LogMessageBuilder msg;
msg.Append("%s,", log_events_[TICK_EVENT]); msg.Append("%s,", kLogEventsNames[TICK_EVENT]);
Address prev_addr = sample->pc; msg.AppendAddress(sample->pc);
msg.AppendAddress(prev_addr);
msg.Append(','); msg.Append(',');
msg.AppendAddress(sample->sp, prev_sp); msg.AppendAddress(sample->sp);
prev_sp = sample->sp;
msg.Append(','); msg.Append(',');
msg.AppendAddress(sample->function, prev_function); msg.AppendAddress(sample->function);
prev_function = sample->function;
msg.Append(",%d", static_cast<int>(sample->state)); msg.Append(",%d", static_cast<int>(sample->state));
if (overflow) { if (overflow) {
msg.Append(",overflow"); msg.Append(",overflow");
} }
for (int i = 0; i < sample->frames_count; ++i) { for (int i = 0; i < sample->frames_count; ++i) {
msg.Append(','); msg.Append(',');
msg.AppendAddress(sample->stack[i], prev_addr); msg.AppendAddress(sample->stack[i]);
prev_addr = sample->stack[i];
}
if (FLAG_compress_log) {
ASSERT(compression_helper_ != NULL);
if (!compression_helper_->HandleMessage(&msg)) return;
} }
msg.Append('\n'); msg.Append('\n');
msg.WriteToLogFile(); msg.WriteToLogFile();
@ -1654,12 +1551,6 @@ bool Logger::Setup() {
sliding_state_window_ = new SlidingStateWindow(); sliding_state_window_ = new SlidingStateWindow();
} }
log_events_ = FLAG_compress_log ?
kCompressedLogEventsNames : kLongLogEventsNames;
if (FLAG_compress_log) {
compression_helper_ = new CompressionHelper(kCompressionWindowSize);
}
if (start_logging) { if (start_logging) {
logging_nesting_ = 1; logging_nesting_ = 1;
} }
@ -1707,9 +1598,6 @@ void Logger::TearDown() {
profiler_ = NULL; profiler_ = NULL;
} }
delete compression_helper_;
compression_helper_ = NULL;
delete sliding_state_window_; delete sliding_state_window_;
sliding_state_window_ = NULL; sliding_state_window_ = NULL;

103
deps/v8/src/log.h

@ -74,7 +74,6 @@ class Profiler;
class Semaphore; class Semaphore;
class SlidingStateWindow; class SlidingStateWindow;
class LogMessageBuilder; class LogMessageBuilder;
class CompressionHelper;
#undef LOG #undef LOG
#ifdef ENABLE_LOGGING_AND_PROFILING #ifdef ENABLE_LOGGING_AND_PROFILING
@ -88,58 +87,55 @@ class CompressionHelper;
#endif #endif
#define LOG_EVENTS_AND_TAGS_LIST(V) \ #define LOG_EVENTS_AND_TAGS_LIST(V) \
V(CODE_CREATION_EVENT, "code-creation", "cc") \ V(CODE_CREATION_EVENT, "code-creation") \
V(CODE_MOVE_EVENT, "code-move", "cm") \ V(CODE_MOVE_EVENT, "code-move") \
V(CODE_DELETE_EVENT, "code-delete", "cd") \ V(CODE_DELETE_EVENT, "code-delete") \
V(CODE_MOVING_GC, "code-moving-gc", "cg") \ V(CODE_MOVING_GC, "code-moving-gc") \
V(FUNCTION_CREATION_EVENT, "function-creation", "fc") \ V(FUNCTION_CREATION_EVENT, "function-creation") \
V(FUNCTION_MOVE_EVENT, "function-move", "fm") \ V(FUNCTION_MOVE_EVENT, "function-move") \
V(FUNCTION_DELETE_EVENT, "function-delete", "fd") \ V(FUNCTION_DELETE_EVENT, "function-delete") \
V(SNAPSHOT_POSITION_EVENT, "snapshot-pos", "sp") \ V(SNAPSHOT_POSITION_EVENT, "snapshot-pos") \
V(TICK_EVENT, "tick", "t") \ V(TICK_EVENT, "tick") \
V(REPEAT_META_EVENT, "repeat", "r") \ V(REPEAT_META_EVENT, "repeat") \
V(BUILTIN_TAG, "Builtin", "bi") \ V(BUILTIN_TAG, "Builtin") \
V(CALL_DEBUG_BREAK_TAG, "CallDebugBreak", "cdb") \ V(CALL_DEBUG_BREAK_TAG, "CallDebugBreak") \
V(CALL_DEBUG_PREPARE_STEP_IN_TAG, "CallDebugPrepareStepIn", "cdbsi") \ V(CALL_DEBUG_PREPARE_STEP_IN_TAG, "CallDebugPrepareStepIn") \
V(CALL_IC_TAG, "CallIC", "cic") \ V(CALL_IC_TAG, "CallIC") \
V(CALL_INITIALIZE_TAG, "CallInitialize", "ci") \ V(CALL_INITIALIZE_TAG, "CallInitialize") \
V(CALL_MEGAMORPHIC_TAG, "CallMegamorphic", "cmm") \ V(CALL_MEGAMORPHIC_TAG, "CallMegamorphic") \
V(CALL_MISS_TAG, "CallMiss", "cm") \ V(CALL_MISS_TAG, "CallMiss") \
V(CALL_NORMAL_TAG, "CallNormal", "cn") \ V(CALL_NORMAL_TAG, "CallNormal") \
V(CALL_PRE_MONOMORPHIC_TAG, "CallPreMonomorphic", "cpm") \ V(CALL_PRE_MONOMORPHIC_TAG, "CallPreMonomorphic") \
V(KEYED_CALL_DEBUG_BREAK_TAG, "KeyedCallDebugBreak", "kcdb") \ V(KEYED_CALL_DEBUG_BREAK_TAG, "KeyedCallDebugBreak") \
V(KEYED_CALL_DEBUG_PREPARE_STEP_IN_TAG, \ V(KEYED_CALL_DEBUG_PREPARE_STEP_IN_TAG, \
"KeyedCallDebugPrepareStepIn", \ "KeyedCallDebugPrepareStepIn") \
"kcdbsi") \ V(KEYED_CALL_IC_TAG, "KeyedCallIC") \
V(KEYED_CALL_IC_TAG, "KeyedCallIC", "kcic") \ V(KEYED_CALL_INITIALIZE_TAG, "KeyedCallInitialize") \
V(KEYED_CALL_INITIALIZE_TAG, "KeyedCallInitialize", "kci") \ V(KEYED_CALL_MEGAMORPHIC_TAG, "KeyedCallMegamorphic") \
V(KEYED_CALL_MEGAMORPHIC_TAG, "KeyedCallMegamorphic", "kcmm") \ V(KEYED_CALL_MISS_TAG, "KeyedCallMiss") \
V(KEYED_CALL_MISS_TAG, "KeyedCallMiss", "kcm") \ V(KEYED_CALL_NORMAL_TAG, "KeyedCallNormal") \
V(KEYED_CALL_NORMAL_TAG, "KeyedCallNormal", "kcn") \ V(KEYED_CALL_PRE_MONOMORPHIC_TAG, "KeyedCallPreMonomorphic") \
V(KEYED_CALL_PRE_MONOMORPHIC_TAG, \ V(CALLBACK_TAG, "Callback") \
"KeyedCallPreMonomorphic", \ V(EVAL_TAG, "Eval") \
"kcpm") \ V(FUNCTION_TAG, "Function") \
V(CALLBACK_TAG, "Callback", "cb") \ V(KEYED_LOAD_IC_TAG, "KeyedLoadIC") \
V(EVAL_TAG, "Eval", "e") \ V(KEYED_STORE_IC_TAG, "KeyedStoreIC") \
V(FUNCTION_TAG, "Function", "f") \ V(LAZY_COMPILE_TAG, "LazyCompile") \
V(KEYED_LOAD_IC_TAG, "KeyedLoadIC", "klic") \ V(LOAD_IC_TAG, "LoadIC") \
V(KEYED_STORE_IC_TAG, "KeyedStoreIC", "ksic") \ V(REG_EXP_TAG, "RegExp") \
V(LAZY_COMPILE_TAG, "LazyCompile", "lc") \ V(SCRIPT_TAG, "Script") \
V(LOAD_IC_TAG, "LoadIC", "lic") \ V(STORE_IC_TAG, "StoreIC") \
V(REG_EXP_TAG, "RegExp", "re") \ V(STUB_TAG, "Stub") \
V(SCRIPT_TAG, "Script", "sc") \ V(NATIVE_FUNCTION_TAG, "Function") \
V(STORE_IC_TAG, "StoreIC", "sic") \ V(NATIVE_LAZY_COMPILE_TAG, "LazyCompile") \
V(STUB_TAG, "Stub", "s") \ V(NATIVE_SCRIPT_TAG, "Script")
V(NATIVE_FUNCTION_TAG, "Function", "f") \
V(NATIVE_LAZY_COMPILE_TAG, "LazyCompile", "lc") \
V(NATIVE_SCRIPT_TAG, "Script", "sc")
// Note that 'NATIVE_' cases for functions and scripts are mapped onto // Note that 'NATIVE_' cases for functions and scripts are mapped onto
// original tags when writing to the log. // original tags when writing to the log.
class Logger { class Logger {
public: public:
#define DECLARE_ENUM(enum_item, ignore1, ignore2) enum_item, #define DECLARE_ENUM(enum_item, ignore) enum_item,
enum LogEventsAndTags { enum LogEventsAndTags {
LOG_EVENTS_AND_TAGS_LIST(DECLARE_ENUM) LOG_EVENTS_AND_TAGS_LIST(DECLARE_ENUM)
NUMBER_OF_LOG_EVENTS NUMBER_OF_LOG_EVENTS
@ -292,9 +288,6 @@ class Logger {
private: private:
// Size of window used for log records compression.
static const int kCompressionWindowSize = 4;
// Emits the profiler's first message. // Emits the profiler's first message.
static void ProfilerBeginEvent(); static void ProfilerBeginEvent();
@ -312,9 +305,6 @@ class Logger {
static void DeleteEventInternal(LogEventsAndTags event, static void DeleteEventInternal(LogEventsAndTags event,
Address from); Address from);
// Emits aliases for compressed messages.
static void LogAliases();
// Emits the source code of a regexp. Used by regexp events. // Emits the source code of a regexp. Used by regexp events.
static void LogRegExpSource(Handle<JSRegExp> regexp); static void LogRegExpSource(Handle<JSRegExp> regexp);
@ -357,15 +347,8 @@ class Logger {
// recent VM states. // recent VM states.
static SlidingStateWindow* sliding_state_window_; static SlidingStateWindow* sliding_state_window_;
// An array of log events names.
static const char** log_events_;
// An instance of helper created if log compression is enabled.
static CompressionHelper* compression_helper_;
// Internal implementation classes with access to // Internal implementation classes with access to
// private members. // private members.
friend class CompressionHelper;
friend class EventLog; friend class EventLog;
friend class TimeLog; friend class TimeLog;
friend class Profiler; friend class Profiler;

1
deps/v8/src/math.js

@ -264,6 +264,7 @@ function SetupMath() {
%SetMathFunctionId($Math.round, 2); %SetMathFunctionId($Math.round, 2);
%SetMathFunctionId($Math.abs, 4); %SetMathFunctionId($Math.abs, 4);
%SetMathFunctionId($Math.sqrt, 0xd); %SetMathFunctionId($Math.sqrt, 0xd);
%SetMathFunctionId($Math.pow, 0xe);
// TODO(erikcorry): Set the id of the other functions so they can be // TODO(erikcorry): Set the id of the other functions so they can be
// optimized. // optimized.
}; };

12
deps/v8/src/objects.h

@ -3729,7 +3729,9 @@ enum MathFunctionId {
kMathACos = 0xa, kMathACos = 0xa,
kMathATan = 0xb, kMathATan = 0xb,
kMathExp = 0xc, kMathExp = 0xc,
kMathSqrt = 0xd kMathSqrt = 0xd,
kMathPow = 0xe,
kMathPowHalf = 0xf
}; };
@ -4154,11 +4156,11 @@ class SharedFunctionInfo: public HeapObject {
static const int kTryFullCodegen = 1; static const int kTryFullCodegen = 1;
static const int kAllowLazyCompilation = 2; static const int kAllowLazyCompilation = 2;
static const int kMathFunctionShift = 3; static const int kMathFunctionShift = 3;
static const int kMathFunctionMask = 0xf; static const int kMathFunctionMask = 0x1f;
static const int kLiveObjectsMayExist = 7; static const int kLiveObjectsMayExist = 8;
static const int kCodeAgeShift = 8; static const int kCodeAgeShift = 9;
static const int kCodeAgeMask = 0x7; static const int kCodeAgeMask = 0x7;
static const int kOptimizationDisabled = 11; static const int kOptimizationDisabled = 12;
DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo); DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
}; };

173
deps/v8/src/parser.cc

@ -609,7 +609,25 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
// Initialize parser state. // Initialize parser state.
source->TryFlatten(); source->TryFlatten();
scanner_.Initialize(source); if (source->IsExternalTwoByteString()) {
// Notice that the stream is destroyed at the end of the branch block.
// The last line of the blocks can't be moved outside, even though they're
// identical calls.
ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length());
scanner_.Initialize(&stream, JavaScriptScanner::kAllLiterals);
return DoParseProgram(source, in_global_context, &zone_scope);
} else {
GenericStringUC16CharacterStream stream(source, 0, source->length());
scanner_.Initialize(&stream, JavaScriptScanner::kAllLiterals);
return DoParseProgram(source, in_global_context, &zone_scope);
}
}
FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
bool in_global_context,
ZoneScope* zone_scope) {
ASSERT(target_stack_ == NULL); ASSERT(target_stack_ == NULL);
if (pre_data_ != NULL) pre_data_->Initialize(); if (pre_data_ != NULL) pre_data_->Initialize();
@ -655,25 +673,45 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
// If there was a syntax error we have to get rid of the AST // If there was a syntax error we have to get rid of the AST
// and it is not safe to do so before the scope has been deleted. // and it is not safe to do so before the scope has been deleted.
if (result == NULL) zone_scope.DeleteOnExit(); if (result == NULL) zone_scope->DeleteOnExit();
return result; return result;
} }
FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) { FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) {
CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT); CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
HistogramTimerScope timer(&Counters::parse_lazy); HistogramTimerScope timer(&Counters::parse_lazy);
Handle<String> source(String::cast(script_->source())); Handle<String> source(String::cast(script_->source()));
Counters::total_parse_size.Increment(source->length()); Counters::total_parse_size.Increment(source->length());
// Initialize parser state.
source->TryFlatten();
if (source->IsExternalTwoByteString()) {
ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source),
info->start_position(),
info->end_position());
FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope);
return result;
} else {
GenericStringUC16CharacterStream stream(source,
info->start_position(),
info->end_position());
FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope);
return result;
}
}
FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info,
UC16CharacterStream* source,
ZoneScope* zone_scope) {
scanner_.Initialize(source, JavaScriptScanner::kAllLiterals);
ASSERT(target_stack_ == NULL);
Handle<String> name(String::cast(info->name())); Handle<String> name(String::cast(info->name()));
fni_ = new FuncNameInferrer(); fni_ = new FuncNameInferrer();
fni_->PushEnclosingName(name); fni_->PushEnclosingName(name);
// Initialize parser state.
source->TryFlatten();
scanner_.Initialize(source, info->start_position(), info->end_position());
ASSERT(target_stack_ == NULL);
mode_ = PARSE_EAGERLY; mode_ = PARSE_EAGERLY;
// Place holder for the result. // Place holder for the result.
@ -705,7 +743,7 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) {
// not safe to do before scope has been deleted. // not safe to do before scope has been deleted.
if (result == NULL) { if (result == NULL) {
Top::StackOverflow(); Top::StackOverflow();
zone_scope.DeleteOnExit(); zone_scope->DeleteOnExit();
} else { } else {
Handle<String> inferred_name(info->inferred_name()); Handle<String> inferred_name(info->inferred_name());
result->set_inferred_name(inferred_name); result->set_inferred_name(inferred_name);
@ -719,12 +757,12 @@ Handle<String> Parser::GetSymbol(bool* ok) {
if (pre_data() != NULL) { if (pre_data() != NULL) {
symbol_id = pre_data()->GetSymbolIdentifier(); symbol_id = pre_data()->GetSymbolIdentifier();
} }
return LookupSymbol(symbol_id, scanner_.literal()); return LookupSymbol(symbol_id, scanner().literal());
} }
void Parser::ReportMessage(const char* type, Vector<const char*> args) { void Parser::ReportMessage(const char* type, Vector<const char*> args) {
Scanner::Location source_location = scanner_.location(); Scanner::Location source_location = scanner().location();
ReportMessageAt(source_location, type, args); ReportMessageAt(source_location, type, args);
} }
@ -1641,7 +1679,7 @@ Statement* Parser::ParseContinueStatement(bool* ok) {
Expect(Token::CONTINUE, CHECK_OK); Expect(Token::CONTINUE, CHECK_OK);
Handle<String> label = Handle<String>::null(); Handle<String> label = Handle<String>::null();
Token::Value tok = peek(); Token::Value tok = peek();
if (!scanner_.has_line_terminator_before_next() && if (!scanner().has_line_terminator_before_next() &&
tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
label = ParseIdentifier(CHECK_OK); label = ParseIdentifier(CHECK_OK);
} }
@ -1667,7 +1705,7 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
Expect(Token::BREAK, CHECK_OK); Expect(Token::BREAK, CHECK_OK);
Handle<String> label; Handle<String> label;
Token::Value tok = peek(); Token::Value tok = peek();
if (!scanner_.has_line_terminator_before_next() && if (!scanner().has_line_terminator_before_next() &&
tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) { tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
label = ParseIdentifier(CHECK_OK); label = ParseIdentifier(CHECK_OK);
} }
@ -1712,7 +1750,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
} }
Token::Value tok = peek(); Token::Value tok = peek();
if (scanner_.has_line_terminator_before_next() || if (scanner().has_line_terminator_before_next() ||
tok == Token::SEMICOLON || tok == Token::SEMICOLON ||
tok == Token::RBRACE || tok == Token::RBRACE ||
tok == Token::EOS) { tok == Token::EOS) {
@ -1844,7 +1882,7 @@ Statement* Parser::ParseThrowStatement(bool* ok) {
Expect(Token::THROW, CHECK_OK); Expect(Token::THROW, CHECK_OK);
int pos = scanner().location().beg_pos; int pos = scanner().location().beg_pos;
if (scanner_.has_line_terminator_before_next()) { if (scanner().has_line_terminator_before_next()) {
ReportMessage("newline_after_throw", Vector<const char*>::empty()); ReportMessage("newline_after_throw", Vector<const char*>::empty());
*ok = false; *ok = false;
return NULL; return NULL;
@ -2408,7 +2446,8 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
// LeftHandSideExpression ('++' | '--')? // LeftHandSideExpression ('++' | '--')?
Expression* expression = ParseLeftHandSideExpression(CHECK_OK); Expression* expression = ParseLeftHandSideExpression(CHECK_OK);
if (!scanner_.has_line_terminator_before_next() && Token::IsCountOp(peek())) { if (!scanner().has_line_terminator_before_next() &&
Token::IsCountOp(peek())) {
// Signal a reference error if the expression is an invalid // Signal a reference error if the expression is an invalid
// left-hand side expression. We could report this as a syntax // left-hand side expression. We could report this as a syntax
// error here but for compatibility with JSC we choose to report the // error here but for compatibility with JSC we choose to report the
@ -2677,7 +2716,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) {
case Token::NUMBER: { case Token::NUMBER: {
Consume(Token::NUMBER); Consume(Token::NUMBER);
double value = double value =
StringToDouble(scanner_.literal(), ALLOW_HEX | ALLOW_OCTALS); StringToDouble(scanner().literal(), ALLOW_HEX | ALLOW_OCTALS);
result = NewNumberLiteral(value); result = NewNumberLiteral(value);
break; break;
} }
@ -3028,7 +3067,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
case Token::NUMBER: { case Token::NUMBER: {
Consume(Token::NUMBER); Consume(Token::NUMBER);
double value = double value =
StringToDouble(scanner_.literal(), ALLOW_HEX | ALLOW_OCTALS); StringToDouble(scanner().literal(), ALLOW_HEX | ALLOW_OCTALS);
key = NewNumberLiteral(value); key = NewNumberLiteral(value);
break; break;
} }
@ -3089,7 +3128,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) { Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
if (!scanner_.ScanRegExpPattern(seen_equal)) { if (!scanner().ScanRegExpPattern(seen_equal)) {
Next(); Next();
ReportMessage("unterminated_regexp", Vector<const char*>::empty()); ReportMessage("unterminated_regexp", Vector<const char*>::empty());
*ok = false; *ok = false;
@ -3099,10 +3138,10 @@ Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) {
int literal_index = temp_scope_->NextMaterializedLiteralIndex(); int literal_index = temp_scope_->NextMaterializedLiteralIndex();
Handle<String> js_pattern = Handle<String> js_pattern =
Factory::NewStringFromUtf8(scanner_.next_literal(), TENURED); Factory::NewStringFromUtf8(scanner().next_literal(), TENURED);
scanner_.ScanRegExpFlags(); scanner().ScanRegExpFlags();
Handle<String> js_flags = Handle<String> js_flags =
Factory::NewStringFromUtf8(scanner_.next_literal(), TENURED); Factory::NewStringFromUtf8(scanner().next_literal(), TENURED);
Next(); Next();
return new RegExpLiteral(js_pattern, js_flags, literal_index); return new RegExpLiteral(js_pattern, js_flags, literal_index);
@ -3158,7 +3197,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
// FormalParameterList :: // FormalParameterList ::
// '(' (Identifier)*[','] ')' // '(' (Identifier)*[','] ')'
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
int start_pos = scanner_.location().beg_pos; int start_pos = scanner().location().beg_pos;
bool done = (peek() == Token::RPAREN); bool done = (peek() == Token::RPAREN);
while (!done) { while (!done) {
Handle<String> param_name = ParseIdentifier(CHECK_OK); Handle<String> param_name = ParseIdentifier(CHECK_OK);
@ -3195,7 +3234,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
bool is_lazily_compiled = bool is_lazily_compiled =
mode() == PARSE_LAZILY && top_scope_->HasTrivialOuterContext(); mode() == PARSE_LAZILY && top_scope_->HasTrivialOuterContext();
int function_block_pos = scanner_.location().beg_pos; int function_block_pos = scanner().location().beg_pos;
int materialized_literal_count; int materialized_literal_count;
int expected_property_count; int expected_property_count;
int end_pos; int end_pos;
@ -3212,7 +3251,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
ReportInvalidPreparseData(name, CHECK_OK); ReportInvalidPreparseData(name, CHECK_OK);
} }
Counters::total_preparse_skipped.Increment(end_pos - function_block_pos); Counters::total_preparse_skipped.Increment(end_pos - function_block_pos);
scanner_.SeekForward(end_pos); // Seek to position just before terminal '}'.
scanner().SeekForward(end_pos - 1);
materialized_literal_count = entry.literal_count(); materialized_literal_count = entry.literal_count();
expected_property_count = entry.property_count(); expected_property_count = entry.property_count();
only_simple_this_property_assignments = false; only_simple_this_property_assignments = false;
@ -3228,7 +3268,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
this_property_assignments = temp_scope.this_property_assignments(); this_property_assignments = temp_scope.this_property_assignments();
Expect(Token::RBRACE, CHECK_OK); Expect(Token::RBRACE, CHECK_OK);
end_pos = scanner_.location().end_pos; end_pos = scanner().location().end_pos;
} }
FunctionLiteral* function_literal = FunctionLiteral* function_literal =
@ -3332,7 +3372,7 @@ void Parser::ExpectSemicolon(bool* ok) {
Next(); Next();
return; return;
} }
if (scanner_.has_line_terminator_before_next() || if (scanner().has_line_terminator_before_next() ||
tok == Token::RBRACE || tok == Token::RBRACE ||
tok == Token::EOS) { tok == Token::EOS) {
return; return;
@ -3383,8 +3423,8 @@ Handle<String> Parser::ParseIdentifierOrGetOrSet(bool* is_get,
bool* ok) { bool* ok) {
Expect(Token::IDENTIFIER, ok); Expect(Token::IDENTIFIER, ok);
if (!*ok) return Handle<String>(); if (!*ok) return Handle<String>();
if (scanner_.literal_length() == 3) { if (scanner().literal_length() == 3) {
const char* token = scanner_.literal_string(); const char* token = scanner().literal_string();
*is_get = strcmp(token, "get") == 0; *is_get = strcmp(token, "get") == 0;
*is_set = !*is_get && strcmp(token, "set") == 0; *is_set = !*is_get && strcmp(token, "set") == 0;
} }
@ -3503,8 +3543,8 @@ Expression* Parser::NewThrowError(Handle<String> constructor,
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// JSON // JSON
Handle<Object> JsonParser::ParseJson(Handle<String> source) { Handle<Object> JsonParser::ParseJson(Handle<String> script,
source->TryFlatten(); UC16CharacterStream* source) {
scanner_.Initialize(source); scanner_.Initialize(source);
stack_overflow_ = false; stack_overflow_ = false;
Handle<Object> result = ParseJsonValue(); Handle<Object> result = ParseJsonValue();
@ -3540,7 +3580,7 @@ Handle<Object> JsonParser::ParseJson(Handle<String> source) {
} }
Scanner::Location source_location = scanner_.location(); Scanner::Location source_location = scanner_.location();
MessageLocation location(Factory::NewScript(source), MessageLocation location(Factory::NewScript(script),
source_location.beg_pos, source_location.beg_pos,
source_location.end_pos); source_location.end_pos);
int argc = (name_opt == NULL) ? 0 : 1; int argc = (name_opt == NULL) ? 0 : 1;
@ -4409,10 +4449,25 @@ CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) {
} }
static const uc16 kNoCharClass = 0;
// Adds range or pre-defined character class to character ranges.
// If char_class is not kInvalidClass, it's interpreted as a class
// escape (i.e., 's' means whitespace, from '\s').
static inline void AddRangeOrEscape(ZoneList<CharacterRange>* ranges,
uc16 char_class,
CharacterRange range) {
if (char_class != kNoCharClass) {
CharacterRange::AddClassEscape(char_class, ranges);
} else {
ranges->Add(range);
}
}
RegExpTree* RegExpParser::ParseCharacterClass() { RegExpTree* RegExpParser::ParseCharacterClass() {
static const char* kUnterminated = "Unterminated character class"; static const char* kUnterminated = "Unterminated character class";
static const char* kRangeOutOfOrder = "Range out of order in character class"; static const char* kRangeOutOfOrder = "Range out of order in character class";
static const char* kInvalidRange = "Invalid character range";
ASSERT_EQ(current(), '['); ASSERT_EQ(current(), '[');
Advance(); Advance();
@ -4421,30 +4476,10 @@ RegExpTree* RegExpParser::ParseCharacterClass() {
is_negated = true; is_negated = true;
Advance(); Advance();
} }
// A CharacterClass is a sequence of single characters, character class
// escapes or ranges. Ranges are on the form "x-y" where x and y are
// single characters (and not character class escapes like \s).
// A "-" may occur at the start or end of the character class (just after
// "[" or "[^", or just before "]") without being considered part of a
// range. A "-" may also appear as the beginning or end of a range.
// I.e., [--+] is valid, so is [!--].
ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2); ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2);
while (has_more() && current() != ']') { while (has_more() && current() != ']') {
uc16 char_class = 0; uc16 char_class = kNoCharClass;
CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED); CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED);
if (char_class) {
CharacterRange::AddClassEscape(char_class, ranges);
if (current() == '-') {
Advance();
ranges->Add(CharacterRange::Singleton('-'));
if (current() != ']') {
ReportError(CStrVector(kInvalidRange) CHECK_FAILED);
}
break;
}
continue;
}
if (current() == '-') { if (current() == '-') {
Advance(); Advance();
if (current() == kEndMarker) { if (current() == kEndMarker) {
@ -4452,20 +4487,25 @@ RegExpTree* RegExpParser::ParseCharacterClass() {
// following code report an error. // following code report an error.
break; break;
} else if (current() == ']') { } else if (current() == ']') {
ranges->Add(first); AddRangeOrEscape(ranges, char_class, first);
ranges->Add(CharacterRange::Singleton('-')); ranges->Add(CharacterRange::Singleton('-'));
break; break;
} }
CharacterRange next = ParseClassAtom(&char_class CHECK_FAILED); uc16 char_class_2 = kNoCharClass;
if (char_class) { CharacterRange next = ParseClassAtom(&char_class_2 CHECK_FAILED);
ReportError(CStrVector(kInvalidRange) CHECK_FAILED); if (char_class != kNoCharClass || char_class_2 != kNoCharClass) {
// Either end is an escaped character class. Treat the '-' verbatim.
AddRangeOrEscape(ranges, char_class, first);
ranges->Add(CharacterRange::Singleton('-'));
AddRangeOrEscape(ranges, char_class_2, next);
continue;
} }
if (first.from() > next.to()) { if (first.from() > next.to()) {
return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED); return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED);
} }
ranges->Add(CharacterRange::Range(first.from(), next.to())); ranges->Add(CharacterRange::Range(first.from(), next.to()));
} else { } else {
ranges->Add(first); AddRangeOrEscape(ranges, char_class, first);
} }
} }
if (!has_more()) { if (!has_more()) {
@ -4555,13 +4595,12 @@ int ScriptDataImpl::ReadNumber(byte** source) {
// Create a Scanner for the preparser to use as input, and preparse the source. // Create a Scanner for the preparser to use as input, and preparse the source.
static ScriptDataImpl* DoPreParse(Handle<String> source, static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
unibrow::CharacterStream* stream,
bool allow_lazy, bool allow_lazy,
ParserRecorder* recorder, ParserRecorder* recorder,
int literal_flags) { int literal_flags) {
V8JavaScriptScanner scanner; V8JavaScriptScanner scanner;
scanner.Initialize(source, stream, literal_flags); scanner.Initialize(source, literal_flags);
intptr_t stack_limit = StackGuard::real_climit(); intptr_t stack_limit = StackGuard::real_climit();
if (!preparser::PreParser::PreParseProgram(&scanner, if (!preparser::PreParser::PreParseProgram(&scanner,
recorder, recorder,
@ -4580,8 +4619,7 @@ static ScriptDataImpl* DoPreParse(Handle<String> source,
// Preparse, but only collect data that is immediately useful, // Preparse, but only collect data that is immediately useful,
// even if the preparser data is only used once. // even if the preparser data is only used once.
ScriptDataImpl* ParserApi::PartialPreParse(Handle<String> source, ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source,
unibrow::CharacterStream* stream,
v8::Extension* extension) { v8::Extension* extension) {
bool allow_lazy = FLAG_lazy && (extension == NULL); bool allow_lazy = FLAG_lazy && (extension == NULL);
if (!allow_lazy) { if (!allow_lazy) {
@ -4590,22 +4628,19 @@ ScriptDataImpl* ParserApi::PartialPreParse(Handle<String> source,
return NULL; return NULL;
} }
PartialParserRecorder recorder; PartialParserRecorder recorder;
return DoPreParse(source, allow_lazy, &recorder,
return DoPreParse(source, stream, allow_lazy, &recorder,
JavaScriptScanner::kNoLiterals); JavaScriptScanner::kNoLiterals);
} }
ScriptDataImpl* ParserApi::PreParse(Handle<String> source, ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source,
unibrow::CharacterStream* stream,
v8::Extension* extension) { v8::Extension* extension) {
Handle<Script> no_script; Handle<Script> no_script;
bool allow_lazy = FLAG_lazy && (extension == NULL); bool allow_lazy = FLAG_lazy && (extension == NULL);
CompleteParserRecorder recorder; CompleteParserRecorder recorder;
int kPreParseLiteralsFlags = int kPreParseLiteralsFlags =
JavaScriptScanner::kLiteralString | JavaScriptScanner::kLiteralIdentifier; JavaScriptScanner::kLiteralString | JavaScriptScanner::kLiteralIdentifier;
return DoPreParse(source, stream, allow_lazy, return DoPreParse(source, allow_lazy, &recorder, kPreParseLiteralsFlags);
&recorder, kPreParseLiteralsFlags);
} }

33
deps/v8/src/parser.h

@ -169,14 +169,12 @@ class ParserApi {
static bool Parse(CompilationInfo* info); static bool Parse(CompilationInfo* info);
// Generic preparser generating full preparse data. // Generic preparser generating full preparse data.
static ScriptDataImpl* PreParse(Handle<String> source, static ScriptDataImpl* PreParse(UC16CharacterStream* source,
unibrow::CharacterStream* stream,
v8::Extension* extension); v8::Extension* extension);
// Preparser that only does preprocessing that makes sense if only used // Preparser that only does preprocessing that makes sense if only used
// immediately after. // immediately after.
static ScriptDataImpl* PartialPreParse(Handle<String> source, static ScriptDataImpl* PartialPreParse(UC16CharacterStream* source,
unibrow::CharacterStream* stream,
v8::Extension* extension); v8::Extension* extension);
}; };
@ -435,18 +433,26 @@ class Parser {
Vector<const char*> args); Vector<const char*> args);
protected: protected:
FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info,
UC16CharacterStream* source,
ZoneScope* zone_scope);
enum Mode { enum Mode {
PARSE_LAZILY, PARSE_LAZILY,
PARSE_EAGERLY PARSE_EAGERLY
}; };
// Called by ParseProgram after setting up the scanner.
FunctionLiteral* DoParseProgram(Handle<String> source,
bool in_global_context,
ZoneScope* zone_scope);
// Report syntax error // Report syntax error
void ReportUnexpectedToken(Token::Value token); void ReportUnexpectedToken(Token::Value token);
void ReportInvalidPreparseData(Handle<String> name, bool* ok); void ReportInvalidPreparseData(Handle<String> name, bool* ok);
void ReportMessage(const char* message, Vector<const char*> args); void ReportMessage(const char* message, Vector<const char*> args);
bool inside_with() const { return with_nesting_level_ > 0; } bool inside_with() const { return with_nesting_level_ > 0; }
Scanner& scanner() { return scanner_; } V8JavaScriptScanner& scanner() { return scanner_; }
Mode mode() const { return mode_; } Mode mode() const { return mode_; }
ScriptDataImpl* pre_data() const { return pre_data_; } ScriptDataImpl* pre_data() const { return pre_data_; }
@ -548,7 +554,7 @@ class Parser {
INLINE(Token::Value peek()) { INLINE(Token::Value peek()) {
if (stack_overflow_) return Token::ILLEGAL; if (stack_overflow_) return Token::ILLEGAL;
return scanner_.peek(); return scanner().peek();
} }
INLINE(Token::Value Next()) { INLINE(Token::Value Next()) {
@ -560,9 +566,11 @@ class Parser {
} }
if (StackLimitCheck().HasOverflowed()) { if (StackLimitCheck().HasOverflowed()) {
// Any further calls to Next or peek will return the illegal token. // Any further calls to Next or peek will return the illegal token.
// The current call must return the next token, which might already
// have been peek'ed.
stack_overflow_ = true; stack_overflow_ = true;
} }
return scanner_.Next(); return scanner().Next();
} }
INLINE(void Consume(Token::Value token)); INLINE(void Consume(Token::Value token));
@ -702,7 +710,14 @@ class JsonParser BASE_EMBEDDED {
// Parse JSON input as a single JSON value. // Parse JSON input as a single JSON value.
// Returns null handle and sets exception if parsing failed. // Returns null handle and sets exception if parsing failed.
static Handle<Object> Parse(Handle<String> source) { static Handle<Object> Parse(Handle<String> source) {
return JsonParser().ParseJson(source); if (source->IsExternalTwoByteString()) {
ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length());
return JsonParser().ParseJson(source, &stream);
} else {
GenericStringUC16CharacterStream stream(source, 0, source->length());
return JsonParser().ParseJson(source, &stream);
}
} }
private: private:
@ -710,7 +725,7 @@ class JsonParser BASE_EMBEDDED {
~JsonParser() { } ~JsonParser() { }
// Parse a string containing a single JSON value. // Parse a string containing a single JSON value.
Handle<Object> ParseJson(Handle<String>); Handle<Object> ParseJson(Handle<String> script, UC16CharacterStream* source);
// Parse a single JSON value from input (grammar production JSONValue). // Parse a single JSON value from input (grammar production JSONValue).
// A JSON value is either a (double-quoted) string literal, a number literal, // A JSON value is either a (double-quoted) string literal, a number literal,
// one of "true", "false", or "null", or an object or array literal. // one of "true", "false", or "null", or an object or array literal.

29
deps/v8/src/platform-linux.cc

@ -134,9 +134,7 @@ static bool CPUInfoContainsString(const char * search_string) {
} }
bool OS::ArmCpuHasFeature(CpuFeature feature) { bool OS::ArmCpuHasFeature(CpuFeature feature) {
const int max_items = 2; const char* search_string = NULL;
const char* search_strings[max_items] = { NULL, NULL };
int search_items = 0;
// Simple detection of VFP at runtime for Linux. // Simple detection of VFP at runtime for Linux.
// It is based on /proc/cpuinfo, which reveals hardware configuration // It is based on /proc/cpuinfo, which reveals hardware configuration
// to user-space applications. According to ARM (mid 2009), no similar // to user-space applications. According to ARM (mid 2009), no similar
@ -144,25 +142,26 @@ bool OS::ArmCpuHasFeature(CpuFeature feature) {
// so it's up to individual OSes to provide such. // so it's up to individual OSes to provide such.
switch (feature) { switch (feature) {
case VFP3: case VFP3:
search_strings[0] = "vfpv3"; search_string = "vfpv3";
// Some old kernels will report vfp for A8, not vfpv3, so we check for
// A8 explicitely. The cpuinfo file report the CPU Part which for Cortex
// A8 is 0xc08.
search_strings[1] = "0xc08";
search_items = 2;
ASSERT(search_items <= max_items);
break; break;
case ARMv7: case ARMv7:
search_strings[0] = "ARMv7" ; search_string = "ARMv7";
search_items = 1;
ASSERT(search_items <= max_items);
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
for (int i = 0; i < search_items; ++i) { if (CPUInfoContainsString(search_string)) {
if (CPUInfoContainsString(search_strings[i])) { return true;
}
if (feature == VFP3) {
// Some old kernels will report vfp not vfpv3. Here we make a last attempt
// to detect vfpv3 by checking for vfp *and* neon, since neon is only
// available on architectures with vfpv3.
// Checking neon on its own is not enough as it is possible to have neon
// without vfp.
if (CPUInfoContainsString("vfp") && CPUInfoContainsString("neon")) {
return true; return true;
} }
} }

109
deps/v8/src/preparser-api.cc

@ -39,39 +39,121 @@ namespace v8 {
namespace internal { namespace internal {
// UTF16Buffer based on a v8::UnicodeInputStream. // UTF16Buffer based on a v8::UnicodeInputStream.
class InputStreamUTF16Buffer : public UTF16Buffer { class InputStreamUTF16Buffer : public UC16CharacterStream {
public: public:
explicit InputStreamUTF16Buffer(UnicodeInputStream* stream) /* The InputStreamUTF16Buffer maintains an internal buffer
: UTF16Buffer(), * that is filled in chunks from the UC16CharacterStream.
stream_(stream) { } * It also maintains unlimited pushback capability, but optimized
* for small pushbacks.
* The pushback_buffer_ pointer points to the limit of pushbacks
* in the current buffer. There is room for a few pushback'ed chars before
* the buffer containing the most recently read chunk. If this is overflowed,
* an external buffer is allocated/reused to hold further pushbacks, and
* pushback_buffer_ and buffer_cursor_/buffer_end_ now points to the
* new buffer. When this buffer is read to the end again, the cursor is
* switched back to the internal buffer
*/
explicit InputStreamUTF16Buffer(v8::UnicodeInputStream* stream)
: UC16CharacterStream(),
stream_(stream),
pushback_buffer_(buffer_),
pushback_buffer_end_cache_(NULL),
pushback_buffer_backing_(NULL),
pushback_buffer_backing_size_(0) {
buffer_cursor_ = buffer_end_ = buffer_ + kPushBackSize;
}
virtual ~InputStreamUTF16Buffer() { } virtual ~InputStreamUTF16Buffer() {
if (pushback_buffer_backing_ != NULL) {
DeleteArray(pushback_buffer_backing_);
}
}
virtual void PushBack(uc32 ch) { virtual void PushBack(uc16 ch) {
stream_->PushBack(ch); ASSERT(pos_ > 0);
if (buffer_cursor_ <= pushback_buffer_) {
// No more room in the current buffer to do pushbacks.
if (pushback_buffer_end_cache_ == NULL) {
// We have overflowed the pushback space at the beginning of buffer_.
// Switch to using a separate allocated pushback buffer.
if (pushback_buffer_backing_ == NULL) {
// Allocate a buffer the first time we need it.
pushback_buffer_backing_ = NewArray<uc16>(kPushBackSize);
pushback_buffer_backing_size_ = kPushBackSize;
}
pushback_buffer_ = pushback_buffer_backing_;
pushback_buffer_end_cache_ = buffer_end_;
buffer_end_ = pushback_buffer_backing_ + pushback_buffer_backing_size_;
buffer_cursor_ = buffer_end_ - 1;
} else {
// Hit the bottom of the allocated pushback buffer.
// Double the buffer and continue.
uc16* new_buffer = NewArray<uc16>(pushback_buffer_backing_size_ * 2);
memcpy(new_buffer + pushback_buffer_backing_size_,
pushback_buffer_backing_,
pushback_buffer_backing_size_);
DeleteArray(pushback_buffer_backing_);
buffer_cursor_ = new_buffer + pushback_buffer_backing_size_;
pushback_buffer_backing_ = pushback_buffer_ = new_buffer;
buffer_end_ = pushback_buffer_backing_ + pushback_buffer_backing_size_;
}
}
pushback_buffer_[buffer_cursor_ - pushback_buffer_- 1] = ch;
pos_--; pos_--;
} }
virtual uc32 Advance() { protected:
uc32 result = stream_->Next(); virtual bool ReadBlock() {
if (result >= 0) pos_++; if (pushback_buffer_end_cache_ != NULL) {
return result; buffer_cursor_ = buffer_;
buffer_end_ = pushback_buffer_end_cache_;
pushback_buffer_end_cache_ = NULL;
return buffer_end_ > buffer_cursor_;
}
// Copy the top of the buffer into the pushback area.
int32_t value;
uc16* buffer_start = buffer_ + kPushBackSize;
buffer_cursor_ = buffer_end_ = buffer_start;
while ((value = stream_->Next()) >= 0) {
if (value > static_cast<int32_t>(unibrow::Utf8::kMaxThreeByteChar)) {
value = unibrow::Utf8::kBadChar;
}
// buffer_end_ is a const pointer, but buffer_ is writable.
buffer_start[buffer_end_++ - buffer_start] = static_cast<uc16>(value);
if (buffer_end_ == buffer_ + kPushBackSize + kBufferSize) break;
}
return buffer_end_ > buffer_start;
} }
virtual void SeekForward(int pos) { virtual unsigned SlowSeekForward(unsigned pos) {
// Seeking in the input is not used by preparsing. // Seeking in the input is not used by preparsing.
// It's only used by the real parser based on preparser data. // It's only used by the real parser based on preparser data.
UNIMPLEMENTED(); UNIMPLEMENTED();
return 0;
} }
private: private:
static const unsigned kBufferSize = 512;
static const unsigned kPushBackSize = 16;
v8::UnicodeInputStream* const stream_; v8::UnicodeInputStream* const stream_;
// Buffer holding first kPushBackSize characters of pushback buffer,
// then kBufferSize chars of read-ahead.
// The pushback buffer is only used if pushing back characters past
// the start of a block.
uc16 buffer_[kPushBackSize + kBufferSize];
// Limit of pushbacks before new allocation is necessary.
uc16* pushback_buffer_;
// Only if that pushback buffer at the start of buffer_ isn't sufficient
// is the following used.
const uc16* pushback_buffer_end_cache_;
uc16* pushback_buffer_backing_;
unsigned pushback_buffer_backing_size_;
}; };
class StandAloneJavaScriptScanner : public JavaScriptScanner { class StandAloneJavaScriptScanner : public JavaScriptScanner {
public: public:
void Initialize(UTF16Buffer* source) { void Initialize(UC16CharacterStream* source) {
source_ = source; source_ = source;
literal_flags_ = kLiteralString | kLiteralIdentifier; literal_flags_ = kLiteralString | kLiteralIdentifier;
Init(); Init();
@ -92,7 +174,6 @@ void FatalProcessOutOfMemory(const char* reason) {
bool EnableSlowAsserts() { return true; } bool EnableSlowAsserts() { return true; }
} // namespace internal. } // namespace internal.

1
deps/v8/src/preparser.cc

@ -1078,6 +1078,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
Expect(i::Token::RBRACE, CHECK_OK); Expect(i::Token::RBRACE, CHECK_OK);
// Position right after terminal '}'.
int end_pos = scanner_->location().end_pos; int end_pos = scanner_->location().end_pos;
log_->LogFunction(function_block_pos, end_pos, log_->LogFunction(function_block_pos, end_pos,
function_scope.materialized_literal_count(), function_scope.materialized_literal_count(),

14
deps/v8/src/profile-generator-inl.h

@ -122,7 +122,7 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
} }
inline uint64_t HeapEntry::id() { uint64_t HeapEntry::id() {
union { union {
Id stored_id; Id stored_id;
uint64_t returned_id; uint64_t returned_id;
@ -146,6 +146,18 @@ void HeapEntriesMap::UpdateEntries(Visitor* visitor) {
} }
} }
bool HeapSnapshotGenerator::ReportProgress(bool force) {
const int kProgressReportGranularity = 10000;
if (control_ != NULL
&& (force || progress_counter_ % kProgressReportGranularity == 0)) {
return
control_->ReportProgressValue(progress_counter_, progress_total_) ==
v8::ActivityControl::kContinue;
}
return true;
}
} } // namespace v8::internal } } // namespace v8::internal
#endif // ENABLE_LOGGING_AND_PROFILING #endif // ENABLE_LOGGING_AND_PROFILING

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

@ -1382,86 +1382,6 @@ HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
} }
void HeapSnapshot::FillReversePostorderIndexes(Vector<HeapEntry*>* entries) {
ClearPaint();
int current_entry = 0;
List<HeapEntry*> nodes_to_visit;
nodes_to_visit.Add(root());
root()->paint_reachable();
while (!nodes_to_visit.is_empty()) {
HeapEntry* entry = nodes_to_visit.last();
Vector<HeapGraphEdge> children = entry->children();
bool has_new_edges = false;
for (int i = 0; i < children.length(); ++i) {
if (children[i].type() == HeapGraphEdge::kShortcut) continue;
HeapEntry* child = children[i].to();
if (!child->painted_reachable()) {
nodes_to_visit.Add(child);
child->paint_reachable();
has_new_edges = true;
}
}
if (!has_new_edges) {
entry->set_ordered_index(current_entry);
(*entries)[current_entry++] = entry;
nodes_to_visit.RemoveLast();
}
}
entries->Truncate(current_entry);
}
static int Intersect(int i1, int i2, const Vector<HeapEntry*>& dominators) {
int finger1 = i1, finger2 = i2;
while (finger1 != finger2) {
while (finger1 < finger2) finger1 = dominators[finger1]->ordered_index();
while (finger2 < finger1) finger2 = dominators[finger2]->ordered_index();
}
return finger1;
}
// The algorithm is based on the article:
// K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm"
// Softw. Pract. Exper. 4 (2001), pp. 1–10.
void HeapSnapshot::BuildDominatorTree(const Vector<HeapEntry*>& entries,
Vector<HeapEntry*>* dominators) {
if (entries.length() == 0) return;
const int root_index = entries.length() - 1;
for (int i = 0; i < root_index; ++i) (*dominators)[i] = NULL;
(*dominators)[root_index] = entries[root_index];
bool changed = true;
while (changed) {
changed = false;
for (int i = root_index - 1; i >= 0; --i) {
HeapEntry* new_idom = NULL;
Vector<HeapGraphEdge*> rets = entries[i]->retainers();
int j = 0;
for (; j < rets.length(); ++j) {
if (rets[j]->type() == HeapGraphEdge::kShortcut) continue;
HeapEntry* ret = rets[j]->From();
if (dominators->at(ret->ordered_index()) != NULL) {
new_idom = ret;
break;
}
}
for (++j; j < rets.length(); ++j) {
if (rets[j]->type() == HeapGraphEdge::kShortcut) continue;
HeapEntry* ret = rets[j]->From();
if (dominators->at(ret->ordered_index()) != NULL) {
new_idom = entries[Intersect(ret->ordered_index(),
new_idom->ordered_index(),
*dominators)];
}
}
if (new_idom != NULL && dominators->at(i) != new_idom) {
(*dominators)[i] = new_idom;
changed = true;
}
}
}
}
void HeapSnapshot::SetDominatorsToSelf() { void HeapSnapshot::SetDominatorsToSelf() {
for (int i = 0; i < entries_.length(); ++i) { for (int i = 0; i < entries_.length(); ++i) {
HeapEntry* entry = entries_[i]; HeapEntry* entry = entries_[i];
@ -1470,61 +1390,6 @@ void HeapSnapshot::SetDominatorsToSelf() {
} }
void HeapSnapshot::SetEntriesDominators() {
// This array is used for maintaining reverse postorder of nodes.
ScopedVector<HeapEntry*> ordered_entries(entries_.length());
FillReversePostorderIndexes(&ordered_entries);
ScopedVector<HeapEntry*> dominators(ordered_entries.length());
BuildDominatorTree(ordered_entries, &dominators);
for (int i = 0; i < ordered_entries.length(); ++i) {
ASSERT(dominators[i] != NULL);
ordered_entries[i]->set_dominator(dominators[i]);
}
// For nodes unreachable from root, set dominator to itself.
SetDominatorsToSelf();
}
void HeapSnapshot::ApproximateRetainedSizes() {
SetEntriesDominators();
// As for the dominators tree we only know parent nodes, not
// children, to sum up total sizes we traverse the tree level by
// level upwards, starting from leaves.
for (int i = 0; i < entries_.length(); ++i) {
HeapEntry* entry = entries_[i];
entry->set_retained_size(entry->self_size());
entry->set_leaf();
}
while (true) {
bool onlyLeaves = true;
for (int i = 0; i < entries_.length(); ++i) {
HeapEntry *entry = entries_[i], *dominator = entry->dominator();
if (!entry->is_processed() && dominator != entry) {
dominator->set_non_leaf();
onlyLeaves = false;
}
}
if (onlyLeaves) break;
for (int i = 0; i < entries_.length(); ++i) {
HeapEntry *entry = entries_[i], *dominator = entry->dominator();
if (entry->is_leaf() && dominator != entry) {
dominator->add_retained_size(entry->retained_size());
}
}
// Mark all current leaves as processed, reset non-leaves back to leaves.
for (int i = 0; i < entries_.length(); ++i) {
HeapEntry* entry = entries_[i];
if (entry->is_leaf())
entry->set_processed();
else if (entry->is_non_leaf())
entry->set_leaf();
}
}
}
HeapEntry* HeapSnapshot::GetNextEntryToInit() { HeapEntry* HeapSnapshot::GetNextEntryToInit() {
if (entries_.length() > 0) { if (entries_.length() > 0) {
HeapEntry* last_entry = entries_.last(); HeapEntry* last_entry = entries_.last();
@ -1716,15 +1581,22 @@ HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(HeapSnapshot::Type type,
const char* name, const char* name,
unsigned uid) { unsigned uid) {
is_tracking_objects_ = true; // Start watching for heap objects moves. is_tracking_objects_ = true; // Start watching for heap objects moves.
HeapSnapshot* snapshot = new HeapSnapshot(this, type, name, uid); return new HeapSnapshot(this, type, name, uid);
snapshots_.Add(snapshot); }
HashMap::Entry* entry =
snapshots_uids_.Lookup(reinterpret_cast<void*>(snapshot->uid()),
static_cast<uint32_t>(snapshot->uid()), void HeapSnapshotsCollection::SnapshotGenerationFinished(
true); HeapSnapshot* snapshot) {
ASSERT(entry->value == NULL); ids_.SnapshotGenerationFinished();
entry->value = snapshot; if (snapshot != NULL) {
return snapshot; snapshots_.Add(snapshot);
HashMap::Entry* entry =
snapshots_uids_.Lookup(reinterpret_cast<void*>(snapshot->uid()),
static_cast<uint32_t>(snapshot->uid()),
true);
ASSERT(entry->value == NULL);
entry->value = snapshot;
}
} }
@ -1832,8 +1704,10 @@ void HeapObjectsSet::Insert(Object* obj) {
} }
HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot) HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot,
v8::ActivityControl* control)
: snapshot_(snapshot), : snapshot_(snapshot),
control_(control),
collection_(snapshot->collection()), collection_(snapshot->collection()),
filler_(NULL) { filler_(NULL) {
} }
@ -1990,21 +1864,13 @@ class RootsReferencesExtractor : public ObjectVisitor {
}; };
void HeapSnapshotGenerator::GenerateSnapshot() { bool HeapSnapshotGenerator::GenerateSnapshot() {
AssertNoAllocation no_alloc; AssertNoAllocation no_alloc;
SetProgressTotal(4); // 2 passes + dominators + sizes.
// Pass 1. Iterate heap contents to count entries and references. // Pass 1. Iterate heap contents to count entries and references.
SnapshotCounter counter(&entries_); if (!CountEntriesAndReferences()) return false;
filler_ = &counter;
filler_->AddEntry(HeapSnapshot::kInternalRootObject);
filler_->AddEntry(HeapSnapshot::kGcRootsObject);
HeapIterator iterator(HeapIterator::kPreciseFiltering);
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
ExtractReferences(obj);
}
SetRootGcRootsReference();
RootsReferencesExtractor extractor(this);
Heap::IterateRoots(&extractor, VISIT_ONLY_STRONG);
// Allocate and fill entries in the snapshot, allocate references. // Allocate and fill entries in the snapshot, allocate references.
snapshot_->AllocateEntries(entries_.entries_count(), snapshot_->AllocateEntries(entries_.entries_count(),
@ -2014,16 +1880,14 @@ void HeapSnapshotGenerator::GenerateSnapshot() {
entries_.UpdateEntries(&allocator); entries_.UpdateEntries(&allocator);
// Pass 2. Fill references. // Pass 2. Fill references.
SnapshotFiller filler(snapshot_, &entries_); if (!FillReferences()) return false;
filler_ = &filler;
iterator.reset(); if (!SetEntriesDominators()) return false;
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { if (!ApproximateRetainedSizes()) return false;
ExtractReferences(obj);
}
SetRootGcRootsReference();
Heap::IterateRoots(&extractor, VISIT_ONLY_STRONG);
snapshot_->ApproximateRetainedSizes(); progress_counter_ = progress_total_;
if (!ReportProgress(true)) return false;
return true;
} }
@ -2351,6 +2215,183 @@ void HeapSnapshotGenerator::SetGcRootsReference(Object* child_obj) {
} }
void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
if (control_ == NULL) return;
HeapIterator iterator(HeapIterator::kPreciseFiltering);
int objects_count = 0;
for (HeapObject* obj = iterator.next();
obj != NULL;
obj = iterator.next(), ++objects_count) {}
progress_total_ = objects_count * iterations_count;
progress_counter_ = 0;
}
bool HeapSnapshotGenerator::CountEntriesAndReferences() {
SnapshotCounter counter(&entries_);
filler_ = &counter;
filler_->AddEntry(HeapSnapshot::kInternalRootObject);
filler_->AddEntry(HeapSnapshot::kGcRootsObject);
return IterateAndExtractReferences();
}
bool HeapSnapshotGenerator::FillReferences() {
SnapshotFiller filler(snapshot_, &entries_);
filler_ = &filler;
return IterateAndExtractReferences();
}
void HeapSnapshotGenerator::FillReversePostorderIndexes(
Vector<HeapEntry*>* entries) {
snapshot_->ClearPaint();
int current_entry = 0;
List<HeapEntry*> nodes_to_visit;
nodes_to_visit.Add(snapshot_->root());
snapshot_->root()->paint_reachable();
while (!nodes_to_visit.is_empty()) {
HeapEntry* entry = nodes_to_visit.last();
Vector<HeapGraphEdge> children = entry->children();
bool has_new_edges = false;
for (int i = 0; i < children.length(); ++i) {
if (children[i].type() == HeapGraphEdge::kShortcut) continue;
HeapEntry* child = children[i].to();
if (!child->painted_reachable()) {
nodes_to_visit.Add(child);
child->paint_reachable();
has_new_edges = true;
}
}
if (!has_new_edges) {
entry->set_ordered_index(current_entry);
(*entries)[current_entry++] = entry;
nodes_to_visit.RemoveLast();
}
}
entries->Truncate(current_entry);
}
static int Intersect(int i1, int i2, const Vector<HeapEntry*>& dominators) {
int finger1 = i1, finger2 = i2;
while (finger1 != finger2) {
while (finger1 < finger2) finger1 = dominators[finger1]->ordered_index();
while (finger2 < finger1) finger2 = dominators[finger2]->ordered_index();
}
return finger1;
}
// The algorithm is based on the article:
// K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm"
// Softw. Pract. Exper. 4 (2001), pp. 1–10.
bool HeapSnapshotGenerator::BuildDominatorTree(
const Vector<HeapEntry*>& entries,
Vector<HeapEntry*>* dominators) {
if (entries.length() == 0) return true;
const int entries_length = entries.length(), root_index = entries_length - 1;
for (int i = 0; i < root_index; ++i) (*dominators)[i] = NULL;
(*dominators)[root_index] = entries[root_index];
int changed = 1;
const int base_progress_counter = progress_counter_;
while (changed != 0) {
changed = 0;
for (int i = root_index - 1; i >= 0; --i) {
HeapEntry* new_idom = NULL;
Vector<HeapGraphEdge*> rets = entries[i]->retainers();
int j = 0;
for (; j < rets.length(); ++j) {
if (rets[j]->type() == HeapGraphEdge::kShortcut) continue;
HeapEntry* ret = rets[j]->From();
if (dominators->at(ret->ordered_index()) != NULL) {
new_idom = ret;
break;
}
}
for (++j; j < rets.length(); ++j) {
if (rets[j]->type() == HeapGraphEdge::kShortcut) continue;
HeapEntry* ret = rets[j]->From();
if (dominators->at(ret->ordered_index()) != NULL) {
new_idom = entries[Intersect(ret->ordered_index(),
new_idom->ordered_index(),
*dominators)];
}
}
if (new_idom != NULL && dominators->at(i) != new_idom) {
(*dominators)[i] = new_idom;
++changed;
}
}
int remaining = entries_length - changed;
if (remaining < 0) remaining = 0;
progress_counter_ = base_progress_counter + remaining;
if (!ReportProgress(true)) return false;
}
return true;
}
bool HeapSnapshotGenerator::SetEntriesDominators() {
// This array is used for maintaining reverse postorder of nodes.
ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length());
FillReversePostorderIndexes(&ordered_entries);
ScopedVector<HeapEntry*> dominators(ordered_entries.length());
if (!BuildDominatorTree(ordered_entries, &dominators)) return false;
for (int i = 0; i < ordered_entries.length(); ++i) {
ASSERT(dominators[i] != NULL);
ordered_entries[i]->set_dominator(dominators[i]);
}
// For nodes unreachable from root, set dominator to itself.
snapshot_->SetDominatorsToSelf();
return true;
}
bool HeapSnapshotGenerator::ApproximateRetainedSizes() {
// As for the dominators tree we only know parent nodes, not
// children, to sum up total sizes we "bubble" node's self size
// adding it to all of its parents.
for (int i = 0; i < snapshot_->entries()->length(); ++i) {
HeapEntry* entry = snapshot_->entries()->at(i);
entry->set_retained_size(entry->self_size());
}
for (int i = 0;
i < snapshot_->entries()->length();
++i, IncProgressCounter()) {
HeapEntry* entry = snapshot_->entries()->at(i);
int entry_size = entry->self_size();
for (HeapEntry* dominator = entry->dominator();
dominator != entry;
entry = dominator, dominator = entry->dominator()) {
dominator->add_retained_size(entry_size);
}
if (!ReportProgress()) return false;
}
return true;
}
bool HeapSnapshotGenerator::IterateAndExtractReferences() {
HeapIterator iterator(HeapIterator::kPreciseFiltering);
bool interrupted = false;
// Heap iteration with precise filtering must be finished in any case.
for (HeapObject* obj = iterator.next();
obj != NULL;
obj = iterator.next(), IncProgressCounter()) {
if (!interrupted) {
ExtractReferences(obj);
if (!ReportProgress()) interrupted = true;
}
}
if (interrupted) return false;
SetRootGcRootsReference();
RootsReferencesExtractor extractor(this);
Heap::IterateRoots(&extractor, VISIT_ONLY_STRONG);
return ReportProgress();
}
void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) { void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) {
raw_additions_root_ = raw_additions_root_ =
NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0)); NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0));

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

@ -526,7 +526,7 @@ class HeapEntry BASE_EMBEDDED {
HeapSnapshot* snapshot() { return snapshot_; } HeapSnapshot* snapshot() { return snapshot_; }
Type type() { return static_cast<Type>(type_); } Type type() { return static_cast<Type>(type_); }
const char* name() { return name_; } const char* name() { return name_; }
uint64_t id(); inline uint64_t id();
int self_size() { return self_size_; } int self_size() { return self_size_; }
int retained_size() { return retained_size_; } int retained_size() { return retained_size_; }
void add_retained_size(int size) { retained_size_ += size; } void add_retained_size(int size) { retained_size_ += size; }
@ -558,13 +558,6 @@ class HeapEntry BASE_EMBEDDED {
void ApplyAndPaintAllReachable(Visitor* visitor); void ApplyAndPaintAllReachable(Visitor* visitor);
void PaintAllReachable(); void PaintAllReachable();
bool is_leaf() { return painted_ == kLeaf; }
void set_leaf() { painted_ = kLeaf; }
bool is_non_leaf() { return painted_ == kNonLeaf; }
void set_non_leaf() { painted_ = kNonLeaf; }
bool is_processed() { return painted_ == kProcessed; }
void set_processed() { painted_ = kProcessed; }
void SetIndexedReference(HeapGraphEdge::Type type, void SetIndexedReference(HeapGraphEdge::Type type,
int child_index, int child_index,
int index, int index,
@ -625,10 +618,6 @@ class HeapEntry BASE_EMBEDDED {
static const unsigned kUnpainted = 0; static const unsigned kUnpainted = 0;
static const unsigned kPainted = 1; static const unsigned kPainted = 1;
static const unsigned kPaintedReachableFromOthers = 2; static const unsigned kPaintedReachableFromOthers = 2;
// Paints used for approximate retained sizes calculation.
static const unsigned kLeaf = 0;
static const unsigned kNonLeaf = 1;
static const unsigned kProcessed = 2;
static const int kExactRetainedSizeTag = 1; static const int kExactRetainedSizeTag = 1;
@ -682,6 +671,7 @@ class HeapSnapshot {
unsigned uid() { return uid_; } unsigned uid() { return uid_; }
HeapEntry* root() { return root_entry_; } HeapEntry* root() { return root_entry_; }
HeapEntry* gc_roots() { return gc_roots_entry_; } HeapEntry* gc_roots() { return gc_roots_entry_; }
List<HeapEntry*>* entries() { return &entries_; }
void AllocateEntries( void AllocateEntries(
int entries_count, int children_count, int retainers_count); int entries_count, int children_count, int retainers_count);
@ -693,7 +683,6 @@ class HeapSnapshot {
int size, int size,
int children_count, int children_count,
int retainers_count); int retainers_count);
void ApproximateRetainedSizes();
void ClearPaint(); void ClearPaint();
HeapSnapshotsDiff* CompareWith(HeapSnapshot* snapshot); HeapSnapshotsDiff* CompareWith(HeapSnapshot* snapshot);
HeapEntry* GetEntryById(uint64_t id); HeapEntry* GetEntryById(uint64_t id);
@ -716,10 +705,6 @@ class HeapSnapshot {
int children_count, int children_count,
int retainers_count); int retainers_count);
HeapEntry* GetNextEntryToInit(); HeapEntry* GetNextEntryToInit();
void BuildDominatorTree(const Vector<HeapEntry*>& entries,
Vector<HeapEntry*>* dominators);
void FillReversePostorderIndexes(Vector<HeapEntry*>* entries);
void SetEntriesDominators();
HeapSnapshotsCollection* collection_; HeapSnapshotsCollection* collection_;
Type type_; Type type_;
@ -845,7 +830,7 @@ class HeapSnapshotsCollection {
HeapSnapshot* NewSnapshot( HeapSnapshot* NewSnapshot(
HeapSnapshot::Type type, const char* name, unsigned uid); HeapSnapshot::Type type, const char* name, unsigned uid);
void SnapshotGenerationFinished() { ids_.SnapshotGenerationFinished(); } void SnapshotGenerationFinished(HeapSnapshot* snapshot);
List<HeapSnapshot*>* snapshots() { return &snapshots_; } List<HeapSnapshot*>* snapshots() { return &snapshots_; }
HeapSnapshot* GetSnapshot(unsigned uid); HeapSnapshot* GetSnapshot(unsigned uid);
@ -968,16 +953,27 @@ class HeapSnapshotGenerator {
HeapEntry* child_entry) = 0; HeapEntry* child_entry) = 0;
}; };
explicit HeapSnapshotGenerator(HeapSnapshot* snapshot); HeapSnapshotGenerator(HeapSnapshot* snapshot,
void GenerateSnapshot(); v8::ActivityControl* control);
bool GenerateSnapshot();
private: private:
bool ApproximateRetainedSizes();
bool BuildDominatorTree(const Vector<HeapEntry*>& entries,
Vector<HeapEntry*>* dominators);
bool CountEntriesAndReferences();
HeapEntry* GetEntry(Object* obj); HeapEntry* GetEntry(Object* obj);
void IncProgressCounter() { ++progress_counter_; }
void ExtractReferences(HeapObject* obj); void ExtractReferences(HeapObject* obj);
void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry); void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry); void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry); void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry); void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry);
bool FillReferences();
void FillReversePostorderIndexes(Vector<HeapEntry*>* entries);
bool IterateAndExtractReferences();
inline bool ReportProgress(bool force = false);
bool SetEntriesDominators();
void SetClosureReference(HeapObject* parent_obj, void SetClosureReference(HeapObject* parent_obj,
HeapEntry* parent, HeapEntry* parent,
String* reference_name, String* reference_name,
@ -1009,8 +1005,10 @@ class HeapSnapshotGenerator {
void SetRootShortcutReference(Object* child); void SetRootShortcutReference(Object* child);
void SetRootGcRootsReference(); void SetRootGcRootsReference();
void SetGcRootsReference(Object* child); void SetGcRootsReference(Object* child);
void SetProgressTotal(int iterations_count);
HeapSnapshot* snapshot_; HeapSnapshot* snapshot_;
v8::ActivityControl* control_;
HeapSnapshotsCollection* collection_; HeapSnapshotsCollection* collection_;
// Mapping from HeapObject* pointers to HeapEntry* pointers. // Mapping from HeapObject* pointers to HeapEntry* pointers.
HeapEntriesMap entries_; HeapEntriesMap entries_;
@ -1018,6 +1016,9 @@ class HeapSnapshotGenerator {
// Used during references extraction to mark heap objects that // Used during references extraction to mark heap objects that
// are references via non-hidden properties. // are references via non-hidden properties.
HeapObjectsSet known_references_; HeapObjectsSet known_references_;
// Used during snapshot generation.
int progress_counter_;
int progress_total_;
friend class IndexedReferencesExtractor; friend class IndexedReferencesExtractor;
friend class RootsReferencesExtractor; friend class RootsReferencesExtractor;

66
deps/v8/src/regexp.js

@ -120,22 +120,28 @@ function DoRegExpExec(regexp, string, index) {
function BuildResultFromMatchInfo(lastMatchInfo, s) { function BuildResultFromMatchInfo(lastMatchInfo, s) {
var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1; var numResults = NUMBER_OF_CAPTURES(lastMatchInfo) >> 1;
var result = %_RegExpConstructResult(numResults, lastMatchInfo[CAPTURE0], s); var start = lastMatchInfo[CAPTURE0];
if (numResults === 1) { var end = lastMatchInfo[CAPTURE1];
var matchStart = lastMatchInfo[CAPTURE(0)]; var result = %_RegExpConstructResult(numResults, start, s);
var matchEnd = lastMatchInfo[CAPTURE(1)]; if (start + 1 == end) {
result[0] = SubString(s, matchStart, matchEnd); result[0] = %_StringCharAt(s, start);
} else { } else {
for (var i = 0; i < numResults; i++) { result[0] = %_SubString(s, start, end);
var matchStart = lastMatchInfo[CAPTURE(i << 1)]; }
var matchEnd = lastMatchInfo[CAPTURE((i << 1) + 1)]; var j = REGEXP_FIRST_CAPTURE + 2;
if (matchStart != -1 && matchEnd != -1) { for (var i = 1; i < numResults; i++) {
result[i] = SubString(s, matchStart, matchEnd); start = lastMatchInfo[j++];
end = lastMatchInfo[j++];
if (end != -1) {
if (start + 1 == end) {
result[i] = %_StringCharAt(s, start);
} else { } else {
// Make sure the element is present. Avoid reading the undefined result[i] = %_SubString(s, start, end);
// property from the global object since this may change.
result[i] = void 0;
} }
} else {
// Make sure the element is present. Avoid reading the undefined
// property from the global object since this may change.
result[i] = void 0;
} }
} }
return result; return result;
@ -166,12 +172,7 @@ function RegExpExec(string) {
} }
string = regExpInput; string = regExpInput;
} }
var s; string = TO_STRING_INLINE(string);
if (IS_STRING(string)) {
s = string;
} else {
s = ToString(string);
}
var lastIndex = this.lastIndex; var lastIndex = this.lastIndex;
// Conversion is required by the ES5 specification (RegExp.prototype.exec // Conversion is required by the ES5 specification (RegExp.prototype.exec
@ -180,7 +181,7 @@ function RegExpExec(string) {
var global = this.global; var global = this.global;
if (global) { if (global) {
if (i < 0 || i > s.length) { if (i < 0 || i > string.length) {
this.lastIndex = 0; this.lastIndex = 0;
return null; return null;
} }
@ -188,9 +189,9 @@ function RegExpExec(string) {
i = 0; i = 0;
} }
%_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]);
// matchIndices is either null or the lastMatchInfo array. // matchIndices is either null or the lastMatchInfo array.
var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo); var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo);
if (matchIndices === null) { if (matchIndices === null) {
if (global) this.lastIndex = 0; if (global) this.lastIndex = 0;
@ -202,7 +203,7 @@ function RegExpExec(string) {
if (global) { if (global) {
this.lastIndex = lastMatchInfo[CAPTURE1]; this.lastIndex = lastMatchInfo[CAPTURE1];
} }
return BuildResultFromMatchInfo(matchIndices, s); return BuildResultFromMatchInfo(matchIndices, string);
} }
@ -227,12 +228,7 @@ function RegExpTest(string) {
string = regExpInput; string = regExpInput;
} }
var s; string = TO_STRING_INLINE(string);
if (IS_STRING(string)) {
s = string;
} else {
s = ToString(string);
}
var lastIndex = this.lastIndex; var lastIndex = this.lastIndex;
@ -241,13 +237,13 @@ function RegExpTest(string) {
var i = TO_INTEGER(lastIndex); var i = TO_INTEGER(lastIndex);
if (this.global) { if (this.global) {
if (i < 0 || i > s.length) { if (i < 0 || i > string.length) {
this.lastIndex = 0; this.lastIndex = 0;
return false; return false;
} }
%_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]);
// matchIndices is either null or the lastMatchInfo array. // matchIndices is either null or the lastMatchInfo array.
var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo); var matchIndices = %_RegExpExec(this, string, i, lastMatchInfo);
if (matchIndices === null) { if (matchIndices === null) {
this.lastIndex = 0; this.lastIndex = 0;
return false; return false;
@ -269,11 +265,11 @@ function RegExpTest(string) {
(this.ignoreCase ? 'i' : '') (this.ignoreCase ? 'i' : '')
+ (this.multiline ? 'm' : '')); + (this.multiline ? 'm' : ''));
} }
if (!regexp_val.test(s)) return false; if (!regexp_val.test(string)) return false;
} }
%_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]);
// matchIndices is either null or the lastMatchInfo array. // matchIndices is either null or the lastMatchInfo array.
var matchIndices = %_RegExpExec(this, s, 0, lastMatchInfo); var matchIndices = %_RegExpExec(this, string, 0, lastMatchInfo);
if (matchIndices === null) return false; if (matchIndices === null) return false;
lastMatchInfoOverride = null; lastMatchInfoOverride = null;
return true; return true;

101
deps/v8/src/runtime-profiler.cc

@ -68,12 +68,18 @@ class PendingListNode : public Malloced {
}; };
enum SamplerState {
IN_NON_JS_STATE = 0,
IN_JS_STATE = 1
};
// Optimization sampler constants. // Optimization sampler constants.
static const int kSamplerFrameCount = 2; static const int kSamplerFrameCount = 2;
static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 }; static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 };
static const int kSamplerWindowSize = 16; static const int kSamplerWindowSize = 16;
static const int kSamplerTicksDelta = 32; static const int kSamplerTicksBetweenThresholdAdjustment = 32;
static const int kSamplerThresholdInit = 3; static const int kSamplerThresholdInit = 3;
static const int kSamplerThresholdMin = 1; static const int kSamplerThresholdMin = 1;
@ -88,6 +94,11 @@ static const int kSizeLimit = 1500;
static int sampler_threshold = kSamplerThresholdInit; static int sampler_threshold = kSamplerThresholdInit;
static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
static int sampler_ticks_until_threshold_adjustment =
kSamplerTicksBetweenThresholdAdjustment;
// The ratio of ticks spent in JS code in percent.
static Atomic32 js_ratio;
// The JSFunctions in the sampler window are not GC safe. Old-space // The JSFunctions in the sampler window are not GC safe. Old-space
// pointers are not cleared during mark-sweep collection and therefore // pointers are not cleared during mark-sweep collection and therefore
@ -261,40 +272,71 @@ void RuntimeProfiler::OptimizeNow() {
// have a sample of the function, we mark it for optimizations // have a sample of the function, we mark it for optimizations
// (eagerly or lazily). // (eagerly or lazily).
JSFunction* samples[kSamplerFrameCount]; JSFunction* samples[kSamplerFrameCount];
int count = 0; int sample_count = 0;
int frame_count = 0;
for (JavaScriptFrameIterator it; for (JavaScriptFrameIterator it;
count < kSamplerFrameCount && !it.done(); frame_count++ < kSamplerFrameCount && !it.done();
it.Advance()) { it.Advance()) {
JavaScriptFrame* frame = it.frame(); JavaScriptFrame* frame = it.frame();
JSFunction* function = JSFunction::cast(frame->function()); JSFunction* function = JSFunction::cast(frame->function());
int function_size = function->shared()->SourceSize();
int threshold_size_factor; // Adjust threshold each time we have processed
if (function_size > kSizeLimit) { // a certain number of ticks.
threshold_size_factor = sampler_threshold_size_factor; if (sampler_ticks_until_threshold_adjustment > 0) {
} else { sampler_ticks_until_threshold_adjustment--;
threshold_size_factor = 1; if (sampler_ticks_until_threshold_adjustment <= 0) {
// If the threshold is not already at the minimum
// modify and reset the ticks until next adjustment.
if (sampler_threshold > kSamplerThresholdMin) {
sampler_threshold -= kSamplerThresholdDelta;
sampler_ticks_until_threshold_adjustment =
kSamplerTicksBetweenThresholdAdjustment;
}
}
} }
int threshold = sampler_threshold * threshold_size_factor;
samples[count++] = function;
if (function->IsMarkedForLazyRecompilation()) { if (function->IsMarkedForLazyRecompilation()) {
Code* unoptimized = function->shared()->code(); Code* unoptimized = function->shared()->code();
int nesting = unoptimized->allow_osr_at_loop_nesting_level(); int nesting = unoptimized->allow_osr_at_loop_nesting_level();
if (nesting == 0) AttemptOnStackReplacement(function); if (nesting == 0) AttemptOnStackReplacement(function);
int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker); int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker);
unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting); unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting);
} else if (LookupSample(function) >= threshold) { }
if (IsOptimizable(function)) {
Optimize(function, false, 0); // Do not record non-optimizable functions.
CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function)); if (!IsOptimizable(function)) continue;
} samples[sample_count++] = function;
int function_size = function->shared()->SourceSize();
int threshold_size_factor = (function_size > kSizeLimit)
? sampler_threshold_size_factor
: 1;
int threshold = sampler_threshold * threshold_size_factor;
int current_js_ratio = NoBarrier_Load(&js_ratio);
// Adjust threshold depending on the ratio of time spent
// in JS code.
if (current_js_ratio < 20) {
// If we spend less than 20% of the time in JS code,
// do not optimize.
continue;
} else if (current_js_ratio < 75) {
// Below 75% of time spent in JS code, only optimize very
// frequently used functions.
threshold *= 3;
}
if (LookupSample(function) >= threshold) {
Optimize(function, false, 0);
CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function));
} }
} }
// Add the collected functions as samples. It's important not to do // Add the collected functions as samples. It's important not to do
// this as part of collecting them because this will interfere with // this as part of collecting them because this will interfere with
// the sample lookup in case of recursive functions. // the sample lookup in case of recursive functions.
for (int i = 0; i < count; i++) { for (int i = 0; i < sample_count; i++) {
AddSample(samples[i], kSamplerFrameWeight[i]); AddSample(samples[i], kSamplerFrameWeight[i]);
} }
} }
@ -308,7 +350,30 @@ void RuntimeProfiler::OptimizeSoon(JSFunction* function) {
} }
static void UpdateStateRatio(SamplerState current_state) {
static const int kStateWindowSize = 128;
static SamplerState state_window[kStateWindowSize];
static int state_window_position = 0;
static int state_counts[2] = { kStateWindowSize, 0 };
SamplerState old_state = state_window[state_window_position];
state_counts[old_state]--;
state_window[state_window_position] = current_state;
state_counts[current_state]++;
ASSERT(IsPowerOf2(kStateWindowSize));
state_window_position = (state_window_position + 1) &
(kStateWindowSize - 1);
NoBarrier_Store(&js_ratio, state_counts[IN_JS_STATE] * 100 /
kStateWindowSize);
}
void RuntimeProfiler::NotifyTick() { void RuntimeProfiler::NotifyTick() {
// Record state sample.
SamplerState state = Top::IsInJSState()
? IN_JS_STATE
: IN_NON_JS_STATE;
UpdateStateRatio(state);
StackGuard::RequestRuntimeProfilerTick(); StackGuard::RequestRuntimeProfilerTick();
} }
@ -341,6 +406,8 @@ void RuntimeProfiler::Setup() {
void RuntimeProfiler::Reset() { void RuntimeProfiler::Reset() {
sampler_threshold = kSamplerThresholdInit; sampler_threshold = kSamplerThresholdInit;
sampler_ticks_until_threshold_adjustment =
kSamplerTicksBetweenThresholdAdjustment;
sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit; sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
} }

76
deps/v8/src/runtime.cc

@ -4689,6 +4689,13 @@ static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
if (!new_alloc->ToObject(&new_object)) { if (!new_alloc->ToObject(&new_object)) {
return new_alloc; return new_alloc;
} }
if (!Heap::new_space()->Contains(new_object)) {
// Even if our string is small enough to fit in new space we still have to
// handle it being allocated in old space as may happen in the third
// attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
// CEntryStub::GenerateCore.
return SlowQuoteJsonString<Char, StringType>(characters);
}
StringType* new_string = StringType::cast(new_object); StringType* new_string = StringType::cast(new_object);
ASSERT(Heap::new_space()->Contains(new_string)); ASSERT(Heap::new_space()->Contains(new_string));
@ -4723,9 +4730,9 @@ static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
} }
*(write_cursor++) = '"'; *(write_cursor++) = '"';
int final_length = int final_length = static_cast<int>(
write_cursor - reinterpret_cast<Char*>( write_cursor - reinterpret_cast<Char*>(
new_string->address() + SeqAsciiString::kHeaderSize); new_string->address() + SeqAsciiString::kHeaderSize));
Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string, Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
final_length); final_length);
return new_string; return new_string;
@ -6022,37 +6029,6 @@ static MaybeObject* Runtime_Math_log(Arguments args) {
} }
// Helper function to compute x^y, where y is known to be an
// integer. Uses binary decomposition to limit the number of
// multiplications; see the discussion in "Hacker's Delight" by Henry
// S. Warren, Jr., figure 11-6, page 213.
static double powi(double x, int y) {
ASSERT(y != kMinInt);
unsigned n = (y < 0) ? -y : y;
double m = x;
double p = 1;
while (true) {
if ((n & 1) != 0) p *= m;
n >>= 1;
if (n == 0) {
if (y < 0) {
// Unfortunately, we have to be careful when p has reached
// infinity in the computation, because sometimes the higher
// internal precision in the pow() implementation would have
// given us a finite p. This happens very rarely.
double result = 1.0 / p;
return (result == 0 && isinf(p))
? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
: result;
} else {
return p;
}
}
m *= m;
}
}
static MaybeObject* Runtime_Math_pow(Arguments args) { static MaybeObject* Runtime_Math_pow(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
@ -6064,31 +6040,11 @@ static MaybeObject* Runtime_Math_pow(Arguments args) {
// custom powi() function than the generic pow(). // custom powi() function than the generic pow().
if (args[1]->IsSmi()) { if (args[1]->IsSmi()) {
int y = Smi::cast(args[1])->value(); int y = Smi::cast(args[1])->value();
return Heap::NumberFromDouble(powi(x, y)); return Heap::NumberFromDouble(power_double_int(x, y));
} }
CONVERT_DOUBLE_CHECKED(y, args[1]); CONVERT_DOUBLE_CHECKED(y, args[1]);
return Heap::AllocateHeapNumber(power_double_double(x, y));
if (!isinf(x)) {
if (y == 0.5) {
// It's not uncommon to use Math.pow(x, 0.5) to compute the
// square root of a number. To speed up such computations, we
// explictly check for this case and use the sqrt() function
// which is faster than pow().
return Heap::AllocateHeapNumber(sqrt(x));
} else if (y == -0.5) {
// Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
return Heap::AllocateHeapNumber(1.0 / sqrt(x));
}
}
if (y == 0) {
return Smi::FromInt(1);
} else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
return Heap::nan_value();
} else {
return Heap::AllocateHeapNumber(pow(x, y));
}
} }
// Fast version of Math.pow if we know that y is not an integer and // Fast version of Math.pow if we know that y is not an integer and
@ -6099,11 +6055,11 @@ static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
CONVERT_DOUBLE_CHECKED(y, args[1]); CONVERT_DOUBLE_CHECKED(y, args[1]);
if (y == 0) { if (y == 0) {
return Smi::FromInt(1); return Smi::FromInt(1);
} else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
return Heap::nan_value(); return Heap::nan_value();
} else { } else {
return Heap::AllocateHeapNumber(pow(x, y)); return Heap::AllocateHeapNumber(pow(x, y));
} }
} }
@ -7716,13 +7672,13 @@ static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
} }
// Push an array unto an array of arrays if it is not already in the // Push an object unto an array of objects if it is not already in the
// array. Returns true if the element was pushed on the stack and // array. Returns true if the element was pushed on the stack and
// false otherwise. // false otherwise.
static MaybeObject* Runtime_PushIfAbsent(Arguments args) { static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
CONVERT_CHECKED(JSArray, array, args[0]); CONVERT_CHECKED(JSArray, array, args[0]);
CONVERT_CHECKED(JSArray, element, args[1]); CONVERT_CHECKED(JSObject, element, args[1]);
RUNTIME_ASSERT(array->HasFastElements()); RUNTIME_ASSERT(array->HasFastElements());
int length = Smi::cast(array->length())->value(); int length = Smi::cast(array->length())->value();
FixedArray* elements = FixedArray::cast(array->elements()); FixedArray* elements = FixedArray::cast(array->elements());

32
deps/v8/src/scanner-base.cc

@ -34,12 +34,6 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// ----------------------------------------------------------------------------
// UTF16Buffer
UTF16Buffer::UTF16Buffer()
: pos_(0), end_(kNoEndPosition) { }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// LiteralCollector // LiteralCollector
@ -92,7 +86,7 @@ bool ScannerConstants::IsIdentifier(unibrow::CharacterStream* buffer) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Scanner // Scanner
Scanner::Scanner() : source_(NULL) {} Scanner::Scanner() { }
uc32 Scanner::ScanHexEscape(uc32 c, int length) { uc32 Scanner::ScanHexEscape(uc32 c, int length) {
@ -142,8 +136,7 @@ uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// JavaScriptScanner // JavaScriptScanner
JavaScriptScanner::JavaScriptScanner() JavaScriptScanner::JavaScriptScanner() : Scanner() {}
: has_line_terminator_before_next_(false) {}
Token::Value JavaScriptScanner::Next() { Token::Value JavaScriptScanner::Next() {
@ -503,12 +496,21 @@ void JavaScriptScanner::Scan() {
void JavaScriptScanner::SeekForward(int pos) { void JavaScriptScanner::SeekForward(int pos) {
source_->SeekForward(pos - 1); // After this call, we will have the token at the given position as
Advance(); // the "next" token. The "current" token will be invalid.
// This function is only called to seek to the location if (pos == next_.location.beg_pos) return;
// of the end of a function (at the "}" token). It doesn't matter int current_pos = source_pos();
// whether there was a line terminator in the part we skip. ASSERT_EQ(next_.location.end_pos, current_pos);
has_line_terminator_before_next_ = false; // Positions inside the lookahead token aren't supported.
ASSERT(pos >= current_pos);
if (pos != current_pos) {
source_->SeekForward(pos - source_->pos());
Advance();
// This function is only called to seek to the location
// of the end of a function (at the "}" token). It doesn't matter
// whether there was a line terminator in the part we skip.
has_line_terminator_before_next_ = false;
}
Scan(); Scan();
} }

80
deps/v8/src/scanner-base.h

@ -52,31 +52,75 @@ inline int HexValue(uc32 c) {
return -1; return -1;
} }
// ----------------------------------------------------------------------------
// UTF16Buffer - scanner input source with pushback.
class UTF16Buffer { // ---------------------------------------------------------------------
// Buffered stream of characters, using an internal UC16 buffer.
class UC16CharacterStream {
public: public:
UTF16Buffer(); UC16CharacterStream() : pos_(0) { }
virtual ~UTF16Buffer() {} virtual ~UC16CharacterStream() { }
// Returns and advances past the next UC16 character in the input
// stream. If there are no more characters, it returns a negative
// value.
inline int32_t Advance() {
if (buffer_cursor_ < buffer_end_ || ReadBlock()) {
pos_++;
return *(buffer_cursor_++);
}
// Note: currently the following increment is necessary to avoid a
// parser problem! The scanner treats the final kEndOfInput as
// a character with a position, and does math relative to that
// position.
pos_++;
virtual void PushBack(uc32 ch) = 0; return kEndOfInput;
// Returns a value < 0 when the buffer end is reached. }
virtual uc32 Advance() = 0;
virtual void SeekForward(int pos) = 0;
int pos() const { return pos_; } // Return the current position in the character stream.
// Starts at zero.
inline unsigned pos() const { return pos_; }
// Skips forward past the next character_count UC16 characters
// in the input, or until the end of input if that comes sooner.
// Returns the number of characters actually skipped. If less
// than character_count,
inline unsigned SeekForward(unsigned character_count) {
unsigned buffered_chars =
static_cast<unsigned>(buffer_end_ - buffer_cursor_);
if (character_count <= buffered_chars) {
buffer_cursor_ += character_count;
pos_ += character_count;
return character_count;
}
return SlowSeekForward(character_count);
}
static const int kNoEndPosition = 1; // Pushes back the most recently read UC16 character, i.e.,
// the value returned by the most recent call to Advance.
// Must not be used right after calling SeekForward.
virtual void PushBack(uc16 character) = 0;
protected: protected:
// Initial value of end_ before the input stream is initialized. static const int32_t kEndOfInput = -1;
int pos_; // Current position in the buffer. // Ensures that the buffer_cursor_ points to the character at
int end_; // Position where scanning should stop (EOF). // position pos_ of the input, if possible. If the position
// is at or after the end of the input, return false. If there
// are more characters available, return true.
virtual bool ReadBlock() = 0;
virtual unsigned SlowSeekForward(unsigned character_count) = 0;
const uc16* buffer_cursor_;
const uc16* buffer_end_;
unsigned pos_;
}; };
// ---------------------------------------------------------------------
// Constants used by scanners.
class ScannerConstants : AllStatic { class ScannerConstants : AllStatic {
public: public:
typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder; typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder;
@ -277,7 +321,7 @@ class Scanner {
// Low-level scanning support. // Low-level scanning support.
void Advance() { c0_ = source_->Advance(); } void Advance() { c0_ = source_->Advance(); }
void PushBack(uc32 ch) { void PushBack(uc32 ch) {
source_->PushBack(ch); source_->PushBack(c0_);
c0_ = ch; c0_ = ch;
} }
@ -307,8 +351,8 @@ class Scanner {
TokenDesc current_; // desc for current token (as returned by Next()) TokenDesc current_; // desc for current token (as returned by Next())
TokenDesc next_; // desc for next token (one token look-ahead) TokenDesc next_; // desc for next token (one token look-ahead)
// Input stream. Must be initialized to an UTF16Buffer. // Input stream. Must be initialized to an UC16CharacterStream.
UTF16Buffer* source_; UC16CharacterStream* source_;
// Buffer to hold literal values (identifiers, strings, numbers) // Buffer to hold literal values (identifiers, strings, numbers)
// using '\x00'-terminated UTF-8 encoding. Handles allocation internally. // using '\x00'-terminated UTF-8 encoding. Handles allocation internally.

367
deps/v8/src/scanner.cc

@ -36,63 +36,265 @@ namespace v8 {
namespace internal { namespace internal {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// UTF16Buffer // BufferedUC16CharacterStreams
// CharacterStreamUTF16Buffer BufferedUC16CharacterStream::BufferedUC16CharacterStream()
CharacterStreamUTF16Buffer::CharacterStreamUTF16Buffer() : UC16CharacterStream(),
: pushback_buffer_(0), last_(0), stream_(NULL) { } pushback_limit_(NULL) {
// Initialize buffer as being empty. First read will fill the buffer.
buffer_cursor_ = buffer_;
buffer_end_ = buffer_;
}
BufferedUC16CharacterStream::~BufferedUC16CharacterStream() { }
void CharacterStreamUTF16Buffer::Initialize(Handle<String> data, void BufferedUC16CharacterStream::PushBack(uc16 character) {
unibrow::CharacterStream* input, if (pushback_limit_ == NULL && buffer_cursor_ > buffer_) {
int start_position, // buffer_ is writable, buffer_cursor_ is const pointer.
int end_position) { buffer_[--buffer_cursor_ - buffer_] = character;
stream_ = input; pos_--;
if (start_position > 0) { return;
SeekForward(start_position);
} }
end_ = end_position != kNoEndPosition ? end_position : kMaxInt; SlowPushBack(character);
} }
void CharacterStreamUTF16Buffer::PushBack(uc32 ch) { void BufferedUC16CharacterStream::SlowPushBack(uc16 character) {
pushback_buffer()->Add(last_); // In pushback mode, the end of the buffer contains pushback,
last_ = ch; // and the start of the buffer (from buffer start to pushback_limit_)
// contains valid data that comes just after the pushback.
// We NULL the pushback_limit_ if pushing all the way back to the
// start of the buffer.
if (pushback_limit_ == NULL) {
// Enter pushback mode.
pushback_limit_ = buffer_end_;
buffer_end_ = buffer_ + kBufferSize;
buffer_cursor_ = buffer_end_;
}
ASSERT(pushback_limit_ > buffer_);
ASSERT(pos_ > 0);
buffer_[--buffer_cursor_ - buffer_] = character;
if (buffer_cursor_ == buffer_) {
pushback_limit_ = NULL;
} else if (buffer_cursor_ < pushback_limit_) {
pushback_limit_ = buffer_cursor_;
}
pos_--; pos_--;
} }
uc32 CharacterStreamUTF16Buffer::Advance() { bool BufferedUC16CharacterStream::ReadBlock() {
ASSERT(end_ != kNoEndPosition); if (pushback_limit_ != NULL) {
ASSERT(end_ >= 0); buffer_cursor_ = buffer_;
// NOTE: It is of importance to Persian / Farsi resources that we do buffer_end_ = pushback_limit_;
// *not* strip format control characters in the scanner; see pushback_limit_ = NULL;
// ASSERT(buffer_cursor_ != buffer_end_);
// https://bugzilla.mozilla.org/show_bug.cgi?id=274152 return true;
//
// So, even though ECMA-262, section 7.1, page 11, dictates that we
// must remove Unicode format-control characters, we do not. This is
// in line with how IE and SpiderMonkey handles it.
if (!pushback_buffer()->is_empty()) {
pos_++;
return last_ = pushback_buffer()->RemoveLast();
} else if (stream_->has_more() && pos_ < end_) {
pos_++;
uc32 next = stream_->GetNext();
return last_ = next;
} else {
// Note: currently the following increment is necessary to avoid a
// test-parser problem!
pos_++;
return last_ = static_cast<uc32>(-1);
} }
unsigned length = FillBuffer(pos_, kBufferSize);
buffer_cursor_ = buffer_;
buffer_end_ = buffer_ + length;
return length > 0;
} }
void CharacterStreamUTF16Buffer::SeekForward(int pos) { unsigned BufferedUC16CharacterStream::SlowSeekForward(unsigned delta) {
pos_ = pos; // Leave pushback mode (i.e., ignore that there might be valid data
ASSERT(pushback_buffer()->is_empty()); // in the buffer before the pushback_limit_ point).
stream_->Seek(pos); pushback_limit_ = NULL;
return BufferSeekForward(delta);
}
// ----------------------------------------------------------------------------
// GenericStringUC16CharacterStream
GenericStringUC16CharacterStream::GenericStringUC16CharacterStream(
Handle<String> data,
unsigned start_position,
unsigned end_position)
: string_(data),
length_(end_position) {
ASSERT(end_position >= start_position);
buffer_cursor_ = buffer_;
buffer_end_ = buffer_;
pos_ = start_position;
}
GenericStringUC16CharacterStream::~GenericStringUC16CharacterStream() { }
unsigned GenericStringUC16CharacterStream::BufferSeekForward(unsigned delta) {
unsigned old_pos = pos_;
pos_ = Min(pos_ + delta, length_);
ReadBlock();
return pos_ - old_pos;
}
unsigned GenericStringUC16CharacterStream::FillBuffer(unsigned from_pos,
unsigned length) {
if (from_pos >= length_) return 0;
if (from_pos + length > length_) {
length = length_ - from_pos;
}
String::WriteToFlat<uc16>(*string_, buffer_, from_pos, from_pos + length);
return length;
}
// ----------------------------------------------------------------------------
// Utf8ToUC16CharacterStream
Utf8ToUC16CharacterStream::Utf8ToUC16CharacterStream(const byte* data,
unsigned length)
: BufferedUC16CharacterStream(),
raw_data_(data),
raw_data_length_(length),
raw_data_pos_(0),
raw_character_position_(0) {
ReadBlock();
}
Utf8ToUC16CharacterStream::~Utf8ToUC16CharacterStream() { }
unsigned Utf8ToUC16CharacterStream::BufferSeekForward(unsigned delta) {
unsigned old_pos = pos_;
unsigned target_pos = pos_ + delta;
SetRawPosition(target_pos);
pos_ = raw_character_position_;
ReadBlock();
return pos_ - old_pos;
}
unsigned Utf8ToUC16CharacterStream::FillBuffer(unsigned char_position,
unsigned length) {
static const unibrow::uchar kMaxUC16Character = 0xffff;
SetRawPosition(char_position);
if (raw_character_position_ != char_position) {
// char_position was not a valid position in the stream (hit the end
// while spooling to it).
return 0u;
}
unsigned i = 0;
while (i < length) {
if (raw_data_pos_ == raw_data_length_) break;
unibrow::uchar c = raw_data_[raw_data_pos_];
if (c <= unibrow::Utf8::kMaxOneByteChar) {
raw_data_pos_++;
} else {
c = unibrow::Utf8::CalculateValue(raw_data_ + raw_data_pos_,
raw_data_length_ - raw_data_pos_,
&raw_data_pos_);
// Don't allow characters outside of the BMP.
if (c > kMaxUC16Character) {
c = unibrow::Utf8::kBadChar;
}
}
buffer_[i++] = static_cast<uc16>(c);
}
raw_character_position_ = char_position + i;
return i;
}
static const byte kUtf8MultiByteMask = 0xC0;
static const byte kUtf8MultiByteCharStart = 0xC0;
static const byte kUtf8MultiByteCharFollower = 0x80;
#ifdef DEBUG
static bool IsUtf8MultiCharacterStart(byte first_byte) {
return (first_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharStart;
}
#endif
static bool IsUtf8MultiCharacterFollower(byte later_byte) {
return (later_byte & kUtf8MultiByteMask) == kUtf8MultiByteCharFollower;
}
// Move the cursor back to point at the preceding UTF-8 character start
// in the buffer.
static inline void Utf8CharacterBack(const byte* buffer, unsigned* cursor) {
byte character = buffer[--*cursor];
if (character > unibrow::Utf8::kMaxOneByteChar) {
ASSERT(IsUtf8MultiCharacterFollower(character));
// Last byte of a multi-byte character encoding. Step backwards until
// pointing to the first byte of the encoding, recognized by having the
// top two bits set.
while (IsUtf8MultiCharacterFollower(buffer[--*cursor])) { }
ASSERT(IsUtf8MultiCharacterStart(buffer[*cursor]));
}
}
// Move the cursor forward to point at the next following UTF-8 character start
// in the buffer.
static inline void Utf8CharacterForward(const byte* buffer, unsigned* cursor) {
byte character = buffer[(*cursor)++];
if (character > unibrow::Utf8::kMaxOneByteChar) {
// First character of a multi-byte character encoding.
// The number of most-significant one-bits determines the length of the
// encoding:
// 110..... - (0xCx, 0xDx) one additional byte (minimum).
// 1110.... - (0xEx) two additional bytes.
// 11110... - (0xFx) three additional bytes (maximum).
ASSERT(IsUtf8MultiCharacterStart(character));
// Additional bytes is:
// 1 if value in range 0xC0 .. 0xDF.
// 2 if value in range 0xE0 .. 0xEF.
// 3 if value in range 0xF0 .. 0xF7.
// Encode that in a single value.
unsigned additional_bytes =
((0x3211u) >> (((character - 0xC0) >> 2) & 0xC)) & 0x03;
*cursor += additional_bytes;
ASSERT(!IsUtf8MultiCharacterFollower(buffer[1 + additional_bytes]));
}
}
void Utf8ToUC16CharacterStream::SetRawPosition(unsigned target_position) {
if (raw_character_position_ > target_position) {
// Spool backwards in utf8 buffer.
do {
Utf8CharacterBack(raw_data_, &raw_data_pos_);
raw_character_position_--;
} while (raw_character_position_ > target_position);
return;
}
// Spool forwards in the utf8 buffer.
while (raw_character_position_ < target_position) {
if (raw_data_pos_ == raw_data_length_) return;
Utf8CharacterForward(raw_data_, &raw_data_pos_);
raw_character_position_++;
}
}
// ----------------------------------------------------------------------------
// ExternalTwoByteStringUC16CharacterStream
ExternalTwoByteStringUC16CharacterStream::
~ExternalTwoByteStringUC16CharacterStream() { }
ExternalTwoByteStringUC16CharacterStream
::ExternalTwoByteStringUC16CharacterStream(
Handle<ExternalTwoByteString> data,
int start_position,
int end_position)
: UC16CharacterStream(),
source_(data),
raw_data_(data->GetTwoByteData(start_position)) {
buffer_cursor_ = raw_data_,
buffer_end_ = raw_data_ + (end_position - start_position);
pos_ = start_position;
} }
@ -115,46 +317,19 @@ void Scanner::LiteralScope::Complete() {
complete_ = true; complete_ = true;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// V8JavaScriptScanner // V8JavaScriptScanner
void V8JavaScriptScanner::Initialize(Handle<String> source, V8JavaScriptScanner::V8JavaScriptScanner() : JavaScriptScanner() { }
int literal_flags) {
source_ = stream_initializer_.Init(source, NULL, 0, source->length());
// Need to capture identifiers in order to recognize "get" and "set"
// in object literals.
literal_flags_ = literal_flags | kLiteralIdentifier;
Init();
// Skip initial whitespace allowing HTML comment ends just like
// after a newline and scan first token.
has_line_terminator_before_next_ = true;
SkipWhiteSpace();
Scan();
}
void V8JavaScriptScanner::Initialize(Handle<String> source,
unibrow::CharacterStream* stream,
int literal_flags) {
source_ = stream_initializer_.Init(source, stream,
0, UTF16Buffer::kNoEndPosition);
literal_flags_ = literal_flags | kLiteralIdentifier;
Init();
// Skip initial whitespace allowing HTML comment ends just like
// after a newline and scan first token.
has_line_terminator_before_next_ = true;
SkipWhiteSpace();
Scan();
}
void V8JavaScriptScanner::Initialize(Handle<String> source, void V8JavaScriptScanner::Initialize(UC16CharacterStream* source,
int start_position,
int end_position,
int literal_flags) { int literal_flags) {
source_ = stream_initializer_.Init(source, NULL, source_ = source;
start_position, end_position);
literal_flags_ = literal_flags | kLiteralIdentifier; literal_flags_ = literal_flags | kLiteralIdentifier;
// Need to capture identifiers in order to recognize "get" and "set"
// in object literals.
Init(); Init();
// Skip initial whitespace allowing HTML comment ends just like // Skip initial whitespace allowing HTML comment ends just like
// after a newline and scan first token. // after a newline and scan first token.
@ -164,48 +339,14 @@ void V8JavaScriptScanner::Initialize(Handle<String> source,
} }
UTF16Buffer* StreamInitializer::Init(Handle<String> source,
unibrow::CharacterStream* stream,
int start_position,
int end_position) {
// Either initialize the scanner from a character stream or from a
// string.
ASSERT(source.is_null() || stream == NULL);
// Initialize the source buffer.
if (!source.is_null() && StringShape(*source).IsExternalTwoByte()) {
two_byte_string_buffer_.Initialize(
Handle<ExternalTwoByteString>::cast(source),
start_position,
end_position);
return &two_byte_string_buffer_;
} else if (!source.is_null() && StringShape(*source).IsExternalAscii()) {
ascii_string_buffer_.Initialize(
Handle<ExternalAsciiString>::cast(source),
start_position,
end_position);
return &ascii_string_buffer_;
} else {
if (!source.is_null()) {
safe_string_input_buffer_.Reset(source.location());
stream = &safe_string_input_buffer_;
}
char_stream_buffer_.Initialize(source,
stream,
start_position,
end_position);
return &char_stream_buffer_;
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// JsonScanner // JsonScanner
JsonScanner::JsonScanner() {} JsonScanner::JsonScanner() : Scanner() { }
void JsonScanner::Initialize(Handle<String> source) { void JsonScanner::Initialize(UC16CharacterStream* source) {
source_ = stream_initializer_.Init(source, NULL, 0, source->length()); source_ = source;
Init(); Init();
// Skip initial whitespace. // Skip initial whitespace.
SkipJsonWhiteSpace(); SkipJsonWhiteSpace();

201
deps/v8/src/scanner.h

@ -35,67 +35,97 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// UTF16 buffer to read characters from a character stream. // A buffered character stream based on a random access character
class CharacterStreamUTF16Buffer: public UTF16Buffer { // source (ReadBlock can be called with pos_ pointing to any position,
// even positions before the current).
class BufferedUC16CharacterStream: public UC16CharacterStream {
public: public:
CharacterStreamUTF16Buffer(); BufferedUC16CharacterStream();
virtual ~CharacterStreamUTF16Buffer() {} virtual ~BufferedUC16CharacterStream();
void Initialize(Handle<String> data,
unibrow::CharacterStream* stream, virtual void PushBack(uc16 character);
int start_position,
int end_position); protected:
virtual void PushBack(uc32 ch); static const unsigned kBufferSize = 512;
virtual uc32 Advance(); static const unsigned kPushBackStepSize = 16;
virtual void SeekForward(int pos);
virtual unsigned SlowSeekForward(unsigned delta);
private: virtual bool ReadBlock();
List<uc32> pushback_buffer_; virtual void SlowPushBack(uc16 character);
uc32 last_;
unibrow::CharacterStream* stream_; virtual unsigned BufferSeekForward(unsigned delta) = 0;
virtual unsigned FillBuffer(unsigned position, unsigned length) = 0;
List<uc32>* pushback_buffer() { return &pushback_buffer_; }
const uc16* pushback_limit_;
uc16 buffer_[kBufferSize];
}; };
// UTF16 buffer to read characters from an external string. // Generic string stream.
template <typename StringType, typename CharType> class GenericStringUC16CharacterStream: public BufferedUC16CharacterStream {
class ExternalStringUTF16Buffer: public UTF16Buffer {
public: public:
ExternalStringUTF16Buffer(); GenericStringUC16CharacterStream(Handle<String> data,
virtual ~ExternalStringUTF16Buffer() {} unsigned start_position,
void Initialize(Handle<StringType> data, unsigned end_position);
int start_position, virtual ~GenericStringUC16CharacterStream();
int end_position);
virtual void PushBack(uc32 ch); protected:
virtual uc32 Advance(); virtual unsigned BufferSeekForward(unsigned delta);
virtual void SeekForward(int pos); virtual unsigned FillBuffer(unsigned position, unsigned length);
private: Handle<String> string_;
const CharType* raw_data_; // Pointer to the actual array of characters. unsigned start_position_;
unsigned length_;
}; };
// Initializes a UTF16Buffer as input stream, using one of a number // UC16 stream based on a literal UTF-8 string.
// of strategies depending on the available character sources. class Utf8ToUC16CharacterStream: public BufferedUC16CharacterStream {
class StreamInitializer {
public: public:
UTF16Buffer* Init(Handle<String> source, Utf8ToUC16CharacterStream(const byte* data, unsigned length);
unibrow::CharacterStream* stream, virtual ~Utf8ToUC16CharacterStream();
int start_position,
int end_position); protected:
private: virtual unsigned BufferSeekForward(unsigned delta);
// Different UTF16 buffers used to pull characters from. Based on input one of virtual unsigned FillBuffer(unsigned char_position, unsigned length);
// these will be initialized as the actual data source. void SetRawPosition(unsigned char_position);
CharacterStreamUTF16Buffer char_stream_buffer_;
ExternalStringUTF16Buffer<ExternalTwoByteString, uint16_t> const byte* raw_data_;
two_byte_string_buffer_; unsigned raw_data_length_; // Measured in bytes, not characters.
ExternalStringUTF16Buffer<ExternalAsciiString, char> ascii_string_buffer_; unsigned raw_data_pos_;
// The character position of the character at raw_data[raw_data_pos_].
// Used to convert the source string into a character stream when a stream // Not necessarily the same as pos_.
// is not passed to the scanner. unsigned raw_character_position_;
SafeStringInputBuffer safe_string_input_buffer_; };
// UTF16 buffer to read characters from an external string.
class ExternalTwoByteStringUC16CharacterStream: public UC16CharacterStream {
public:
ExternalTwoByteStringUC16CharacterStream(Handle<ExternalTwoByteString> data,
int start_position,
int end_position);
virtual ~ExternalTwoByteStringUC16CharacterStream();
virtual void PushBack(uc16 character) {
ASSERT(buffer_cursor_ > raw_data_);
buffer_cursor_--;
pos_--;
}
protected:
virtual unsigned SlowSeekForward(unsigned delta) {
// Fast case always handles seeking.
return 0;
}
virtual bool ReadBlock() {
// Entire string is read at start.
return false;
}
Handle<ExternalTwoByteString> source_;
const uc16* raw_data_; // Pointer to the actual array of characters.
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// V8JavaScriptScanner // V8JavaScriptScanner
// JavaScript scanner getting its input from either a V8 String or a unicode // JavaScript scanner getting its input from either a V8 String or a unicode
@ -103,19 +133,9 @@ class StreamInitializer {
class V8JavaScriptScanner : public JavaScriptScanner { class V8JavaScriptScanner : public JavaScriptScanner {
public: public:
V8JavaScriptScanner() {} V8JavaScriptScanner();
void Initialize(UC16CharacterStream* source,
// Initialize the Scanner to scan source.
void Initialize(Handle<String> source, int literal_flags = kAllLiterals);
void Initialize(Handle<String> source,
unibrow::CharacterStream* stream,
int literal_flags = kAllLiterals);
void Initialize(Handle<String> source,
int start_position, int end_position,
int literal_flags = kAllLiterals); int literal_flags = kAllLiterals);
protected:
StreamInitializer stream_initializer_;
}; };
@ -123,8 +143,7 @@ class JsonScanner : public Scanner {
public: public:
JsonScanner(); JsonScanner();
// Initialize the Scanner to scan source. void Initialize(UC16CharacterStream* source);
void Initialize(Handle<String> source);
// Returns the next token. // Returns the next token.
Token::Value Next(); Token::Value Next();
@ -138,7 +157,7 @@ class JsonScanner : public Scanner {
// Recognizes all of the single-character tokens directly, or calls a function // Recognizes all of the single-character tokens directly, or calls a function
// to scan a number, string or identifier literal. // to scan a number, string or identifier literal.
// The only allowed whitespace characters between tokens are tab, // The only allowed whitespace characters between tokens are tab,
// carrige-return, newline and space. // carriage-return, newline and space.
void ScanJson(); void ScanJson();
// A JSON number (production JSONNumber) is a subset of the valid JavaScript // A JSON number (production JSONNumber) is a subset of the valid JavaScript
@ -159,60 +178,8 @@ class JsonScanner : public Scanner {
// are the only valid JSON identifiers (productions JSONBooleanLiteral, // are the only valid JSON identifiers (productions JSONBooleanLiteral,
// JSONNullLiteral). // JSONNullLiteral).
Token::Value ScanJsonIdentifier(const char* text, Token::Value token); Token::Value ScanJsonIdentifier(const char* text, Token::Value token);
StreamInitializer stream_initializer_;
}; };
// ExternalStringUTF16Buffer
template <typename StringType, typename CharType>
ExternalStringUTF16Buffer<StringType, CharType>::ExternalStringUTF16Buffer()
: raw_data_(NULL) { }
template <typename StringType, typename CharType>
void ExternalStringUTF16Buffer<StringType, CharType>::Initialize(
Handle<StringType> data,
int start_position,
int end_position) {
ASSERT(!data.is_null());
raw_data_ = data->resource()->data();
ASSERT(end_position <= data->length());
if (start_position > 0) {
SeekForward(start_position);
}
end_ =
end_position != kNoEndPosition ? end_position : data->length();
}
template <typename StringType, typename CharType>
uc32 ExternalStringUTF16Buffer<StringType, CharType>::Advance() {
if (pos_ < end_) {
return raw_data_[pos_++];
} else {
// note: currently the following increment is necessary to avoid a
// test-parser problem!
pos_++;
return static_cast<uc32>(-1);
}
}
template <typename StringType, typename CharType>
void ExternalStringUTF16Buffer<StringType, CharType>::PushBack(uc32 ch) {
pos_--;
ASSERT(pos_ >= Scanner::kCharacterLookaheadBufferSize);
ASSERT(raw_data_[pos_ - Scanner::kCharacterLookaheadBufferSize] == ch);
}
template <typename StringType, typename CharType>
void ExternalStringUTF16Buffer<StringType, CharType>::SeekForward(int pos) {
pos_ = pos;
}
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_SCANNER_H_ #endif // V8_SCANNER_H_

12
deps/v8/src/serialize.cc

@ -486,6 +486,18 @@ void ExternalReferenceTable::PopulateTable() {
UNCLASSIFIED, UNCLASSIFIED,
36, 36,
"LDoubleConstant::one_half"); "LDoubleConstant::one_half");
Add(ExternalReference::address_of_negative_infinity().address(),
UNCLASSIFIED,
37,
"LDoubleConstant::negative_infinity");
Add(ExternalReference::power_double_double_function().address(),
UNCLASSIFIED,
38,
"power_double_double_function");
Add(ExternalReference::power_double_int_function().address(),
UNCLASSIFIED,
39,
"power_double_int_function");
} }

2
deps/v8/src/spaces.cc

@ -917,7 +917,7 @@ AtomicWord* MemoryAllocator::AllocatedChunksFinder(
} }
more_fine_grained_table = new AtomicWord[words_needed]; more_fine_grained_table = new AtomicWord[words_needed];
for (int i = 0; i < words_needed; i++) { for (int i = 0; i < words_needed; i++) {
more_fine_grained_table[i] = NULL; more_fine_grained_table[i] = kUnusedChunkTableEntry;
} }
Release_Store(&table[index], Release_Store(&table[index],
reinterpret_cast<AtomicWord>(more_fine_grained_table)); reinterpret_cast<AtomicWord>(more_fine_grained_table));

93
deps/v8/src/string.js

@ -101,28 +101,28 @@ function StringConcat() {
// ECMA-262 section 15.5.4.7 // ECMA-262 section 15.5.4.7
function StringIndexOf(searchString /* position */) { // length == 1 function StringIndexOf(pattern /* position */) { // length == 1
var subject_str = TO_STRING_INLINE(this); var subject = TO_STRING_INLINE(this);
var pattern_str = TO_STRING_INLINE(searchString); var pattern = TO_STRING_INLINE(pattern);
var subject_str_len = subject_str.length; var subject_len = subject.length;
var pattern_str_len = pattern_str.length; var pattern_len = pattern.length;
var index = 0; var index = 0;
if (%_ArgumentsLength() > 1) { if (%_ArgumentsLength() > 1) {
var arg1 = %_Arguments(1); // position var arg1 = %_Arguments(1); // position
index = TO_INTEGER(arg1); index = TO_INTEGER(arg1);
} }
if (index < 0) index = 0; if (index < 0) index = 0;
if (index > subject_str_len) index = subject_str_len; if (index > subject_len) index = subject_len;
if (pattern_str_len + index > subject_str_len) return -1; if (pattern_len + index > subject_len) return -1;
return %StringIndexOf(subject_str, pattern_str, index); return %StringIndexOf(subject, pattern, index);
} }
// ECMA-262 section 15.5.4.8 // ECMA-262 section 15.5.4.8
function StringLastIndexOf(searchString /* position */) { // length == 1 function StringLastIndexOf(pat /* position */) { // length == 1
var sub = TO_STRING_INLINE(this); var sub = TO_STRING_INLINE(this);
var subLength = sub.length; var subLength = sub.length;
var pat = TO_STRING_INLINE(searchString); var pat = TO_STRING_INLINE(pat);
var patLength = pat.length; var patLength = pat.length;
var index = subLength - patLength; var index = subLength - patLength;
if (%_ArgumentsLength() > 1) { if (%_ArgumentsLength() > 1) {
@ -150,10 +150,8 @@ function StringLastIndexOf(searchString /* position */) { // length == 1
// do anything locale specific. // do anything locale specific.
function StringLocaleCompare(other) { function StringLocaleCompare(other) {
if (%_ArgumentsLength() === 0) return 0; if (%_ArgumentsLength() === 0) return 0;
return %StringLocaleCompare(TO_STRING_INLINE(this),
var this_str = TO_STRING_INLINE(this); TO_STRING_INLINE(other));
var other_str = TO_STRING_INLINE(other);
return %StringLocaleCompare(this_str, other_str);
} }
@ -177,9 +175,7 @@ function StringMatch(regexp) {
// otherwise we call the runtime system. // otherwise we call the runtime system.
function SubString(string, start, end) { function SubString(string, start, end) {
// Use the one character string cache. // Use the one character string cache.
if (start + 1 == end) { if (start + 1 == end) return %_StringCharAt(string, start);
return %_StringCharAt(string, start);
}
return %_SubString(string, start, end); return %_SubString(string, start, end);
} }
@ -208,7 +204,10 @@ function StringReplace(search, replace) {
replace); replace);
} }
} else { } else {
return StringReplaceRegExp(subject, search, replace); return %StringReplaceRegExpWithString(subject,
search,
TO_STRING_INLINE(replace),
lastMatchInfo);
} }
} }
@ -224,7 +223,11 @@ function StringReplace(search, replace) {
// Compute the string to replace with. // Compute the string to replace with.
if (IS_FUNCTION(replace)) { if (IS_FUNCTION(replace)) {
builder.add(replace.call(null, search, start, subject)); builder.add(%_CallFunction(%GetGlobalReceiver(),
search,
start,
subject,
replace));
} else { } else {
reusableMatchInfo[CAPTURE0] = start; reusableMatchInfo[CAPTURE0] = start;
reusableMatchInfo[CAPTURE1] = end; reusableMatchInfo[CAPTURE1] = end;
@ -239,15 +242,6 @@ function StringReplace(search, replace) {
} }
// Helper function for regular expressions in String.prototype.replace.
function StringReplaceRegExp(subject, regexp, replace) {
return %StringReplaceRegExpWithString(subject,
regexp,
TO_STRING_INLINE(replace),
lastMatchInfo);
}
// Expand the $-expressions in the string and return a new string with // Expand the $-expressions in the string and return a new string with
// the result. // the result.
function ExpandReplacement(string, subject, matchInfo, builder) { function ExpandReplacement(string, subject, matchInfo, builder) {
@ -408,9 +402,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
lastMatchInfoOverride = override; lastMatchInfoOverride = override;
var func_result = var func_result =
%_CallFunction(receiver, elem, match_start, subject, replace); %_CallFunction(receiver, elem, match_start, subject, replace);
if (!IS_STRING(func_result)) { func_result = TO_STRING_INLINE(func_result);
func_result = NonStringToString(func_result);
}
res[i] = func_result; res[i] = func_result;
match_start += elem.length; match_start += elem.length;
} }
@ -424,9 +416,7 @@ function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
// Use the apply argument as backing for global RegExp properties. // Use the apply argument as backing for global RegExp properties.
lastMatchInfoOverride = elem; lastMatchInfoOverride = elem;
var func_result = replace.apply(null, elem); var func_result = replace.apply(null, elem);
if (!IS_STRING(func_result)) { func_result = TO_STRING_INLINE(func_result);
func_result = NonStringToString(func_result);
}
res[i] = func_result; res[i] = func_result;
} }
i++; i++;
@ -487,8 +477,7 @@ function StringSearch(re) {
} else { } else {
regexp = new $RegExp(re); regexp = new $RegExp(re);
} }
var s = TO_STRING_INLINE(this); var match = DoRegExpExec(regexp, TO_STRING_INLINE(this), 0);
var match = DoRegExpExec(regexp, s, 0);
if (match) { if (match) {
return match[CAPTURE0]; return match[CAPTURE0];
} }
@ -576,14 +565,14 @@ function StringSplit(separator, limit) {
while (true) { while (true) {
if (startIndex === length) { if (startIndex === length) {
result[result.length] = subject.slice(currentIndex, length); result.push(subject.slice(currentIndex, length));
break; break;
} }
var matchInfo = splitMatch(separator, subject, currentIndex, startIndex); var matchInfo = splitMatch(separator, subject, currentIndex, startIndex);
if (IS_NULL(matchInfo)) { if (IS_NULL(matchInfo)) {
result[result.length] = subject.slice(currentIndex, length); result.push(subject.slice(currentIndex, length));
break; break;
} }
@ -595,17 +584,21 @@ function StringSplit(separator, limit) {
continue; continue;
} }
result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]); result.push(SubString(subject, currentIndex, matchInfo[CAPTURE0]));
if (result.length === limit) break; if (result.length === limit) break;
var num_captures = NUMBER_OF_CAPTURES(matchInfo); var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE;
for (var i = 2; i < num_captures; i += 2) { for (var i = REGEXP_FIRST_CAPTURE + 2; i < matchinfo_len; ) {
var start = matchInfo[CAPTURE(i)]; var start = matchInfo[i++];
var end = matchInfo[CAPTURE(i + 1)]; var end = matchInfo[i++];
if (start != -1 && end != -1) { if (end != -1) {
result[result.length] = SubString(subject, start, end); if (start + 1 == end) {
result.push(%_StringCharAt(subject, start));
} else {
result.push(%_SubString(subject, start, end));
}
} else { } else {
result[result.length] = void 0; result.push(void 0);
} }
if (result.length === limit) break outer_loop; if (result.length === limit) break outer_loop;
} }
@ -656,7 +649,9 @@ function StringSubstring(start, end) {
} }
} }
return SubString(s, start_i, end_i); return (start_i + 1 == end_i
? %_StringCharAt(s, start_i)
: %_SubString(s, start_i, end_i));
} }
@ -694,7 +689,9 @@ function StringSubstr(start, n) {
var end = start + len; var end = start + len;
if (end > s.length) end = s.length; if (end > s.length) end = s.length;
return SubString(s, start, end); return (start + 1 == end
? %_StringCharAt(s, start)
: %_SubString(s, start, end));
} }

8
deps/v8/src/v8natives.js

@ -615,7 +615,13 @@ function DefineOwnProperty(obj, p, desc, should_throw) {
} else { } else {
flag |= READ_ONLY; flag |= READ_ONLY;
} }
%DefineOrRedefineDataProperty(obj, p, desc.getValue(), flag); var value = void 0; // Default value is undefined.
if (desc.hasValue()) {
value = desc.getValue();
} else if (!IS_UNDEFINED(current)) {
value = current.getValue();
}
%DefineOrRedefineDataProperty(obj, p, value, flag);
} else { } else {
if (desc.hasGetter() && IS_FUNCTION(desc.getGet())) { if (desc.hasGetter() && IS_FUNCTION(desc.getGet())) {
%DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag); %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag);

39
deps/v8/src/v8preparserdll-main.cc

@ -0,0 +1,39 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <windows.h>
#include "../include/v8-preparser.h"
extern "C" {
BOOL WINAPI DllMain(HANDLE hinstDLL,
DWORD dwReason,
LPVOID lpvReserved) {
// Do nothing.
return TRUE;
}
}

4
deps/v8/src/version.cc

@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script. // cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3 #define MAJOR_VERSION 3
#define MINOR_VERSION 0 #define MINOR_VERSION 0
#define BUILD_NUMBER 0 #define BUILD_NUMBER 1
#define PATCH_LEVEL 1 #define PATCH_LEVEL 0
#define CANDIDATE_VERSION false #define CANDIDATE_VERSION false
// Define SONAME to have the SCons build the put a specific SONAME into the // Define SONAME to have the SCons build the put a specific SONAME into the

2220
deps/v8/src/x64/builtins-x64.cc

File diff suppressed because it is too large

16
deps/v8/src/x64/full-codegen-x64.cc

@ -839,7 +839,9 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
__ bind(&update_each); __ bind(&update_each);
__ movq(result_register(), rbx); __ movq(result_register(), rbx);
// Perform the assignment as if via '='. // Perform the assignment as if via '='.
EmitAssignment(stmt->each()); { EffectContext context(this);
EmitAssignment(stmt->each(), stmt->AssignmentId());
}
// Generate code for the body of the loop. // Generate code for the body of the loop.
Visit(stmt->body()); Visit(stmt->body());
@ -1521,7 +1523,7 @@ void FullCodeGenerator::EmitBinaryOp(Token::Value op,
} }
void FullCodeGenerator::EmitAssignment(Expression* expr) { void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_id) {
// Invalid left-hand sides are rewritten to have a 'throw // Invalid left-hand sides are rewritten to have a 'throw
// ReferenceError' on the left-hand side. // ReferenceError' on the left-hand side.
if (!expr->IsValidLeftHandSide()) { if (!expr->IsValidLeftHandSide()) {
@ -1569,6 +1571,7 @@ void FullCodeGenerator::EmitAssignment(Expression* expr) {
break; break;
} }
} }
context()->Plug(rax);
} }
@ -1641,8 +1644,6 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
} }
__ bind(&done); __ bind(&done);
} }
context()->Plug(rax);
} }
@ -1679,10 +1680,9 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
__ push(Operand(rsp, kPointerSize)); // Receiver is under value. __ push(Operand(rsp, kPointerSize)); // Receiver is under value.
__ CallRuntime(Runtime::kToFastProperties, 1); __ CallRuntime(Runtime::kToFastProperties, 1);
__ pop(rax); __ pop(rax);
context()->DropAndPlug(1, rax); __ Drop(1);
} else {
context()->Plug(rax);
} }
context()->Plug(rax);
} }
@ -3127,6 +3127,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
{ EffectContext context(this); { EffectContext context(this);
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Token::ASSIGN); Token::ASSIGN);
context.Plug(rax);
} }
// For all contexts except kEffect: We have the result on // For all contexts except kEffect: We have the result on
// top of the stack. // top of the stack.
@ -3137,6 +3138,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
// Perform the assignment as if via '='. // Perform the assignment as if via '='.
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
Token::ASSIGN); Token::ASSIGN);
context()->Plug(rax);
} }
break; break;
case NAMED_PROPERTY: { case NAMED_PROPERTY: {

5
deps/v8/src/x64/lithium-x64.h

@ -216,11 +216,6 @@ class LChunk: public ZoneObject {
return 0; return 0;
} }
int NearestNextGapPos(int index) const {
UNIMPLEMENTED();
return 0;
}
void MarkEmptyBlocks() { UNIMPLEMENTED(); } void MarkEmptyBlocks() { UNIMPLEMENTED(); }
#ifdef DEBUG #ifdef DEBUG

25
deps/v8/src/x64/macro-assembler-x64.cc

@ -2250,6 +2250,31 @@ void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
} }
void MacroAssembler::LoadGlobalFunction(int index, Register function) {
// Load the global or builtins object from the current context.
movq(function, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
// Load the global context from the global or builtins object.
movq(function, FieldOperand(function, GlobalObject::kGlobalContextOffset));
// Load the function from the global context.
movq(function, Operand(function, Context::SlotOffset(index)));
}
void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
Register map) {
// Load the initial map. The global functions all have initial maps.
movq(map, FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
if (FLAG_debug_code) {
Label ok, fail;
CheckMap(map, Factory::meta_map(), &fail, false);
jmp(&ok);
bind(&fail);
Abort("Global functions must have initial map");
bind(&ok);
}
}
int MacroAssembler::ArgumentStackSlotsForCFunctionCall(int num_arguments) { int MacroAssembler::ArgumentStackSlotsForCFunctionCall(int num_arguments) {
// On Windows 64 stack slots are reserved by the caller for all arguments // On Windows 64 stack slots are reserved by the caller for all arguments
// including the ones passed in registers, and space is always allocated for // including the ones passed in registers, and space is always allocated for

7
deps/v8/src/x64/macro-assembler-x64.h

@ -772,6 +772,13 @@ class MacroAssembler: public Assembler {
// Find the function context up the context chain. // Find the function context up the context chain.
void LoadContext(Register dst, int context_chain_length); void LoadContext(Register dst, int context_chain_length);
// Load the global function with the given index.
void LoadGlobalFunction(int index, Register function);
// Load the initial map from the global function. The registers
// function and map can be the same.
void LoadGlobalFunctionInitialMap(Register function, Register map);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Runtime calls // Runtime calls

3
deps/v8/test/cctest/cctest.status

@ -42,9 +42,6 @@ test-api/ApplyInterruption: PASS || TIMEOUT
# when snapshot is on, so I am marking it PASS || FAIL # when snapshot is on, so I am marking it PASS || FAIL
test-heap-profiler/HeapSnapshotsDiff: PASS || FAIL test-heap-profiler/HeapSnapshotsDiff: PASS || FAIL
# BUG(3260336): Flaky test. May be timing related.
test-profile-generator/RecordStackTraceAtStartProfiling: PASS || FAIL
# These tests always fail. They are here to test test.py. If # These tests always fail. They are here to test test.py. If
# they don't fail then test.py has failed. # they don't fail then test.py has failed.
test-serialize/TestThatAlwaysFails: FAIL test-serialize/TestThatAlwaysFails: FAIL

47
deps/v8/test/cctest/test-heap-profiler.cc

@ -1211,4 +1211,51 @@ TEST(HeapSnapshotGetNodeById) {
CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL)); CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL));
} }
namespace {
class TestActivityControl : public v8::ActivityControl {
public:
explicit TestActivityControl(int abort_count)
: done_(0), total_(0), abort_count_(abort_count) {}
ControlOption ReportProgressValue(int done, int total) {
done_ = done;
total_ = total;
return --abort_count_ != 0 ? kContinue : kAbort;
}
int done() { return done_; }
int total() { return total_; }
private:
int done_;
int total_;
int abort_count_;
};
}
TEST(TakeHeapSnapshotAborting) {
v8::HandleScope scope;
LocalContext env;
const int snapshots_count = v8::HeapProfiler::GetSnapshotsCount();
TestActivityControl aborting_control(3);
const v8::HeapSnapshot* no_snapshot =
v8::HeapProfiler::TakeSnapshot(v8::String::New("abort"),
v8::HeapSnapshot::kFull,
&aborting_control);
CHECK_EQ(NULL, no_snapshot);
CHECK_EQ(snapshots_count, v8::HeapProfiler::GetSnapshotsCount());
CHECK_GT(aborting_control.total(), aborting_control.done());
TestActivityControl control(-1); // Don't abort.
const v8::HeapSnapshot* snapshot =
v8::HeapProfiler::TakeSnapshot(v8::String::New("full"),
v8::HeapSnapshot::kFull,
&control);
CHECK_NE(NULL, snapshot);
CHECK_EQ(snapshots_count + 1, v8::HeapProfiler::GetSnapshotsCount());
CHECK_EQ(control.total(), control.done());
CHECK_GT(control.total(), 0);
}
#endif // ENABLE_LOGGING_AND_PROFILING #endif // ENABLE_LOGGING_AND_PROFILING

170
deps/v8/test/cctest/test-log-utils.cc

@ -12,7 +12,6 @@
using v8::internal::CStrVector; using v8::internal::CStrVector;
using v8::internal::EmbeddedVector; using v8::internal::EmbeddedVector;
using v8::internal::LogDynamicBuffer; using v8::internal::LogDynamicBuffer;
using v8::internal::LogRecordCompressor;
using v8::internal::MutableCStrVector; using v8::internal::MutableCStrVector;
using v8::internal::ScopedVector; using v8::internal::ScopedVector;
using v8::internal::Vector; using v8::internal::Vector;
@ -138,173 +137,4 @@ TEST(DynaBufSealing) {
CHECK_EQ(0, ReadData(&dynabuf, 100 + seal_size, &buf)); CHECK_EQ(0, ReadData(&dynabuf, 100 + seal_size, &buf));
} }
TEST(CompressorStore) {
LogRecordCompressor comp(2);
const Vector<const char> empty = CStrVector("");
CHECK(comp.Store(empty));
CHECK(!comp.Store(empty));
CHECK(!comp.Store(empty));
const Vector<const char> aaa = CStrVector("aaa");
CHECK(comp.Store(aaa));
CHECK(!comp.Store(aaa));
CHECK(!comp.Store(aaa));
CHECK(comp.Store(empty));
CHECK(!comp.Store(empty));
CHECK(!comp.Store(empty));
}
void CheckCompression(LogRecordCompressor* comp,
const Vector<const char>& after) {
EmbeddedVector<char, 100> result;
CHECK(comp->RetrievePreviousCompressed(&result));
CHECK_EQ(after, result);
}
void CheckCompression(LogRecordCompressor* comp,
const char* after) {
CheckCompression(comp, CStrVector(after));
}
TEST(CompressorNonCompressed) {
LogRecordCompressor comp(0);
CHECK(!comp.RetrievePreviousCompressed(NULL));
const Vector<const char> empty = CStrVector("");
CHECK(comp.Store(empty));
CHECK(!comp.RetrievePreviousCompressed(NULL));
const Vector<const char> a_x_20 = CStrVector("aaaaaaaaaaaaaaaaaaaa");
CHECK(comp.Store(a_x_20));
CheckCompression(&comp, empty);
CheckCompression(&comp, empty);
CHECK(comp.Store(empty));
CheckCompression(&comp, a_x_20);
CheckCompression(&comp, a_x_20);
}
TEST(CompressorSingleLine) {
LogRecordCompressor comp(1);
const Vector<const char> string_1 = CStrVector("eee,ddd,ccc,bbb,aaa");
CHECK(comp.Store(string_1));
const Vector<const char> string_2 = CStrVector("fff,ddd,ccc,bbb,aaa");
CHECK(comp.Store(string_2));
// string_1 hasn't been compressed.
CheckCompression(&comp, string_1);
CheckCompression(&comp, string_1);
const Vector<const char> string_3 = CStrVector("hhh,ggg,ccc,bbb,aaa");
CHECK(comp.Store(string_3));
// string_2 compressed using string_1.
CheckCompression(&comp, "fff#1:3");
CheckCompression(&comp, "fff#1:3");
CHECK(!comp.Store(string_3));
// Expecting no changes.
CheckCompression(&comp, "fff#1:3");
CHECK(!comp.Store(string_3));
// Expecting no changes.
CheckCompression(&comp, "fff#1:3");
const Vector<const char> string_4 = CStrVector("iii,hhh,ggg,ccc,bbb,aaa");
CHECK(comp.Store(string_4));
// string_3 compressed using string_2.
CheckCompression(&comp, "hhh,ggg#1:7");
const Vector<const char> string_5 = CStrVector("nnn,mmm,lll,kkk,jjj");
CHECK(comp.Store(string_5));
// string_4 compressed using string_3.
CheckCompression(&comp, "iii,#1");
const Vector<const char> string_6 = CStrVector("nnn,mmmmmm,lll,kkk,jjj");
CHECK(comp.Store(string_6));
// string_5 hasn't been compressed.
CheckCompression(&comp, string_5);
CHECK(comp.Store(string_5));
// string_6 compressed using string_5.
CheckCompression(&comp, "nnn,mmm#1:4");
const Vector<const char> string_7 = CStrVector("nnnnnn,mmm,lll,kkk,jjj");
CHECK(comp.Store(string_7));
// string_5 compressed using string_6.
CheckCompression(&comp, "nnn,#1:7");
const Vector<const char> string_8 = CStrVector("xxn,mmm,lll,kkk,jjj");
CHECK(comp.Store(string_8));
// string_7 compressed using string_5.
CheckCompression(&comp, "nnn#1");
const Vector<const char> string_9 =
CStrVector("aaaaaaaaaaaaa,bbbbbbbbbbbbbbbbb");
CHECK(comp.Store(string_9));
// string_8 compressed using string_7.
CheckCompression(&comp, "xx#1:5");
const Vector<const char> string_10 =
CStrVector("aaaaaaaaaaaaa,cccccccbbbbbbbbbb");
CHECK(comp.Store(string_10));
// string_9 hasn't been compressed.
CheckCompression(&comp, string_9);
CHECK(comp.Store(string_1));
// string_10 compressed using string_9.
CheckCompression(&comp, "aaaaaaaaaaaaa,ccccccc#1:21");
}
TEST(CompressorMultiLines) {
const int kWindowSize = 3;
LogRecordCompressor comp(kWindowSize);
const Vector<const char> string_1 = CStrVector("eee,ddd,ccc,bbb,aaa");
CHECK(comp.Store(string_1));
const Vector<const char> string_2 = CStrVector("iii,hhh,ggg,fff,aaa");
CHECK(comp.Store(string_2));
const Vector<const char> string_3 = CStrVector("mmm,lll,kkk,jjj,aaa");
CHECK(comp.Store(string_3));
const Vector<const char> string_4 = CStrVector("nnn,hhh,ggg,fff,aaa");
CHECK(comp.Store(string_4));
const Vector<const char> string_5 = CStrVector("ooo,lll,kkk,jjj,aaa");
CHECK(comp.Store(string_5));
// string_4 compressed using string_2.
CheckCompression(&comp, "nnn#2:3");
CHECK(comp.Store(string_1));
// string_5 compressed using string_3.
CheckCompression(&comp, "ooo#2:3");
CHECK(comp.Store(string_4));
// string_1 is out of buffer by now, so it shouldn't be compressed.
CHECK_GE(3, kWindowSize);
CheckCompression(&comp, string_1);
CHECK(comp.Store(string_2));
// string_4 compressed using itself.
CheckCompression(&comp, "#3");
}
TEST(CompressorBestSelection) {
LogRecordCompressor comp(3);
const Vector<const char> string_1 = CStrVector("eee,ddd,ccc,bbb,aaa");
CHECK(comp.Store(string_1));
const Vector<const char> string_2 = CStrVector("ddd,ccc,bbb,aaa");
CHECK(comp.Store(string_2));
const Vector<const char> string_3 = CStrVector("fff,eee,ddd,ccc,bbb,aaa");
CHECK(comp.Store(string_3));
// string_2 compressed using string_1.
CheckCompression(&comp, "#1:4");
const Vector<const char> string_4 = CStrVector("nnn,hhh,ggg,fff,aaa");
CHECK(comp.Store(string_4));
// Compressing string_3 using string_1 gives a better compression than
// using string_2.
CheckCompression(&comp, "fff,#2");
}
TEST(CompressorCompressibility) {
LogRecordCompressor comp(2);
const Vector<const char> string_1 = CStrVector("eee,ddd,ccc,bbb,aaa");
CHECK(comp.Store(string_1));
const Vector<const char> string_2 = CStrVector("ccc,bbb,aaa");
CHECK(comp.Store(string_2));
const Vector<const char> string_3 = CStrVector("aaa");
CHECK(comp.Store(string_3));
// string_2 compressed using string_1.
CheckCompression(&comp, "#1:8");
const Vector<const char> string_4 = CStrVector("xxx");
CHECK(comp.Store(string_4));
// string_3 can't be compressed using string_2 --- too short.
CheckCompression(&comp, string_3);
}
#endif // ENABLE_LOGGING_AND_PROFILING #endif // ENABLE_LOGGING_AND_PROFILING

303
deps/v8/test/cctest/test-parsing.cc

@ -260,10 +260,12 @@ TEST(StandAlonePreParser) {
uintptr_t stack_limit = i::StackGuard::real_climit(); uintptr_t stack_limit = i::StackGuard::real_climit();
for (int i = 0; programs[i]; i++) { for (int i = 0; programs[i]; i++) {
const char* program = programs[i]; const char* program = programs[i];
unibrow::Utf8InputBuffer<256> stream(program, strlen(program)); i::Utf8ToUC16CharacterStream stream(
reinterpret_cast<const i::byte*>(program),
static_cast<unsigned>(strlen(program)));
i::CompleteParserRecorder log; i::CompleteParserRecorder log;
i::V8JavaScriptScanner scanner; i::V8JavaScriptScanner scanner;
scanner.Initialize(i::Handle<i::String>::null(), &stream); scanner.Initialize(&stream);
v8::preparser::PreParser::PreParseResult result = v8::preparser::PreParser::PreParseResult result =
v8::preparser::PreParser::PreParseProgram(&scanner, v8::preparser::PreParser::PreParseProgram(&scanner,
@ -289,9 +291,10 @@ TEST(RegressChromium62639) {
// and then used the invalid currently scanned literal. This always // and then used the invalid currently scanned literal. This always
// failed in debug mode, and sometimes crashed in release mode. // failed in debug mode, and sometimes crashed in release mode.
unibrow::Utf8InputBuffer<256> stream(program, strlen(program)); i::Utf8ToUC16CharacterStream stream(reinterpret_cast<const i::byte*>(program),
static_cast<unsigned>(strlen(program)));
i::ScriptDataImpl* data = i::ScriptDataImpl* data =
i::ParserApi::PreParse(i::Handle<i::String>::null(), &stream, NULL); i::ParserApi::PreParse(&stream, NULL);
CHECK(data->HasError()); CHECK(data->HasError());
delete data; delete data;
} }
@ -310,10 +313,10 @@ TEST(Regress928) {
"try { } catch (e) { var foo = function () { /* first */ } }" "try { } catch (e) { var foo = function () { /* first */ } }"
"var bar = function () { /* second */ }"; "var bar = function () { /* second */ }";
unibrow::Utf8InputBuffer<256> stream(program, strlen(program)); i::Utf8ToUC16CharacterStream stream(reinterpret_cast<const i::byte*>(program),
static_cast<unsigned>(strlen(program)));
i::ScriptDataImpl* data = i::ScriptDataImpl* data =
i::ParserApi::PartialPreParse(i::Handle<i::String>::null(), i::ParserApi::PartialPreParse(&stream, NULL);
&stream, NULL);
CHECK(!data->HasError()); CHECK(!data->HasError());
data->Initialize(); data->Initialize();
@ -347,10 +350,12 @@ TEST(PreParseOverflow) {
uintptr_t stack_limit = i::StackGuard::real_climit(); uintptr_t stack_limit = i::StackGuard::real_climit();
unibrow::Utf8InputBuffer<256> stream(*program, strlen(*program)); i::Utf8ToUC16CharacterStream stream(
reinterpret_cast<const i::byte*>(*program),
static_cast<unsigned>(kProgramSize));
i::CompleteParserRecorder log; i::CompleteParserRecorder log;
i::V8JavaScriptScanner scanner; i::V8JavaScriptScanner scanner;
scanner.Initialize(i::Handle<i::String>::null(), &stream); scanner.Initialize(&stream);
v8::preparser::PreParser::PreParseResult result = v8::preparser::PreParser::PreParseResult result =
@ -360,3 +365,283 @@ TEST(PreParseOverflow) {
stack_limit); stack_limit);
CHECK_EQ(v8::preparser::PreParser::kPreParseStackOverflow, result); CHECK_EQ(v8::preparser::PreParser::kPreParseStackOverflow, result);
} }
class TestExternalResource: public v8::String::ExternalStringResource {
public:
explicit TestExternalResource(uint16_t* data, int length)
: data_(data), length_(static_cast<size_t>(length)) { }
~TestExternalResource() { }
const uint16_t* data() const {
return data_;
}
size_t length() const {
return length_;
}
private:
uint16_t* data_;
size_t length_;
};
#define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
void TestCharacterStream(const char* ascii_source,
unsigned length,
unsigned start = 0,
unsigned end = 0) {
if (end == 0) end = length;
unsigned sub_length = end - start;
i::HandleScope test_scope;
i::SmartPointer<i::uc16> uc16_buffer(new i::uc16[length]);
for (unsigned i = 0; i < length; i++) {
uc16_buffer[i] = static_cast<i::uc16>(ascii_source[i]);
}
i::Vector<const char> ascii_vector(ascii_source, static_cast<int>(length));
i::Handle<i::String> ascii_string(
i::Factory::NewStringFromAscii(ascii_vector));
TestExternalResource resource(*uc16_buffer, length);
i::Handle<i::String> uc16_string(
i::Factory::NewExternalStringFromTwoByte(&resource));
i::ExternalTwoByteStringUC16CharacterStream uc16_stream(
i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
i::GenericStringUC16CharacterStream string_stream(ascii_string, start, end);
i::Utf8ToUC16CharacterStream utf8_stream(
reinterpret_cast<const i::byte*>(ascii_source), end);
utf8_stream.SeekForward(start);
unsigned i = start;
while (i < end) {
// Read streams one char at a time
CHECK_EQU(i, uc16_stream.pos());
CHECK_EQU(i, string_stream.pos());
CHECK_EQU(i, utf8_stream.pos());
int32_t c0 = ascii_source[i];
int32_t c1 = uc16_stream.Advance();
int32_t c2 = string_stream.Advance();
int32_t c3 = utf8_stream.Advance();
i++;
CHECK_EQ(c0, c1);
CHECK_EQ(c0, c2);
CHECK_EQ(c0, c3);
CHECK_EQU(i, uc16_stream.pos());
CHECK_EQU(i, string_stream.pos());
CHECK_EQU(i, utf8_stream.pos());
}
while (i > start + sub_length / 4) {
// Pushback, re-read, pushback again.
int32_t c0 = ascii_source[i - 1];
CHECK_EQU(i, uc16_stream.pos());
CHECK_EQU(i, string_stream.pos());
CHECK_EQU(i, utf8_stream.pos());
uc16_stream.PushBack(c0);
string_stream.PushBack(c0);
utf8_stream.PushBack(c0);
i--;
CHECK_EQU(i, uc16_stream.pos());
CHECK_EQU(i, string_stream.pos());
CHECK_EQU(i, utf8_stream.pos());
int32_t c1 = uc16_stream.Advance();
int32_t c2 = string_stream.Advance();
int32_t c3 = utf8_stream.Advance();
i++;
CHECK_EQU(i, uc16_stream.pos());
CHECK_EQU(i, string_stream.pos());
CHECK_EQU(i, utf8_stream.pos());
CHECK_EQ(c0, c1);
CHECK_EQ(c0, c2);
CHECK_EQ(c0, c3);
uc16_stream.PushBack(c0);
string_stream.PushBack(c0);
utf8_stream.PushBack(c0);
i--;
CHECK_EQU(i, uc16_stream.pos());
CHECK_EQU(i, string_stream.pos());
CHECK_EQU(i, utf8_stream.pos());
}
unsigned halfway = start + sub_length / 2;
uc16_stream.SeekForward(halfway - i);
string_stream.SeekForward(halfway - i);
utf8_stream.SeekForward(halfway - i);
i = halfway;
CHECK_EQU(i, uc16_stream.pos());
CHECK_EQU(i, string_stream.pos());
CHECK_EQU(i, utf8_stream.pos());
while (i < end) {
// Read streams one char at a time
CHECK_EQU(i, uc16_stream.pos());
CHECK_EQU(i, string_stream.pos());
CHECK_EQU(i, utf8_stream.pos());
int32_t c0 = ascii_source[i];
int32_t c1 = uc16_stream.Advance();
int32_t c2 = string_stream.Advance();
int32_t c3 = utf8_stream.Advance();
i++;
CHECK_EQ(c0, c1);
CHECK_EQ(c0, c2);
CHECK_EQ(c0, c3);
CHECK_EQU(i, uc16_stream.pos());
CHECK_EQU(i, string_stream.pos());
CHECK_EQU(i, utf8_stream.pos());
}
int32_t c1 = uc16_stream.Advance();
int32_t c2 = string_stream.Advance();
int32_t c3 = utf8_stream.Advance();
CHECK_LT(c1, 0);
CHECK_LT(c2, 0);
CHECK_LT(c3, 0);
}
TEST(CharacterStreams) {
v8::HandleScope handles;
v8::Persistent<v8::Context> context = v8::Context::New();
v8::Context::Scope context_scope(context);
TestCharacterStream("abc\0\n\r\x7f", 7);
static const unsigned kBigStringSize = 4096;
char buffer[kBigStringSize + 1];
for (unsigned i = 0; i < kBigStringSize; i++) {
buffer[i] = static_cast<char>(i & 0x7f);
}
TestCharacterStream(buffer, kBigStringSize);
TestCharacterStream(buffer, kBigStringSize, 576, 3298);
TestCharacterStream("\0", 1);
TestCharacterStream("", 0);
}
TEST(Utf8CharacterStream) {
static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
static const int kAllUtf8CharsSize =
(unibrow::Utf8::kMaxOneByteChar + 1) +
(unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
(unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
static const unsigned kAllUtf8CharsSizeU =
static_cast<unsigned>(kAllUtf8CharsSize);
char buffer[kAllUtf8CharsSizeU];
unsigned cursor = 0;
for (int i = 0; i <= kMaxUC16Char; i++) {
cursor += unibrow::Utf8::Encode(buffer + cursor, i);
}
ASSERT(cursor == kAllUtf8CharsSizeU);
i::Utf8ToUC16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
kAllUtf8CharsSizeU);
for (int i = 0; i <= kMaxUC16Char; i++) {
CHECK_EQU(i, stream.pos());
int32_t c = stream.Advance();
CHECK_EQ(i, c);
CHECK_EQU(i + 1, stream.pos());
}
for (int i = kMaxUC16Char; i >= 0; i--) {
CHECK_EQU(i + 1, stream.pos());
stream.PushBack(i);
CHECK_EQU(i, stream.pos());
}
int i = 0;
while (stream.pos() < kMaxUC16CharU) {
CHECK_EQU(i, stream.pos());
unsigned progress = stream.SeekForward(12);
i += progress;
int32_t c = stream.Advance();
if (i <= kMaxUC16Char) {
CHECK_EQ(i, c);
} else {
CHECK_EQ(-1, c);
}
i += 1;
CHECK_EQU(i, stream.pos());
}
}
#undef CHECK_EQU
void TestStreamScanner(i::UC16CharacterStream* stream,
i::Token::Value* expected_tokens,
int skip_pos = 0, // Zero means not skipping.
int skip_to = 0) {
i::V8JavaScriptScanner scanner;
scanner.Initialize(stream, i::JavaScriptScanner::kAllLiterals);
int i = 0;
do {
i::Token::Value expected = expected_tokens[i];
i::Token::Value actual = scanner.Next();
CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
if (scanner.location().end_pos == skip_pos) {
scanner.SeekForward(skip_to);
}
i++;
} while (expected_tokens[i] != i::Token::ILLEGAL);
}
TEST(StreamScanner) {
const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
i::Utf8ToUC16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
static_cast<unsigned>(strlen(str1)));
i::Token::Value expectations1[] = {
i::Token::LBRACE,
i::Token::IDENTIFIER,
i::Token::IDENTIFIER,
i::Token::FOR,
i::Token::COLON,
i::Token::MUL,
i::Token::DIV,
i::Token::LT,
i::Token::SUB,
i::Token::IDENTIFIER,
i::Token::EOS,
i::Token::ILLEGAL
};
TestStreamScanner(&stream1, expectations1, 0, 0);
const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
i::Utf8ToUC16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
static_cast<unsigned>(strlen(str2)));
i::Token::Value expectations2[] = {
i::Token::CASE,
i::Token::DEFAULT,
i::Token::CONST,
i::Token::LBRACE,
// Skipped part here
i::Token::RBRACE,
i::Token::DO,
i::Token::EOS,
i::Token::ILLEGAL
};
ASSERT_EQ('{', str2[19]);
ASSERT_EQ('}', str2[37]);
TestStreamScanner(&stream2, expectations2, 20, 37);
const char* str3 = "{}}}}";
i::Token::Value expectations3[] = {
i::Token::LBRACE,
i::Token::RBRACE,
i::Token::RBRACE,
i::Token::RBRACE,
i::Token::RBRACE,
i::Token::EOS,
i::Token::ILLEGAL
};
// Skip zero-four RBRACEs.
for (int i = 0; i <= 4; i++) {
expectations3[6 - i] = i::Token::ILLEGAL;
expectations3[5 - i] = i::Token::EOS;
i::Utf8ToUC16CharacterStream stream3(
reinterpret_cast<const i::byte*>(str3),
static_cast<unsigned>(strlen(str3)));
TestStreamScanner(&stream3, expectations3, 1, 1 + i);
}
}

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

@ -782,12 +782,16 @@ TEST(RecordStackTraceAtStartProfiling) {
CpuProfiler::GetProfile(NULL, 0); CpuProfiler::GetProfile(NULL, 0);
const ProfileTree* topDown = profile->top_down(); const ProfileTree* topDown = profile->top_down();
const ProfileNode* current = topDown->root(); const ProfileNode* current = topDown->root();
const_cast<ProfileNode*>(current)->Print(0);
// The tree should look like this: // The tree should look like this:
// (root) // (root)
// (anonymous function) // (anonymous function)
// a // a
// b // b
// c // c
// There can also be:
// startProfiling
// if the sampler managed to get a tick.
current = PickChild(current, "(anonymous function)"); current = PickChild(current, "(anonymous function)");
CHECK_NE(NULL, const_cast<ProfileNode*>(current)); CHECK_NE(NULL, const_cast<ProfileNode*>(current));
current = PickChild(current, "a"); current = PickChild(current, "a");
@ -796,7 +800,12 @@ TEST(RecordStackTraceAtStartProfiling) {
CHECK_NE(NULL, const_cast<ProfileNode*>(current)); CHECK_NE(NULL, const_cast<ProfileNode*>(current));
current = PickChild(current, "c"); current = PickChild(current, "c");
CHECK_NE(NULL, const_cast<ProfileNode*>(current)); CHECK_NE(NULL, const_cast<ProfileNode*>(current));
CHECK_EQ(0, current->children()->length()); CHECK(current->children()->length() == 0 ||
current->children()->length() == 1);
if (current->children()->length() == 1) {
current = PickChild(current, "startProfiling");
CHECK_EQ(0, current->children()->length());
}
} }

3
deps/v8/test/cctest/test-regexp.cc

@ -173,6 +173,9 @@ TEST(Parser) {
CHECK_PARSE_EQ("[a-b-c]", "[a-b - c]"); CHECK_PARSE_EQ("[a-b-c]", "[a-b - c]");
CHECK_PARSE_EQ("[\\d]", "[0-9]"); CHECK_PARSE_EQ("[\\d]", "[0-9]");
CHECK_PARSE_EQ("[x\\dz]", "[x 0-9 z]"); CHECK_PARSE_EQ("[x\\dz]", "[x 0-9 z]");
CHECK_PARSE_EQ("[\\d-z]", "[0-9 - z]");
CHECK_PARSE_EQ("[\\d-\\d]", "[0-9 - 0-9]");
CHECK_PARSE_EQ("[z-\\d]", "[z - 0-9]");
CHECK_PARSE_EQ("\\cj\\cJ\\ci\\cI\\ck\\cK", CHECK_PARSE_EQ("\\cj\\cJ\\ci\\cI\\ck\\cK",
"'\\x0a\\x0a\\x09\\x09\\x0b\\x0b'"); "'\\x0a\\x0a\\x09\\x09\\x0b\\x0b'");
CHECK_PARSE_EQ("\\c!", "'c!'"); CHECK_PARSE_EQ("\\c!", "'c!'");

5
deps/v8/test/mjsunit/mjsunit.status

@ -104,6 +104,11 @@ regress/regress-create-exception: SKIP
regress/regress-3218915: SKIP regress/regress-3218915: SKIP
regress/regress-3247124: SKIP regress/regress-3247124: SKIP
##############################################################################
[ $arch == arm && $crankshaft ]
# Test that currently fail with crankshaft on ARM.
compiler/simple-osr: FAIL
############################################################################## ##############################################################################
[ $arch == mips ] [ $arch == mips ]

32
deps/v8/test/mjsunit/object-define-property.js

@ -866,4 +866,36 @@ assertFalse(desc.writable);
assertFalse(desc.enumerable); assertFalse(desc.enumerable);
assertFalse(desc.configurable); assertFalse(desc.configurable);
// See issue 968: http://code.google.com/p/v8/issues/detail?id=968
var o = { x : 42 };
Object.defineProperty(o, "x", { writable: false });
assertEquals(42, o.x);
o.x = 37;
assertEquals(42, o.x);
o = { x : 42 };
Object.defineProperty(o, "x", {});
assertEquals(42, o.x);
o.x = 37;
// Writability is preserved.
assertEquals(37, o.x);
var o = { };
Object.defineProperty(o, "x", { writable: false });
assertEquals(undefined, o.x);
o.x = 37;
assertEquals(undefined, o.x);
o = { get x() { return 87; } };
Object.defineProperty(o, "x", { writable: false });
assertEquals(undefined, o.x);
o.x = 37;
assertEquals(undefined, o.x);
// Ignore inherited properties.
o = { __proto__ : { x : 87 } };
Object.defineProperty(o, "x", { writable: false });
assertEquals(undefined, o.x);
o.x = 37;
assertEquals(undefined, o.x);

92
deps/v8/test/mjsunit/regexp.js

@ -110,6 +110,44 @@ assertFalse(re.test("\\]"));
assertFalse(re.test("\x03]")); // I.e., read as \cc assertFalse(re.test("\x03]")); // I.e., read as \cc
// Test that we handle \s and \S correctly inside some bizarre
// character classes.
re = /[\s-:]/;
assertTrue(re.test('-'));
assertTrue(re.test(':'));
assertTrue(re.test(' '));
assertTrue(re.test('\t'));
assertTrue(re.test('\n'));
assertFalse(re.test('a'));
assertFalse(re.test('Z'));
re = /[\S-:]/;
assertTrue(re.test('-'));
assertTrue(re.test(':'));
assertFalse(re.test(' '));
assertFalse(re.test('\t'));
assertFalse(re.test('\n'));
assertTrue(re.test('a'));
assertTrue(re.test('Z'));
re = /[^\s-:]/;
assertFalse(re.test('-'));
assertFalse(re.test(':'));
assertFalse(re.test(' '));
assertFalse(re.test('\t'));
assertFalse(re.test('\n'));
assertTrue(re.test('a'));
assertTrue(re.test('Z'));
re = /[^\S-:]/;
assertFalse(re.test('-'));
assertFalse(re.test(':'));
assertTrue(re.test(' '));
assertTrue(re.test('\t'));
assertTrue(re.test('\n'));
assertFalse(re.test('a'));
assertFalse(re.test('Z'));
re = /[\s]/; re = /[\s]/;
assertFalse(re.test('-')); assertFalse(re.test('-'));
assertFalse(re.test(':')); assertFalse(re.test(':'));
@ -164,6 +202,17 @@ assertFalse(re.test('\n'));
assertFalse(re.test('a')); assertFalse(re.test('a'));
assertFalse(re.test('Z')); assertFalse(re.test('Z'));
// First - is treated as range operator, second as literal minus.
// This follows the specification in parsing, but doesn't throw on
// the \s at the beginning of the range.
re = /[\s-0-9]/;
assertTrue(re.test(' '));
assertTrue(re.test('\xA0'));
assertTrue(re.test('-'));
assertTrue(re.test('0'));
assertTrue(re.test('9'));
assertFalse(re.test('1'));
// Test beginning and end of line assertions with or without the // Test beginning and end of line assertions with or without the
// multiline flag. // multiline flag.
re = /^\d+/; re = /^\d+/;
@ -610,46 +659,3 @@ assertEquals(["bc"], re.exec("zimzomzumbc"));
assertFalse(re.test("c")); assertFalse(re.test("c"));
assertFalse(re.test("")); assertFalse(re.test(""));
function testInvalidRange(str) {
try {
RegExp(str).test("x");
} catch (e) {
return;
}
assetUnreachable("Allowed invalid range in " + str);
}
function testValidRange(str) {
try {
RegExp(str).test("x");
} catch (e) {
assertUnreachable("Shouldn't fail parsing: " + str + ", was: " + e);
}
}
testInvalidRange("[\\d-z]");
testInvalidRange("[z-\\d]");
testInvalidRange("[\\d-\\d]");
testInvalidRange("[z-x]"); // Larger value first.
testInvalidRange("[x-\\d-\\d]");
testValidRange("[x-z]");
testValidRange("[!--\d]"); // Second "-" is end of range.
testValidRange("[\d-]");
testValidRange("[-\d]");
testValidRange("[-\d-]");
testValidRange("[^-\d-]");
testValidRange("[^-\d-]");
testValidRange("[0-9-\w]");
// Escaped dashes do not count as range operators.
testValidRange("[\\d\\-z]");
testValidRange("[z\\-\\d]");
testValidRange("[\\d\\-\\d]");
testValidRange("[z\\-x]");
testValidRange("[x\\-\\d\\-\\d]");

53
deps/v8/test/mjsunit/regress/regress-962.js

@ -0,0 +1,53 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function L(scope) { this.s = new Object(); }
L.prototype.c = function() { return true; }
function F() {
this.l = [new L, new L];
}
F.prototype.foo = function () {
var f, d = arguments,
e, b = this.l,
g;
for (e = 0; e < b.length; e++) {
g = b[e];
f = g.c.apply(g.s, d);
if (f === false) {
break
}
}
return f
}
var ctx = new F;
for (var i = 0; i < 10000000; i++) ctx.foo();

127
deps/v8/test/mjsunit/regress/regress-969.js

@ -0,0 +1,127 @@
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Regression test for bugs when deoptimizing after assignments in effect
// contexts.
// Bug 989 is that there was an extra value on the expression stack when
// deoptimizing after an assignment in effect context (the value of the
// assignment was lingering). This is hard to observe in the unoptimized
// code.
//
// This test uses comma expressions to put assignments in effect contexts,
// references to deleted global variables to force deoptimization, and
// function calls to observe an extra value.
function first(x, y) { return x; }
var y = 0;
var o = {};
o.x = 0;
o[0] = 0;
// Assignment to global variable.
x0 = 0;
function test0() { return first((y = 1, typeof x0), 2); }
// Call the function once to compile it.
assertEquals('number', test0());
// Delete to force deoptimization on the next call.
delete x0;
assertEquals('undefined', test0());
// Compound assignment to global variable.
x1 = 0;
function test1() { return first((y += 1, typeof x1), 2); }
assertEquals('number', test1(), 'test1 before');
delete x1;
assertEquals('undefined', test1(), 'test1 after');
// Pre and post-increment of global variable.
x2 = 0;
function test2() { return first((++y, typeof x2), 2); }
assertEquals('number', test2(), 'test2 before');
delete x2;
assertEquals('undefined', test2(), 'test2 after');
x3 = 0;
function test3() { return first((y++, typeof x3), 2); }
assertEquals('number', test3(), 'test3 before');
delete x3;
assertEquals('undefined', test3(), 'test3 after');
// Assignment, compound assignment, and pre and post-increment of named
// properties.
x4 = 0;
function test4() { return first((o.x = 1, typeof x4), 2); }
assertEquals('number', test4());
delete x4;
assertEquals('undefined', test4());
x5 = 0;
function test5() { return first((o.x += 1, typeof x5), 2); }
assertEquals('number', test5());
delete x5;
assertEquals('undefined', test5());
x6 = 0;
function test6() { return first((++o.x, typeof x6), 2); }
assertEquals('number', test6());
delete x6;
assertEquals('undefined', test6());
x7 = 0;
function test7() { return first((o.x++, typeof x7), 2); }
assertEquals('number', test7());
delete x7;
assertEquals('undefined', test7());
// Assignment, compound assignment, and pre and post-increment of indexed
// properties.
x8 = 0;
function test8(index) { return first((o[index] = 1, typeof x8), 2); }
assertEquals('number', test8());
delete x8;
assertEquals('undefined', test8());
x9 = 0;
function test9(index) { return first((o[index] += 1, typeof x9), 2); }
assertEquals('number', test9());
delete x9;
assertEquals('undefined', test9());
x10 = 0;
function test10(index) { return first((++o[index], typeof x10), 2); }
assertEquals('number', test10());
delete x10;
assertEquals('undefined', test10());
x11 = 0;
function test11(index) { return first((o[index]++, typeof x11), 2); }
assertEquals('number', test11());
delete x11;
assertEquals('undefined', test11());

24
deps/v8/test/mjsunit/third_party/regexp-pcre.js

@ -962,7 +962,7 @@ res[882] = /[az-]+/;
res[883] = /[a\-z]+/; res[883] = /[a\-z]+/;
res[884] = /[a-z]+/; res[884] = /[a-z]+/;
res[885] = /[\d-]+/; res[885] = /[\d-]+/;
// res[886] - Disabled after making [\d-z] invalid to be compatible with JSC. res[886] = /[\d-z]+/;
res[887] = /\x5c/; res[887] = /\x5c/;
res[888] = /\x20Z/; res[888] = /\x20Z/;
res[889] = /ab{3cd/; res[889] = /ab{3cd/;
@ -1346,7 +1346,7 @@ res[1266] = /((Z)+|A)*/;
res[1267] = /(Z()|A)*/; res[1267] = /(Z()|A)*/;
res[1268] = /(Z(())|A)*/; res[1268] = /(Z(())|A)*/;
res[1269] = /a*/g; res[1269] = /a*/g;
// res[1270] disabled after making /^[\d-a]/ invalid to be compatible with JSC. res[1270] = /^[\d-a]/;
res[1271] = /[[:space:]]+/; res[1271] = /[[:space:]]+/;
res[1272] = /[[:blank:]]+/; res[1272] = /[[:blank:]]+/;
res[1273] = /[\s]+/; res[1273] = /[\s]+/;
@ -2530,7 +2530,7 @@ assertEquals(null, res[431].exec("a\x0db ", 882));
assertEquals(null, res[431].exec("a\x85b", 883)); assertEquals(null, res[431].exec("a\x85b", 883));
assertThrows("var re = /(?-+a)/;", 884); assertThrows("var re = /(?-+a)/;", 884);
assertEquals(null, res[443].exec("aaaa", 885)); assertEquals(null, res[443].exec("aaaa", 885));
// assertEquals(null, res[443].exec("bacxxx", 886)); assertEquals(null, res[443].exec("bacxxx", 886));
assertEquals(null, res[443].exec("bbaccxxx ", 887)); assertEquals(null, res[443].exec("bbaccxxx ", 887));
assertEquals(null, res[443].exec("bbbacccxx", 888)); assertEquals(null, res[443].exec("bbbacccxx", 888));
assertEquals(null, res[443].exec("aaaa", 889)); assertEquals(null, res[443].exec("aaaa", 889));
@ -4391,10 +4391,9 @@ assertEquals("abcdxyz", res[884].exec("abcdxyz"), 2743);
assertEquals("12-34", res[885].exec("12-34"), 2744); assertEquals("12-34", res[885].exec("12-34"), 2744);
assertEquals(null, res[885].exec("*** Failers", 2745)); assertEquals(null, res[885].exec("*** Failers", 2745));
assertEquals(null, res[885].exec("aaa", 2746)); assertEquals(null, res[885].exec("aaa", 2746));
// Disabled. To be compatible with JSC, the regexp is no longer valid. assertEquals("12-34z", res[886].exec("12-34z"), 2747);
// assertEquals("12-34z", res[886].exec("12-34z"), 2747); assertEquals(null, res[886].exec("*** Failers", 2748));
// assertEquals(null, res[886].exec("*** Failers", 2748)); assertEquals(null, res[886].exec("aaa", 2749));
// assertEquals(null, res[886].exec("aaa", 2749));
assertEquals("\\", res[887].exec("\\\\"), 2750); assertEquals("\\", res[887].exec("\\\\"), 2750);
assertEquals(" Z", res[888].exec("the Zoo"), 2751); assertEquals(" Z", res[888].exec("the Zoo"), 2751);
assertEquals(null, res[888].exec("*** Failers", 2752)); assertEquals(null, res[888].exec("*** Failers", 2752));
@ -5356,12 +5355,11 @@ assertEquals("", res[1269].exec("-things"), 3707);
assertEquals("", res[1269].exec("0digit"), 3708); assertEquals("", res[1269].exec("0digit"), 3708);
assertEquals("", res[1269].exec("*** Failers"), 3709); assertEquals("", res[1269].exec("*** Failers"), 3709);
assertEquals("", res[1269].exec("bcdef "), 3710); assertEquals("", res[1269].exec("bcdef "), 3710);
// Disabled. To be compatible with JSC, the RegExp is no longer valid. assertEquals("a", res[1270].exec("abcde"), 3711);
// assertEquals("a", res[1270].exec("abcde"), 3711); assertEquals("-", res[1270].exec("-things"), 3712);
// assertEquals("-", res[1270].exec("-things"), 3712); assertEquals("0", res[1270].exec("0digit"), 3713);
// assertEquals("0", res[1270].exec("0digit"), 3713); assertEquals(null, res[1270].exec("*** Failers", 3714));
// assertEquals(null, res[1270].exec("*** Failers", 3714)); assertEquals(null, res[1270].exec("bcdef ", 3715));
// assertEquals(null, res[1270].exec("bcdef ", 3715));
assertEquals(null, res[1271].exec("> \x09\n\x0c\x0d\x0b<", 3716)); assertEquals(null, res[1271].exec("> \x09\n\x0c\x0d\x0b<", 3716));
assertEquals(null, res[1271].exec(" ", 3717)); assertEquals(null, res[1271].exec(" ", 3717));
assertEquals(null, res[1272].exec("> \x09\n\x0c\x0d\x0b<", 3718)); assertEquals(null, res[1272].exec("> \x09\n\x0c\x0d\x0b<", 3718));

82
deps/v8/test/mjsunit/tools/logreader.js

@ -1,82 +0,0 @@
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Load CSV Parser and Log Reader implementations from <project root>/tools.
// Files: tools/csvparser.js tools/logreader.js
(function testAddressParser() {
var reader = new devtools.profiler.LogReader({});
var parser = reader.createAddressParser('test');
// Test that 0x values are parsed, and prevAddresses_ are untouched.
assertFalse('test' in reader.prevAddresses_);
assertEquals(0, parser('0x0'));
assertFalse('test' in reader.prevAddresses_);
assertEquals(0x100, parser('0x100'));
assertFalse('test' in reader.prevAddresses_);
assertEquals(0xffffffff, parser('0xffffffff'));
assertFalse('test' in reader.prevAddresses_);
// Test that values that has no '+' or '-' prefix are parsed
// and saved to prevAddresses_.
assertEquals(0, parser('0'));
assertEquals(0, reader.prevAddresses_.test);
assertEquals(0x100, parser('100'));
assertEquals(0x100, reader.prevAddresses_.test);
assertEquals(0xffffffff, parser('ffffffff'));
assertEquals(0xffffffff, reader.prevAddresses_.test);
// Test that values prefixed with '+' or '-' are treated as deltas,
// and prevAddresses_ is updated.
// Set base value.
assertEquals(0x100, parser('100'));
assertEquals(0x100, reader.prevAddresses_.test);
assertEquals(0x200, parser('+100'));
assertEquals(0x200, reader.prevAddresses_.test);
assertEquals(0x100, parser('-100'));
assertEquals(0x100, reader.prevAddresses_.test);
})();
(function testAddressParser() {
var reader = new devtools.profiler.LogReader({});
assertEquals([0x10000000, 0x10001000, 0xffff000, 0x10000000],
reader.processStack(0x10000000, 0, ['overflow',
'+1000', '-2000', '+1000']));
})();
(function testExpandBackRef() {
var reader = new devtools.profiler.LogReader({});
assertEquals('aaaaaaaa', reader.expandBackRef_('aaaaaaaa'));
assertEquals('aaaaaaaa', reader.expandBackRef_('#1'));
assertEquals('bbbbaaaa', reader.expandBackRef_('bbbb#2:4'));
assertEquals('"#1:1"', reader.expandBackRef_('"#1:1"'));
})();

7
deps/v8/test/mozilla/mozilla.status

@ -53,6 +53,9 @@ def FAIL_OK = FAIL, OKAY
# time to do so. # time to do so.
js1_5/Regress/regress-271716-n: SKIP js1_5/Regress/regress-271716-n: SKIP
# BUG(960): This test has an insane amount of output when it times out,
# messing up ability to see other failures on the waterfall.
js1_5/extensions/regress-342960: SKIP
# This test uses a unitialized variable. A Bug has been filed: # This test uses a unitialized variable. A Bug has been filed:
# https://bugzilla.mozilla.org/show_bug.cgi?id=575575 # https://bugzilla.mozilla.org/show_bug.cgi?id=575575
@ -289,10 +292,6 @@ js1_2/regexp/RegExp_multiline_as_array: FAIL_OK
js1_2/regexp/beginLine: FAIL_OK js1_2/regexp/beginLine: FAIL_OK
js1_2/regexp/endLine: FAIL_OK js1_2/regexp/endLine: FAIL_OK
# To be compatible with JSC, we no longer accept [\d-x], [x-\d] or
# [\d-\d] as valid ranges.
ecma_3/RegExp/regress-375715-02: FAIL
js1_5/extensions/regress-351463-01: FAIL
# To be compatible with safari typeof a regexp yields 'function'; # To be compatible with safari typeof a regexp yields 'function';
# in firefox it yields 'object'. # in firefox it yields 'object'.

2
deps/v8/test/sputnik/README

@ -1,6 +1,6 @@
To run the sputniktests you must check out the test suite from To run the sputniktests you must check out the test suite from
googlecode.com. The test expectations are currently relative to googlecode.com. The test expectations are currently relative to
version 28. To get the tests run the following command within version 28. To get the tests run the following command within
v8/tests/sputnik/ v8/test/sputnik/
svn co http://sputniktests.googlecode.com/svn/trunk/ -r28 sputniktests svn co http://sputniktests.googlecode.com/svn/trunk/ -r28 sputniktests

32
deps/v8/tools/gyp/v8.gyp

@ -195,6 +195,38 @@
], ],
}, },
}, },
{
'target_name': 'v8_preparser',
'include_dirs': [
'../../include',
'../../src',
],
'sources': [
'../../src/allocation.cc',
'../../src/hashmap.cc',
'../../src/preparse-data.cc',
'../../src/preparser.cc',
'../../src/preparser-api.cc',
'../../src/scanner-base.cc',
'../../src/token.cc',
'../../src/unicode.cc',
],
'conditions': [
['OS=="win" and component=="shared_library"', {
'sources': [ '../../src/v8preparserdll-main.cc' ],
'defines': [ 'BUILDING_V8_SHARED' ],
'direct_dependent_settings': {
'defines': [ 'USING_V8_SHARED' ]
},
'type': '<(component)',
} , {
'type': 'none'
}],
['OS!="win"', {
'type': '<(library)'
}],
]
},
{ {
'target_name': 'v8_snapshot', 'target_name': 'v8_snapshot',
'type': '<(library)', 'type': '<(library)',

149
deps/v8/tools/logreader.js

@ -46,36 +46,6 @@ devtools.profiler.LogReader = function(dispatchTable) {
* @type {Array.<Object>} * @type {Array.<Object>}
*/ */
this.dispatchTable_ = dispatchTable; this.dispatchTable_ = dispatchTable;
this.dispatchTable_['alias'] =
{ parsers: [null, null], processor: this.processAlias_ };
this.dispatchTable_['repeat'] =
{ parsers: [parseInt, 'var-args'], processor: this.processRepeat_,
backrefs: true };
/**
* A key-value map for aliases. Translates short name -> full name.
* @type {Object}
*/
this.aliases_ = {};
/**
* A key-value map for previous address values.
* @type {Object}
*/
this.prevAddresses_ = {};
/**
* A key-value map for events than can be backreference-compressed.
* @type {Object}
*/
this.backRefsCommands_ = {};
this.initBackRefsCommands_();
/**
* Back references for decompression.
* @type {Array.<string>}
*/
this.backRefs_ = [];
/** /**
* Current line. * Current line.
@ -91,42 +61,6 @@ devtools.profiler.LogReader = function(dispatchTable) {
}; };
/**
* Creates a parser for an address entry.
*
* @param {string} addressTag Address tag to perform offset decoding.
* @return {function(string):number} Address parser.
*/
devtools.profiler.LogReader.prototype.createAddressParser = function(
addressTag) {
var self = this;
return (function (str) {
var value = parseInt(str, 16);
var firstChar = str.charAt(0);
if (firstChar == '+' || firstChar == '-') {
var addr = self.prevAddresses_[addressTag];
addr += value;
self.prevAddresses_[addressTag] = addr;
return addr;
} else if (firstChar != '0' || str.charAt(1) != 'x') {
self.prevAddresses_[addressTag] = value;
}
return value;
});
};
/**
* Expands an alias symbol, if applicable.
*
* @param {string} symbol Symbol to expand.
* @return {string} Expanded symbol, or the input symbol itself.
*/
devtools.profiler.LogReader.prototype.expandAlias = function(symbol) {
return symbol in this.aliases_ ? this.aliases_[symbol] : symbol;
};
/** /**
* Used for printing error messages. * Used for printing error messages.
* *
@ -233,68 +167,6 @@ devtools.profiler.LogReader.prototype.dispatchLogRow_ = function(fields) {
}; };
/**
* Decompresses a line if it was backreference-compressed.
*
* @param {string} line Possibly compressed line.
* @return {string} Decompressed line.
* @private
*/
devtools.profiler.LogReader.prototype.expandBackRef_ = function(line) {
var backRefPos;
// Filter out case when a regexp is created containing '#'.
if (line.charAt(line.length - 1) != '"'
&& (backRefPos = line.lastIndexOf('#')) != -1) {
var backRef = line.substr(backRefPos + 1);
var backRefIdx = parseInt(backRef, 10) - 1;
var colonPos = backRef.indexOf(':');
var backRefStart =
colonPos != -1 ? parseInt(backRef.substr(colonPos + 1), 10) : 0;
line = line.substr(0, backRefPos) +
this.backRefs_[backRefIdx].substr(backRefStart);
}
this.backRefs_.unshift(line);
if (this.backRefs_.length > 10) {
this.backRefs_.length = 10;
}
return line;
};
/**
* Initializes the map of backward reference compressible commands.
* @private
*/
devtools.profiler.LogReader.prototype.initBackRefsCommands_ = function() {
for (var event in this.dispatchTable_) {
var dispatch = this.dispatchTable_[event];
if (dispatch && dispatch.backrefs) {
this.backRefsCommands_[event] = true;
}
}
};
/**
* Processes alias log record. Adds an alias to a corresponding map.
*
* @param {string} symbol Short name.
* @param {string} expansion Long name.
* @private
*/
devtools.profiler.LogReader.prototype.processAlias_ = function(
symbol, expansion) {
if (expansion in this.dispatchTable_) {
this.dispatchTable_[symbol] = this.dispatchTable_[expansion];
if (expansion in this.backRefsCommands_) {
this.backRefsCommands_[symbol] = true;
}
} else {
this.aliases_[symbol] = expansion;
}
};
/** /**
* Processes log lines. * Processes log lines.
* *
@ -308,10 +180,6 @@ devtools.profiler.LogReader.prototype.processLog_ = function(lines) {
continue; continue;
} }
try { try {
if (line.charAt(0) == '#' ||
line.substr(0, line.indexOf(',')) in this.backRefsCommands_) {
line = this.expandBackRef_(line);
}
var fields = this.csvParser_.parseLine(line); var fields = this.csvParser_.parseLine(line);
this.dispatchLogRow_(fields); this.dispatchLogRow_(fields);
} catch (e) { } catch (e) {
@ -319,20 +187,3 @@ devtools.profiler.LogReader.prototype.processLog_ = function(lines) {
} }
} }
}; };
/**
* Processes repeat log record. Expands it according to calls count and
* invokes processing.
*
* @param {number} count Count.
* @param {Array.<string>} cmd Parsed command.
* @private
*/
devtools.profiler.LogReader.prototype.processRepeat_ = function(count, cmd) {
// Replace the repeat-prefixed command from backrefs list with a non-prefixed.
this.backRefs_[0] = cmd.join(',');
for (var i = 0; i < count; ++i) {
this.dispatchLogRow_(cmd);
}
};

14
deps/v8/tools/test.py

@ -729,6 +729,9 @@ class Variable(Expression):
if self.name in env: return ListSet([env[self.name]]) if self.name in env: return ListSet([env[self.name]])
else: return Nothing() else: return Nothing()
def Evaluate(self, env, defs):
return env[self.name]
class Outcome(Expression): class Outcome(Expression):
@ -1175,6 +1178,9 @@ def BuildOptions():
result.add_option("--nostress", result.add_option("--nostress",
help="Don't run crankshaft --always-opt --stress-op test", help="Don't run crankshaft --always-opt --stress-op test",
default=False, action="store_true") default=False, action="store_true")
result.add_option("--crankshaft",
help="Run with the --crankshaft flag",
default=False, action="store_true")
return result return result
@ -1209,6 +1215,11 @@ def ProcessOptions(options):
VARIANT_FLAGS = [['--stress-opt', '--always-opt']] VARIANT_FLAGS = [['--stress-opt', '--always-opt']]
if options.nostress: if options.nostress:
VARIANT_FLAGS = [[],['--nocrankshaft']] VARIANT_FLAGS = [[],['--nocrankshaft']]
if options.crankshaft:
if options.special_command:
options.special_command += " --crankshaft"
else:
options.special_command = "@--crankshaft"
return True return True
@ -1359,7 +1370,8 @@ def Main():
'mode': mode, 'mode': mode,
'system': utils.GuessOS(), 'system': utils.GuessOS(),
'arch': options.arch, 'arch': options.arch,
'simulator': options.simulator 'simulator': options.simulator,
'crankshaft': options.crankshaft
} }
test_list = root.ListTests([], path, context, mode) test_list = root.ListTests([], path, context, mode)
unclassified_tests += test_list unclassified_tests += test_list

62
deps/v8/tools/tickprocessor.js

@ -60,18 +60,17 @@ function inherits(childCtor, parentCtor) {
function SnapshotLogProcessor() { function SnapshotLogProcessor() {
devtools.profiler.LogReader.call(this, { devtools.profiler.LogReader.call(this, {
'code-creation': { 'code-creation': {
parsers: [null, this.createAddressParser('code'), parseInt, null], parsers: [null, parseInt, parseInt, null],
processor: this.processCodeCreation, backrefs: true }, processor: this.processCodeCreation },
'code-move': { parsers: [this.createAddressParser('code'), 'code-move': { parsers: [parseInt, parseInt],
this.createAddressParser('code-move-to')], processor: this.processCodeMove },
processor: this.processCodeMove, backrefs: true }, 'code-delete': { parsers: [parseInt],
'code-delete': { parsers: [this.createAddressParser('code')], processor: this.processCodeDelete },
processor: this.processCodeDelete, backrefs: true },
'function-creation': null, 'function-creation': null,
'function-move': null, 'function-move': null,
'function-delete': null, 'function-delete': null,
'snapshot-pos': { parsers: [this.createAddressParser('code'), parseInt], 'snapshot-pos': { parsers: [parseInt, parseInt],
processor: this.processSnapshotPosition, backrefs: true }}); processor: this.processSnapshotPosition }});
Profile.prototype.handleUnknownCode = function(operation, addr) { Profile.prototype.handleUnknownCode = function(operation, addr) {
var op = devtools.profiler.Profile.Operation; var op = devtools.profiler.Profile.Operation;
@ -95,8 +94,7 @@ inherits(SnapshotLogProcessor, devtools.profiler.LogReader);
SnapshotLogProcessor.prototype.processCodeCreation = function( SnapshotLogProcessor.prototype.processCodeCreation = function(
type, start, size, name) { type, start, size, name) {
var entry = this.profile_.addCode( var entry = this.profile_.addCode(type, name, start, size);
this.expandAlias(type), name, start, size);
}; };
@ -133,33 +131,28 @@ function TickProcessor(
'shared-library': { parsers: [null, parseInt, parseInt], 'shared-library': { parsers: [null, parseInt, parseInt],
processor: this.processSharedLibrary }, processor: this.processSharedLibrary },
'code-creation': { 'code-creation': {
parsers: [null, this.createAddressParser('code'), parseInt, null], parsers: [null, parseInt, parseInt, null],
processor: this.processCodeCreation, backrefs: true }, processor: this.processCodeCreation },
'code-move': { parsers: [this.createAddressParser('code'), 'code-move': { parsers: [parseInt, parseInt],
this.createAddressParser('code-move-to')], processor: this.processCodeMove },
processor: this.processCodeMove, backrefs: true }, 'code-delete': { parsers: [parseInt],
'code-delete': { parsers: [this.createAddressParser('code')], processor: this.processCodeDelete },
processor: this.processCodeDelete, backrefs: true }, 'function-creation': { parsers: [parseInt, parseInt],
'function-creation': { parsers: [this.createAddressParser('code'), processor: this.processFunctionCreation },
this.createAddressParser('function-obj')], 'function-move': { parsers: [parseInt, parseInt],
processor: this.processFunctionCreation, backrefs: true }, processor: this.processFunctionMove },
'function-move': { parsers: [this.createAddressParser('code'), 'function-delete': { parsers: [parseInt],
this.createAddressParser('code-move-to')], processor: this.processFunctionDelete },
processor: this.processFunctionMove, backrefs: true }, 'snapshot-pos': { parsers: [parseInt, parseInt],
'function-delete': { parsers: [this.createAddressParser('code')], processor: this.processSnapshotPosition },
processor: this.processFunctionDelete, backrefs: true }, 'tick': { parsers: [parseInt, parseInt, parseInt, parseInt, 'var-args'],
'snapshot-pos': { parsers: [this.createAddressParser('code'), parseInt], processor: this.processTick },
processor: this.processSnapshotPosition, backrefs: true },
'tick': { parsers: [this.createAddressParser('code'),
this.createAddressParser('stack'),
this.createAddressParser('func'), parseInt, 'var-args'],
processor: this.processTick, backrefs: true },
'heap-sample-begin': { parsers: [null, null, parseInt], 'heap-sample-begin': { parsers: [null, null, parseInt],
processor: this.processHeapSampleBegin }, processor: this.processHeapSampleBegin },
'heap-sample-end': { parsers: [null, null], 'heap-sample-end': { parsers: [null, null],
processor: this.processHeapSampleEnd }, processor: this.processHeapSampleEnd },
'heap-js-prod-item': { parsers: [null, 'var-args'], 'heap-js-prod-item': { parsers: [null, 'var-args'],
processor: this.processJSProducer, backrefs: true }, processor: this.processJSProducer },
// Ignored events. // Ignored events.
'profiler': null, 'profiler': null,
'heap-sample-stats': null, 'heap-sample-stats': null,
@ -294,8 +287,7 @@ TickProcessor.prototype.processSharedLibrary = function(
TickProcessor.prototype.processCodeCreation = function( TickProcessor.prototype.processCodeCreation = function(
type, start, size, name) { type, start, size, name) {
name = this.deserializedEntriesNames_[start] || name; name = this.deserializedEntriesNames_[start] || name;
var entry = this.profile_.addCode( var entry = this.profile_.addCode(type, name, start, size);
this.expandAlias(type), name, start, size);
}; };

2504
deps/v8/tools/visual_studio/v8_base.vcproj

File diff suppressed because it is too large

2398
deps/v8/tools/visual_studio/v8_base_arm.vcproj

File diff suppressed because it is too large

2344
deps/v8/tools/visual_studio/v8_base_x64.vcproj

File diff suppressed because it is too large

2
deps/v8/tools/visual_studio/v8_shell_sample.vcproj

@ -37,6 +37,7 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalIncludeDirectories="$(ProjectDir)\..\..\include"
/> />
<Tool <Tool
Name="VCManagedResourceCompilerTool" Name="VCManagedResourceCompilerTool"
@ -95,6 +96,7 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalIncludeDirectories="$(ProjectDir)\..\..\include"
/> />
<Tool <Tool
Name="VCManagedResourceCompilerTool" Name="VCManagedResourceCompilerTool"

2
deps/v8/tools/visual_studio/v8_shell_sample_arm.vcproj

@ -37,6 +37,7 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalIncludeDirectories="$(ProjectDir)\..\..\include"
/> />
<Tool <Tool
Name="VCManagedResourceCompilerTool" Name="VCManagedResourceCompilerTool"
@ -95,6 +96,7 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalIncludeDirectories="$(ProjectDir)\..\..\include"
/> />
<Tool <Tool
Name="VCManagedResourceCompilerTool" Name="VCManagedResourceCompilerTool"

4
deps/v8/tools/visual_studio/v8_shell_sample_x64.vcproj

@ -37,7 +37,8 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
/> AdditionalIncludeDirectories="$(ProjectDir)\..\..\include"
/>
<Tool <Tool
Name="VCManagedResourceCompilerTool" Name="VCManagedResourceCompilerTool"
/> />
@ -95,6 +96,7 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalIncludeDirectories="$(ProjectDir)\..\..\include"
/> />
<Tool <Tool
Name="VCManagedResourceCompilerTool" Name="VCManagedResourceCompilerTool"

Loading…
Cancel
Save