From ea700a8851023a1967083f22daa40f4c7a4366bf Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 16 Dec 2010 11:52:08 -0800 Subject: Upgrade V8 to 3.0.2 --- deps/v8/ChangeLog | 5 + deps/v8/include/v8-preparser.h | 7 + deps/v8/include/v8-profiler.h | 4 +- deps/v8/include/v8.h | 18 - deps/v8/preparser/preparser-process.cc | 26 +- deps/v8/samples/shell.cc | 6 + deps/v8/src/api.cc | 20 +- deps/v8/src/arm/full-codegen-arm.cc | 30 +- deps/v8/src/arm/lithium-arm.cc | 23 +- deps/v8/src/arm/lithium-arm.h | 11 +- deps/v8/src/arm/lithium-codegen-arm.cc | 7 +- deps/v8/src/arm/macro-assembler-arm.cc | 5 - deps/v8/src/array.js | 13 +- deps/v8/src/assembler.cc | 52 - deps/v8/src/assembler.h | 8 - deps/v8/src/ast-inl.h | 3 +- deps/v8/src/ast.cc | 11 +- deps/v8/src/ast.h | 22 +- deps/v8/src/checks.h | 2 - deps/v8/src/compiler.cc | 34 +- .../src/extensions/experimental/i18n-extension.cc | 263 -- .../src/extensions/experimental/i18n-extension.h | 64 - deps/v8/src/flag-definitions.h | 3 +- deps/v8/src/full-codegen.h | 2 +- deps/v8/src/heap-profiler.cc | 33 +- deps/v8/src/heap-profiler.h | 16 +- deps/v8/src/heap.cc | 18 +- deps/v8/src/heap.h | 4 +- deps/v8/src/hydrogen-instructions.h | 20 - deps/v8/src/hydrogen.cc | 1005 ++++---- deps/v8/src/hydrogen.h | 81 +- deps/v8/src/ia32/builtins-ia32.cc | 1 + deps/v8/src/ia32/full-codegen-ia32.cc | 27 +- deps/v8/src/ia32/lithium-codegen-ia32.cc | 64 - deps/v8/src/ia32/lithium-codegen-ia32.h | 1 - deps/v8/src/ia32/lithium-ia32.cc | 24 +- deps/v8/src/ia32/lithium-ia32.h | 13 +- deps/v8/src/ia32/macro-assembler-ia32.cc | 24 +- deps/v8/src/json.js | 22 +- deps/v8/src/lithium-allocator.cc | 356 ++- deps/v8/src/lithium-allocator.h | 83 +- deps/v8/src/log-utils.cc | 181 +- deps/v8/src/log-utils.h | 64 +- deps/v8/src/log.cc | 176 +- deps/v8/src/log.h | 103 +- deps/v8/src/math.js | 1 - deps/v8/src/objects.h | 12 +- deps/v8/src/parser.cc | 119 +- deps/v8/src/parser.h | 33 +- deps/v8/src/platform-linux.cc | 29 +- deps/v8/src/preparser-api.cc | 109 +- deps/v8/src/preparser.cc | 1 - deps/v8/src/profile-generator-inl.h | 14 +- deps/v8/src/profile-generator.cc | 373 ++- deps/v8/src/profile-generator.h | 41 +- deps/v8/src/regexp.js | 66 +- deps/v8/src/runtime-profiler.cc | 101 +- deps/v8/src/runtime.cc | 273 ++- deps/v8/src/scanner-base.cc | 32 +- deps/v8/src/scanner-base.h | 80 +- deps/v8/src/scanner.cc | 367 +-- deps/v8/src/scanner.h | 201 +- deps/v8/src/serialize.cc | 12 - deps/v8/src/spaces-inl.h | 14 +- deps/v8/src/spaces.cc | 2 +- deps/v8/src/spaces.h | 5 - deps/v8/src/string.js | 93 +- deps/v8/src/v8natives.js | 8 +- deps/v8/src/v8preparserdll-main.cc | 39 - deps/v8/src/version.cc | 4 +- deps/v8/src/x64/builtins-x64.cc | 2220 ++++++++--------- deps/v8/src/x64/full-codegen-x64.cc | 16 +- deps/v8/src/x64/lithium-x64.h | 5 + deps/v8/src/x64/macro-assembler-x64.cc | 25 - deps/v8/src/x64/macro-assembler-x64.h | 7 - deps/v8/test/cctest/cctest.status | 3 + deps/v8/test/cctest/test-heap-profiler.cc | 47 - deps/v8/test/cctest/test-log-utils.cc | 170 ++ deps/v8/test/cctest/test-parsing.cc | 303 +-- deps/v8/test/cctest/test-profile-generator.cc | 11 +- deps/v8/test/mjsunit/mjsunit.status | 5 - deps/v8/test/mjsunit/object-define-property.js | 32 - deps/v8/test/mjsunit/regress/regress-962.js | 53 - deps/v8/test/mjsunit/regress/regress-969.js | 127 - deps/v8/test/mjsunit/tools/logreader.js | 82 + deps/v8/test/mozilla/mozilla.status | 3 - deps/v8/test/sputnik/README | 2 +- deps/v8/tools/gyp/v8.gyp | 32 - deps/v8/tools/logreader.js | 149 ++ deps/v8/tools/test.py | 14 +- deps/v8/tools/tickprocessor.js | 62 +- deps/v8/tools/visual_studio/v8_base.vcproj | 2504 ++++++++++---------- deps/v8/tools/visual_studio/v8_base_arm.vcproj | 2398 +++++++++---------- deps/v8/tools/visual_studio/v8_base_x64.vcproj | 2344 +++++++++--------- deps/v8/tools/visual_studio/v8_shell_sample.vcproj | 2 - .../tools/visual_studio/v8_shell_sample_arm.vcproj | 2 - .../tools/visual_studio/v8_shell_sample_x64.vcproj | 4 +- 97 files changed, 7134 insertions(+), 8472 deletions(-) delete mode 100644 deps/v8/src/extensions/experimental/i18n-extension.cc delete mode 100644 deps/v8/src/extensions/experimental/i18n-extension.h delete mode 100644 deps/v8/src/v8preparserdll-main.cc delete mode 100644 deps/v8/test/mjsunit/regress/regress-962.js delete mode 100644 deps/v8/test/mjsunit/regress/regress-969.js create mode 100644 deps/v8/test/mjsunit/tools/logreader.js (limited to 'deps') diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 2debaa09fc..c1feb19223 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,8 @@ +2010-12-15: Version 3.0.2 + + Revert version 3.0.1 and patch 3.0.1.1. + + 2010-12-13: Version 3.0.1 Added support for an experimental internationalization API as an diff --git a/deps/v8/include/v8-preparser.h b/deps/v8/include/v8-preparser.h index 9425f7d467..68ce50223e 100644 --- a/deps/v8/include/v8-preparser.h +++ b/deps/v8/include/v8-preparser.h @@ -99,6 +99,13 @@ class UnicodeInputStream { // Returns the next Unicode code-point in the input, or a negative value when // there is no more input in the stream. 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; }; diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h index 675a229854..08f47ca36e 100644 --- a/deps/v8/include/v8-profiler.h +++ b/deps/v8/include/v8-profiler.h @@ -245,6 +245,7 @@ class V8EXPORT HeapGraphPath { class V8EXPORT HeapGraphNode { public: enum Type { + kInternal = 0, // For compatibility, will be removed. kHidden = 0, // Hidden node, may be filtered when shown to user. kArray = 1, // An array of elements. kString = 2, // A string. @@ -412,8 +413,7 @@ class V8EXPORT HeapProfiler { */ static const HeapSnapshot* TakeSnapshot( Handle title, - HeapSnapshot::Type type = HeapSnapshot::kFull, - ActivityControl* control = NULL); + HeapSnapshot::Type type = HeapSnapshot::kFull); }; diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 7fd063197e..8ecf63aebd 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -3281,24 +3281,6 @@ 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 --- diff --git a/deps/v8/preparser/preparser-process.cc b/deps/v8/preparser/preparser-process.cc index 26dfc42b53..80e83508e4 100644 --- a/deps/v8/preparser/preparser-process.cc +++ b/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) { - size_t actually_read = fread(buffer, 1, length, source); + size_t actually_read = fread(buffer, 1, length, stdin); return (actually_read == length); } @@ -150,25 +150,22 @@ class ScopedPointer { }; -// Preparse input and output result on stdout. -int PreParseIO(FILE* input) { +// Preparse stdin and output result on stdout. +int PreParseIO() { fprintf(stderr, "LOG: Enter parsing loop\n"); bool ok = true; - uint32_t length = ReadUInt32(input, &ok); - fprintf(stderr, "LOG: Input length: %d\n", length); + uint32_t length = ReadUInt32(stdin, &ok); if (!ok) return kErrorReading; ScopedPointer buffer(new uint8_t[length]); - if (!ReadBuffer(input, *buffer, length)) { + if (!ReadBuffer(stdin, *buffer, length)) { return kErrorReading; } UTF8InputStream input_buffer(*buffer, static_cast(length)); v8::PreParserData data = - v8::Preparse(&input_buffer, 64 * 1024 * sizeof(void*)); // NOLINT + v8::Preparse(&input_buffer, 64 * sizeof(void*)); // NOLINT if (data.stack_overflow()) { - fprintf(stderr, "LOG: Stack overflow\n"); - fflush(stderr); // Report stack overflow error/no-preparser-data. WriteUInt32(stdout, 0, &ok); if (!ok) return kErrorWriting; @@ -176,8 +173,6 @@ int PreParseIO(FILE* input) { } uint32_t size = data.size(); - fprintf(stderr, "LOG: Success, data size: %u\n", size); - fflush(stderr); WriteUInt32(stdout, size, &ok); if (!ok) return kErrorWriting; if (!WriteBuffer(stdout, data.data(), size)) { @@ -190,17 +185,10 @@ int PreParseIO(FILE* input) { 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; do { - status = v8::internal::PreParseIO(input); + status = v8::internal::PreParseIO(); } while (status == 0); fprintf(stderr, "EXIT: Failure %d\n", status); - fflush(stderr); return EXIT_FAILURE; } diff --git a/deps/v8/samples/shell.cc b/deps/v8/samples/shell.cc index 6b67df6c6c..460457552c 100644 --- a/deps/v8/samples/shell.cc +++ b/deps/v8/samples/shell.cc @@ -45,6 +45,7 @@ v8::Handle Quit(const v8::Arguments& args); v8::Handle Version(const v8::Arguments& args); v8::Handle ReadFile(const char* name); void ReportException(v8::TryCatch* handler); +void SetFlagsFromString(const char* flags); int RunMain(int argc, char* argv[]) { @@ -344,3 +345,8 @@ void ReportException(v8::TryCatch* try_catch) { } } } + + +void SetFlagsFromString(const char* flags) { + v8::V8::SetFlagsFromString(flags, strlen(flags)); +} diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index e169bd08a0..0ec8cf123e 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -1165,22 +1165,14 @@ void ObjectTemplate::SetInternalFieldCount(int value) { ScriptData* ScriptData::PreCompile(const char* input, int length) { - i::Utf8ToUC16CharacterStream stream( - reinterpret_cast(input), length); - return i::ParserApi::PreParse(&stream, NULL); + unibrow::Utf8InputBuffer<> buf(input, length); + return i::ParserApi::PreParse(i::Handle(), &buf, NULL); } ScriptData* ScriptData::PreCompile(v8::Handle source) { i::Handle str = Utils::OpenHandle(*source); - if (str->IsExternalTwoByteString()) { - i::ExternalTwoByteStringUC16CharacterStream stream( - i::Handle::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); - } + return i::ParserApi::PreParse(str, NULL, NULL); } @@ -4947,8 +4939,7 @@ const HeapSnapshot* HeapProfiler::FindSnapshot(unsigned uid) { const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle title, - HeapSnapshot::Type type, - ActivityControl* control) { + HeapSnapshot::Type type) { IsDeadCheck("v8::HeapProfiler::TakeSnapshot"); i::HeapSnapshot::Type internal_type = i::HeapSnapshot::kFull; switch (type) { @@ -4962,8 +4953,7 @@ const HeapSnapshot* HeapProfiler::TakeSnapshot(Handle title, UNREACHABLE(); } return reinterpret_cast( - i::HeapProfiler::TakeSnapshot( - *Utils::OpenHandle(*title), internal_type, control)); + i::HeapProfiler::TakeSnapshot(*Utils::OpenHandle(*title), internal_type)); } #endif // ENABLE_LOGGING_AND_PROFILING diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 921629d6f2..7e4a28042f 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -890,9 +890,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ bind(&update_each); __ mov(result_register(), r3); // Perform the assignment as if via '='. - { EffectContext context(this); - EmitAssignment(stmt->each(), stmt->AssignmentId()); - } + EmitAssignment(stmt->each()); // Generate code for the body of the loop. Visit(stmt->body()); @@ -1446,7 +1444,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { // For property compound assignments we need another deoptimization // point after the property load. if (property != NULL) { - PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); + PrepareForBailoutForId(expr->compound_bailout_id(), TOS_REG); } Token::Value op = expr->binary_op(); @@ -1538,7 +1536,7 @@ void FullCodeGenerator::EmitBinaryOp(Token::Value op, } -void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { +void FullCodeGenerator::EmitAssignment(Expression* expr) { // Invalid left-hand sides are rewritten to have a 'throw // ReferenceError' on the left-hand side. if (!expr->IsValidLeftHandSide()) { @@ -1586,8 +1584,6 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { break; } } - PrepareForBailoutForId(bailout_ast_id, TOS_REG); - context()->Plug(r0); } @@ -1661,6 +1657,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, } __ bind(&done); } + + context()->Plug(result_register()); } @@ -1703,10 +1701,10 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { __ push(ip); __ CallRuntime(Runtime::kToFastProperties, 1); __ pop(r0); - __ Drop(1); + context()->DropAndPlug(1, r0); + } else { + context()->Plug(r0); } - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); - context()->Plug(r0); } @@ -1747,10 +1745,10 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { __ push(ip); __ CallRuntime(Runtime::kToFastProperties, 1); __ pop(r0); - __ Drop(1); + context()->DropAndPlug(1, r0); + } else { + context()->Plug(r0); } - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); - context()->Plug(r0); } @@ -3202,8 +3200,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { { EffectContext context(this); EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), Token::ASSIGN); - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); - context.Plug(r0); } // For all contexts except EffectConstant We have the result on // top of the stack. @@ -3213,8 +3209,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { } else { EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), Token::ASSIGN); - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); - context()->Plug(r0); } break; case NAMED_PROPERTY: { @@ -3222,7 +3216,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ pop(r1); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { if (!context()->IsEffect()) { context()->PlugTOS(); @@ -3237,7 +3230,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ pop(r2); // Receiver. Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { if (!context()->IsEffect()) { context()->PlugTOS(); diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index ef982f1076..682c448fd5 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -460,6 +460,12 @@ 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) { GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to); } @@ -1351,9 +1357,6 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { return AssignEnvironment(DefineAsRegister(result)); case kMathSqrt: return DefineSameAsFirst(result); - case kMathPowHalf: - Abort("MathPowHalf LUnaryMathOperation not implemented"); - return NULL; default: UNREACHABLE(); return NULL; @@ -1551,12 +1554,6 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { } -LInstruction* LChunkBuilder::DoPower(HPower* instr) { - Abort("LPower instruction not implemented on ARM"); - return NULL; -} - - LInstruction* LChunkBuilder::DoCompare(HCompare* instr) { Token::Value op = instr->token(); if (instr->left()->representation().IsInteger32()) { @@ -1691,13 +1688,11 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) { } else if (from.IsDouble()) { if (to.IsTagged()) { LOperand* value = UseRegister(instr->value()); - LOperand* temp1 = TempRegister(); - LOperand* temp2 = TempRegister(); + LOperand* temp = TempRegister(); - // Make sure that the temp and result_temp registers are - // different. + // Make sure that temp and result_temp are different registers. LUnallocated* result_temp = TempRegister(); - LInstruction* result = new LNumberTagD(value, temp1, temp2); + LInstruction* result = new LNumberTagD(value, temp); Define(result, result_temp); return AssignPointerMap(result); } else { diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index 048d4fc80b..0d5ba0f73f 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -1395,17 +1395,15 @@ class LNumberTagI: public LUnaryOperation { class LNumberTagD: public LUnaryOperation { public: - LNumberTagD(LOperand* value, LOperand* temp1, LOperand* temp2) - : LUnaryOperation(value), temp1_(temp1), temp2_(temp2) { } + explicit LNumberTagD(LOperand* value, LOperand* temp) + : LUnaryOperation(value), temp_(temp) { } DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d") - LOperand* temp1() const { return temp1_; } - LOperand* temp2() const { return temp2_; } + LOperand* temp() const { return temp_; } private: - LOperand* temp1_; - LOperand* temp2_; + LOperand* temp_; }; @@ -1889,6 +1887,7 @@ class LChunk: public ZoneObject { LGap* GetGapAt(int index) const; bool IsGapAt(int index) const; int NearestGapPos(int index) const; + int NearestNextGapPos(int index) const; void MarkEmptyBlocks(); const ZoneList* pointer_maps() const { return &pointer_maps_; } LLabel* GetLabel(int block_id) const { diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index 5b3f23bb02..db8037a62d 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -136,7 +136,7 @@ bool LCodeGen::GeneratePrologue() { Label loop; __ bind(&loop); __ push(r2); - __ sub(r0, r0, Operand(1), SetCC); + __ sub(r0, r0, Operand(1)); __ b(ne, &loop); } else { __ sub(sp, sp, Operand(slots * kPointerSize)); @@ -1733,14 +1733,13 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { DoubleRegister input_reg = ToDoubleRegister(instr->input()); Register reg = ToRegister(instr->result()); - Register temp1 = ToRegister(instr->temp1()); - Register temp2 = ToRegister(instr->temp2()); + Register tmp = ToRegister(instr->temp()); Register scratch = r9; DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); if (FLAG_inline_new) { __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex); - __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry()); + __ AllocateHeapNumber(reg, tmp, ip, scratch, deferred->entry()); } else { __ jmp(deferred->entry()); } diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 6effec1e31..6ad8918f17 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -1060,14 +1060,9 @@ void MacroAssembler::AllocateInNewSpace(Register object_size, 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(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. // The values must be adjacent in memory to allow the use of LDM. diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index a805157b13..c5ff505c1d 100644 --- a/deps/v8/src/array.js +++ b/deps/v8/src/array.js @@ -159,11 +159,9 @@ function Join(array, length, separator, convert) { } -function ConvertToString(x) { - if (IS_STRING(x)) return x; - if (IS_NUMBER(x)) return %_NumberToString(x); - if (IS_BOOLEAN(x)) return x ? 'true' : 'false'; - return (IS_NULL_OR_UNDEFINED(x)) ? '' : %ToString(%DefaultString(x)); +function ConvertToString(e) { + if (e == null) return ''; + else return ToString(e); } @@ -367,13 +365,14 @@ function ArrayJoin(separator) { if (IS_UNDEFINED(separator)) { separator = ','; } else if (!IS_STRING(separator)) { - separator = NonStringToString(separator); + separator = ToString(separator); } var result = %_FastAsciiArrayJoin(this, separator); if (!IS_UNDEFINED(result)) return result; - return Join(this, TO_UINT32(this.length), separator, ConvertToString); + var length = TO_UINT32(this.length); + return Join(this, length, separator, ConvertToString); } diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index 3b44efa9c0..d71a35a4a5 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -66,7 +66,6 @@ namespace internal { const double DoubleConstant::min_int = kMinInt; const double DoubleConstant::one_half = 0.5; -const double DoubleConstant::negative_infinity = -V8_INFINITY; // ----------------------------------------------------------------------------- @@ -723,12 +722,6 @@ ExternalReference ExternalReference::address_of_one_half() { } -ExternalReference ExternalReference::address_of_negative_infinity() { - return ExternalReference(reinterpret_cast( - const_cast(&DoubleConstant::negative_infinity))); -} - - #ifndef V8_INTERPRETED_REGEXP ExternalReference ExternalReference::re_check_stack_guard_state() { @@ -800,51 +793,6 @@ 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(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) { if (x == y) return EQUAL; return x < y ? LESS : GREATER; diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index 72a9b15380..82c9fc24c5 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -50,7 +50,6 @@ class DoubleConstant: public AllStatic { public: static const double min_int; static const double one_half; - static const double negative_infinity; }; @@ -540,8 +539,6 @@ class ExternalReference BASE_EMBEDDED { static ExternalReference double_fp_operation(Token::Value operation); 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_limit_address(); @@ -552,7 +549,6 @@ class ExternalReference BASE_EMBEDDED { // Static variables containing common double constants. static ExternalReference address_of_min_int(); static ExternalReference address_of_one_half(); - static ExternalReference address_of_negative_infinity(); Address address() const {return reinterpret_cast
(address_);} @@ -714,10 +710,6 @@ static inline int NumberOfBitsSet(uint32_t x) { 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 #endif // V8_ASSEMBLER_H_ diff --git a/deps/v8/src/ast-inl.h b/deps/v8/src/ast-inl.h index d1017121da..e88156d6e4 100644 --- a/deps/v8/src/ast-inl.h +++ b/deps/v8/src/ast-inl.h @@ -94,8 +94,7 @@ ForStatement::ForStatement(ZoneStringList* labels) ForInStatement::ForInStatement(ZoneStringList* labels) - : IterationStatement(labels), each_(NULL), enumerable_(NULL), - assignment_id_(GetNextId()) { + : IterationStatement(labels), each_(NULL), enumerable_(NULL) { } diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index 7ddb01e3e4..c1ea0a8b3d 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -125,18 +125,17 @@ Assignment::Assignment(Token::Value op, target_(target), value_(value), pos_(pos), - binary_operation_(NULL), - compound_load_id_(kNoNumber), - assignment_id_(GetNextId()), + compound_bailout_id_(kNoNumber), block_start_(false), block_end_(false), is_monomorphic_(false), receiver_types_(NULL) { ASSERT(Token::IsAssignmentOp(op)); + binary_operation_ = is_compound() + ? new BinaryOperation(binary_op(), target, value, pos + 1) + : NULL; if (is_compound()) { - binary_operation_ = - new BinaryOperation(binary_op(), target, value, pos + 1); - compound_load_id_ = GetNextId(); + compound_bailout_id_ = GetNextId(); } } diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index c33838e011..cdf456f67b 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -435,6 +435,7 @@ class IterationStatement: public BreakableStatement { virtual IterationStatement* AsIterationStatement() { return this; } Statement* body() const { return body_; } + void set_body(Statement* stmt) { body_ = stmt; } // Bailout support. int OsrEntryId() const { return osr_entry_id_; } @@ -531,8 +532,11 @@ class ForStatement: public IterationStatement { } Statement* init() const { return init_; } + void set_init(Statement* stmt) { init_ = stmt; } Expression* cond() const { return cond_; } + void set_cond(Expression* expr) { cond_ = expr; } Statement* next() const { return next_; } + void set_next(Statement* stmt) { next_ = stmt; } bool may_have_function_literal() const { return may_have_function_literal_; @@ -575,13 +579,11 @@ class ForInStatement: public IterationStatement { Expression* enumerable() const { return enumerable_; } // Bailout support. - int AssignmentId() const { return assignment_id_; } virtual int ContinueId() const { return EntryId(); } private: Expression* each_; Expression* enumerable_; - int assignment_id_; }; @@ -746,7 +748,9 @@ class IfStatement: public Statement { Expression* condition() const { return condition_; } Statement* then_statement() const { return then_statement_; } + void set_then_statement(Statement* stmt) { then_statement_ = stmt; } Statement* else_statement() const { return else_statement_; } + void set_else_statement(Statement* stmt) { else_statement_ = stmt; } private: Expression* condition_; @@ -1428,9 +1432,7 @@ class IncrementOperation: public Expression { class CountOperation: public Expression { public: CountOperation(bool is_prefix, IncrementOperation* increment, int pos) - : is_prefix_(is_prefix), increment_(increment), pos_(pos), - assignment_id_(GetNextId()) { - } + : is_prefix_(is_prefix), increment_(increment), pos_(pos) { } DECLARE_NODE_TYPE(CountOperation) @@ -1450,14 +1452,10 @@ class CountOperation: public Expression { virtual bool IsInlineable() const; - // Bailout support. - int AssignmentId() const { return assignment_id_; } - private: bool is_prefix_; IncrementOperation* increment_; int pos_; - int assignment_id_; }; @@ -1587,8 +1585,7 @@ class Assignment: public Expression { } // Bailout support. - int CompoundLoadId() const { return compound_load_id_; } - int AssignmentId() const { return assignment_id_; } + int compound_bailout_id() const { return compound_bailout_id_; } private: Token::Value op_; @@ -1596,8 +1593,7 @@ class Assignment: public Expression { Expression* value_; int pos_; BinaryOperation* binary_operation_; - int compound_load_id_; - int assignment_id_; + int compound_bailout_id_; bool block_start_; bool block_end_; diff --git a/deps/v8/src/checks.h b/deps/v8/src/checks.h index 8d13d65f6e..aa557f00bc 100644 --- a/deps/v8/src/checks.h +++ b/deps/v8/src/checks.h @@ -231,8 +231,6 @@ static inline void CheckNonEqualsHelper(const char* file, #define CHECK_GT(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 diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index e4864e4801..59a684c69f 100755 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -116,26 +116,13 @@ static bool AlwaysFullCompiler() { static void FinishOptimization(Handle function, int64_t start) { int opt_count = function->shared()->opt_count(); function->shared()->set_opt_count(opt_count + 1); + if (!FLAG_trace_opt) return; + double ms = static_cast(OS::Ticks() - start) / 1000; - if (FLAG_trace_opt) { - PrintF("[optimizing: "); - function->PrintName(); - PrintF(" / %" V8PRIxPTR, reinterpret_cast(*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); - } + PrintF("[optimizing: "); + function->PrintName(); + PrintF(" / %" V8PRIxPTR, reinterpret_cast(*function)); + PrintF(" - took %0.3f ms]\n", ms); } @@ -474,14 +461,7 @@ Handle Compiler::Compile(Handle source, ScriptDataImpl* pre_data = input_pre_data; if (pre_data == NULL && source_length >= FLAG_min_preparse_length) { - if (source->IsExternalTwoByteString()) { - ExternalTwoByteStringUC16CharacterStream stream( - Handle::cast(source), 0, source->length()); - pre_data = ParserApi::PartialPreParse(&stream, extension); - } else { - GenericStringUC16CharacterStream stream(source, 0, source->length()); - pre_data = ParserApi::PartialPreParse(&stream, extension); - } + pre_data = ParserApi::PartialPreParse(source, NULL, extension); } // Create a script object describing the script to be compiled. diff --git a/deps/v8/src/extensions/experimental/i18n-extension.cc b/deps/v8/src/extensions/experimental/i18n-extension.cc deleted file mode 100644 index 22a1c912d0..0000000000 --- a/deps/v8/src/extensions/experimental/i18n-extension.cc +++ /dev/null @@ -1,263 +0,0 @@ -// 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 -#include - -#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 I18NExtension::GetNativeFunction( - v8::Handle 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::Handle 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 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 I18NExtension::JSAvailableLocales( - const v8::Arguments& args) { - v8::Local 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 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 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 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(result.getBuffer()), result.length()); - } - - return v8::Undefined(); -} - -v8::Handle I18NExtension::JSDisplayLanguage( - const v8::Arguments& args) { - return GetDisplayItem(args, "language"); -} - -v8::Handle I18NExtension::JSDisplayScript( - const v8::Arguments& args) { - return GetDisplayItem(args, "script"); -} - -v8::Handle I18NExtension::JSDisplayRegion( - const v8::Arguments& args) { - return GetDisplayItem(args, "region"); -} - -v8::Handle 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 diff --git a/deps/v8/src/extensions/experimental/i18n-extension.h b/deps/v8/src/extensions/experimental/i18n-extension.h deleted file mode 100644 index 629332babb..0000000000 --- a/deps/v8/src/extensions/experimental/i18n-extension.h +++ /dev/null @@ -1,64 +0,0 @@ -// 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 - -namespace v8 { -namespace internal { - - -class I18NExtension : public v8::Extension { - public: - I18NExtension() : v8::Extension("v8/i18n", kSource) {} - virtual v8::Handle GetNativeFunction( - v8::Handle name); - - // Implementations of window.Locale methods. - static v8::Handle JSLocale(const v8::Arguments& args); - static v8::Handle JSAvailableLocales(const v8::Arguments& args); - static v8::Handle JSMaximizedLocale(const v8::Arguments& args); - static v8::Handle JSMinimizedLocale(const v8::Arguments& args); - static v8::Handle JSDisplayLanguage(const v8::Arguments& args); - static v8::Handle JSDisplayScript(const v8::Arguments& args); - static v8::Handle JSDisplayRegion(const v8::Arguments& args); - static v8::Handle 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_ diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index fc5fe1ee0f..37653a4a15 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -194,7 +194,6 @@ DEFINE_bool(mask_constants_with_cookie, // codegen.cc DEFINE_bool(lazy, true, "use lazy compilation") 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_eagerly, false, "be more eager when adaptively optimizing") DEFINE_bool(always_opt, false, "always try to optimize functions") @@ -457,6 +456,8 @@ DEFINE_bool(log_snapshot_positions, false, "log positions of (de)serialized objects in the snapshot.") DEFINE_bool(log_suspect, false, "Log suspect operations.") 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, "Log statistical profiling information (implies --log-code).") DEFINE_bool(prof_auto, true, diff --git a/deps/v8/src/full-codegen.h b/deps/v8/src/full-codegen.h index e0fd192a21..8d9fe2d332 100644 --- a/deps/v8/src/full-codegen.h +++ b/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 // is expected in the accumulator. - void EmitAssignment(Expression* expr, int bailout_ast_id); + void EmitAssignment(Expression* expr); // Complete a variable assignment. The right-hand-side value is expected // in the accumulator. diff --git a/deps/v8/src/heap-profiler.cc b/deps/v8/src/heap-profiler.cc index 6700d38b25..91ac9867a2 100644 --- a/deps/v8/src/heap-profiler.cc +++ b/deps/v8/src/heap-profiler.cc @@ -348,34 +348,27 @@ void HeapProfiler::TearDown() { #ifdef ENABLE_LOGGING_AND_PROFILING -HeapSnapshot* HeapProfiler::TakeSnapshot(const char* name, - int type, - v8::ActivityControl* control) { +HeapSnapshot* HeapProfiler::TakeSnapshot(const char* name, int type) { ASSERT(singleton_ != NULL); - return singleton_->TakeSnapshotImpl(name, type, control); + return singleton_->TakeSnapshotImpl(name, type); } -HeapSnapshot* HeapProfiler::TakeSnapshot(String* name, - int type, - v8::ActivityControl* control) { +HeapSnapshot* HeapProfiler::TakeSnapshot(String* name, int type) { ASSERT(singleton_ != NULL); - return singleton_->TakeSnapshotImpl(name, type, control); + return singleton_->TakeSnapshotImpl(name, type); } -HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name, - int type, - v8::ActivityControl* control) { +HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name, int type) { Heap::CollectAllGarbage(true); HeapSnapshot::Type s_type = static_cast(type); HeapSnapshot* result = snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++); - bool generation_completed = true; switch (s_type) { case HeapSnapshot::kFull: { - HeapSnapshotGenerator generator(result, control); - generation_completed = generator.GenerateSnapshot(); + HeapSnapshotGenerator generator(result); + generator.GenerateSnapshot(); break; } case HeapSnapshot::kAggregated: { @@ -388,19 +381,13 @@ HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name, default: UNREACHABLE(); } - if (!generation_completed) { - delete result; - result = NULL; - } - snapshots_->SnapshotGenerationFinished(result); + snapshots_->SnapshotGenerationFinished(); return result; } -HeapSnapshot* HeapProfiler::TakeSnapshotImpl(String* name, - int type, - v8::ActivityControl* control) { - return TakeSnapshotImpl(snapshots_->GetName(name), type, control); +HeapSnapshot* HeapProfiler::TakeSnapshotImpl(String* name, int type) { + return TakeSnapshotImpl(snapshots_->GetName(name), type); } diff --git a/deps/v8/src/heap-profiler.h b/deps/v8/src/heap-profiler.h index 31d0aff02f..2ef081ee29 100644 --- a/deps/v8/src/heap-profiler.h +++ b/deps/v8/src/heap-profiler.h @@ -56,12 +56,8 @@ class HeapProfiler { static void TearDown(); #ifdef ENABLE_LOGGING_AND_PROFILING - static HeapSnapshot* TakeSnapshot(const char* name, - int type, - v8::ActivityControl* control); - static HeapSnapshot* TakeSnapshot(String* name, - int type, - v8::ActivityControl* control); + static HeapSnapshot* TakeSnapshot(const char* name, int type); + static HeapSnapshot* TakeSnapshot(String* name, int type); static int GetSnapshotsCount(); static HeapSnapshot* GetSnapshot(int index); static HeapSnapshot* FindSnapshot(unsigned uid); @@ -79,12 +75,8 @@ class HeapProfiler { private: HeapProfiler(); ~HeapProfiler(); - HeapSnapshot* TakeSnapshotImpl(const char* name, - int type, - v8::ActivityControl* control); - HeapSnapshot* TakeSnapshotImpl(String* name, - int type, - v8::ActivityControl* control); + HeapSnapshot* TakeSnapshotImpl(const char* name, int type); + HeapSnapshot* TakeSnapshotImpl(String* name, int type); HeapSnapshotsCollection* snapshots_; unsigned next_snapshot_uid_; diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index ccf9b47a35..0497ad5f6a 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -3757,21 +3757,14 @@ bool Heap::IdleNotification() { static const int kIdlesBeforeScavenge = 4; static const int kIdlesBeforeMarkSweep = 7; static const int kIdlesBeforeMarkCompact = 8; - static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1; - static const int kGCsBetweenCleanup = 4; static int number_idle_notifications = 0; static int last_gc_count = gc_count_; bool uncommit = true; bool finished = false; - // Reset the number of idle notifications received when a number of - // 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); + if (last_gc_count == gc_count_) { + number_idle_notifications++; } else { number_idle_notifications = 0; last_gc_count = gc_count_; @@ -3786,6 +3779,7 @@ bool Heap::IdleNotification() { } new_space_.Shrink(); last_gc_count = gc_count_; + } else if (number_idle_notifications == kIdlesBeforeMarkSweep) { // Before doing the mark-sweep collections we clear the // compilation cache to avoid hanging on to source code and @@ -3800,6 +3794,7 @@ bool Heap::IdleNotification() { CollectAllGarbage(true); new_space_.Shrink(); last_gc_count = gc_count_; + number_idle_notifications = 0; finished = true; } else if (contexts_disposed_ > 0) { @@ -3818,11 +3813,6 @@ bool Heap::IdleNotification() { number_idle_notifications = 0; 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 diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index 06b3ee4689..e4dcb4ad7d 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -1119,9 +1119,9 @@ class Heap : public AllStatic { static int contexts_disposed_; #if defined(V8_TARGET_ARCH_X64) - static const int kMaxObjectSizeInNewSpace = 1024*KB; -#else static const int kMaxObjectSizeInNewSpace = 512*KB; +#else + static const int kMaxObjectSizeInNewSpace = 256*KB; #endif static NewSpace new_space_; diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index 34316319aa..ff1ab1a36e 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -77,7 +77,6 @@ class LChunkBuilder; // HLoadKeyedFastElement // HLoadKeyedGeneric // HLoadNamedGeneric -// HPower // HStoreNamed // HStoreNamedField // HStoreNamedGeneric @@ -224,7 +223,6 @@ class LChunkBuilder; V(ObjectLiteral) \ V(OsrEntry) \ V(Parameter) \ - V(Power) \ V(PushArgument) \ V(RegExpLiteral) \ V(Return) \ @@ -1379,7 +1377,6 @@ class HUnaryMathOperation: public HUnaryOperation { SetFlag(kFlexibleRepresentation); break; case kMathSqrt: - case kMathPowHalf: default: set_representation(Representation::Double()); } @@ -1398,7 +1395,6 @@ class HUnaryMathOperation: public HUnaryOperation { case kMathRound: case kMathCeil: case kMathSqrt: - case kMathPowHalf: return Representation::Double(); break; case kMathAbs: @@ -2188,22 +2184,6 @@ 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 { public: HAdd(HValue* left, HValue* right) : HArithmeticBinaryOperation(left, right) { diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index bc49f06a20..0e8c4760dd 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -1983,9 +1983,6 @@ void HGraph::InsertRepresentationChanges() { AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) : owner_(owner), kind_(kind), outer_(owner->ast_context()) { owner->set_ast_context(this); // Push. -#ifdef DEBUG - original_count_ = owner->environment()->total_count(); -#endif } @@ -1994,101 +1991,6 @@ AstContext::~AstContext() { } -EffectContext::~EffectContext() { - ASSERT(owner()->HasStackOverflow() || - !owner()->subgraph()->HasExit() || - owner()->environment()->total_count() == original_count_); -} - - -ValueContext::~ValueContext() { - ASSERT(owner()->HasStackOverflow() || - !owner()->subgraph()->HasExit() || - owner()->environment()->total_count() == original_count_ + 1); -} - - -void EffectContext::ReturnValue(HValue* value) { - // The value is simply ignored. -} - - -void ValueContext::ReturnValue(HValue* value) { - // The value is tracked in the bailout environment, and communicated - // through the environment as the result of the expression. - owner()->Push(value); -} - - -void TestContext::ReturnValue(HValue* value) { - BuildBranch(value); -} - - -void EffectContext::ReturnInstruction(HInstruction* instr, int ast_id) { - owner()->AddInstruction(instr); - if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); -} - - -void ValueContext::ReturnInstruction(HInstruction* instr, int ast_id) { - owner()->AddInstruction(instr); - owner()->Push(instr); - if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); -} - - -void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) { - HGraphBuilder* builder = owner(); - builder->AddInstruction(instr); - // We expect a simulate after every expression with side effects, though - // this one isn't actually needed (and wouldn't work if it were targeted). - if (instr->HasSideEffects()) { - builder->Push(instr); - builder->AddSimulate(ast_id); - builder->Pop(); - } - BuildBranch(instr); -} - - -void TestContext::BuildBranch(HValue* value) { - HGraphBuilder* builder = owner(); - HBasicBlock* materialize_true = builder->graph()->CreateBasicBlock(); - HBasicBlock* materialize_false = builder->graph()->CreateBasicBlock(); - HBranch* branch = new HBranch(materialize_true, materialize_false, value); - builder->CurrentBlock()->Finish(branch); - - HBasicBlock* true_block = if_true(); - HValue* true_value = invert_true() - ? builder->graph()->GetConstantFalse() - : builder->graph()->GetConstantTrue(); - materialize_true->set_inverted(invert_true()); - true_block->set_deopt_predecessor(materialize_true); - - if (true_block->IsInlineReturnTarget()) { - materialize_true->AddLeaveInlined(true_value, true_block); - } else { - materialize_true->last_environment()->Push(true_value); - materialize_true->Goto(true_block); - } - - HBasicBlock* false_block = if_false(); - HValue* false_value = invert_false() - ? builder->graph()->GetConstantTrue() - : builder->graph()->GetConstantFalse(); - materialize_false->set_inverted(invert_false()); - false_block->set_deopt_predecessor(materialize_false); - - if (false_block->IsInlineReturnTarget()) { - materialize_false->AddLeaveInlined(false_value, false_block); - } else { - materialize_false->last_environment()->Push(false_value); - materialize_false->Goto(false_block); - } - builder->subgraph()->set_exit_block(NULL); -} - // HGraphBuilder infrastructure for bailing out and checking bailouts. #define BAILOUT(reason) \ @@ -2159,14 +2061,55 @@ void HGraphBuilder::Bailout(const char* reason) { void HGraphBuilder::VisitForEffect(Expression* expr) { - EffectContext for_effect(this); - Visit(expr); +#ifdef DEBUG + int original_count = environment()->total_count(); +#endif + BinaryOperation* binary_op = expr->AsBinaryOperation(); + + // We use special casing for expression types not handled properly by our + // usual trick of pretending they're in a value context and cleaning up + // later. + if (binary_op != NULL && binary_op->op() == Token::COMMA) { + VISIT_FOR_EFFECT(binary_op->left()); + VISIT_FOR_EFFECT(binary_op->right()); + } else { + { EffectContext for_effect(this); + Visit(expr); + } + if (HasStackOverflow() || !subgraph()->HasExit()) return; + // Discard return value. + Pop(); + // TODO(kasperl): Try to improve the way we compute the last added + // instruction. The NULL check makes me uncomfortable. + HValue* last = subgraph()->exit_block()->GetLastInstruction(); + // We need to ensure we emit a simulate after inlined functions in an + // effect context, to avoid having a bailout target the fictional + // environment with the return value on top. + if ((last != NULL && last->HasSideEffects()) || + subgraph()->exit_block()->IsInlineReturnTarget()) { + AddSimulate(expr->id()); + } + } + + ASSERT(environment()->total_count() == original_count); } void HGraphBuilder::VisitForValue(Expression* expr) { - ValueContext for_value(this); - Visit(expr); +#ifdef DEBUG + int original_height = environment()->values()->length(); +#endif + { ValueContext for_value(this); + Visit(expr); + } + if (HasStackOverflow() || !subgraph()->HasExit()) return; + // TODO(kasperl): Try to improve the way we compute the last added + // instruction. The NULL check makes me uncomfortable. + HValue* last = subgraph()->exit_block()->GetLastInstruction(); + if (last != NULL && last->HasSideEffects()) { + AddSimulate(expr->id()); + } + ASSERT(environment()->values()->length() == original_height + 1); } @@ -2301,7 +2244,99 @@ void HGraphBuilder::VisitForControl(Expression* expr, bool invert_false) { TestContext for_test(this, true_block, false_block, invert_true, invert_false); - Visit(expr); + BinaryOperation* binary_op = expr->AsBinaryOperation(); + UnaryOperation* unary_op = expr->AsUnaryOperation(); + + if (unary_op != NULL && unary_op->op() == Token::NOT) { + VisitForControl(unary_op->expression(), + false_block, + true_block, + !invert_false, + !invert_true); + } else if (binary_op != NULL && binary_op->op() == Token::AND) { + // Translate left subexpression. + HBasicBlock* eval_right = graph()->CreateBasicBlock(); + VisitForControl(binary_op->left(), + eval_right, + false_block, + false, + invert_false); + if (HasStackOverflow()) return; + eval_right->SetJoinId(binary_op->left()->id()); + + // Translate right subexpression. + eval_right->last_environment()->Pop(); + subgraph()->set_exit_block(eval_right); + VisitForControl(binary_op->right(), + true_block, + false_block, + invert_true, + invert_false); + } else if (binary_op != NULL && binary_op->op() == Token::OR) { + // Translate left subexpression. + HBasicBlock* eval_right = graph()->CreateBasicBlock(); + VisitForControl(binary_op->left(), + true_block, + eval_right, + invert_true, + false); + if (HasStackOverflow()) return; + eval_right->SetJoinId(binary_op->left()->id()); + + // Translate right subexpression + eval_right->last_environment()->Pop(); + subgraph()->set_exit_block(eval_right); + VisitForControl(binary_op->right(), + true_block, + false_block, + invert_true, + invert_false); + } else { +#ifdef DEBUG + int original_length = environment()->values()->length(); +#endif + // TODO(kmillikin): Refactor to avoid. This code is duplicated from + // VisitForValue, except without pushing a value context on the + // expression context stack. + Visit(expr); + if (HasStackOverflow() || !subgraph()->HasExit()) return; + HValue* last = subgraph()->exit_block()->GetLastInstruction(); + if (last != NULL && last->HasSideEffects()) { + AddSimulate(expr->id()); + } + ASSERT(environment()->values()->length() == original_length + 1); + HValue* value = Pop(); + HBasicBlock* materialize_true = graph()->CreateBasicBlock(); + HBasicBlock* materialize_false = graph()->CreateBasicBlock(); + CurrentBlock()->Finish(new HBranch(materialize_true, + materialize_false, + value)); + HValue* true_value = invert_true + ? graph()->GetConstantFalse() + : graph()->GetConstantTrue(); + materialize_true->set_inverted(invert_true); + true_block->set_deopt_predecessor(materialize_true); + + if (true_block->IsInlineReturnTarget()) { + materialize_true->AddLeaveInlined(true_value, true_block); + } else { + materialize_true->last_environment()->Push(true_value); + materialize_true->Goto(true_block); + } + HValue* false_value = invert_false + ? graph()->GetConstantTrue() + : graph()->GetConstantFalse(); + materialize_false->set_inverted(invert_false); + false_block->set_deopt_predecessor(materialize_false); + + if (false_block->IsInlineReturnTarget()) { + materialize_false->AddLeaveInlined(false_value, false_block); + } else { + materialize_false->last_environment()->Push(false_value); + materialize_false->Goto(false_block); + } + subgraph()->set_exit_block(NULL); + } } @@ -2337,6 +2372,12 @@ void HGraphBuilder::PushAndAdd(HInstruction* instr) { } +void HGraphBuilder::PushAndAdd(HInstruction* instr, int position) { + instr->set_position(position); + PushAndAdd(instr); +} + + void HGraphBuilder::PushArgumentsForStubCall(int argument_count) { const int kMaxStubArguments = 4; ASSERT_GE(kMaxStubArguments, argument_count); @@ -2351,7 +2392,7 @@ void HGraphBuilder::PushArgumentsForStubCall(int argument_count) { } -void HGraphBuilder::ProcessCall(HCall* call) { +void HGraphBuilder::ProcessCall(HCall* call, int source_position) { for (int i = call->argument_count() - 1; i >= 0; --i) { HValue* value = Pop(); HPushArgument* push = new HPushArgument(value); @@ -2361,6 +2402,8 @@ void HGraphBuilder::ProcessCall(HCall* call) { for (int i = 0; i < call->argument_count(); ++i) { AddInstruction(call->PushArgumentAt(i)); } + + PushAndAdd(call, source_position); } @@ -2871,9 +2914,7 @@ void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { Handle shared_info = Compiler::BuildFunctionInfo(expr, graph_->info()->script()); CHECK_BAILOUT; - HFunctionLiteral* instr = - new HFunctionLiteral(shared_info, expr->pretenure()); - ast_context()->ReturnInstruction(instr, expr->id()); + PushAndAdd(new HFunctionLiteral(shared_info, expr->pretenure())); } @@ -2894,21 +2935,20 @@ void HGraphBuilder::VisitConditional(Conditional* expr) { ADD_TO_SUBGRAPH(then_graph, expr->then_expression()); ADD_TO_SUBGRAPH(else_graph, expr->else_expression()); current_subgraph_->AppendJoin(then_graph, else_graph, expr); - ast_context()->ReturnValue(Pop()); } -void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, +void HGraphBuilder::LookupGlobalPropertyCell(VariableProxy* expr, LookupResult* lookup, bool is_store) { - if (var->is_this()) { + if (expr->is_this()) { BAILOUT("global this reference"); } if (!graph()->info()->has_global_object()) { BAILOUT("no global object to optimize VariableProxy"); } Handle global(graph()->info()->global_object()); - global->Lookup(*var->name(), lookup); + global->Lookup(*expr->name(), lookup); if (!lookup->IsProperty()) { BAILOUT("global variable cell not yet introduced"); } @@ -2921,6 +2961,23 @@ void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, } +void HGraphBuilder::HandleGlobalVariableLoad(VariableProxy* expr) { + LookupResult lookup; + LookupGlobalPropertyCell(expr, &lookup, false); + CHECK_BAILOUT; + + Handle global(graph()->info()->global_object()); + // TODO(3039103): Handle global property load through an IC call when access + // checks are enabled. + if (global->IsAccessCheckNeeded()) { + BAILOUT("global object requires access check"); + } + Handle cell(global->GetPropertyCell(&lookup)); + bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); + PushAndAdd(new HLoadGlobal(cell, check_hole)); +} + + void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { Variable* variable = expr->AsVariable(); if (variable == NULL) { @@ -2929,22 +2986,9 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { BAILOUT("unsupported context for arguments object"); } - ast_context()->ReturnValue(environment()->Lookup(variable)); + Push(environment()->Lookup(variable)); } else if (variable->is_global()) { - LookupResult lookup; - LookupGlobalPropertyCell(variable, &lookup, false); - CHECK_BAILOUT; - - Handle global(graph()->info()->global_object()); - // TODO(3039103): Handle global property load through an IC call when access - // checks are enabled. - if (global->IsAccessCheckNeeded()) { - BAILOUT("global object requires access check"); - } - Handle cell(global->GetPropertyCell(&lookup)); - bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); - HLoadGlobal* instr = new HLoadGlobal(cell, check_hole); - ast_context()->ReturnInstruction(instr, expr->id()); + HandleGlobalVariableLoad(expr); } else { BAILOUT("reference to non-stack-allocated/non-global variable"); } @@ -2952,16 +2996,14 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { void HGraphBuilder::VisitLiteral(Literal* expr) { - HConstant* instr = new HConstant(expr->handle(), Representation::Tagged()); - ast_context()->ReturnInstruction(instr, expr->id()); + PushAndAdd(new HConstant(expr->handle(), Representation::Tagged())); } void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { - HRegExpLiteral* instr = new HRegExpLiteral(expr->pattern(), - expr->flags(), - expr->literal_index()); - ast_context()->ReturnInstruction(instr, expr->id()); + PushAndAdd(new HRegExpLiteral(expr->pattern(), + expr->flags(), + expr->literal_index())); } @@ -2970,8 +3012,6 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { expr->fast_elements(), expr->literal_index(), expr->depth())); - // The object is expected in the bailout environment during computation - // of the property values and is the value of the entire expression. PushAndAdd(literal); expr->CalculateEmitStore(); @@ -3008,7 +3048,6 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { default: UNREACHABLE(); } } - ast_context()->ReturnValue(Pop()); } @@ -3020,8 +3059,6 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { length, expr->literal_index(), expr->depth()); - // The array is expected in the bailout environment during computation - // of the property values and is the value of the entire expression. PushAndAdd(literal); HValue* elements = AddInstruction(new HLoadElements(literal)); @@ -3039,7 +3076,6 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { AddInstruction(new HStoreKeyedFastElement(elements, key, value)); AddSimulate(expr->GetIdForElement(i)); } - ast_context()->ReturnValue(Pop()); } @@ -3221,29 +3257,27 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, Push(value); instr->set_position(expr->position()); AddInstruction(instr); - if (instr->HasSideEffects()) AddSimulate(expr->id()); - } else { - // Build subgraph for generic store through IC. - { - HSubgraph* subgraph = CreateBranchSubgraph(environment()); - SubgraphScope scope(this, subgraph); - if (!needs_generic && FLAG_deoptimize_uncommon_cases) { - subgraph->FinishExit(new HDeoptimize()); - } else { - HInstruction* instr = new HStoreNamedGeneric(object, name, value); - Push(value); - instr->set_position(expr->position()); - AddInstruction(instr); - } - subgraphs.Add(subgraph); - } + return; + } - HBasicBlock* new_exit_block = - BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); - subgraph()->set_exit_block(new_exit_block); + // Build subgraph for generic store through IC. + { + HSubgraph* subgraph = CreateBranchSubgraph(environment()); + SubgraphScope scope(this, subgraph); + if (!needs_generic && FLAG_deoptimize_uncommon_cases) { + subgraph->FinishExit(new HDeoptimize()); + } else { + HInstruction* instr = new HStoreNamedGeneric(object, name, value); + Push(value); + instr->set_position(expr->position()); + AddInstruction(instr); + } + subgraphs.Add(subgraph); } - if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); + HBasicBlock* new_exit_block = + BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); + current_subgraph_->set_exit_block(new_exit_block); } @@ -3299,20 +3333,14 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { Push(value); instr->set_position(expr->position()); AddInstruction(instr); - if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); - ast_context()->ReturnValue(Pop()); } -// Because not every expression has a position and there is not common -// superclass of Assignment and CountOperation, we cannot just pass the -// owning expression instead of position and ast_id separately. -void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, +void HGraphBuilder::HandleGlobalVariableAssignment(VariableProxy* proxy, HValue* value, - int position, - int ast_id) { + int position) { LookupResult lookup; - LookupGlobalPropertyCell(var, &lookup, true); + LookupGlobalPropertyCell(proxy, &lookup, true); CHECK_BAILOUT; Handle global(graph()->info()->global_object()); @@ -3320,7 +3348,6 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, HInstruction* instr = new HStoreGlobal(value, cell); instr->set_position(position); AddInstruction(instr); - if (instr->HasSideEffects()) AddSimulate(ast_id); } @@ -3344,15 +3371,10 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { VISIT_FOR_VALUE(operation); if (var->is_global()) { - HandleGlobalVariableAssignment(var, - Top(), - expr->position(), - expr->AssignmentId()); + HandleGlobalVariableAssignment(proxy, Top(), expr->position()); } else { Bind(var, Top()); } - ast_context()->ReturnValue(Pop()); - } else if (prop != NULL) { prop->RecordTypeFeedback(oracle()); @@ -3370,7 +3392,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { load = BuildLoadNamedGeneric(obj, prop); } PushAndAdd(load); - if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); + if (load->HasSideEffects()) { + AddSimulate(expr->compound_bailout_id()); + } VISIT_FOR_VALUE(expr->value()); HValue* right = Pop(); @@ -3382,11 +3406,10 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { HInstruction* store = BuildStoreNamed(obj, instr, prop); AddInstruction(store); - // Drop the simulated receiver and value. Return the value. + + // Drop the simulated receiver and value and put back the value. Drop(2); Push(instr); - if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); - ast_context()->ReturnValue(Pop()); } else { // Keyed property. @@ -3402,7 +3425,9 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { ? BuildLoadKeyedFastElement(obj, key, prop) : BuildLoadKeyedGeneric(obj, key); PushAndAdd(load); - if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); + if (load->HasSideEffects()) { + AddSimulate(expr->compound_bailout_id()); + } VISIT_FOR_VALUE(expr->value()); HValue* right = Pop(); @@ -3416,13 +3441,11 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { ? BuildStoreKeyedFastElement(obj, key, instr, prop) : BuildStoreKeyedGeneric(obj, key, instr); AddInstruction(store); - // Drop the simulated receiver, key, and value. Return the value. + + // Drop the simulated receiver, key and value and put back the value. Drop(3); Push(instr); - if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); - ast_context()->ReturnValue(Pop()); } - } else { BAILOUT("invalid lhs in compound assignment"); } @@ -3442,14 +3465,9 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { if (var != NULL) { if (proxy->IsArguments()) BAILOUT("assignment to arguments"); - - // Handle the assignment. if (var->is_global()) { VISIT_FOR_VALUE(expr->value()); - HandleGlobalVariableAssignment(var, - Top(), - expr->position(), - expr->AssignmentId()); + HandleGlobalVariableAssignment(proxy, Top(), expr->position()); } else { // We allow reference to the arguments object only in assignemtns // to local variables to make sure that the arguments object does @@ -3462,11 +3480,9 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { } else { VISIT_FOR_VALUE(expr->value()); } + Bind(proxy->var(), Top()); } - // Return the value. - ast_context()->ReturnValue(Pop()); - } else if (prop != NULL) { HandlePropertyAssignment(expr); } else { @@ -3476,10 +3492,6 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { void HGraphBuilder::VisitThrow(Throw* expr) { - // We don't optimize functions with invalid left-hand sides in - // assignments, count operations, or for-in. Consequently throw can - // currently only occur in an effect context. - ASSERT(ast_context()->IsEffect()); VISIT_FOR_VALUE(expr->exception()); HValue* value = environment()->Pop(); @@ -3513,8 +3525,7 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, SubgraphScope scope(this, subgraph); HInstruction* instr = BuildLoadNamedField(object, expr, map, &lookup, false); - instr->set_position(expr->position()); - PushAndAdd(instr); + PushAndAdd(instr, expr->position()); subgraphs.Add(subgraph); } else { needs_generic = true; @@ -3525,30 +3536,26 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, // generic load. if (maps.length() == 0) { HInstruction* instr = BuildLoadNamedGeneric(object, expr); - instr->set_position(expr->position()); - PushAndAdd(instr); - if (instr->HasSideEffects()) AddSimulate(expr->id()); - } else { - // Build subgraph for generic load through IC. - { - HSubgraph* subgraph = CreateBranchSubgraph(environment()); - SubgraphScope scope(this, subgraph); - if (!needs_generic && FLAG_deoptimize_uncommon_cases) { - subgraph->FinishExit(new HDeoptimize()); - } else { - HInstruction* instr = BuildLoadNamedGeneric(object, expr); - instr->set_position(expr->position()); - PushAndAdd(instr); - } - subgraphs.Add(subgraph); - } + PushAndAdd(instr, expr->position()); + return; + } - HBasicBlock* new_exit_block = - BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); - subgraph()->set_exit_block(new_exit_block); + // Build subgraph for generic load through IC. + { + HSubgraph* subgraph = CreateBranchSubgraph(environment()); + SubgraphScope scope(this, subgraph); + if (!needs_generic && FLAG_deoptimize_uncommon_cases) { + subgraph->FinishExit(new HDeoptimize()); + } else { + HInstruction* instr = BuildLoadNamedGeneric(object, expr); + PushAndAdd(instr, expr->position()); + } + subgraphs.Add(subgraph); } - if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop()); + HBasicBlock* new_exit_block = + BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); + current_subgraph_->set_exit_block(new_exit_block); } @@ -3661,12 +3668,11 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) { return false; } - HInstruction* result = NULL; if (expr->key()->IsPropertyName()) { Handle name = expr->key()->AsLiteral()->AsPropertyName(); if (!name->IsEqualTo(CStrVector("length"))) return false; HInstruction* elements = AddInstruction(new HArgumentsElements); - result = new HArgumentsLength(elements); + PushAndAdd(new HArgumentsLength(elements)); } else { VisitForValue(expr->key()); if (HasStackOverflow()) return false; @@ -3674,9 +3680,8 @@ bool HGraphBuilder::TryArgumentsAccess(Property* expr) { HInstruction* elements = AddInstruction(new HArgumentsElements); HInstruction* length = AddInstruction(new HArgumentsLength(elements)); AddInstruction(new HBoundsCheck(key, length)); - result = new HAccessArgumentsAt(elements, length, key); + PushAndAdd(new HAccessArgumentsAt(elements, length, key)); } - ast_context()->ReturnInstruction(result, expr->id()); return true; } @@ -3723,8 +3728,7 @@ void HGraphBuilder::VisitProperty(Property* expr) { ? BuildLoadKeyedFastElement(obj, key, expr) : BuildLoadKeyedGeneric(obj, key); } - instr->set_position(expr->position()); - ast_context()->ReturnInstruction(instr, expr->id()); + PushAndAdd(instr, expr->position()); } @@ -3759,9 +3763,9 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, // Build subgraphs for each of the specific maps. // - // TODO(ager): We should recognize when the prototype chains for different - // maps are identical. In that case we can avoid repeatedly generating the - // same prototype map checks. + // TODO(ager): We should recognize when the prototype chains for + // different maps are identical. In that case we can avoid + // repeatedly generating the same prototype map checks. for (int i = 0; i < number_of_types; ++i) { Handle map = types->at(i); if (expr->ComputeTarget(map, name)) { @@ -3778,9 +3782,7 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, // during hydrogen processing. CHECK_BAILOUT; HCall* call = new HCallConstantFunction(expr->target(), argument_count); - call->set_position(expr->position()); - ProcessCall(call); - PushAndAdd(call); + ProcessCall(call, expr->position()); } subgraphs.Add(subgraph); } else { @@ -3788,34 +3790,30 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, } } - // If we couldn't compute the target for any of the maps just perform an - // IC call. + // If we couldn't compute the target for any of the maps just + // perform an IC call. if (maps.length() == 0) { HCall* call = new HCallNamed(name, argument_count); - call->set_position(expr->position()); - ProcessCall(call); - ast_context()->ReturnInstruction(call, expr->id()); - } else { - // Build subgraph for generic call through IC. - { - HSubgraph* subgraph = CreateBranchSubgraph(environment()); - SubgraphScope scope(this, subgraph); - if (!needs_generic && FLAG_deoptimize_uncommon_cases) { - subgraph->FinishExit(new HDeoptimize()); - } else { - HCall* call = new HCallNamed(name, argument_count); - call->set_position(expr->position()); - ProcessCall(call); - PushAndAdd(call); - } - subgraphs.Add(subgraph); - } + ProcessCall(call, expr->position()); + return; + } - HBasicBlock* new_exit_block = - BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); - subgraph()->set_exit_block(new_exit_block); - if (new_exit_block != NULL) ast_context()->ReturnValue(Pop()); + // Build subgraph for generic call through IC. + { + HSubgraph* subgraph = CreateBranchSubgraph(environment()); + SubgraphScope scope(this, subgraph); + if (!needs_generic && FLAG_deoptimize_uncommon_cases) { + subgraph->FinishExit(new HDeoptimize()); + } else { + HCall* call = new HCallNamed(name, argument_count); + ProcessCall(call, expr->position()); + } + subgraphs.Add(subgraph); } + + HBasicBlock* new_exit_block = + BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); + current_subgraph_->set_exit_block(new_exit_block); } @@ -4063,7 +4061,6 @@ bool HGraphBuilder::TryInline(Call* expr) { function_return_ = saved_function_return; oracle_ = saved_oracle; graph()->info()->SetOsrAstId(saved_osr_ast_id); - return true; } @@ -4089,55 +4086,10 @@ bool HGraphBuilder::TryMathFunctionInline(Call* expr) { case kMathSqrt: if (argument_count == 2) { HValue* argument = Pop(); - Drop(1); // Receiver. + // Pop receiver. + Pop(); HUnaryMathOperation* op = new HUnaryMathOperation(argument, id); - op->set_position(expr->position()); - ast_context()->ReturnInstruction(op, expr->id()); - return true; - } - break; - case kMathPow: - if (argument_count == 3) { - HValue* right = Pop(); - HValue* left = Pop(); - Pop(); // Pop receiver. - HInstruction* result = NULL; - // Use sqrt() if exponent is 0.5 or -0.5. - if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { - double exponent = HConstant::cast(right)->DoubleValue(); - if (exponent == 0.5) { - result = new HUnaryMathOperation(left, kMathPowHalf); - ast_context()->ReturnInstruction(result, expr->id()); - return true; - } else if (exponent == -0.5) { - HConstant* double_one = - new HConstant(Handle(Smi::FromInt(1)), - Representation::Double()); - AddInstruction(double_one); - HUnaryMathOperation* square_root = - new HUnaryMathOperation(left, kMathPowHalf); - AddInstruction(square_root); - // MathPowHalf doesn't have side effects so there's no need for - // an environment simulation here. - ASSERT(!square_root->HasSideEffects()); - result = new HDiv(double_one, square_root); - ast_context()->ReturnInstruction(result, expr->id()); - return true; - } else if (exponent == 2.0) { - result = new HMul(left, left); - ast_context()->ReturnInstruction(result, expr->id()); - return true; - } - } else if (right->IsConstant() && - HConstant::cast(right)->HasInteger32Value() && - HConstant::cast(right)->Integer32Value() == 2) { - result = new HMul(left, left); - ast_context()->ReturnInstruction(result, expr->id()); - return true; - } - - result = new HPower(left, right); - ast_context()->ReturnInstruction(result, expr->id()); + PushAndAdd(op, expr->position()); return true; } break; @@ -4182,10 +4134,8 @@ bool HGraphBuilder::TryCallApply(Call* expr) { function, expr->GetReceiverTypes()->first(), true); - HInstruction* result = - new HApplyArguments(function, receiver, length, elements); - result->set_position(expr->position()); - ast_context()->ReturnInstruction(result, expr->id()); + PushAndAdd(new HApplyArguments(function, receiver, length, elements), + expr->position()); return true; } @@ -4213,10 +4163,12 @@ void HGraphBuilder::VisitCall(Call* expr) { CHECK_BAILOUT; call = new HCallKeyed(key, argument_count); - call->set_position(expr->position()); - ProcessCall(call); - Drop(1); // Key. - ast_context()->ReturnInstruction(call, expr->id()); + ProcessCall(call, expr->position()); + HValue* result = Pop(); + // Drop the receiver from the environment and put back the result of + // the call. + Drop(1); + Push(result); return; } @@ -4239,19 +4191,7 @@ void HGraphBuilder::VisitCall(Call* expr) { if (expr->IsMonomorphic()) { AddCheckConstantFunction(expr, receiver, types->first(), true); - if (TryMathFunctionInline(expr)) { - return; - } else if (TryInline(expr)) { - if (subgraph()->HasExit()) { - HValue* return_value = Pop(); - // If we inlined a function in a test context then we need to emit - // a simulate here to shadow the ones at the end of the - // predecessor blocks. Those environments contain the return - // value on top and do not correspond to any actual state of the - // unoptimized code. - if (ast_context()->IsEffect()) AddSimulate(expr->id()); - ast_context()->ReturnValue(return_value); - } + if (TryMathFunctionInline(expr) || TryInline(expr)) { return; } else { // Check for bailout, as the TryInline call in the if condition above @@ -4259,7 +4199,6 @@ void HGraphBuilder::VisitCall(Call* expr) { CHECK_BAILOUT; call = new HCallConstantFunction(expr->target(), argument_count); } - } else if (types != NULL && types->length() > 1) { HandlePolymorphicCallNamed(expr, receiver, types, name); return; @@ -4307,19 +4246,7 @@ void HGraphBuilder::VisitCall(Call* expr) { IsGlobalObject()); environment()->SetExpressionStackAt(receiver_index, global_receiver); - if (TryInline(expr)) { - if (subgraph()->HasExit()) { - HValue* return_value = Pop(); - // If we inlined a function in a test context then we need to - // emit a simulate here to shadow the ones at the end of the - // predecessor blocks. Those environments contain the return - // value on top and do not correspond to any actual state of the - // unoptimized code. - if (ast_context()->IsEffect()) AddSimulate(expr->id()); - ast_context()->ReturnValue(return_value); - } - return; - } + if (TryInline(expr)) return; // Check for bailout, as trying to inline might fail due to bailout // during hydrogen processing. CHECK_BAILOUT; @@ -4342,9 +4269,7 @@ void HGraphBuilder::VisitCall(Call* expr) { } } - call->set_position(expr->position()); - ProcessCall(call); - ast_context()->ReturnInstruction(call, expr->id()); + ProcessCall(call, expr->position()); } @@ -4358,9 +4283,8 @@ void HGraphBuilder::VisitCallNew(CallNew* expr) { int argument_count = expr->arguments()->length() + 1; // Plus constructor. HCall* call = new HCallNew(argument_count); - call->set_position(expr->position()); - ProcessCall(call); - ast_context()->ReturnInstruction(call, expr->id()); + + ProcessCall(call, expr->position()); } @@ -4368,7 +4292,7 @@ void HGraphBuilder::VisitCallNew(CallNew* expr) { // Lookup table for generators for runtime calls that are generated inline. // Elements of the table are member pointers to functions of HGraphBuilder. -#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ +#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ &HGraphBuilder::Generate##Name, const HGraphBuilder::InlineFunctionGenerator @@ -4382,7 +4306,7 @@ const HGraphBuilder::InlineFunctionGenerator void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { Handle name = expr->name(); if (name->IsEqualTo(CStrVector("_Log"))) { - ast_context()->ReturnValue(graph()->GetConstantUndefined()); + Push(graph()->GetConstantUndefined()); return; } @@ -4408,13 +4332,11 @@ void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; // Call the inline code generator using the pointer-to-member. - (this->*generator)(argument_count, expr->id()); + (this->*generator)(argument_count); } else { ASSERT(function->intrinsic_type == Runtime::RUNTIME); HCall* call = new HCallRuntime(name, expr->function(), argument_count); - call->set_position(RelocInfo::kNoPosition); - ProcessCall(call); - ast_context()->ReturnInstruction(call, expr->id()); + ProcessCall(call, RelocInfo::kNoPosition); } } @@ -4423,7 +4345,7 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { Token::Value op = expr->op(); if (op == Token::VOID) { VISIT_FOR_EFFECT(expr->expression()); - ast_context()->ReturnValue(graph()->GetConstantUndefined()); + Push(graph()->GetConstantUndefined()); } else if (op == Token::DELETE) { Property* prop = expr->expression()->AsProperty(); Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); @@ -4431,47 +4353,36 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { // Result of deleting non-property, non-variable reference is true. // Evaluate the subexpression for side effects. VISIT_FOR_EFFECT(expr->expression()); - ast_context()->ReturnValue(graph()->GetConstantTrue()); + Push(graph_->GetConstantTrue()); } else if (var != NULL && !var->is_global() && var->AsSlot() != NULL && var->AsSlot()->type() != Slot::LOOKUP) { // Result of deleting non-global, non-dynamic variables is false. // The subexpression does not have side effects. - ast_context()->ReturnValue(graph()->GetConstantFalse()); + Push(graph_->GetConstantFalse()); } else if (prop != NULL) { VISIT_FOR_VALUE(prop->obj()); VISIT_FOR_VALUE(prop->key()); HValue* key = Pop(); HValue* obj = Pop(); - ast_context()->ReturnInstruction(new HDeleteProperty(obj, key), - expr->id()); + PushAndAdd(new HDeleteProperty(obj, key)); } else if (var->is_global()) { BAILOUT("delete with global variable"); } else { BAILOUT("delete with non-global variable"); } } else if (op == Token::NOT) { - if (ast_context()->IsTest()) { - TestContext* context = TestContext::cast(ast_context()); - VisitForControl(expr->expression(), - context->if_false(), - context->if_true(), - !context->invert_false(), - !context->invert_true()); - } else { - HSubgraph* true_graph = CreateEmptySubgraph(); - HSubgraph* false_graph = CreateEmptySubgraph(); - VisitCondition(expr->expression(), - false_graph->entry_block(), - true_graph->entry_block(), - true, true); - if (HasStackOverflow()) return; - true_graph->environment()->Push(graph_->GetConstantTrue()); - false_graph->environment()->Push(graph_->GetConstantFalse()); - current_subgraph_->AppendJoin(true_graph, false_graph, expr); - ast_context()->ReturnValue(Pop()); - } + HSubgraph* true_graph = CreateEmptySubgraph(); + HSubgraph* false_graph = CreateEmptySubgraph(); + VisitCondition(expr->expression(), + false_graph->entry_block(), + true_graph->entry_block(), + true, true); + if (HasStackOverflow()) return; + true_graph->environment()->Push(graph_->GetConstantTrue()); + false_graph->environment()->Push(graph_->GetConstantFalse()); + current_subgraph_->AppendJoin(true_graph, false_graph, expr); } else if (op == Token::BIT_NOT || op == Token::SUB) { VISIT_FOR_VALUE(expr->expression()); HValue* value = Pop(); @@ -4487,11 +4398,11 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { UNREACHABLE(); break; } - ast_context()->ReturnInstruction(instr, expr->id()); + PushAndAdd(instr); } else if (op == Token::TYPEOF) { VISIT_FOR_VALUE(expr->expression()); HValue* value = Pop(); - ast_context()->ReturnInstruction(new HTypeof(value), expr->id()); + PushAndAdd(new HTypeof(value)); } else { BAILOUT("Value: unsupported unary operation"); } @@ -4542,15 +4453,11 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { } if (var->is_global()) { - HandleGlobalVariableAssignment(var, - instr, - expr->position(), - expr->AssignmentId()); + HandleGlobalVariableAssignment(proxy, instr, expr->position()); } else { ASSERT(var->IsStackAllocated()); Bind(var, instr); } - ast_context()->ReturnValue(Pop()); } else if (prop != NULL) { prop->RecordTypeFeedback(oracle()); @@ -4558,10 +4465,11 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { if (prop->key()->IsPropertyName()) { // Named property. - // Match the full code generator stack by simulating an extra stack - // element for postfix operations in a value context. - bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); - if (has_extra) Push(graph_->GetConstantUndefined()); + // Match the full code generator stack by simulate an extra stack element + // for postfix operations in a value context. + if (expr->is_postfix() && !ast_context()->IsEffect()) { + Push(graph_->GetConstantUndefined()); + } VISIT_FOR_VALUE(prop->obj()); HValue* obj = Top(); @@ -4577,35 +4485,37 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { PushAndAdd(load); if (load->HasSideEffects()) AddSimulate(increment->id()); - HValue* before = Pop(); - // There is no deoptimization to after the increment, so we don't need - // to simulate the expression stack after this instruction. - HInstruction* after = BuildIncrement(before, inc); - AddInstruction(after); + HValue* value = Pop(); - HInstruction* store = BuildStoreNamed(obj, after, prop); - AddInstruction(store); + HInstruction* instr = BuildIncrement(value, inc); + AddInstruction(instr); - // Overwrite the receiver in the bailout environment with the result - // of the operation, and the placeholder with the original value if - // necessary. - environment()->SetExpressionStackAt(0, after); - if (has_extra) environment()->SetExpressionStackAt(1, before); - if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); - Drop(has_extra ? 2 : 1); + HInstruction* store = BuildStoreNamed(obj, instr, prop); + AddInstruction(store); - ast_context()->ReturnValue(expr->is_postfix() ? before : after); + // Drop simulated receiver and push the result. + // There is no deoptimization to after the increment, so we can simulate + // the expression stack here. + Drop(1); + if (expr->is_prefix()) { + Push(instr); + } else { + if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero. + Push(value); + } } else { // Keyed property. // Match the full code generator stack by simulate an extra stack element // for postfix operations in a value context. - bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); - if (has_extra) Push(graph_->GetConstantUndefined()); + if (expr->is_postfix() && !ast_context()->IsEffect()) { + Push(graph_->GetConstantUndefined()); + } VISIT_FOR_VALUE(prop->obj()); VISIT_FOR_VALUE(prop->key()); + HValue* obj = environment()->ExpressionStackAt(1); HValue* key = environment()->ExpressionStackAt(0); @@ -4618,29 +4528,27 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { PushAndAdd(load); if (load->HasSideEffects()) AddSimulate(increment->id()); - HValue* before = Pop(); - // There is no deoptimization to after the increment, so we don't need - // to simulate the expression stack after this instruction. - HInstruction* after = BuildIncrement(before, inc); - AddInstruction(after); + HValue* value = Pop(); + + HInstruction* instr = BuildIncrement(value, inc); + AddInstruction(instr); HInstruction* store = is_fast_elements - ? BuildStoreKeyedFastElement(obj, key, after, prop) - : new HStoreKeyedGeneric(obj, key, after); + ? BuildStoreKeyedFastElement(obj, key, instr, prop) + : new HStoreKeyedGeneric(obj, key, instr); AddInstruction(store); - // Drop the key from the bailout environment. Overwrite the receiver - // with the result of the operation, and the placeholder with the - // original value if necessary. - Drop(1); - environment()->SetExpressionStackAt(0, after); - if (has_extra) environment()->SetExpressionStackAt(1, before); - if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); - Drop(has_extra ? 2 : 1); - - ast_context()->ReturnValue(expr->is_postfix() ? before : after); + // Drop simulated receiver and key and push the result. + // There is no deoptimization to after the increment, so we can simulate + // the expression stack here. + Drop(2); + if (expr->is_prefix()) { + Push(instr); + } else { + if (!ast_context()->IsEffect()) Drop(1); // Drop simulated zero. + Push(value); + } } - } else { BAILOUT("invalid lhs in count operation"); } @@ -4722,47 +4630,21 @@ static bool IsClassOfTest(CompareOperation* expr) { void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { if (expr->op() == Token::COMMA) { VISIT_FOR_EFFECT(expr->left()); - // Visit the right subexpression in the same AST context as the entire - // expression. - Visit(expr->right()); - + VISIT_FOR_VALUE(expr->right()); } else if (expr->op() == Token::AND || expr->op() == Token::OR) { - bool is_logical_and = (expr->op() == Token::AND); - if (ast_context()->IsTest()) { - TestContext* context = TestContext::cast(ast_context()); - // Translate left subexpression. - HBasicBlock* eval_right = graph()->CreateBasicBlock(); - if (is_logical_and) { - VisitForControl(expr->left(), eval_right, context->if_false(), - false, context->invert_false()); - } else { - VisitForControl(expr->left(), context->if_true(), eval_right, - context->invert_true(), false); - } - if (HasStackOverflow()) return; - eval_right->SetJoinId(expr->left()->id()); - - // Translate right subexpression by visiting it in the same AST - // context as the entire expression. - eval_right->last_environment()->Pop(); - subgraph()->set_exit_block(eval_right); - Visit(expr->right()); + VISIT_FOR_VALUE(expr->left()); + ASSERT(current_subgraph_->HasExit()); - } else { - VISIT_FOR_VALUE(expr->left()); - ASSERT(current_subgraph_->HasExit()); - - HValue* left = Top(); - HEnvironment* environment_copy = environment()->Copy(); - environment_copy->Pop(); - HSubgraph* right_subgraph; - right_subgraph = CreateBranchSubgraph(environment_copy); - ADD_TO_SUBGRAPH(right_subgraph, expr->right()); - current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left); - current_subgraph_->exit_block()->SetJoinId(expr->id()); - ast_context()->ReturnValue(Pop()); - } + HValue* left = Top(); + bool is_logical_and = (expr->op() == Token::AND); + HEnvironment* environment_copy = environment()->Copy(); + environment_copy->Pop(); + HSubgraph* right_subgraph; + right_subgraph = CreateBranchSubgraph(environment_copy); + ADD_TO_SUBGRAPH(right_subgraph, expr->right()); + current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left); + current_subgraph_->exit_block()->SetJoinId(expr->id()); } else { VISIT_FOR_VALUE(expr->left()); VISIT_FOR_VALUE(expr->right()); @@ -4770,8 +4652,7 @@ void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { HValue* right = Pop(); HValue* left = Pop(); HInstruction* instr = BuildBinaryOperation(expr, left, right); - instr->set_position(expr->position()); - ast_context()->ReturnInstruction(instr, expr->id()); + PushAndAdd(instr, expr->position()); } } @@ -4810,8 +4691,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { Literal* literal = expr->right()->AsLiteral(); Handle rhs = Handle::cast(literal->handle()); HInstruction* instr = new HClassOfTest(value, rhs); - instr->set_position(expr->position()); - ast_context()->ReturnInstruction(instr, expr->id()); + PushAndAdd(instr, expr->position()); return; } @@ -4825,8 +4705,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { HValue* left = Pop(); HInstruction* instr = new HTypeofIs(left, Handle::cast(right_literal->handle())); - instr->set_position(expr->position()); - ast_context()->ReturnInstruction(instr, expr->id()); + PushAndAdd(instr, expr->position()); return; } @@ -4862,8 +4741,7 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { compare->SetInputRepresentation(r); instr = compare; } - instr->set_position(expr->position()); - ast_context()->ReturnInstruction(instr, expr->id()); + PushAndAdd(instr, expr->position()); } @@ -4872,7 +4750,8 @@ void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { HValue* value = Pop(); HIsNull* compare = new HIsNull(value, expr->is_strict()); - ast_context()->ReturnInstruction(compare, expr->id()); + + PushAndAdd(compare); } @@ -4899,305 +4778,301 @@ void HGraphBuilder::VisitDeclaration(Declaration* decl) { // Generators for inline runtime functions. // Support for types. -void HGraphBuilder::GenerateIsSmi(int argument_count, int ast_id) { +void HGraphBuilder::GenerateIsSmi(int argument_count) { ASSERT(argument_count == 1); + HValue* value = Pop(); - HIsSmi* result = new HIsSmi(value); - ast_context()->ReturnInstruction(result, ast_id); + PushAndAdd(new HIsSmi(value)); } -void HGraphBuilder::GenerateIsSpecObject(int argument_count, int ast_id) { +void HGraphBuilder::GenerateIsSpecObject(int argument_count) { ASSERT(argument_count == 1); + HValue* value = Pop(); - HHasInstanceType* result = + HHasInstanceType* test = new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); - ast_context()->ReturnInstruction(result, ast_id); + PushAndAdd(test); } -void HGraphBuilder::GenerateIsFunction(int argument_count, int ast_id) { +void HGraphBuilder::GenerateIsFunction(int argument_count) { ASSERT(argument_count == 1); + HValue* value = Pop(); - HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE); - ast_context()->ReturnInstruction(result, ast_id); + HHasInstanceType* test = + new HHasInstanceType(value, JS_FUNCTION_TYPE); + PushAndAdd(test); } -void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count, - int ast_id) { +void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count) { ASSERT(argument_count == 1); + HValue* value = Pop(); - HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value); - ast_context()->ReturnInstruction(result, ast_id); + HHasCachedArrayIndex* spec_test = new HHasCachedArrayIndex(value); + PushAndAdd(spec_test); } -void HGraphBuilder::GenerateIsArray(int argument_count, int ast_id) { +void HGraphBuilder::GenerateIsArray(int argument_count) { ASSERT(argument_count == 1); + HValue* value = Pop(); - HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE); - ast_context()->ReturnInstruction(result, ast_id); + HHasInstanceType* test = + new HHasInstanceType(value, JS_ARRAY_TYPE); + PushAndAdd(test); } -void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) { +void HGraphBuilder::GenerateIsRegExp(int argument_count) { ASSERT(argument_count == 1); + HValue* value = Pop(); - HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE); - ast_context()->ReturnInstruction(result, ast_id); + HHasInstanceType* test = + new HHasInstanceType(value, JS_REGEXP_TYPE); + PushAndAdd(test); } -void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count, - int ast_id) { +void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count) { BAILOUT("inlined runtime function: IsNonNegativeSmi"); } -void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) { +void HGraphBuilder::GenerateIsObject(int argument_count) { BAILOUT("inlined runtime function: IsObject"); } -void HGraphBuilder::GenerateIsUndetectableObject(int argument_count, - int ast_id) { +void HGraphBuilder::GenerateIsUndetectableObject(int argument_count) { BAILOUT("inlined runtime function: IsUndetectableObject"); } void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( - int argument_count, - int ast_id) { + int argument_count) { BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); } // Support for construct call checks. -void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) { +void HGraphBuilder::GenerateIsConstructCall(int argument_count) { BAILOUT("inlined runtime function: IsConstructCall"); } // Support for arguments.length and arguments[?]. -void HGraphBuilder::GenerateArgumentsLength(int argument_count, int ast_id) { +void HGraphBuilder::GenerateArgumentsLength(int argument_count) { ASSERT(argument_count == 0); HInstruction* elements = AddInstruction(new HArgumentsElements); - HArgumentsLength* result = new HArgumentsLength(elements); - ast_context()->ReturnInstruction(result, ast_id); + PushAndAdd(new HArgumentsLength(elements)); } -void HGraphBuilder::GenerateArguments(int argument_count, int ast_id) { +void HGraphBuilder::GenerateArguments(int argument_count) { ASSERT(argument_count == 1); HValue* index = Pop(); HInstruction* elements = AddInstruction(new HArgumentsElements); HInstruction* length = AddInstruction(new HArgumentsLength(elements)); - HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index); - ast_context()->ReturnInstruction(result, ast_id); + PushAndAdd(new HAccessArgumentsAt(elements, length, index)); } // Support for accessing the class and value fields of an object. -void HGraphBuilder::GenerateClassOf(int argument_count, int ast_id) { +void HGraphBuilder::GenerateClassOf(int argument_count) { // The special form detected by IsClassOfTest is detected before we get here // and does not cause a bailout. BAILOUT("inlined runtime function: ClassOf"); } -void HGraphBuilder::GenerateValueOf(int argument_count, int ast_id) { +void HGraphBuilder::GenerateValueOf(int argument_count) { ASSERT(argument_count == 1); + HValue* value = Pop(); - HValueOf* result = new HValueOf(value); - ast_context()->ReturnInstruction(result, ast_id); + HValueOf* op = new HValueOf(value); + PushAndAdd(op); } -void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) { +void HGraphBuilder::GenerateSetValueOf(int argument_count) { BAILOUT("inlined runtime function: SetValueOf"); } // Fast support for charCodeAt(n). -void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) { +void HGraphBuilder::GenerateStringCharCodeAt(int argument_count) { BAILOUT("inlined runtime function: StringCharCodeAt"); } // Fast support for string.charAt(n) and string[n]. -void HGraphBuilder::GenerateStringCharFromCode(int argument_count, - int ast_id) { +void HGraphBuilder::GenerateStringCharFromCode(int argument_count) { BAILOUT("inlined runtime function: StringCharFromCode"); } // Fast support for string.charAt(n) and string[n]. -void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) { +void HGraphBuilder::GenerateStringCharAt(int argument_count) { ASSERT_EQ(2, argument_count); PushArgumentsForStubCall(argument_count); - HCallStub* result = new HCallStub(CodeStub::StringCharAt, argument_count); - ast_context()->ReturnInstruction(result, ast_id); + PushAndAdd(new HCallStub(CodeStub::StringCharAt, argument_count), + RelocInfo::kNoPosition); } // Fast support for object equality testing. -void HGraphBuilder::GenerateObjectEquals(int argument_count, int ast_id) { +void HGraphBuilder::GenerateObjectEquals(int argument_count) { ASSERT(argument_count == 2); + HValue* right = Pop(); HValue* left = Pop(); - HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right); - ast_context()->ReturnInstruction(result, ast_id); + PushAndAdd(new HCompareJSObjectEq(left, right)); } -void HGraphBuilder::GenerateLog(int argument_count, int ast_id) { +void HGraphBuilder::GenerateLog(int argument_count) { UNREACHABLE(); // We caught this in VisitCallRuntime. } // Fast support for Math.random(). -void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) { +void HGraphBuilder::GenerateRandomHeapNumber(int argument_count) { BAILOUT("inlined runtime function: RandomHeapNumber"); } // Fast support for StringAdd. -void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) { +void HGraphBuilder::GenerateStringAdd(int argument_count) { ASSERT_EQ(2, argument_count); PushArgumentsForStubCall(argument_count); - HCallStub* result = new HCallStub(CodeStub::StringAdd, argument_count); - ast_context()->ReturnInstruction(result, ast_id); + PushAndAdd(new HCallStub(CodeStub::StringAdd, argument_count), + RelocInfo::kNoPosition); } // Fast support for SubString. -void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) { +void HGraphBuilder::GenerateSubString(int argument_count) { ASSERT_EQ(3, argument_count); PushArgumentsForStubCall(argument_count); - HCallStub* result = new HCallStub(CodeStub::SubString, argument_count); - ast_context()->ReturnInstruction(result, ast_id); + PushAndAdd(new HCallStub(CodeStub::SubString, argument_count), + RelocInfo::kNoPosition); } // Fast support for StringCompare. -void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) { +void HGraphBuilder::GenerateStringCompare(int argument_count) { ASSERT_EQ(2, argument_count); PushArgumentsForStubCall(argument_count); - HCallStub* result = new HCallStub(CodeStub::StringCompare, argument_count); - ast_context()->ReturnInstruction(result, ast_id); + PushAndAdd(new HCallStub(CodeStub::StringCompare, argument_count), + RelocInfo::kNoPosition); } // Support for direct calls from JavaScript to native RegExp code. -void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) { +void HGraphBuilder::GenerateRegExpExec(int argument_count) { ASSERT_EQ(4, argument_count); PushArgumentsForStubCall(argument_count); - HCallStub* result = new HCallStub(CodeStub::RegExpExec, argument_count); - ast_context()->ReturnInstruction(result, ast_id); + PushAndAdd(new HCallStub(CodeStub::RegExpExec, argument_count), + RelocInfo::kNoPosition); } // Construct a RegExp exec result with two in-object properties. -void HGraphBuilder::GenerateRegExpConstructResult(int argument_count, - int ast_id) { +void HGraphBuilder::GenerateRegExpConstructResult(int argument_count) { ASSERT_EQ(3, argument_count); PushArgumentsForStubCall(argument_count); - HCallStub* result = - new HCallStub(CodeStub::RegExpConstructResult, argument_count); - ast_context()->ReturnInstruction(result, ast_id); + PushAndAdd(new HCallStub(CodeStub::RegExpConstructResult, argument_count), + RelocInfo::kNoPosition); } // Support for fast native caches. -void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) { +void HGraphBuilder::GenerateGetFromCache(int argument_count) { BAILOUT("inlined runtime function: GetFromCache"); } // Fast support for number to string. -void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) { +void HGraphBuilder::GenerateNumberToString(int argument_count) { ASSERT_EQ(1, argument_count); PushArgumentsForStubCall(argument_count); - HCallStub* result = new HCallStub(CodeStub::NumberToString, argument_count); - ast_context()->ReturnInstruction(result, ast_id); + PushAndAdd(new HCallStub(CodeStub::NumberToString, argument_count), + RelocInfo::kNoPosition); } // Fast swapping of elements. Takes three expressions, the object and two // indices. This should only be used if the indices are known to be // non-negative and within bounds of the elements array at the call site. -void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) { +void HGraphBuilder::GenerateSwapElements(int argument_count) { BAILOUT("inlined runtime function: SwapElements"); } // Fast call for custom callbacks. -void HGraphBuilder::GenerateCallFunction(int argument_count, int ast_id) { +void HGraphBuilder::GenerateCallFunction(int argument_count) { BAILOUT("inlined runtime function: CallFunction"); } // Fast call to math functions. -void HGraphBuilder::GenerateMathPow(int argument_count, int ast_id) { +void HGraphBuilder::GenerateMathPow(int argument_count) { ASSERT_EQ(2, argument_count); - HValue* right = Pop(); - HValue* left = Pop(); - HPower* result = new HPower(left, right); - ast_context()->ReturnInstruction(result, ast_id); + PushArgumentsForStubCall(argument_count); + PushAndAdd(new HCallStub(CodeStub::MathPow, argument_count), + RelocInfo::kNoPosition); } -void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) { +void HGraphBuilder::GenerateMathSin(int argument_count) { ASSERT_EQ(1, argument_count); PushArgumentsForStubCall(argument_count); - HCallStub* result = + HCallStub* instr = new HCallStub(CodeStub::TranscendentalCache, argument_count); - result->set_transcendental_type(TranscendentalCache::SIN); - ast_context()->ReturnInstruction(result, ast_id); + instr->set_transcendental_type(TranscendentalCache::SIN); + PushAndAdd(instr, RelocInfo::kNoPosition); } -void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) { +void HGraphBuilder::GenerateMathCos(int argument_count) { ASSERT_EQ(1, argument_count); PushArgumentsForStubCall(argument_count); - HCallStub* result = + HCallStub* instr = new HCallStub(CodeStub::TranscendentalCache, argument_count); - result->set_transcendental_type(TranscendentalCache::COS); - ast_context()->ReturnInstruction(result, ast_id); + instr->set_transcendental_type(TranscendentalCache::COS); + PushAndAdd(instr, RelocInfo::kNoPosition); } -void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) { +void HGraphBuilder::GenerateMathLog(int argument_count) { ASSERT_EQ(1, argument_count); PushArgumentsForStubCall(argument_count); - HCallStub* result = + HCallStub* instr = new HCallStub(CodeStub::TranscendentalCache, argument_count); - result->set_transcendental_type(TranscendentalCache::LOG); - ast_context()->ReturnInstruction(result, ast_id); + instr->set_transcendental_type(TranscendentalCache::LOG); + PushAndAdd(instr, RelocInfo::kNoPosition); } -void HGraphBuilder::GenerateMathSqrt(int argument_count, int ast_id) { +void HGraphBuilder::GenerateMathSqrt(int argument_count) { BAILOUT("inlined runtime function: MathSqrt"); } // Check whether two RegExps are equivalent -void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count, - int ast_id) { +void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count) { BAILOUT("inlined runtime function: IsRegExpEquivalent"); } -void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count, - int ast_id) { +void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count) { BAILOUT("inlined runtime function: GetCachedArrayIndex"); } -void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count, - int ast_id) { +void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count) { BAILOUT("inlined runtime function: FastAsciiArrayJoin"); } diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h index 5611d8da18..91f3c9e2d6 100644 --- a/deps/v8/src/hydrogen.h +++ b/deps/v8/src/hydrogen.h @@ -557,29 +557,10 @@ class AstContext { bool IsValue() const { return kind_ == Expression::kValue; } 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: AstContext(HGraphBuilder* owner, Expression::Context kind); 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: HGraphBuilder* owner_; Expression::Context kind_; @@ -592,10 +573,6 @@ class EffectContext: public AstContext { explicit EffectContext(HGraphBuilder* owner) : AstContext(owner, Expression::kEffect) { } - virtual ~EffectContext(); - - virtual void ReturnValue(HValue* value); - virtual void ReturnInstruction(HInstruction* instr, int ast_id); }; @@ -604,10 +581,6 @@ class ValueContext: public AstContext { explicit ValueContext(HGraphBuilder* owner) : AstContext(owner, Expression::kValue) { } - virtual ~ValueContext(); - - virtual void ReturnValue(HValue* value); - virtual void ReturnInstruction(HInstruction* instr, int ast_id); }; @@ -625,9 +598,6 @@ class TestContext: public AstContext { invert_false_(invert_false) { } - virtual void ReturnValue(HValue* value); - virtual void ReturnInstruction(HInstruction* instr, int ast_id); - static TestContext* cast(AstContext* context) { ASSERT(context->IsTest()); return reinterpret_cast(context); @@ -640,10 +610,6 @@ class TestContext: public AstContext { bool invert_false() { return invert_false_; } private: - // Build the shared core part of the translation unpacking a value into - // control flow. - void BuildBranch(HValue* value); - HBasicBlock* if_true_; HBasicBlock* if_false_; bool invert_true_; @@ -665,25 +631,9 @@ class HGraphBuilder: public AstVisitor { 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: // Type of a member function that generates inline code for a native function. - typedef void (HGraphBuilder::*InlineFunctionGenerator)(int argument_count, - int ast_id); + typedef void (HGraphBuilder::*InlineFunctionGenerator)(int argument_count); // Forward declarations for inner scope classes. class SubgraphScope; @@ -700,14 +650,19 @@ class HGraphBuilder: public AstVisitor { // Simple accessors. TypeFeedbackOracle* oracle() const { return oracle_; } + HGraph* graph() const { return graph_; } + HSubgraph* subgraph() const { return current_subgraph_; } AstContext* ast_context() const { return ast_context_; } void set_ast_context(AstContext* context) { ast_context_ = context; } AstContext* call_context() const { return call_context_; } 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. -#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \ - void Generate##Name(int argument_count, int ast_id); +#define INLINE_FUNCTION_GENERATOR_DECLARATION(Name, argc, ressize) \ + void Generate##Name(int argument_count); INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_DECLARATION) @@ -728,6 +683,8 @@ class HGraphBuilder: public AstVisitor { HSubgraph* true_graph, HSubgraph* false_graph); + void Push(HValue* value) { environment()->Push(value); } + HValue* Pop() { return environment()->Pop(); } HValue* Top() const { return environment()->Top(); } void Drop(int n) { environment()->Drop(n); } void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); } @@ -751,15 +708,18 @@ class HGraphBuilder: public AstVisitor { HValue* VisitArgument(Expression* expr); void VisitArgumentList(ZoneList* arguments); + HInstruction* AddInstruction(HInstruction* instr); + void AddSimulate(int id); void AddPhi(HPhi* phi); void PushAndAdd(HInstruction* instr); + void PushAndAdd(HInstruction* instr, int position); void PushArgumentsForStubCall(int argument_count); - // Remove the arguments from the bailout environment and emit instructions - // to push them as outgoing parameters. - void ProcessCall(HCall* call); + // Initialize the arguments to the call based on then environment, add it + // to the graph, and drop the arguments from the environment. + void ProcessCall(HCall* call, int source_position); void AssumeRepresentation(HValue* value, Representation r); static Representation ToRepresentation(TypeInfo info); @@ -783,7 +743,7 @@ class HGraphBuilder: public AstVisitor { FunctionLiteral* function); // Helpers for flow graph construction. - void LookupGlobalPropertyCell(Variable* var, + void LookupGlobalPropertyCell(VariableProxy* expr, LookupResult* lookup, bool is_store); @@ -793,11 +753,10 @@ class HGraphBuilder: public AstVisitor { bool TryMathFunctionInline(Call* expr); void TraceInline(Handle target, bool result); - void HandleGlobalVariableAssignment(Variable* var, + void HandleGlobalVariableAssignment(VariableProxy* proxy, HValue* value, - int position, - int ast_id); - + int position); + void HandleGlobalVariableLoad(VariableProxy* expr); void HandlePropertyAssignment(Assignment* expr); void HandleCompoundAssignment(Assignment* expr); void HandlePolymorphicLoadNamedField(Property* expr, diff --git a/deps/v8/src/ia32/builtins-ia32.cc b/deps/v8/src/ia32/builtins-ia32.cc index 918f346d89..c28e144410 100644 --- a/deps/v8/src/ia32/builtins-ia32.cc +++ b/deps/v8/src/ia32/builtins-ia32.cc @@ -29,6 +29,7 @@ #if defined(V8_TARGET_ARCH_IA32) +#include "code-stubs.h" #include "codegen-inl.h" #include "deoptimizer.h" #include "full-codegen.h" diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index e538ee4b9f..1f7095f578 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -911,9 +911,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { __ bind(&update_each); __ mov(result_register(), ebx); // Perform the assignment as if via '='. - { EffectContext context(this); - EmitAssignment(stmt->each(), stmt->AssignmentId()); - } + EmitAssignment(stmt->each()); // Generate code for the body of the loop. Visit(stmt->body()); @@ -1480,7 +1478,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { // For property compound assignments we need another deoptimization // point after the property load. if (property != NULL) { - PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); + PrepareForBailoutForId(expr->compound_bailout_id(), TOS_REG); } Token::Value op = expr->binary_op(); @@ -1523,8 +1521,6 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { case VARIABLE: EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), expr->op()); - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); - context()->Plug(eax); break; case NAMED_PROPERTY: EmitNamedPropertyAssignment(expr); @@ -1853,7 +1849,7 @@ void FullCodeGenerator::EmitBinaryOp(Token::Value op, } -void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { +void FullCodeGenerator::EmitAssignment(Expression* expr) { // Invalid left-hand sides are rewritten to have a 'throw // ReferenceError' on the left-hand side. if (!expr->IsValidLeftHandSide()) { @@ -1901,8 +1897,6 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { break; } } - PrepareForBailoutForId(bailout_ast_id, TOS_REG); - context()->Plug(eax); } @@ -1975,6 +1969,8 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, } __ bind(&done); } + + context()->Plug(eax); } @@ -2011,10 +2007,10 @@ void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { __ push(Operand(esp, kPointerSize)); // Receiver is under value. __ CallRuntime(Runtime::kToFastProperties, 1); __ pop(eax); - __ Drop(1); + context()->DropAndPlug(1, eax); + } else { + context()->Plug(eax); } - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); - context()->Plug(eax); } @@ -2052,7 +2048,6 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { __ pop(eax); } - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); context()->Plug(eax); } @@ -3754,8 +3749,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { { EffectContext context(this); EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), Token::ASSIGN); - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); - context.Plug(eax); } // For all contexts except EffectContext We have the result on // top of the stack. @@ -3766,8 +3759,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { // Perform the assignment as if via '='. EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), Token::ASSIGN); - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); - context()->Plug(eax); } break; case NAMED_PROPERTY: { @@ -3775,7 +3766,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ pop(edx); Handle ic(Builtins::builtin(Builtins::StoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { if (!context()->IsEffect()) { context()->PlugTOS(); @@ -3790,7 +3780,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { __ pop(edx); Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); EmitCallIC(ic, RelocInfo::CODE_TARGET); - PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); if (expr->is_postfix()) { // Result is on the stack if (!context()->IsEffect()) { diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index b5c0289174..dc0f5e90f9 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -2174,67 +2174,6 @@ 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) { switch (instr->op()) { case kMathAbs: @@ -2249,9 +2188,6 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { case kMathSqrt: DoMathSqrt(instr); break; - case kMathPowHalf: - DoMathPowHalf(instr); - break; default: UNREACHABLE(); } diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.h b/deps/v8/src/ia32/lithium-codegen-ia32.h index ca4e9b3fae..91b3fabca3 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.h +++ b/deps/v8/src/ia32/lithium-codegen-ia32.h @@ -175,7 +175,6 @@ class LCodeGen BASE_EMBEDDED { void DoMathFloor(LUnaryMathOperation* instr); void DoMathRound(LUnaryMathOperation* instr); void DoMathSqrt(LUnaryMathOperation* instr); - void DoMathPowHalf(LUnaryMathOperation* instr); // Support for recording safepoint and position information. void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); diff --git a/deps/v8/src/ia32/lithium-ia32.cc b/deps/v8/src/ia32/lithium-ia32.cc index 1f9714357e..e3a3d7bcb0 100644 --- a/deps/v8/src/ia32/lithium-ia32.cc +++ b/deps/v8/src/ia32/lithium-ia32.cc @@ -460,6 +460,12 @@ 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) { GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to); } @@ -1366,8 +1372,6 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { return AssignEnvironment(DefineAsRegister(result)); case kMathSqrt: return DefineSameAsFirst(result); - case kMathPowHalf: - return AssignEnvironment(DefineSameAsFirst(result)); default: UNREACHABLE(); return NULL; @@ -1568,22 +1572,6 @@ 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) { Token::Value op = instr->token(); if (instr->left()->representation().IsInteger32()) { diff --git a/deps/v8/src/ia32/lithium-ia32.h b/deps/v8/src/ia32/lithium-ia32.h index c97859cfc9..af0d5604dd 100644 --- a/deps/v8/src/ia32/lithium-ia32.h +++ b/deps/v8/src/ia32/lithium-ia32.h @@ -67,7 +67,6 @@ class LGapNode; // LLoadKeyedGeneric // LModI // LMulI -// LPower // LShiftI // LSubI // LCallConstantFunction @@ -230,7 +229,6 @@ class LGapNode; V(ObjectLiteral) \ V(OsrEntry) \ V(Parameter) \ - V(Power) \ V(PushArgument) \ V(RegExpLiteral) \ V(Return) \ @@ -1156,16 +1154,6 @@ 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 { public: LArithmeticD(Token::Value op, LOperand* left, LOperand* right) @@ -1902,6 +1890,7 @@ class LChunk: public ZoneObject { LGap* GetGapAt(int index) const; bool IsGapAt(int index) const; int NearestGapPos(int index) const; + int NearestNextGapPos(int index) const; void MarkEmptyBlocks(); const ZoneList* pointer_maps() const { return &pointer_maps_; } LLabel* GetLabel(int block_id) const { diff --git a/deps/v8/src/ia32/macro-assembler-ia32.cc b/deps/v8/src/ia32/macro-assembler-ia32.cc index 6c51d6859c..84911ecec5 100644 --- a/deps/v8/src/ia32/macro-assembler-ia32.cc +++ b/deps/v8/src/ia32/macro-assembler-ia32.cc @@ -1216,29 +1216,25 @@ MaybeObject* MacroAssembler::TryTailCallRuntime(Runtime::FunctionId fid, } -// If true, a Handle returned by value from a function with cdecl calling -// convention will be returned directly as a value of location_ field in a -// register eax. -// If false, it is returned as a pointer to a preallocated by caller memory -// 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; +// If true, a Handle passed by value is passed and returned by +// using the location_ field directly. If false, it is passed and +// returned as a pointer to a handle. +#ifdef USING_BSD_ABI +static const bool kPassHandlesDirectly = true; #else -static const bool kReturnHandlesDirectly = false; +static const bool kPassHandlesDirectly = false; #endif Operand ApiParameterOperand(int index) { - return Operand( - esp, (index + (kReturnHandlesDirectly ? 0 : 1)) * kPointerSize); + return Operand(esp, (index + (kPassHandlesDirectly ? 0 : 1)) * kPointerSize); } void MacroAssembler::PrepareCallApiFunction(int argc, Register scratch) { - if (kReturnHandlesDirectly) { + if (kPassHandlesDirectly) { EnterApiExitFrame(argc); - // When handles are returned directly we don't have to allocate extra + // When handles as passed directly we don't have to allocate extra // space for and pass an out parameter. } else { // We allocate two additional slots: return value and pointer to it. @@ -1283,7 +1279,7 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn(ApiFunction* function, // Call the api function! call(function->address(), RelocInfo::RUNTIME_ENTRY); - if (!kReturnHandlesDirectly) { + if (!kPassHandlesDirectly) { // The returned value is a pointer to the handle holding the result. // Dereference this to get to the location. mov(eax, Operand(eax, 0)); diff --git a/deps/v8/src/json.js b/deps/v8/src/json.js index c0af9d0e46..e8b732a52a 100644 --- a/deps/v8/src/json.js +++ b/deps/v8/src/json.js @@ -66,10 +66,21 @@ 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) { - if (!%PushIfAbsent(stack, value)) { + if (StackContains(stack, value)) { throw MakeTypeError('circular_structure', []); } + stack.push(value); var stepback = indent; indent += gap; var partial = []; @@ -97,9 +108,10 @@ function SerializeArray(value, replacer, stack, indent, gap) { } function SerializeObject(value, replacer, stack, indent, gap) { - if (!%PushIfAbsent(stack, value)) { + if (StackContains(stack, value)) { throw MakeTypeError('circular_structure', []); } + stack.push(value); var stepback = indent; indent += gap; var partial = []; @@ -185,9 +197,10 @@ function JSONSerialize(key, holder, replacer, stack, indent, gap) { function BasicSerializeArray(value, stack, builder) { - if (!%PushIfAbsent(stack, value)) { + if (StackContains(stack, value)) { throw MakeTypeError('circular_structure', []); } + stack.push(value); builder.push("["); var len = value.length; for (var i = 0; i < len; i++) { @@ -207,9 +220,10 @@ function BasicSerializeArray(value, stack, builder) { function BasicSerializeObject(value, stack, builder) { - if (!%PushIfAbsent(stack, value)) { + if (StackContains(stack, value)) { throw MakeTypeError('circular_structure', []); } + stack.push(value); builder.push("{"); for (var p in value) { if (%HasLocalProperty(value, p)) { diff --git a/deps/v8/src/lithium-allocator.cc b/deps/v8/src/lithium-allocator.cc index 513a67c7c8..db0bc8b72d 100644 --- a/deps/v8/src/lithium-allocator.cc +++ b/deps/v8/src/lithium-allocator.cc @@ -247,7 +247,7 @@ LOperand* LiveRange::CreateAssignedOperand() { LOperand* op = NULL; if (HasRegisterAssigned()) { ASSERT(!IsSpilled()); - if (IsDouble()) { + if (assigned_double_) { op = LDoubleRegister::Create(assigned_register()); } else { op = LRegister::Create(assigned_register()); @@ -290,7 +290,7 @@ void LiveRange::AdvanceLastProcessedMarker( void LiveRange::SplitAt(LifetimePosition position, LiveRange* result) { - ASSERT(Start().Value() < position.Value()); + ASSERT(Start().Value() <= position.Value()); ASSERT(result->IsEmpty()); // Find the last interval that ends before the position. If the // position is contained in one of the intervals in the chain, we @@ -625,7 +625,7 @@ LiveRange* LAllocator::FixedLiveRangeFor(int index) { if (result == NULL) { result = new LiveRange(FixedLiveRangeID(index)); ASSERT(result->IsFixed()); - result->set_assigned_register(index, GENERAL_REGISTERS); + result->set_assigned_register(index, false); fixed_live_ranges_[index] = result; } return result; @@ -642,7 +642,7 @@ LiveRange* LAllocator::FixedDoubleLiveRangeFor(int index) { if (result == NULL) { result = new LiveRange(FixedDoubleLiveRangeID(index)); ASSERT(result->IsFixed()); - result->set_assigned_register(index, DOUBLE_REGISTERS); + result->set_assigned_register(index, true); fixed_double_live_ranges_[index] = result; } return result; @@ -1258,6 +1258,14 @@ void LAllocator::BuildLiveRanges() { } +void LAllocator::AllocateGeneralRegisters() { + HPhase phase("Allocate general registers", this); + num_registers_ = Register::kNumAllocatableRegisters; + mode_ = CPU_REGISTERS; + AllocateRegisters(); +} + + bool LAllocator::SafePointsAreInOrder() const { const ZoneList* pointer_maps = chunk_->pointer_maps(); int safe_point = 0; @@ -1389,18 +1397,10 @@ void LAllocator::ProcessOsrEntry() { } -void LAllocator::AllocateGeneralRegisters() { - HPhase phase("Allocate general registers", this); - num_registers_ = Register::kNumAllocatableRegisters; - mode_ = GENERAL_REGISTERS; - AllocateRegisters(); -} - - void LAllocator::AllocateDoubleRegisters() { HPhase phase("Allocate double registers", this); num_registers_ = DoubleRegister::kNumAllocatableRegisters; - mode_ = DOUBLE_REGISTERS; + mode_ = XMM_REGISTERS; AllocateRegisters(); } @@ -1411,7 +1411,7 @@ void LAllocator::AllocateRegisters() { for (int i = 0; i < live_ranges_.length(); ++i) { if (live_ranges_[i] != NULL) { - if (RequiredRegisterKind(live_ranges_[i]->id()) == mode_) { + if (HasDoubleValue(live_ranges_[i]->id()) == (mode_ == XMM_REGISTERS)) { AddToUnhandledUnsorted(live_ranges_[i]); } } @@ -1422,7 +1422,7 @@ void LAllocator::AllocateRegisters() { ASSERT(active_live_ranges_.is_empty()); ASSERT(inactive_live_ranges_.is_empty()); - if (mode_ == DOUBLE_REGISTERS) { + if (mode_ == XMM_REGISTERS) { for (int i = 0; i < fixed_double_live_ranges_.length(); ++i) { LiveRange* current = fixed_double_live_ranges_.at(i); if (current != NULL) { @@ -1463,7 +1463,11 @@ void LAllocator::AllocateRegisters() { current->Start().NextInstruction().Value()) { // Do not spill live range eagerly if use position that can benefit from // the register is too close to the start of live range. - SpillBetween(current, current->Start(), pos->pos()); + LiveRange* part = Split(current, + current->Start().NextInstruction(), + pos->pos()); + Spill(current); + AddToUnhandledSorted(part); ASSERT(UnhandledIsSorted()); continue; } @@ -1517,16 +1521,6 @@ 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, ...) { if (FLAG_trace_alloc) { va_list arguments; @@ -1550,12 +1544,10 @@ bool LAllocator::HasTaggedValue(int virtual_register) const { } -RegisterKind LAllocator::RequiredRegisterKind(int virtual_register) const { +bool LAllocator::HasDoubleValue(int virtual_register) const { HValue* value = graph()->LookupValue(virtual_register); - if (value != NULL && value->representation().IsDouble()) { - return DOUBLE_REGISTERS; - } - return GENERAL_REGISTERS; + if (value == NULL) return false; + return value->representation().IsDouble(); } @@ -1736,22 +1728,16 @@ 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) { - LifetimePosition free_until_pos[DoubleRegister::kNumAllocatableRegisters]; - - for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; i++) { - free_until_pos[i] = LifetimePosition::MaxPosition(); - } - + LifetimePosition max_pos = LifetimePosition::FromInstructionIndex( + chunk_->instructions()->length() + 1); + ASSERT(DoubleRegister::kNumAllocatableRegisters >= + Register::kNumAllocatableRegisters); + EmbeddedVector + free_pos(max_pos); for (int i = 0; i < active_live_ranges_.length(); ++i) { LiveRange* cur_active = active_live_ranges_.at(i); - free_until_pos[cur_active->assigned_register()] = + free_pos[cur_active->assigned_register()] = LifetimePosition::FromInstructionIndex(0); } @@ -1762,83 +1748,67 @@ bool LAllocator::TryAllocateFreeReg(LiveRange* current) { cur_inactive->FirstIntersection(current); if (!next_intersection.IsValid()) continue; int cur_reg = cur_inactive->assigned_register(); - free_until_pos[cur_reg] = Min(free_until_pos[cur_reg], next_intersection); + free_pos[cur_reg] = Min(free_pos[cur_reg], next_intersection); } - UsePosition* hinted_use = current->FirstPosWithHint(); - if (hinted_use != NULL) { - LOperand* hint = hinted_use->hint(); + UsePosition* pos = current->FirstPosWithHint(); + if (pos != NULL) { + LOperand* hint = pos->hint(); if (hint->IsRegister() || hint->IsDoubleRegister()) { int register_index = hint->index(); - TraceAlloc( - "Found reg hint %s (free until [%d) for live range %d (end %d[).\n", - RegisterName(register_index), - free_until_pos[register_index].Value(), - current->id(), - current->End().Value()); - - // 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), + TraceAlloc("Found reg hint %d for live range %d (free [%d, end %d[)\n", + register_index, + current->id(), + free_pos[register_index].Value(), + current->End().Value()); + if (free_pos[register_index].Value() >= current->End().Value()) { + TraceAlloc("Assigning preferred reg %d to live range %d\n", + register_index, current->id()); - current->set_assigned_register(register_index, mode_); + current->set_assigned_register(register_index, mode_ == XMM_REGISTERS); return true; } } } - // Find the register which stays free for the longest time. - int reg = 0; + int max_reg = 0; for (int i = 1; i < RegisterCount(); ++i) { - if (free_until_pos[i].Value() > free_until_pos[reg].Value()) { - reg = i; + if (free_pos[i].Value() > free_pos[max_reg].Value()) { + max_reg = i; } } - LifetimePosition pos = free_until_pos[reg]; - - if (pos.Value() <= current->Start().Value()) { - // All registers are blocked. + if (free_pos[max_reg].InstructionIndex() == 0) { 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; } void LAllocator::AllocateBlockedReg(LiveRange* current) { - UsePosition* register_use = current->NextRegisterPosition(current->Start()); - if (register_use == NULL) { - // There is no use in the current live range that requires a register. - // We can just spill it. - Spill(current); - return; - } - - - 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(); - } + LifetimePosition max_pos = + LifetimePosition::FromInstructionIndex( + chunk_->instructions()->length() + 1); + ASSERT(DoubleRegister::kNumAllocatableRegisters >= + Register::kNumAllocatableRegisters); + EmbeddedVector + use_pos(max_pos); + EmbeddedVector + block_pos(max_pos); for (int i = 0; i < active_live_ranges_.length(); ++i) { LiveRange* range = active_live_ranges_[i]; @@ -1871,63 +1841,47 @@ void LAllocator::AllocateBlockedReg(LiveRange* current) { } } - int reg = 0; + int max_reg = 0; for (int i = 1; i < RegisterCount(); ++i) { - if (use_pos[i].Value() > use_pos[reg].Value()) { - reg = i; + if (use_pos[i].Value() > use_pos[max_reg].Value()) { + max_reg = i; } } - LifetimePosition pos = use_pos[reg]; - - if (pos.Value() < register_use->pos().Value()) { - // All registers are blocked before the first use that requires a register. - // Spill starting part of live range up to that use. - // - // Corner case: the first use position is equal to the start of the range. - // In this case we have nothing to spill and SpillBetween will just return - // this range to the list of unhandled ones. This will lead to the infinite - // loop. - ASSERT(current->Start().Value() < register_use->pos().Value()); - SpillBetween(current, current->Start(), register_use->pos()); - return; - } + UsePosition* first_usage = current->NextRegisterPosition(current->Start()); + if (first_usage == NULL) { + Spill(current); + } else if (use_pos[max_reg].Value() < first_usage->pos().Value()) { + SplitAndSpill(current, current->Start(), first_usage->pos()); + } else { + if (block_pos[max_reg].Value() < current->End().Value()) { + // Split current before blocked position. + LiveRange* second_range = Split(current, + current->Start(), + block_pos[max_reg]); + AddToUnhandledSorted(second_range); + } - if (block_pos[reg].Value() < current->End().Value()) { - // Register becomes blocked before the current range end. Split before that - // position. - LiveRange* tail = SplitBetween(current, - current->Start(), - block_pos[reg].InstructionStart()); - AddToUnhandledSorted(tail); + current->set_assigned_register(max_reg, mode_ == XMM_REGISTERS); + SplitAndSpillIntersecting(current); } - - // 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) { ASSERT(current->HasRegisterAssigned()); int reg = current->assigned_register(); - LifetimePosition split_pos = current->Start(); + LifetimePosition split_pos = + LifetimePosition::FromInstructionIndex( + chunk_->NearestGapPos(current->Start().InstructionIndex())); for (int i = 0; i < active_live_ranges_.length(); ++i) { LiveRange* range = active_live_ranges_[i]; if (range->assigned_register() == reg) { UsePosition* next_pos = range->NextRegisterPosition(current->Start()); if (next_pos == NULL) { - SpillAfter(range, split_pos); + SplitAndSpill(range, split_pos); } else { - SpillBetween(range, split_pos, next_pos->pos()); + SplitAndSpill(range, split_pos, next_pos->pos()); } ActiveToHandled(range); --i; @@ -1942,10 +1896,10 @@ void LAllocator::SplitAndSpillIntersecting(LiveRange* current) { if (next_intersection.IsValid()) { UsePosition* next_pos = range->NextRegisterPosition(current->Start()); if (next_pos == NULL) { - SpillAfter(range, split_pos); + SplitAndSpill(range, split_pos); } else { next_intersection = Min(next_intersection, next_pos->pos()); - SpillBetween(range, split_pos, next_intersection); + SplitAndSpill(range, split_pos, next_intersection); } InactiveToHandled(range); --i; @@ -1955,50 +1909,19 @@ void LAllocator::SplitAndSpillIntersecting(LiveRange* current) { } -bool LAllocator::IsBlockBoundary(LifetimePosition pos) { - return pos.IsInstructionStart() && - 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) { +LiveRange* LAllocator::Split(LiveRange* range, + LifetimePosition start, + LifetimePosition end) { 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(), start.Value(), end.Value()); - LifetimePosition split_pos = FindOptimalSplitPos(start, end); + LifetimePosition split_pos = FindOptimalSplitPos( + start, end.PrevInstruction().InstructionEnd()); ASSERT(split_pos.Value() >= start.Value()); - return SplitAt(range, split_pos); + return Split(range, split_pos); } @@ -2021,52 +1944,81 @@ LifetimePosition LAllocator::FindOptimalSplitPos(LifetimePosition start, } HBasicBlock* block = end_block; - // Find header of outermost loop. + // Move to the most outside loop header. while (block->parent_loop_header() != NULL && block->parent_loop_header()->block_id() > start_block->block_id()) { block = block->parent_loop_header(); } - if (block == end_block) return end; + if (block == end_block) { + return end; + } return LifetimePosition::FromInstructionIndex( block->first_instruction_index()); } -void LAllocator::SpillAfter(LiveRange* range, LifetimePosition pos) { - LiveRange* second_part = SplitAt(range, pos); - Spill(second_part); +bool LAllocator::IsBlockBoundary(LifetimePosition pos) { + return pos.IsInstructionStart() && + chunk_->instructions()->at(pos.InstructionIndex())->IsLabel(); } -void LAllocator::SpillBetween(LiveRange* range, - LifetimePosition start, - LifetimePosition end) { - ASSERT(start.Value() < end.Value()); - LiveRange* second_part = SplitAt(range, start); +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); +} - if (second_part->Start().Value() < end.Value()) { - // The split result intersects with [start, end[. - // Split it at position between ]start+1, end[, spill the middle part - // and put the rest to unhandled. - LiveRange* third_part = SplitBetween( - second_part, - second_part->Start().InstructionEnd(), - end.PrevInstruction().InstructionEnd()); - ASSERT(third_part != second_part); +LiveRange* LAllocator::Split(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; +} - Spill(second_part); + +void LAllocator::SplitAndSpill(LiveRange* range, + 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); } else { - // The split result does not intersect with [start, end[. - // Nothing to spill. Just put it to unhandled as whole. - AddToUnhandledSorted(second_part); + AddToUnhandledSorted(tail_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) { ASSERT(!range->IsSpilled()); TraceAlloc("Spilling live range %d\n", range->id()); @@ -2074,7 +2026,7 @@ void LAllocator::Spill(LiveRange* range) { if (!first->HasAllocatedSpillOperand()) { LOperand* op = TryReuseSpillSlot(range); - if (op == NULL) op = chunk_->GetNextSpillSlot(mode_ == DOUBLE_REGISTERS); + if (op == NULL) op = chunk_->GetNextSpillSlot(mode_ == XMM_REGISTERS); first->SetSpillOperand(op); } range->MakeSpilled(); diff --git a/deps/v8/src/lithium-allocator.h b/deps/v8/src/lithium-allocator.h index 3ec984e262..52fee6455f 100644 --- a/deps/v8/src/lithium-allocator.h +++ b/deps/v8/src/lithium-allocator.h @@ -55,7 +55,6 @@ class LPointerMap; class LStackSlot; class LRegister; - // This class represents a single point of a LOperand's lifetime. // For each lithium instruction there are exactly two lifetime positions: // the beginning and the end of the instruction. Lifetime positions for @@ -122,13 +121,7 @@ class LifetimePosition { // instruction. bool IsValid() const { return value_ != -1; } - 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); - } + static LifetimePosition Invalid() { return LifetimePosition(); } private: static const int kStep = 2; @@ -142,13 +135,6 @@ class LifetimePosition { }; -enum RegisterKind { - NONE, - GENERAL_REGISTERS, - DOUBLE_REGISTERS -}; - - class LOperand: public ZoneObject { public: enum Kind { @@ -608,8 +594,8 @@ class LiveRange: public ZoneObject { explicit LiveRange(int id) : id_(id), spilled_(false), + assigned_double_(false), assigned_register_(kInvalidAssignment), - assigned_register_kind_(NONE), last_interval_(NULL), first_interval_(NULL), first_pos_(NULL), @@ -634,10 +620,10 @@ class LiveRange: public ZoneObject { LOperand* CreateAssignedOperand(); int assigned_register() const { return assigned_register_; } int spill_start_index() const { return spill_start_index_; } - void set_assigned_register(int reg, RegisterKind register_kind) { + void set_assigned_register(int reg, bool double_reg) { ASSERT(!HasRegisterAssigned() && !IsSpilled()); assigned_register_ = reg; - assigned_register_kind_ = register_kind; + assigned_double_ = double_reg; ConvertOperands(); } void MakeSpilled() { @@ -666,13 +652,9 @@ class LiveRange: public ZoneObject { // Can this live range be spilled at this position. 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); - bool IsDouble() const { return assigned_register_kind_ == DOUBLE_REGISTERS; } + bool IsDouble() const { return assigned_double_; } bool HasRegisterAssigned() const { return assigned_register_ != kInvalidAssignment; } @@ -739,8 +721,8 @@ class LiveRange: public ZoneObject { int id_; bool spilled_; + bool assigned_double_; int assigned_register_; - RegisterKind assigned_register_kind_; UseInterval* last_interval_; UseInterval* first_interval_; UsePosition* first_pos_; @@ -792,8 +774,8 @@ class LAllocator BASE_EMBEDDED { // Checks whether the value of a given virtual register is tagged. bool HasTaggedValue(int virtual_register) const; - // Returns the register kind required by the given virtual register. - RegisterKind RequiredRegisterKind(int virtual_register) const; + // Checks whether the value of a given virtual register is a double. + bool HasDoubleValue(int virtual_register) const; // Begin a new instruction. void BeginInstruction(); @@ -832,6 +814,12 @@ class LAllocator BASE_EMBEDDED { #endif private: + enum OperationMode { + NONE, + CPU_REGISTERS, + XMM_REGISTERS + }; + void MeetRegisterConstraints(); void ResolvePhis(); void BuildLiveRanges(); @@ -883,38 +871,17 @@ class LAllocator BASE_EMBEDDED { // Helper methods for allocating registers. bool TryAllocateFreeReg(LiveRange* range); void AllocateBlockedReg(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. + void SplitAndSpillIntersecting(LiveRange* range); LifetimePosition FindOptimalSplitPos(LifetimePosition start, LifetimePosition end); - - // Spill the given life range after position pos. - void SpillAfter(LiveRange* range, LifetimePosition pos); - - // Spill the given life range after position start and up to position end. - void SpillBetween(LiveRange* range, - LifetimePosition start, - LifetimePosition end); - - void SplitAndSpillIntersecting(LiveRange* range); - + LiveRange* Split(LiveRange* range, + LifetimePosition start, + LifetimePosition end); + LiveRange* Split(LiveRange* range, LifetimePosition split_pos); + void SplitAndSpill(LiveRange* range, + LifetimePosition start, + LifetimePosition end); + void SplitAndSpill(LiveRange* range, LifetimePosition at); void Spill(LiveRange* range); bool IsBlockBoundary(LifetimePosition pos); void AddGapMove(int pos, LiveRange* prev, LiveRange* next); @@ -947,8 +914,6 @@ class LAllocator BASE_EMBEDDED { HPhi* LookupPhi(LOperand* operand) const; LGap* GetLastGap(HBasicBlock* block) const; - const char* RegisterName(int allocation_index); - LChunk* chunk_; ZoneList summaries_; InstructionSummary* next_summary_; @@ -973,7 +938,7 @@ class LAllocator BASE_EMBEDDED { // Next virtual register number to be assigned to temporaries. int next_virtual_register_; - RegisterKind mode_; + OperationMode mode_; int num_registers_; HGraph* graph_; diff --git a/deps/v8/src/log-utils.cc b/deps/v8/src/log-utils.cc index c7b75679ea..d6d8754b23 100644 --- a/deps/v8/src/log-utils.cc +++ b/deps/v8/src/log-utils.cc @@ -273,7 +273,29 @@ void LogMessageBuilder::Append(String* str) { void LogMessageBuilder::AppendAddress(Address addr) { - Append("0x%" V8PRIxPTR, addr); + static Address last_address_ = NULL; + 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); + } } @@ -321,6 +343,24 @@ void LogMessageBuilder::AppendStringPart(const char* str, int len) { } +bool LogMessageBuilder::StoreInCompressor(LogRecordCompressor* compressor) { + return compressor->Store(Vector(Log::message_buffer_, pos_)); +} + + +bool LogMessageBuilder::RetrieveCompressedPrevious( + LogRecordCompressor* compressor, const char* prefix) { + pos_ = 0; + if (prefix[0] != '\0') Append(prefix); + Vector 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() { ASSERT(pos_ <= Log::kMessageBufferSize); const int written = Log::Write(Log::message_buffer_, pos_); @@ -329,6 +369,145 @@ 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 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& record) { + // Check if the record is the same as the last stored one. + if (curr_ != -1) { + Vector& 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 record_copy = Vector::New(record.length()); + memcpy(record_copy.start(), record.start(), record.length()); + buffer_[curr_].Dispose(); + buffer_[curr_] = + Vector(record_copy.start(), record_copy.length()); + return true; +} + + +bool LogRecordCompressor::RetrievePreviousCompressed( + Vector* 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& 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& 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(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 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(unchanged_len + best.backref_size)); + } + return true; +} + #endif // ENABLE_LOGGING_AND_PROFILING } } // namespace v8::internal diff --git a/deps/v8/src/log-utils.h b/deps/v8/src/log-utils.h index 719d37030e..ffea9282cb 100644 --- a/deps/v8/src/log-utils.h +++ b/deps/v8/src/log-utils.h @@ -176,6 +176,50 @@ class Log : public AllStatic { friend class Logger; 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* 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& 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 dest, int distance, int pos); + + ScopedVector< Vector > buffer_; + const int kMaxBackwardReferenceSize; + int curr_; + int prev_; }; @@ -200,14 +244,32 @@ class LogMessageBuilder BASE_EMBEDDED { // Append a heap string. void Append(String* str); - // Appends an address. + // Appends an address, compressing it if needed by offsetting + // from Logger::last_address_. 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); // Append a portion of a string. 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. void WriteToLogFile(); diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc index b8e3f05a47..6723347924 100644 --- a/deps/v8/src/log.cc +++ b/deps/v8/src/log.cc @@ -303,6 +303,7 @@ void Profiler::Engage() { Logger::ticker_->SetProfiler(this); Logger::ProfilerBeginEvent(); + Logger::LogAliases(); } @@ -342,21 +343,43 @@ void Profiler::Run() { Ticker* Logger::ticker_ = NULL; Profiler* Logger::profiler_ = 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::cpu_profiler_nesting_ = 0; int Logger::heap_profiler_nesting_ = 0; -#define DECLARE_EVENT(ignore1, name) name, -const char* kLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = { - LOG_EVENTS_AND_TAGS_LIST(DECLARE_EVENT) +#define DECLARE_LONG_EVENT(ignore1, long_name, ignore2) long_name, +const char* kLongLogEventsNames[Logger::NUMBER_OF_LOG_EVENTS] = { + LOG_EVENTS_AND_TAGS_LIST(DECLARE_LONG_EVENT) }; -#undef DECLARE_EVENT +#undef DECLARE_LONG_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() { if (!Log::IsEnabled()) return; LogMessageBuilder msg; 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(); } @@ -663,16 +686,55 @@ 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 prefix_; +}; + +#endif // ENABLE_LOGGING_AND_PROFILING + + #ifdef ENABLE_LOGGING_AND_PROFILING void Logger::CallbackEventInternal(const char* prefix, const char* name, Address entry_point) { if (!Log::IsEnabled() || !FLAG_log_code) return; LogMessageBuilder msg; msg.Append("%s,%s,", - kLogEventsNames[CODE_CREATION_EVENT], - kLogEventsNames[CALLBACK_TAG]); + log_events_[CODE_CREATION_EVENT], log_events_[CALLBACK_TAG]); msg.AppendAddress(entry_point); 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.WriteToLogFile(); } @@ -724,9 +786,7 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, #ifdef ENABLE_LOGGING_AND_PROFILING if (!Log::IsEnabled() || !FLAG_log_code) return; LogMessageBuilder msg; - msg.Append("%s,%s,", - kLogEventsNames[CODE_CREATION_EVENT], - kLogEventsNames[tag]); + msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.AppendAddress(code->address()); msg.Append(",%d,\"%s", code->ExecutableSize(), ComputeMarker(code)); for (const char* p = comment; *p != '\0'; p++) { @@ -737,6 +797,10 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, } msg.Append('"'); LowLevelCodeCreateEvent(code, &msg); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } msg.Append('\n'); msg.WriteToLogFile(); #endif @@ -749,12 +813,14 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, String* name) { LogMessageBuilder msg; SmartPointer str = name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); - msg.Append("%s,%s,", - kLogEventsNames[CODE_CREATION_EVENT], - kLogEventsNames[tag]); + msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.AppendAddress(code->address()); msg.Append(",%d,\"%s%s\"", code->ExecutableSize(), ComputeMarker(code), *str); LowLevelCodeCreateEvent(code, &msg); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } msg.Append('\n'); msg.WriteToLogFile(); #endif @@ -771,9 +837,7 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); SmartPointer sourcestr = source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); - msg.Append("%s,%s,", - kLogEventsNames[CODE_CREATION_EVENT], - kLogEventsNames[tag]); + msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.AppendAddress(code->address()); msg.Append(",%d,\"%s%s %s:%d\"", code->ExecutableSize(), @@ -782,6 +846,10 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, *sourcestr, line); LowLevelCodeCreateEvent(code, &msg); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } msg.Append('\n'); msg.WriteToLogFile(); #endif @@ -792,12 +860,14 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) { #ifdef ENABLE_LOGGING_AND_PROFILING if (!Log::IsEnabled() || !FLAG_log_code) return; LogMessageBuilder msg; - msg.Append("%s,%s,", - kLogEventsNames[CODE_CREATION_EVENT], - kLogEventsNames[tag]); + msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.AppendAddress(code->address()); msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count); LowLevelCodeCreateEvent(code, &msg); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } msg.Append('\n'); msg.WriteToLogFile(); #endif @@ -808,7 +878,7 @@ void Logger::CodeMovingGCEvent() { #ifdef ENABLE_LOGGING_AND_PROFILING if (!Log::IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return; LogMessageBuilder msg; - msg.Append("%s\n", kLogEventsNames[CODE_MOVING_GC]); + msg.Append("%s\n", log_events_[CODE_MOVING_GC]); msg.WriteToLogFile(); OS::SignalCodeMovingGC(); #endif @@ -820,13 +890,16 @@ void Logger::RegExpCodeCreateEvent(Code* code, String* source) { if (!Log::IsEnabled() || !FLAG_log_code) return; LogMessageBuilder msg; msg.Append("%s,%s,", - kLogEventsNames[CODE_CREATION_EVENT], - kLogEventsNames[REG_EXP_TAG]); + log_events_[CODE_CREATION_EVENT], log_events_[REG_EXP_TAG]); msg.AppendAddress(code->address()); msg.Append(",%d,\"", code->ExecutableSize()); msg.AppendDetailed(source, false); msg.Append('\"'); LowLevelCodeCreateEvent(code, &msg); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } msg.Append('\n'); msg.WriteToLogFile(); #endif @@ -851,9 +924,13 @@ void Logger::SnapshotPositionEvent(Address addr, int pos) { #ifdef ENABLE_LOGGING_AND_PROFILING if (!Log::IsEnabled() || !FLAG_log_snapshot_positions) return; LogMessageBuilder msg; - msg.Append("%s,", kLogEventsNames[SNAPSHOT_POSITION_EVENT]); + msg.Append("%s,", log_events_[SNAPSHOT_POSITION_EVENT]); msg.AppendAddress(addr); msg.Append(",%d", pos); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } msg.Append('\n'); msg.WriteToLogFile(); #endif @@ -865,12 +942,18 @@ void Logger::FunctionCreateEvent(JSFunction* function) { // This function can be called from GC iterators (during Scavenge, // MC, and MS), so marking bits can be set on objects. That's // why unchecked accessors are used here. + static Address prev_code = NULL; if (!Log::IsEnabled() || !FLAG_log_code) return; LogMessageBuilder msg; - msg.Append("%s,", kLogEventsNames[FUNCTION_CREATION_EVENT]); + msg.Append("%s,", log_events_[FUNCTION_CREATION_EVENT]); msg.AppendAddress(function->address()); msg.Append(','); - msg.AppendAddress(function->unchecked_code()->address()); + msg.AppendAddress(function->unchecked_code()->address(), prev_code); + prev_code = function->unchecked_code()->address(); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } msg.Append('\n'); msg.WriteToLogFile(); #endif @@ -904,12 +987,18 @@ void Logger::FunctionDeleteEvent(Address from) { void Logger::MoveEventInternal(LogEventsAndTags event, Address from, Address to) { + static Address prev_to_ = NULL; if (!Log::IsEnabled() || !FLAG_log_code) return; LogMessageBuilder msg; - msg.Append("%s,", kLogEventsNames[event]); + msg.Append("%s,", log_events_[event]); msg.AppendAddress(from); msg.Append(','); - msg.AppendAddress(to); + msg.AppendAddress(to, prev_to_); + prev_to_ = to; + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } msg.Append('\n'); msg.WriteToLogFile(); } @@ -920,8 +1009,12 @@ void Logger::MoveEventInternal(LogEventsAndTags event, void Logger::DeleteEventInternal(LogEventsAndTags event, Address from) { if (!Log::IsEnabled() || !FLAG_log_code) return; LogMessageBuilder msg; - msg.Append("%s,", kLogEventsNames[event]); + msg.Append("%s,", log_events_[event]); msg.AppendAddress(from); + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; + } msg.Append('\n'); msg.WriteToLogFile(); } @@ -1109,20 +1202,30 @@ void Logger::DebugEvent(const char* event_type, Vector parameter) { #ifdef ENABLE_LOGGING_AND_PROFILING void Logger::TickEvent(TickSample* sample, bool overflow) { if (!Log::IsEnabled() || !FLAG_prof) return; + static Address prev_sp = NULL; + static Address prev_function = NULL; LogMessageBuilder msg; - msg.Append("%s,", kLogEventsNames[TICK_EVENT]); - msg.AppendAddress(sample->pc); + msg.Append("%s,", log_events_[TICK_EVENT]); + Address prev_addr = sample->pc; + msg.AppendAddress(prev_addr); msg.Append(','); - msg.AppendAddress(sample->sp); + msg.AppendAddress(sample->sp, prev_sp); + prev_sp = sample->sp; msg.Append(','); - msg.AppendAddress(sample->function); + msg.AppendAddress(sample->function, prev_function); + prev_function = sample->function; msg.Append(",%d", static_cast(sample->state)); if (overflow) { msg.Append(",overflow"); } for (int i = 0; i < sample->frames_count; ++i) { msg.Append(','); - msg.AppendAddress(sample->stack[i]); + msg.AppendAddress(sample->stack[i], prev_addr); + prev_addr = sample->stack[i]; + } + if (FLAG_compress_log) { + ASSERT(compression_helper_ != NULL); + if (!compression_helper_->HandleMessage(&msg)) return; } msg.Append('\n'); msg.WriteToLogFile(); @@ -1551,6 +1654,12 @@ bool Logger::Setup() { sliding_state_window_ = new SlidingStateWindow(); } + log_events_ = FLAG_compress_log ? + kCompressedLogEventsNames : kLongLogEventsNames; + if (FLAG_compress_log) { + compression_helper_ = new CompressionHelper(kCompressionWindowSize); + } + if (start_logging) { logging_nesting_ = 1; } @@ -1598,6 +1707,9 @@ void Logger::TearDown() { profiler_ = NULL; } + delete compression_helper_; + compression_helper_ = NULL; + delete sliding_state_window_; sliding_state_window_ = NULL; diff --git a/deps/v8/src/log.h b/deps/v8/src/log.h index 771709c8a1..54b131bb0c 100644 --- a/deps/v8/src/log.h +++ b/deps/v8/src/log.h @@ -74,6 +74,7 @@ class Profiler; class Semaphore; class SlidingStateWindow; class LogMessageBuilder; +class CompressionHelper; #undef LOG #ifdef ENABLE_LOGGING_AND_PROFILING @@ -87,55 +88,58 @@ class LogMessageBuilder; #endif #define LOG_EVENTS_AND_TAGS_LIST(V) \ - V(CODE_CREATION_EVENT, "code-creation") \ - V(CODE_MOVE_EVENT, "code-move") \ - V(CODE_DELETE_EVENT, "code-delete") \ - V(CODE_MOVING_GC, "code-moving-gc") \ - V(FUNCTION_CREATION_EVENT, "function-creation") \ - V(FUNCTION_MOVE_EVENT, "function-move") \ - V(FUNCTION_DELETE_EVENT, "function-delete") \ - V(SNAPSHOT_POSITION_EVENT, "snapshot-pos") \ - V(TICK_EVENT, "tick") \ - V(REPEAT_META_EVENT, "repeat") \ - V(BUILTIN_TAG, "Builtin") \ - V(CALL_DEBUG_BREAK_TAG, "CallDebugBreak") \ - V(CALL_DEBUG_PREPARE_STEP_IN_TAG, "CallDebugPrepareStepIn") \ - V(CALL_IC_TAG, "CallIC") \ - V(CALL_INITIALIZE_TAG, "CallInitialize") \ - V(CALL_MEGAMORPHIC_TAG, "CallMegamorphic") \ - V(CALL_MISS_TAG, "CallMiss") \ - V(CALL_NORMAL_TAG, "CallNormal") \ - V(CALL_PRE_MONOMORPHIC_TAG, "CallPreMonomorphic") \ - V(KEYED_CALL_DEBUG_BREAK_TAG, "KeyedCallDebugBreak") \ - V(KEYED_CALL_DEBUG_PREPARE_STEP_IN_TAG, \ - "KeyedCallDebugPrepareStepIn") \ - V(KEYED_CALL_IC_TAG, "KeyedCallIC") \ - V(KEYED_CALL_INITIALIZE_TAG, "KeyedCallInitialize") \ - V(KEYED_CALL_MEGAMORPHIC_TAG, "KeyedCallMegamorphic") \ - V(KEYED_CALL_MISS_TAG, "KeyedCallMiss") \ - V(KEYED_CALL_NORMAL_TAG, "KeyedCallNormal") \ - V(KEYED_CALL_PRE_MONOMORPHIC_TAG, "KeyedCallPreMonomorphic") \ - V(CALLBACK_TAG, "Callback") \ - V(EVAL_TAG, "Eval") \ - V(FUNCTION_TAG, "Function") \ - V(KEYED_LOAD_IC_TAG, "KeyedLoadIC") \ - V(KEYED_STORE_IC_TAG, "KeyedStoreIC") \ - V(LAZY_COMPILE_TAG, "LazyCompile") \ - V(LOAD_IC_TAG, "LoadIC") \ - V(REG_EXP_TAG, "RegExp") \ - V(SCRIPT_TAG, "Script") \ - V(STORE_IC_TAG, "StoreIC") \ - V(STUB_TAG, "Stub") \ - V(NATIVE_FUNCTION_TAG, "Function") \ - V(NATIVE_LAZY_COMPILE_TAG, "LazyCompile") \ - V(NATIVE_SCRIPT_TAG, "Script") + V(CODE_CREATION_EVENT, "code-creation", "cc") \ + V(CODE_MOVE_EVENT, "code-move", "cm") \ + V(CODE_DELETE_EVENT, "code-delete", "cd") \ + V(CODE_MOVING_GC, "code-moving-gc", "cg") \ + V(FUNCTION_CREATION_EVENT, "function-creation", "fc") \ + V(FUNCTION_MOVE_EVENT, "function-move", "fm") \ + V(FUNCTION_DELETE_EVENT, "function-delete", "fd") \ + V(SNAPSHOT_POSITION_EVENT, "snapshot-pos", "sp") \ + V(TICK_EVENT, "tick", "t") \ + V(REPEAT_META_EVENT, "repeat", "r") \ + V(BUILTIN_TAG, "Builtin", "bi") \ + V(CALL_DEBUG_BREAK_TAG, "CallDebugBreak", "cdb") \ + V(CALL_DEBUG_PREPARE_STEP_IN_TAG, "CallDebugPrepareStepIn", "cdbsi") \ + V(CALL_IC_TAG, "CallIC", "cic") \ + V(CALL_INITIALIZE_TAG, "CallInitialize", "ci") \ + V(CALL_MEGAMORPHIC_TAG, "CallMegamorphic", "cmm") \ + V(CALL_MISS_TAG, "CallMiss", "cm") \ + V(CALL_NORMAL_TAG, "CallNormal", "cn") \ + V(CALL_PRE_MONOMORPHIC_TAG, "CallPreMonomorphic", "cpm") \ + V(KEYED_CALL_DEBUG_BREAK_TAG, "KeyedCallDebugBreak", "kcdb") \ + V(KEYED_CALL_DEBUG_PREPARE_STEP_IN_TAG, \ + "KeyedCallDebugPrepareStepIn", \ + "kcdbsi") \ + V(KEYED_CALL_IC_TAG, "KeyedCallIC", "kcic") \ + V(KEYED_CALL_INITIALIZE_TAG, "KeyedCallInitialize", "kci") \ + V(KEYED_CALL_MEGAMORPHIC_TAG, "KeyedCallMegamorphic", "kcmm") \ + V(KEYED_CALL_MISS_TAG, "KeyedCallMiss", "kcm") \ + V(KEYED_CALL_NORMAL_TAG, "KeyedCallNormal", "kcn") \ + V(KEYED_CALL_PRE_MONOMORPHIC_TAG, \ + "KeyedCallPreMonomorphic", \ + "kcpm") \ + V(CALLBACK_TAG, "Callback", "cb") \ + V(EVAL_TAG, "Eval", "e") \ + V(FUNCTION_TAG, "Function", "f") \ + V(KEYED_LOAD_IC_TAG, "KeyedLoadIC", "klic") \ + V(KEYED_STORE_IC_TAG, "KeyedStoreIC", "ksic") \ + V(LAZY_COMPILE_TAG, "LazyCompile", "lc") \ + V(LOAD_IC_TAG, "LoadIC", "lic") \ + V(REG_EXP_TAG, "RegExp", "re") \ + V(SCRIPT_TAG, "Script", "sc") \ + V(STORE_IC_TAG, "StoreIC", "sic") \ + V(STUB_TAG, "Stub", "s") \ + 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 // original tags when writing to the log. class Logger { public: -#define DECLARE_ENUM(enum_item, ignore) enum_item, +#define DECLARE_ENUM(enum_item, ignore1, ignore2) enum_item, enum LogEventsAndTags { LOG_EVENTS_AND_TAGS_LIST(DECLARE_ENUM) NUMBER_OF_LOG_EVENTS @@ -288,6 +292,9 @@ class Logger { private: + // Size of window used for log records compression. + static const int kCompressionWindowSize = 4; + // Emits the profiler's first message. static void ProfilerBeginEvent(); @@ -305,6 +312,9 @@ class Logger { static void DeleteEventInternal(LogEventsAndTags event, Address from); + // Emits aliases for compressed messages. + static void LogAliases(); + // Emits the source code of a regexp. Used by regexp events. static void LogRegExpSource(Handle regexp); @@ -347,8 +357,15 @@ class Logger { // recent VM states. 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 // private members. + friend class CompressionHelper; friend class EventLog; friend class TimeLog; friend class Profiler; diff --git a/deps/v8/src/math.js b/deps/v8/src/math.js index 2e886d099a..fa1934da41 100644 --- a/deps/v8/src/math.js +++ b/deps/v8/src/math.js @@ -264,7 +264,6 @@ function SetupMath() { %SetMathFunctionId($Math.round, 2); %SetMathFunctionId($Math.abs, 4); %SetMathFunctionId($Math.sqrt, 0xd); - %SetMathFunctionId($Math.pow, 0xe); // TODO(erikcorry): Set the id of the other functions so they can be // optimized. }; diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index c3958e2396..1827ab0114 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -3729,9 +3729,7 @@ enum MathFunctionId { kMathACos = 0xa, kMathATan = 0xb, kMathExp = 0xc, - kMathSqrt = 0xd, - kMathPow = 0xe, - kMathPowHalf = 0xf + kMathSqrt = 0xd }; @@ -4156,11 +4154,11 @@ class SharedFunctionInfo: public HeapObject { static const int kTryFullCodegen = 1; static const int kAllowLazyCompilation = 2; static const int kMathFunctionShift = 3; - static const int kMathFunctionMask = 0x1f; - static const int kLiveObjectsMayExist = 8; - static const int kCodeAgeShift = 9; + static const int kMathFunctionMask = 0xf; + static const int kLiveObjectsMayExist = 7; + static const int kCodeAgeShift = 8; static const int kCodeAgeMask = 0x7; - static const int kOptimizationDisabled = 12; + static const int kOptimizationDisabled = 11; DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo); }; diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index 94ad57c9c2..5473f25164 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -609,25 +609,7 @@ FunctionLiteral* Parser::ParseProgram(Handle source, // Initialize parser state. source->TryFlatten(); - 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::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 source, - bool in_global_context, - ZoneScope* zone_scope) { + scanner_.Initialize(source); ASSERT(target_stack_ == NULL); if (pre_data_ != NULL) pre_data_->Initialize(); @@ -673,45 +655,25 @@ FunctionLiteral* Parser::DoParseProgram(Handle source, // 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. - if (result == NULL) zone_scope->DeleteOnExit(); + if (result == NULL) zone_scope.DeleteOnExit(); return result; } + FunctionLiteral* Parser::ParseLazy(Handle info) { CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT); HistogramTimerScope timer(&Counters::parse_lazy); Handle source(String::cast(script_->source())); Counters::total_parse_size.Increment(source->length()); - // Initialize parser state. - source->TryFlatten(); - if (source->IsExternalTwoByteString()) { - ExternalTwoByteStringUC16CharacterStream stream( - Handle::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 info, - UC16CharacterStream* source, - ZoneScope* zone_scope) { - scanner_.Initialize(source, JavaScriptScanner::kAllLiterals); - ASSERT(target_stack_ == NULL); - Handle name(String::cast(info->name())); fni_ = new FuncNameInferrer(); fni_->PushEnclosingName(name); + // Initialize parser state. + source->TryFlatten(); + scanner_.Initialize(source, info->start_position(), info->end_position()); + ASSERT(target_stack_ == NULL); mode_ = PARSE_EAGERLY; // Place holder for the result. @@ -743,7 +705,7 @@ FunctionLiteral* Parser::ParseLazy(Handle info, // not safe to do before scope has been deleted. if (result == NULL) { Top::StackOverflow(); - zone_scope->DeleteOnExit(); + zone_scope.DeleteOnExit(); } else { Handle inferred_name(info->inferred_name()); result->set_inferred_name(inferred_name); @@ -757,12 +719,12 @@ Handle Parser::GetSymbol(bool* ok) { if (pre_data() != NULL) { symbol_id = pre_data()->GetSymbolIdentifier(); } - return LookupSymbol(symbol_id, scanner().literal()); + return LookupSymbol(symbol_id, scanner_.literal()); } void Parser::ReportMessage(const char* type, Vector args) { - Scanner::Location source_location = scanner().location(); + Scanner::Location source_location = scanner_.location(); ReportMessageAt(source_location, type, args); } @@ -1679,7 +1641,7 @@ Statement* Parser::ParseContinueStatement(bool* ok) { Expect(Token::CONTINUE, CHECK_OK); Handle label = Handle::null(); 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) { label = ParseIdentifier(CHECK_OK); } @@ -1705,7 +1667,7 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) { Expect(Token::BREAK, CHECK_OK); Handle label; 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) { label = ParseIdentifier(CHECK_OK); } @@ -1750,7 +1712,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) { } 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) { @@ -1882,7 +1844,7 @@ Statement* Parser::ParseThrowStatement(bool* ok) { Expect(Token::THROW, CHECK_OK); 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::empty()); *ok = false; return NULL; @@ -2446,8 +2408,7 @@ Expression* Parser::ParsePostfixExpression(bool* ok) { // LeftHandSideExpression ('++' | '--')? 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 // left-hand side expression. We could report this as a syntax // error here but for compatibility with JSC we choose to report the @@ -2716,7 +2677,7 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { case Token::NUMBER: { Consume(Token::NUMBER); double value = - StringToDouble(scanner().literal(), ALLOW_HEX | ALLOW_OCTALS); + StringToDouble(scanner_.literal(), ALLOW_HEX | ALLOW_OCTALS); result = NewNumberLiteral(value); break; } @@ -3067,7 +3028,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { case Token::NUMBER: { Consume(Token::NUMBER); double value = - StringToDouble(scanner().literal(), ALLOW_HEX | ALLOW_OCTALS); + StringToDouble(scanner_.literal(), ALLOW_HEX | ALLOW_OCTALS); key = NewNumberLiteral(value); break; } @@ -3128,7 +3089,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) { - if (!scanner().ScanRegExpPattern(seen_equal)) { + if (!scanner_.ScanRegExpPattern(seen_equal)) { Next(); ReportMessage("unterminated_regexp", Vector::empty()); *ok = false; @@ -3138,10 +3099,10 @@ Expression* Parser::ParseRegExpLiteral(bool seen_equal, bool* ok) { int literal_index = temp_scope_->NextMaterializedLiteralIndex(); Handle js_pattern = - Factory::NewStringFromUtf8(scanner().next_literal(), TENURED); - scanner().ScanRegExpFlags(); + Factory::NewStringFromUtf8(scanner_.next_literal(), TENURED); + scanner_.ScanRegExpFlags(); Handle js_flags = - Factory::NewStringFromUtf8(scanner().next_literal(), TENURED); + Factory::NewStringFromUtf8(scanner_.next_literal(), TENURED); Next(); return new RegExpLiteral(js_pattern, js_flags, literal_index); @@ -3197,7 +3158,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle var_name, // FormalParameterList :: // '(' (Identifier)*[','] ')' Expect(Token::LPAREN, CHECK_OK); - int start_pos = scanner().location().beg_pos; + int start_pos = scanner_.location().beg_pos; bool done = (peek() == Token::RPAREN); while (!done) { Handle param_name = ParseIdentifier(CHECK_OK); @@ -3234,7 +3195,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle var_name, bool is_lazily_compiled = 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 expected_property_count; int end_pos; @@ -3251,8 +3212,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle var_name, ReportInvalidPreparseData(name, CHECK_OK); } Counters::total_preparse_skipped.Increment(end_pos - function_block_pos); - // Seek to position just before terminal '}'. - scanner().SeekForward(end_pos - 1); + scanner_.SeekForward(end_pos); materialized_literal_count = entry.literal_count(); expected_property_count = entry.property_count(); only_simple_this_property_assignments = false; @@ -3268,7 +3228,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle var_name, this_property_assignments = temp_scope.this_property_assignments(); Expect(Token::RBRACE, CHECK_OK); - end_pos = scanner().location().end_pos; + end_pos = scanner_.location().end_pos; } FunctionLiteral* function_literal = @@ -3372,7 +3332,7 @@ void Parser::ExpectSemicolon(bool* ok) { Next(); return; } - if (scanner().has_line_terminator_before_next() || + if (scanner_.has_line_terminator_before_next() || tok == Token::RBRACE || tok == Token::EOS) { return; @@ -3423,8 +3383,8 @@ Handle Parser::ParseIdentifierOrGetOrSet(bool* is_get, bool* ok) { Expect(Token::IDENTIFIER, ok); if (!*ok) return Handle(); - if (scanner().literal_length() == 3) { - const char* token = scanner().literal_string(); + if (scanner_.literal_length() == 3) { + const char* token = scanner_.literal_string(); *is_get = strcmp(token, "get") == 0; *is_set = !*is_get && strcmp(token, "set") == 0; } @@ -3543,8 +3503,8 @@ Expression* Parser::NewThrowError(Handle constructor, // ---------------------------------------------------------------------------- // JSON -Handle JsonParser::ParseJson(Handle script, - UC16CharacterStream* source) { +Handle JsonParser::ParseJson(Handle source) { + source->TryFlatten(); scanner_.Initialize(source); stack_overflow_ = false; Handle result = ParseJsonValue(); @@ -3580,7 +3540,7 @@ Handle JsonParser::ParseJson(Handle script, } Scanner::Location source_location = scanner_.location(); - MessageLocation location(Factory::NewScript(script), + MessageLocation location(Factory::NewScript(source), source_location.beg_pos, source_location.end_pos); int argc = (name_opt == NULL) ? 0 : 1; @@ -4595,12 +4555,13 @@ int ScriptDataImpl::ReadNumber(byte** source) { // Create a Scanner for the preparser to use as input, and preparse the source. -static ScriptDataImpl* DoPreParse(UC16CharacterStream* source, +static ScriptDataImpl* DoPreParse(Handle source, + unibrow::CharacterStream* stream, bool allow_lazy, ParserRecorder* recorder, int literal_flags) { V8JavaScriptScanner scanner; - scanner.Initialize(source, literal_flags); + scanner.Initialize(source, stream, literal_flags); intptr_t stack_limit = StackGuard::real_climit(); if (!preparser::PreParser::PreParseProgram(&scanner, recorder, @@ -4619,7 +4580,8 @@ static ScriptDataImpl* DoPreParse(UC16CharacterStream* source, // Preparse, but only collect data that is immediately useful, // even if the preparser data is only used once. -ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source, +ScriptDataImpl* ParserApi::PartialPreParse(Handle source, + unibrow::CharacterStream* stream, v8::Extension* extension) { bool allow_lazy = FLAG_lazy && (extension == NULL); if (!allow_lazy) { @@ -4628,19 +4590,22 @@ ScriptDataImpl* ParserApi::PartialPreParse(UC16CharacterStream* source, return NULL; } PartialParserRecorder recorder; - return DoPreParse(source, allow_lazy, &recorder, + + return DoPreParse(source, stream, allow_lazy, &recorder, JavaScriptScanner::kNoLiterals); } -ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source, +ScriptDataImpl* ParserApi::PreParse(Handle source, + unibrow::CharacterStream* stream, v8::Extension* extension) { Handle