Revision: 24827
Author: [email protected]
Date: Thu Oct 23 08:44:45 2014 UTC
Log: Version 3.30.17 (based on bleeding_edge revision r24817)
ARM64: Fix stack manipulation (Chromium issue 425585).
Speed up creation of Objects whose prototype has dictionary elements
(Chromium issue 422754).
Enable libstdc++ debug mode in debug builds (issue 3638).
Performance and stability improvements on all platforms.
https://code.google.com/p/v8/source/detail?r=24827
Added:
/trunk/test/mjsunit/regress/regress-425551.js
/trunk/test/mjsunit/regress/regress-crbug-425585.js
Modified:
/trunk/ChangeLog
/trunk/build/standalone.gypi
/trunk/include/v8config.h
/trunk/src/arm/full-codegen-arm.cc
/trunk/src/arm64/assembler-arm64.cc
/trunk/src/arm64/assembler-arm64.h
/trunk/src/arm64/builtins-arm64.cc
/trunk/src/arm64/full-codegen-arm64.cc
/trunk/src/arm64/macro-assembler-arm64-inl.h
/trunk/src/arm64/macro-assembler-arm64.h
/trunk/src/arm64/simulator-arm64.cc
/trunk/src/array.js
/trunk/src/base/cpu.cc
/trunk/src/compiler/ast-graph-builder.cc
/trunk/src/compiler/change-lowering.cc
/trunk/src/compiler/code-generator.cc
/trunk/src/compiler/code-generator.h
/trunk/src/compiler/common-operator.cc
/trunk/src/compiler/common-operator.h
/trunk/src/compiler/graph-visualizer.cc
/trunk/src/compiler/instruction-selector.cc
/trunk/src/compiler/instruction.cc
/trunk/src/compiler/instruction.h
/trunk/src/compiler/opcodes.h
/trunk/src/compiler/operator-properties-inl.h
/trunk/src/compiler/schedule.cc
/trunk/src/compiler/schedule.h
/trunk/src/compiler/scheduler.cc
/trunk/src/compiler/simplified-lowering.cc
/trunk/src/compiler/verifier.cc
/trunk/src/conversions.cc
/trunk/src/conversions.h
/trunk/src/d8.cc
/trunk/src/flag-definitions.h
/trunk/src/harmony-tostring.js
/trunk/src/heap/heap.cc
/trunk/src/heap/heap.h
/trunk/src/heap/spaces.cc
/trunk/src/heap/spaces.h
/trunk/src/hydrogen.cc
/trunk/src/ia32/full-codegen-ia32.cc
/trunk/src/lookup.cc
/trunk/src/mips/full-codegen-mips.cc
/trunk/src/mips64/full-codegen-mips64.cc
/trunk/src/objects.cc
/trunk/src/runtime/runtime-numbers.cc
/trunk/src/sampler.cc
/trunk/src/third_party/vtune/v8-vtune.h
/trunk/src/third_party/vtune/vtune-jit.cc
/trunk/src/version.cc
/trunk/src/x64/full-codegen-x64.cc
/trunk/src/x87/full-codegen-x87.cc
/trunk/test/cctest/cctest.h
/trunk/test/cctest/compiler/test-scheduler.cc
/trunk/test/cctest/test-assembler-arm64.cc
/trunk/test/cctest/test-disasm-arm64.cc
/trunk/test/cctest/test-spaces.cc
/trunk/test/js-perf-test/Classes/Classes.json
/trunk/test/js-perf-test/Collections/Collections.json
/trunk/test/js-perf-test/Iterators/Iterators.json
/trunk/test/js-perf-test/Strings/Strings.json
/trunk/test/js-perf-test/Strings/harmony-string.js
/trunk/test/mjsunit/array-reduce.js
/trunk/test/mjsunit/fast-prototype.js
/trunk/test/mjsunit/getters-on-elements.js
/trunk/test/mjsunit/setters-on-elements.js
/trunk/test/unittests/compiler/common-operator-unittest.cc
/trunk/test/webkit/webkit.status
/trunk/tools/run-deopt-fuzzer.py
/trunk/tools/run-tests.py
/trunk/tools/whitespace.txt
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-425551.js Thu Oct 23 08:44:45 2014
UTC
@@ -0,0 +1,7 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var array = new Int8Array(10);
+array[/\u007d\u00fc\u0043/] = 1.499
+assertEquals(1.499, array[/\u007d\u00fc\u0043/]);
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-crbug-425585.js Thu Oct 23 08:44:45
2014 UTC
@@ -0,0 +1,48 @@
+// Copyright 2014 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.
+
+
+var correct_result = "This is the correct result.";
+
+function foo(recursion_depth) {
+ if (recursion_depth > 0) return foo(recursion_depth - 1);
+ return new String(correct_result, 1, 2, 3, 4, 5, 6);
+}
+
+// Roll our own non-strict assertEquals replacement.
+function test(i) {
+ var actual = foo(i);
+ if (correct_result != actual) {
+ var msg = "Expected \"" + correct_result + "\", found " + actual;
+ throw new MjsUnitAssertionError(msg);
+ }
+}
+
+test(1);
+test(1);
+test(10);
+test(100);
=======================================
--- /trunk/ChangeLog Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/ChangeLog Thu Oct 23 08:44:45 2014 UTC
@@ -1,3 +1,15 @@
+2014-10-23: Version 3.30.17
+
+ ARM64: Fix stack manipulation (Chromium issue 425585).
+
+ Speed up creation of Objects whose prototype has dictionary
elements
+ (Chromium issue 422754).
+
+ Enable libstdc++ debug mode in debug builds (issue 3638).
+
+ Performance and stability improvements on all platforms.
+
+
2014-10-22: Version 3.30.16
Remove v8stdint.h, it doesn't serve a purpose anymore.
=======================================
--- /trunk/build/standalone.gypi Mon Oct 20 08:53:36 2014 UTC
+++ /trunk/build/standalone.gypi Thu Oct 23 08:44:45 2014 UTC
@@ -136,6 +136,14 @@
'configurations': {
'DebugBaseCommon': {
'cflags': [ '-g', '-O0' ],
+ 'conditions': [
+ ['(v8_target_arch=="ia32" or v8_target_arch=="x87") and \
+ OS=="linux"', {
+ 'defines': [
+ '_GLIBCXX_DEBUG'
+ ],
+ }],
+ ],
},
'Optdebug': {
'inherit_from': [ 'DebugBaseCommon', 'DebugBase2' ],
=======================================
--- /trunk/include/v8config.h Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/include/v8config.h Thu Oct 23 08:44:45 2014 UTC
@@ -120,7 +120,6 @@
// V8_LIBC_BIONIC - Bionic libc
// V8_LIBC_BSD - BSD libc derivate
// V8_LIBC_GLIBC - GNU C library
-// V8_LIBC_UCLIBC - uClibc
//
// Note that testing for libc must be done using #if not #ifdef. For
example,
// to test for the GNU C library, use:
@@ -133,8 +132,6 @@
#elif defined(__BIONIC__)
# define V8_LIBC_BIONIC 1
# define V8_LIBC_BSD 1
-#elif defined(__UCLIBC__)
-# define V8_LIBC_UCLIBC 1
#elif defined(__GLIBC__) || defined(__GNU_LIBRARY__)
# define V8_LIBC_GLIBC 1
#else
=======================================
--- /trunk/src/arm/full-codegen-arm.cc Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/arm/full-codegen-arm.cc Thu Oct 23 08:44:45 2014 UTC
@@ -1726,6 +1726,8 @@
DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
// Fall through.
case ObjectLiteral::Property::COMPUTED:
+ // It is safe to use [[Put]] here because the boilerplate already
+ // contains computed properties with an uninitialized value.
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
@@ -1758,7 +1760,7 @@
__ push(r0);
VisitForStackValue(value);
if (property->emit_store()) {
- __ CallRuntime(Runtime::kSetPrototype, 2);
+ __ CallRuntime(Runtime::kInternalSetPrototype, 2);
} else {
__ Drop(2);
}
=======================================
--- /trunk/src/arm64/assembler-arm64.cc Fri Sep 12 00:05:16 2014 UTC
+++ /trunk/src/arm64/assembler-arm64.cc Thu Oct 23 08:44:45 2014 UTC
@@ -1934,6 +1934,12 @@
DCHECK(fd.SizeInBits() == fn.SizeInBits());
FPDataProcessing1Source(fd, fn, FRINTN);
}
+
+
+void Assembler::frintp(const FPRegister& fd, const FPRegister& fn) {
+ DCHECK(fd.SizeInBits() == fn.SizeInBits());
+ FPDataProcessing1Source(fd, fn, FRINTP);
+}
void Assembler::frintz(const FPRegister& fd,
=======================================
--- /trunk/src/arm64/assembler-arm64.h Fri Sep 26 00:05:23 2014 UTC
+++ /trunk/src/arm64/assembler-arm64.h Thu Oct 23 08:44:45 2014 UTC
@@ -1663,6 +1663,9 @@
// FP round to integer (nearest with ties to even).
void frintn(const FPRegister& fd, const FPRegister& fn);
+ // FP round to integer (towards plus infinity).
+ void frintp(const FPRegister& fd, const FPRegister& fn);
+
// FP round to integer (towards zero.)
void frintz(const FPRegister& fd, const FPRegister& fn);
=======================================
--- /trunk/src/arm64/builtins-arm64.cc Fri Sep 26 00:05:23 2014 UTC
+++ /trunk/src/arm64/builtins-arm64.cc Thu Oct 23 08:44:45 2014 UTC
@@ -156,7 +156,7 @@
__ Cbz(argc, &no_arguments);
// First args = sp[(argc - 1) * 8].
__ Sub(argc, argc, 1);
- __ Claim(argc, kXRegSize);
+ __ Drop(argc, kXRegSize);
// jssp now point to args[0], load and drop args[0] + receiver.
Register arg = argc;
__ Ldr(arg, MemOperand(jssp, 2 * kPointerSize, PostIndex));
=======================================
--- /trunk/src/arm64/full-codegen-arm64.cc Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/arm64/full-codegen-arm64.cc Thu Oct 23 08:44:45 2014 UTC
@@ -1706,6 +1706,8 @@
DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
// Fall through.
case ObjectLiteral::Property::COMPUTED:
+ // It is safe to use [[Put]] here because the boilerplate already
+ // contains computed properties with an uninitialized value.
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
@@ -1739,7 +1741,7 @@
__ Peek(x0, 0);
__ Push(x0);
VisitForStackValue(value);
- __ CallRuntime(Runtime::kSetPrototype, 2);
+ __ CallRuntime(Runtime::kInternalSetPrototype, 2);
} else {
VisitForEffect(value);
}
=======================================
--- /trunk/src/arm64/macro-assembler-arm64-inl.h Wed Sep 3 08:32:14 2014
UTC
+++ /trunk/src/arm64/macro-assembler-arm64-inl.h Thu Oct 23 08:44:45 2014
UTC
@@ -823,6 +823,12 @@
DCHECK(allow_macro_instructions_);
frintn(fd, fn);
}
+
+
+void MacroAssembler::Frintp(const FPRegister& fd, const FPRegister& fn) {
+ DCHECK(allow_macro_instructions_);
+ frintp(fd, fn);
+}
void MacroAssembler::Frintz(const FPRegister& fd, const FPRegister& fn) {
=======================================
--- /trunk/src/arm64/macro-assembler-arm64.h Tue Oct 14 07:51:07 2014 UTC
+++ /trunk/src/arm64/macro-assembler-arm64.h Thu Oct 23 08:44:45 2014 UTC
@@ -422,6 +422,7 @@
inline void Frinta(const FPRegister& fd, const FPRegister& fn);
inline void Frintm(const FPRegister& fd, const FPRegister& fn);
inline void Frintn(const FPRegister& fd, const FPRegister& fn);
+ inline void Frintp(const FPRegister& fd, const FPRegister& fn);
inline void Frintz(const FPRegister& fd, const FPRegister& fn);
inline void Fsqrt(const FPRegister& fd, const FPRegister& fn);
inline void Fsub(const FPRegister& fd,
=======================================
--- /trunk/src/arm64/simulator-arm64.cc Wed Sep 24 00:05:07 2014 UTC
+++ /trunk/src/arm64/simulator-arm64.cc Thu Oct 23 08:44:45 2014 UTC
@@ -2463,6 +2463,12 @@
set_sreg(fd, FPRoundInt(sreg(fn), FPNegativeInfinity)); break;
case FRINTM_d:
set_dreg(fd, FPRoundInt(dreg(fn), FPNegativeInfinity)); break;
+ case FRINTP_s:
+ set_sreg(fd, FPRoundInt(sreg(fn), FPPositiveInfinity));
+ break;
+ case FRINTP_d:
+ set_dreg(fd, FPRoundInt(dreg(fn), FPPositiveInfinity));
+ break;
case FRINTN_s: set_sreg(fd, FPRoundInt(sreg(fn), FPTieEven)); break;
case FRINTN_d: set_dreg(fd, FPRoundInt(dreg(fn), FPTieEven)); break;
case FRINTZ_s: set_sreg(fd, FPRoundInt(sreg(fn), FPZero)); break;
@@ -2767,6 +2773,10 @@
// We always use floor(value).
break;
}
+ case FPPositiveInfinity: {
+ int_result = ceil(value);
+ break;
+ }
default: UNIMPLEMENTED();
}
return int_result;
=======================================
--- /trunk/src/array.js Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/array.js Thu Oct 23 08:44:45 2014 UTC
@@ -1418,9 +1418,8 @@
var i = 0;
find_initial: if (%_ArgumentsLength() < 2) {
for (; i < length; i++) {
- current = array[i];
- if (!IS_UNDEFINED(current) || i in array) {
- i++;
+ if (i in array) {
+ current = array[i++];
break find_initial;
}
}
@@ -1455,9 +1454,8 @@
var i = length - 1;
find_initial: if (%_ArgumentsLength() < 2) {
for (; i >= 0; i--) {
- current = array[i];
- if (!IS_UNDEFINED(current) || i in array) {
- i--;
+ if (i in array) {
+ current = array[i--];
break find_initial;
}
}
=======================================
--- /trunk/src/base/cpu.cc Fri Oct 10 00:05:16 2014 UTC
+++ /trunk/src/base/cpu.cc Thu Oct 23 08:44:45 2014 UTC
@@ -7,12 +7,18 @@
#if V8_LIBC_MSVCRT
#include <intrin.h> // __cpuid()
#endif
-#if V8_OS_POSIX
-#include <unistd.h> // sysconf()
+#if V8_OS_LINUX
+#include <linux/auxvec.h> // AT_HWCAP
+#endif
+#if V8_GLIBC_PREREQ(2, 16)
+#include <sys/auxv.h> // getauxval()
#endif
#if V8_OS_QNX
#include <sys/syspage.h> // cpuinfo
#endif
+#if V8_OS_POSIX
+#include <unistd.h> // sysconf()
+#endif
#include <ctype.h>
#include <limits.h>
@@ -92,11 +98,12 @@
#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
#define HWCAP_LPAE (1 << 20)
-#define AT_HWCAP 16
-
-// Read the ELF HWCAP flags by parsing /proc/self/auxv.
static uint32_t ReadELFHWCaps() {
uint32_t result = 0;
+#if V8_GLIBC_PREREQ(2, 16)
+ result = static_cast<uint32_t>(getauxval(AT_HWCAP));
+#else
+ // Read the ELF HWCAP flags by parsing /proc/self/auxv.
FILE* fp = fopen("/proc/self/auxv", "r");
if (fp != NULL) {
struct { uint32_t tag; uint32_t value; } entry;
@@ -112,6 +119,7 @@
}
fclose(fp);
}
+#endif
return result;
}
@@ -310,7 +318,7 @@
has_vfp3_d32_(false),
is_fp64_mode_(false) {
memcpy(vendor_, "Unknown", 8);
-#if defined(__pnacl__)
+#if V8_OS_NACL
// Portable host shouldn't do feature detection.
// TODO(jfb): Remove the hardcoded ARM simulator flags in the build, and
// hardcode them here instead.
=======================================
--- /trunk/src/compiler/ast-graph-builder.cc Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/ast-graph-builder.cc Thu Oct 23 08:44:45 2014 UTC
@@ -942,7 +942,7 @@
Node* receiver = environment()->Pop();
if (property->emit_store()) {
const Operator* op =
- javascript()->CallRuntime(Runtime::kSetPrototype, 2);
+ javascript()->CallRuntime(Runtime::kInternalSetPrototype, 2);
NewNode(op, receiver, value);
}
break;
=======================================
--- /trunk/src/compiler/change-lowering.cc Thu Oct 2 00:05:29 2014 UTC
+++ /trunk/src/compiler/change-lowering.cc Thu Oct 23 08:44:45 2014 UTC
@@ -142,7 +142,8 @@
Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), val,
val);
Node* ovf = graph()->NewNode(common()->Projection(1), add);
- Node* branch = graph()->NewNode(common()->Branch(), ovf, control);
+ Node* branch =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), ovf, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* heap_number = AllocateHeapNumberWithValue(
@@ -215,7 +216,8 @@
Node* cmp = graph()->NewNode(machine()->Uint32LessThanOrEqual(), val,
SmiMaxValueConstant());
- Node* branch = graph()->NewNode(common()->Branch(), cmp, control);
+ Node* branch =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), cmp, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* smi = graph()->NewNode(
=======================================
--- /trunk/src/compiler/code-generator.cc Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/code-generator.cc Thu Oct 23 08:44:45 2014 UTC
@@ -44,10 +44,20 @@
info->set_prologue_offset(masm()->pc_offset());
AssemblePrologue();
- // Assemble all instructions.
- for (InstructionSequence::const_iterator i = code()->begin();
- i != code()->end(); ++i) {
- AssembleInstruction(*i);
+ // Assemble all non-deferred instructions.
+ for (auto const block : code()->instruction_blocks()) {
+ if (block->IsDeferred()) continue;
+ for (int i = block->code_start(); i < block->code_end(); ++i) {
+ AssembleInstruction(code()->InstructionAt(i));
+ }
+ }
+
+ // Assemble all deferred instructions.
+ for (auto const block : code()->instruction_blocks()) {
+ if (!block->IsDeferred()) continue;
+ for (int i = block->code_start(); i < block->code_end(); ++i) {
+ AssembleInstruction(code()->InstructionAt(i));
+ }
}
FinishCode(masm());
@@ -81,6 +91,12 @@
return result;
}
+
+
+bool CodeGenerator::IsNextInAssemblyOrder(BasicBlock::RpoNumber block)
const {
+ return code()->InstructionBlockAt(current_block_)->ao_number().IsNext(
+ code()->InstructionBlockAt(block)->ao_number());
+}
void CodeGenerator::RecordSafepoint(PointerMap* pointers, Safepoint::Kind
kind,
=======================================
--- /trunk/src/compiler/code-generator.h Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/code-generator.h Thu Oct 23 08:44:45 2014 UTC
@@ -39,9 +39,7 @@
// Checks if {block} will appear directly after {current_block_} when
// assembling code, in which case, a fall-through can be used.
- bool IsNextInAssemblyOrder(BasicBlock::RpoNumber block) const {
- return current_block_.IsNext(block);
- }
+ bool IsNextInAssemblyOrder(BasicBlock::RpoNumber block) const;
// Record a safepoint with the given pointer map.
void RecordSafepoint(PointerMap* pointers, Safepoint::Kind kind,
=======================================
--- /trunk/src/compiler/common-operator.cc Wed Oct 8 13:44:16 2014 UTC
+++ /trunk/src/compiler/common-operator.cc Thu Oct 23 08:44:45 2014 UTC
@@ -30,6 +30,26 @@
} // namespace
+std::ostream& operator<<(std::ostream& os, BranchHint hint) {
+ switch (hint) {
+ case BranchHint::kNone:
+ return os << "None";
+ case BranchHint::kTrue:
+ return os << "True";
+ case BranchHint::kFalse:
+ return os << "False";
+ }
+ UNREACHABLE();
+ return os;
+}
+
+
+BranchHint BranchHintOf(const Operator* const op) {
+ DCHECK_EQ(IrOpcode::kBranch, op->opcode());
+ return OpParameter<BranchHint>(op);
+}
+
+
size_t hash_value(OutputFrameStateCombine const& sc) {
return base::hash_combine(sc.kind_, sc.parameter_);
}
@@ -74,7 +94,6 @@
#define SHARED_OP_LIST(V) \
V(Dead, Operator::kFoldable, 0, 0) \
V(End, Operator::kFoldable, 0, 1) \
- V(Branch, Operator::kFoldable, 1, 1) \
V(IfTrue, Operator::kFoldable, 0, 1) \
V(IfFalse, Operator::kFoldable, 0, 1) \
V(Throw, Operator::kFoldable, 1, 1) \
@@ -110,6 +129,12 @@
#undef SHARED
+const Operator* CommonOperatorBuilder::Branch(BranchHint hint) {
+ return new (zone()) Operator1<BranchHint>(
+ IrOpcode::kBranch, Operator::kFoldable, 1, 0, "Branch", hint);
+}
+
+
const Operator* CommonOperatorBuilder::Start(int num_formal_parameters) {
// Outputs are formal parameters, plus context, receiver, and JSFunction.
const int value_output_count = num_formal_parameters + 3;
@@ -128,6 +153,13 @@
return new (zone()) ControlOperator(IrOpcode::kLoop,
Operator::kFoldable, 0,
0, controls, "Loop");
}
+
+
+const Operator* CommonOperatorBuilder::Terminate(int effects) {
+ return new (zone()) Operator1<int>(IrOpcode::kTerminate,
+ Operator::kNoRead |
Operator::kNoWrite, 0,
+ 0, "Terminate", effects);
+}
const Operator* CommonOperatorBuilder::Parameter(int index) {
=======================================
--- /trunk/src/compiler/common-operator.h Wed Oct 8 00:05:11 2014 UTC
+++ /trunk/src/compiler/common-operator.h Thu Oct 23 08:44:45 2014 UTC
@@ -23,6 +23,16 @@
class Operator;
+// Prediction hint for branches.
+enum class BranchHint : uint8_t { kNone, kTrue, kFalse };
+
+inline size_t hash_value(BranchHint hint) { return
static_cast<size_t>(hint); }
+
+std::ostream& operator<<(std::ostream&, BranchHint);
+
+BranchHint BranchHintOf(const Operator* const);
+
+
// Flag that describes how to combine the current environment with
// the output of a node to obtain a framestate for lazy bailout.
class OutputFrameStateCombine {
@@ -123,10 +133,11 @@
const Operator* Dead();
const Operator* End();
- const Operator* Branch();
+ const Operator* Branch(BranchHint = BranchHint::kNone);
const Operator* IfTrue();
const Operator* IfFalse();
const Operator* Throw();
+ const Operator* Terminate(int effects);
const Operator* Return();
const Operator* Start(int num_formal_parameters);
=======================================
--- /trunk/src/compiler/graph-visualizer.cc Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/compiler/graph-visualizer.cc Thu Oct 23 08:44:45 2014 UTC
@@ -562,6 +562,7 @@
BasicBlock* current = (*rpo)[i];
Tag block_tag(this, "block");
PrintBlockProperty("name", current->id());
+ PrintStringProperty("deferred",
current->deferred() ? "true" : "false");
PrintIntProperty("from_bci", -1);
PrintIntProperty("to_bci", -1);
=======================================
--- /trunk/src/compiler/instruction-selector.cc Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/instruction-selector.cc Thu Oct 23 08:44:45 2014 UTC
@@ -147,7 +147,7 @@
bool InstructionSelector::IsNextInAssemblyOrder(const BasicBlock* block)
const {
- return current_block_->GetRpoNumber().IsNext(block->GetRpoNumber());
+ return current_block_->GetAoNumber().IsNext(block->GetAoNumber());
}
@@ -457,6 +457,7 @@
case IrOpcode::kIfFalse:
case IrOpcode::kEffectPhi:
case IrOpcode::kMerge:
+ case IrOpcode::kTerminate:
// No code needed for these graph artifacts.
return kMachNone;
case IrOpcode::kFinish:
=======================================
--- /trunk/src/compiler/instruction.cc Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/instruction.cc Thu Oct 23 08:44:45 2014 UTC
@@ -336,11 +336,13 @@
BasicBlock::RpoNumber::Invalid(), zone),
phis_(zone),
id_(block->id()),
+ ao_number_(block->GetAoNumber()),
rpo_number_(block->GetRpoNumber()),
loop_header_(GetRpo(block->loop_header())),
loop_end_(GetLoopEndRpo(block)),
code_start_(-1),
- code_end_(-1) {
+ code_end_(-1),
+ deferred_(block->deferred()) {
// Map successors and precessors
size_t index = 0;
for (BasicBlock::Successors::const_iterator it =
block->successors_begin();
@@ -604,7 +606,10 @@
const InstructionBlock* block = code.InstructionBlockAt(rpo);
CHECK(block->rpo_number() == rpo);
- os << "RPO#" << block->rpo_number() << ": B" << block->id();
+ os << "RPO#" << block->rpo_number();
+ os << ": AO#" << block->ao_number();
+ os << ": B" << block->id();
+ if (block->IsDeferred()) os << " (deferred)";
if (block->IsLoopHeader()) {
os << " loop blocks: [" << block->rpo_number() << ", "
<< block->loop_end() << ")";
=======================================
--- /trunk/src/compiler/instruction.h Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/instruction.h Thu Oct 23 08:44:45 2014 UTC
@@ -794,8 +794,11 @@
int32_t code_end() const { return code_end_; }
void set_code_end(int32_t end) { code_end_ = end; }
+
+ bool IsDeferred() const { return deferred_; }
BasicBlock::Id id() const { return id_; }
+ BasicBlock::RpoNumber ao_number() const { return ao_number_; }
BasicBlock::RpoNumber rpo_number() const { return rpo_number_; }
BasicBlock::RpoNumber loop_header() const { return loop_header_; }
BasicBlock::RpoNumber loop_end() const {
@@ -822,12 +825,14 @@
Predecessors predecessors_;
PhiInstructions phis_;
BasicBlock::Id id_;
+ BasicBlock::RpoNumber ao_number_; // Assembly order number.
// TODO(dcarney): probably dont't need this.
BasicBlock::RpoNumber rpo_number_;
BasicBlock::RpoNumber loop_header_;
BasicBlock::RpoNumber loop_end_;
- int32_t code_start_; // start index of arch-specific code.
- int32_t code_end_; // end index of arch-specific code.
+ int32_t code_start_; // start index of arch-specific code.
+ int32_t code_end_; // end index of arch-specific code.
+ const bool deferred_; // Block contains deferred code.
};
typedef ZoneDeque<Constant> ConstantDeque;
@@ -853,6 +858,10 @@
int VirtualRegisterCount() const { return next_virtual_register_; }
int node_count() const { return static_cast<int>(node_map_.size()); }
+
+ const InstructionBlocks& instruction_blocks() const {
+ return instruction_blocks_;
+ }
int InstructionBlockCount() const {
return static_cast<int>(instruction_blocks_.size());
=======================================
--- /trunk/src/compiler/opcodes.h Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/compiler/opcodes.h Thu Oct 23 08:44:45 2014 UTC
@@ -7,13 +7,14 @@
// Opcodes for control operators.
#define INNER_CONTROL_OP_LIST(V) \
- V(Dead) \
- V(Loop) \
- V(Branch) \
- V(IfTrue) \
- V(IfFalse) \
- V(Merge) \
- V(Return) \
+ V(Dead) \
+ V(Loop) \
+ V(Branch) \
+ V(IfTrue) \
+ V(IfFalse) \
+ V(Merge) \
+ V(Return) \
+ V(Terminate) \
V(Throw)
#define CONTROL_OP_LIST(V) \
=======================================
--- /trunk/src/compiler/operator-properties-inl.h Wed Oct 15 00:05:09 2014
UTC
+++ /trunk/src/compiler/operator-properties-inl.h Thu Oct 23 08:44:45 2014
UTC
@@ -104,7 +104,8 @@
inline int OperatorProperties::GetEffectInputCount(const Operator* op) {
if (op->opcode() == IrOpcode::kEffectPhi ||
- op->opcode() == IrOpcode::kFinish) {
+ op->opcode() == IrOpcode::kFinish ||
+ op->opcode() == IrOpcode::kTerminate) {
return OpParameter<int>(op);
}
if (op->HasProperty(Operator::kNoRead) &&
op->HasProperty(Operator::kNoWrite))
@@ -123,6 +124,8 @@
#define OPCODE_CASE(x) case IrOpcode::k##x:
CONTROL_OP_LIST(OPCODE_CASE)
#undef OPCODE_CASE
+ // Branch operator is special
+ if (op->opcode() == IrOpcode::kBranch) return 1;
// Control operators are Operator1<int>.
return OpParameter<int>(op);
default:
@@ -152,7 +155,8 @@
inline bool OperatorProperties::HasEffectOutput(const Operator* op) {
return op->opcode() == IrOpcode::kStart ||
op->opcode() == IrOpcode::kValueEffect ||
- (op->opcode() != IrOpcode::kFinish && GetEffectInputCount(op) >
0);
+ (op->opcode() != IrOpcode::kFinish &&
+ op->opcode() != IrOpcode::kTerminate && GetEffectInputCount(op)
0);
}
inline bool OperatorProperties::HasControlOutput(const Operator* op) {
=======================================
--- /trunk/src/compiler/schedule.cc Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/compiler/schedule.cc Thu Oct 23 08:44:45 2014 UTC
@@ -13,7 +13,9 @@
namespace compiler {
BasicBlock::BasicBlock(Zone* zone, Id id)
- : rpo_number_(-1),
+ : ao_number_(-1),
+ rpo_number_(-1),
+ deferred_(false),
dominator_(NULL),
loop_header_(NULL),
loop_depth_(0),
@@ -194,10 +196,6 @@
AddSuccessor(block, tblock);
AddSuccessor(block, fblock);
SetControlInput(block, branch);
- if (branch->opcode() == IrOpcode::kBranch) {
- // TODO(titzer): require a Branch node here. (sloppy tests).
- SetBlockForNode(block, branch);
- }
}
@@ -205,13 +203,7 @@
DCHECK(block->control() == BasicBlock::kNone);
block->set_control(BasicBlock::kReturn);
SetControlInput(block, input);
- if (block != end()) {
- AddSuccessor(block, end());
- }
- if (input->opcode() == IrOpcode::kReturn) {
- // TODO(titzer): require a Return node here. (sloppy tests).
- SetBlockForNode(block, input);
- }
+ if (block != end()) AddSuccessor(block, end());
}
@@ -250,6 +242,7 @@
for (BasicBlockVectorIter i = rpo->begin(); i != rpo->end(); ++i) {
BasicBlock* block = *i;
os << "--- BLOCK B" << block->id();
+ if (block->deferred()) os << " (deferred)";
if (block->PredecessorCount() != 0) os << " <- ";
bool comma = false;
for (BasicBlock::Predecessors::iterator j =
block->predecessors_begin();
=======================================
--- /trunk/src/compiler/schedule.h Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/compiler/schedule.h Thu Oct 23 08:44:45 2014 UTC
@@ -139,6 +139,9 @@
Node* control_input() const { return control_input_; }
void set_control_input(Node* control_input);
+
+ bool deferred() const { return deferred_; }
+ void set_deferred(bool deferred) { deferred_ = deferred; }
BasicBlock* dominator() const { return dominator_; }
void set_dominator(BasicBlock* dominator);
@@ -151,6 +154,10 @@
int32_t loop_end() const { return loop_end_; }
void set_loop_end(int32_t loop_end);
+
+ RpoNumber GetAoNumber() const { return RpoNumber::FromInt(ao_number_); }
+ int32_t ao_number() const { return ao_number_; }
+ void set_ao_number(int32_t ao_number) { ao_number_ = ao_number; }
RpoNumber GetRpoNumber() const { return RpoNumber::FromInt(rpo_number_);
}
int32_t rpo_number() const { return rpo_number_; }
@@ -161,7 +168,9 @@
bool LoopContains(BasicBlock* block) const;
private:
+ int32_t ao_number_; // assembly order number of the block.
int32_t rpo_number_; // special RPO number of the block.
+ bool deferred_; // true if the block contains deferred code.
BasicBlock* dominator_; // Immediate dominator of the block.
BasicBlock* loop_header_; // Pointer to dominating loop header basic
block,
// NULL if none. For loop headers, this
points to
=======================================
--- /trunk/src/compiler/scheduler.cc Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/scheduler.cc Thu Oct 23 08:44:45 2014 UTC
@@ -277,6 +277,20 @@
TraceConnect(branch, branch_block, successor_blocks[0]);
TraceConnect(branch, branch_block, successor_blocks[1]);
+
+ // Consider branch hints.
+ // TODO(turbofan): Propagate the deferred flag to all blocks dominated
by
+ // this IfTrue/IfFalse later.
+ switch (BranchHintOf(branch->op())) {
+ case BranchHint::kNone:
+ break;
+ case BranchHint::kTrue:
+ successor_blocks[1]->set_deferred(true);
+ break;
+ case BranchHint::kFalse:
+ successor_blocks[0]->set_deferred(true);
+ break;
+ }
schedule_->AddBranch(branch_block, branch, successor_blocks[0],
successor_blocks[1]);
@@ -521,27 +535,42 @@
// Phase 4: Schedule nodes late.
-class ScheduleLateNodeVisitor : public NullNodeVisitor {
+class ScheduleLateNodeVisitor {
public:
- explicit ScheduleLateNodeVisitor(Scheduler* scheduler)
- : scheduler_(scheduler), schedule_(scheduler_->schedule_) {}
+ ScheduleLateNodeVisitor(Zone* zone, Scheduler* scheduler)
+ : scheduler_(scheduler), schedule_(scheduler_->schedule_),
queue_(zone) {}
+
+ // Run the schedule late algorithm on a set of fixed root nodes.
+ void Run(NodeVector* roots) {
+ for (NodeVectorIter i = roots->begin(); i != roots->end(); ++i) {
+ ProcessQueue(*i);
+ }
+ }
+
+ private:
+ void ProcessQueue(Node* root) {
+ for (InputIter i = root->inputs().begin(); i != root->inputs().end();
++i) {
+ if (scheduler_->GetData(*i)->unscheduled_count_ != 0) continue;
+ queue_.push(*i);
+ while (!queue_.empty()) {
+ VisitNode(queue_.front());
+ queue_.pop();
+ }
+ }
+ }
+
+ // Visits one node from the queue of schedulable nodes and determines its
+ // schedule late position. Also hoists nodes out of loops to find a more
+ // optimal scheduling position.
+ void VisitNode(Node* node) {
+ DCHECK(scheduler_->GetData(node)->unscheduled_count_ == 0);
- GenericGraphVisit::Control Pre(Node* node) {
// Don't schedule nodes that are already scheduled.
- if (schedule_->IsScheduled(node)) {
- return GenericGraphVisit::CONTINUE;
- }
+ if (schedule_->IsScheduled(node)) return;
Scheduler::SchedulerData* data = scheduler_->GetData(node);
DCHECK_EQ(Scheduler::kSchedulable, data->placement_);
- // If all the uses of a node have been scheduled, then the node itself
can
- // be scheduled.
- bool eligible = data->unscheduled_count_ == 0;
- Trace("Testing for schedule eligibility for #%d:%s = %s\n", node->id(),
- node->op()->mnemonic(), eligible ? "true" : "false");
- if (!eligible) return GenericGraphVisit::DEFER;
-
// Determine the dominating block for all of the uses of this node. It
is
// the latest block that this node can be scheduled in.
BasicBlock* block = NULL;
@@ -586,11 +615,8 @@
}
ScheduleNode(block, node);
-
- return GenericGraphVisit::CONTINUE;
}
- private:
BasicBlock* GetBlockForUse(Node::Edge edge) {
Node* use = edge.from();
IrOpcode::Value opcode = use->opcode();
@@ -619,7 +645,8 @@
scheduler_->scheduled_nodes_[block->id().ToSize()].push_back(node);
// Reduce the use count of the node's inputs to potentially make them
- // schedulable.
+ // schedulable. If all the uses of a node have been scheduled, then
the node
+ // itself can be scheduled.
for (InputIter i = node->inputs().begin(); i != node->inputs().end();
++i) {
Scheduler::SchedulerData* data = scheduler_->GetData(*i);
DCHECK(data->unscheduled_count_ > 0);
@@ -628,10 +655,10 @@
Trace(" Use count for #%d:%s (used by #%d:%s)-- = %d\n",
(*i)->id(),
(*i)->op()->mnemonic(), i.edge().from()->id(),
i.edge().from()->op()->mnemonic(), data->unscheduled_count_);
- if (data->unscheduled_count_ == 0) {
- Trace(" newly eligible #%d:%s\n", (*i)->id(),
- (*i)->op()->mnemonic());
- }
+ }
+ if (data->unscheduled_count_ == 0) {
+ Trace(" newly eligible #%d:%s\n", (*i)->id(),
(*i)->op()->mnemonic());
+ queue_.push(*i);
}
}
@@ -649,10 +676,11 @@
"%d\n",
(*i)->id(), (*i)->op()->mnemonic(), node->id(),
node->op()->mnemonic(), data->unscheduled_count_);
- if (data->unscheduled_count_ == 0) {
- Trace(" newly eligible #%d:%s\n", (*i)->id(),
- (*i)->op()->mnemonic());
- }
+ }
+ if (data->unscheduled_count_ == 0) {
+ Trace(" newly eligible #%d:%s\n", (*i)->id(),
+ (*i)->op()->mnemonic());
+ queue_.push(*i);
}
}
}
@@ -661,6 +689,7 @@
Scheduler* scheduler_;
Schedule* schedule_;
+ ZoneQueue<Node*> queue_;
};
@@ -676,15 +705,10 @@
}
// Schedule: Places nodes in dominator block of all their uses.
- ScheduleLateNodeVisitor schedule_late_visitor(this);
-
{
ZonePool::Scope zone_scope(zone_pool_);
- Zone* zone = zone_scope.zone();
- GenericGraphVisit::Visit<ScheduleLateNodeVisitor,
- NodeInputIterationTraits<Node> >(
- graph_, zone, schedule_root_nodes_.begin(),
schedule_root_nodes_.end(),
- &schedule_late_visitor);
+ ScheduleLateNodeVisitor schedule_late_visitor(zone_scope.zone(), this);
+ schedule_late_visitor.Run(&schedule_root_nodes_);
}
// Add collected nodes for basic blocks to their blocks in the right
order.
@@ -1194,6 +1218,18 @@
current->loop_header()->id().ToInt(), current->loop_depth());
}
}
+
+ // Compute the assembly order (non-deferred code first, deferred code
+ // afterwards).
+ int32_t number = 0;
+ for (auto block : *final_order) {
+ if (block->deferred()) continue;
+ block->set_ao_number(number++);
+ }
+ for (auto block : *final_order) {
+ if (!block->deferred()) continue;
+ block->set_ao_number(number++);
+ }
#if DEBUG
if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order);
=======================================
--- /trunk/src/compiler/simplified-lowering.cc Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/compiler/simplified-lowering.cc Thu Oct 23 08:44:45 2014 UTC
@@ -1027,7 +1027,8 @@
Node* control = node->InputAt(4);
Node* check = graph()->NewNode(machine()->Uint32LessThan(), key,
length);
- Node* branch = graph()->NewNode(common()->Branch(), check, control);
+ Node* branch =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check,
control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* load = graph()->NewNode(op, base, index, effect, if_true);
@@ -1098,7 +1099,8 @@
Node* control = node->InputAt(5);
Node* check = graph()->NewNode(machine()->Uint32LessThan(), key,
length);
- Node* branch = graph()->NewNode(common()->Branch(), check, control);
+ Node* branch =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check,
control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* store = graph()->NewNode(op, base, index, value, effect,
if_true);
=======================================
--- /trunk/src/compiler/verifier.cc Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/compiler/verifier.cc Thu Oct 23 08:44:45 2014 UTC
@@ -6,6 +6,8 @@
#include <deque>
#include <queue>
+#include <sstream>
+#include <string>
#include "src/compiler/generic-algorithm.h"
#include "src/compiler/generic-node-inl.h"
@@ -20,6 +22,7 @@
#include "src/compiler/schedule.h"
#include "src/compiler/simplified-operator.h"
#include "src/data-flow.h"
+#include "src/ostreams.h"
namespace v8 {
namespace internal {
@@ -56,10 +59,8 @@
private:
// TODO(rossberg): Get rid of these once we got rid of NodeProperties.
- Bounds bounds(Node* node) {
- return NodeProperties::GetBounds(node);
- }
- Node* Operand(Node* node, int i = 0) {
+ Bounds bounds(Node* node) { return NodeProperties::GetBounds(node); }
+ Node* ValueInput(Node* node, int i = 0) {
return NodeProperties::GetValueInput(node, i);
}
FieldAccess Field(Node* node) {
@@ -72,6 +73,50 @@
node->opcode() == IrOpcode::kStoreElement);
return OpParameter<ElementAccess>(node);
}
+ void CheckNotTyped(Node* node) {
+ if (NodeProperties::IsTyped(node)) {
+ std::ostringstream str;
+ str << "TypeError: node #" << node->opcode() << ":"
+ << node->op()->mnemonic() << " should never have a type";
+ V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+ }
+ }
+ void CheckUpperIs(Node* node, Type* type) {
+ if (typing == TYPED && !bounds(node).upper->Is(type)) {
+ std::ostringstream str;
+ str << "TypeError: node #" << node->opcode() << ":"
+ << node->op()->mnemonic() << " upper bound ";
+ bounds(node).upper->PrintTo(str);
+ str << " is not ";
+ type->PrintTo(str);
+ V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+ }
+ }
+ void CheckUpperMaybe(Node* node, Type* type) {
+ if (typing == TYPED && !bounds(node).upper->Maybe(type)) {
+ std::ostringstream str;
+ str << "TypeError: node #" << node->opcode() << ":"
+ << node->op()->mnemonic() << " upper bound ";
+ bounds(node).upper->PrintTo(str);
+ str << " must intersect ";
+ type->PrintTo(str);
+ V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+ }
+ }
+ void CheckValueInputIs(Node* node, int i, Type* type) {
+ Node* input = ValueInput(node, i);
+ if (typing == TYPED && !bounds(input).upper->Is(type)) {
+ std::ostringstream str;
+ str << "TypeError: node #" << node->opcode() << ":"
+ << node->op()->mnemonic() << "(input @" << i << " = "
+ << input->opcode() << ":" << input->op()->mnemonic()
+ << ") upper bound ";
+ bounds(input).upper->PrintTo(str);
+ str << " is not ";
+ type->PrintTo(str);
+ V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+ }
+ }
};
@@ -141,527 +186,538 @@
}
}
- if (typing == TYPED) {
- switch (node->opcode()) {
- // Control operators
- // -----------------
- case IrOpcode::kStart:
- // Start has no inputs.
- CHECK_EQ(0, input_count);
- // Type is a tuple.
- // TODO(rossberg): Multiple outputs are currently typed as
Internal.
- CHECK(bounds(node).upper->Is(Type::Internal()));
- break;
- case IrOpcode::kEnd:
- // End has no outputs.
- CHECK(!OperatorProperties::HasValueOutput(node->op()));
- CHECK(!OperatorProperties::HasEffectOutput(node->op()));
- CHECK(!OperatorProperties::HasControlOutput(node->op()));
- // Type is empty.
- CHECK(!NodeProperties::IsTyped(node));
- break;
- case IrOpcode::kDead:
- // Dead is never connected to the graph.
- UNREACHABLE();
- case IrOpcode::kBranch: {
- // Branch uses are IfTrue and IfFalse.
- Node::Uses uses = node->uses();
- int count_true = 0, count_false = 0;
- for (Node::Uses::iterator it = uses.begin(); it != uses.end();
++it) {
- CHECK((*it)->opcode() == IrOpcode::kIfTrue ||
- (*it)->opcode() == IrOpcode::kIfFalse);
- if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true;
- if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false;
- }
- CHECK(count_true == 1 && count_false == 1);
- // Type is empty.
- CHECK(!NodeProperties::IsTyped(node));
- break;
+ switch (node->opcode()) {
+ case IrOpcode::kStart:
+ // Start has no inputs.
+ CHECK_EQ(0, input_count);
+ // Type is a tuple.
+ // TODO(rossberg): Multiple outputs are currently typed as Internal.
+ CheckUpperIs(node, Type::Internal());
+ break;
+ case IrOpcode::kEnd:
+ // End has no outputs.
+ CHECK(!OperatorProperties::HasValueOutput(node->op()));
+ CHECK(!OperatorProperties::HasEffectOutput(node->op()));
+ CHECK(!OperatorProperties::HasControlOutput(node->op()));
+ // Type is empty.
+ CheckNotTyped(node);
+ break;
+ case IrOpcode::kDead:
+ // Dead is never connected to the graph.
+ UNREACHABLE();
+ case IrOpcode::kBranch: {
+ // Branch uses are IfTrue and IfFalse.
+ Node::Uses uses = node->uses();
+ int count_true = 0, count_false = 0;
+ for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it)
{
+ CHECK((*it)->opcode() == IrOpcode::kIfTrue ||
+ (*it)->opcode() == IrOpcode::kIfFalse);
+ if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true;
+ if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false;
}
- case IrOpcode::kIfTrue:
- case IrOpcode::kIfFalse:
- CHECK_EQ(IrOpcode::kBranch,
- NodeProperties::GetControlInput(node, 0)->opcode());
- // Type is empty.
- CHECK(!NodeProperties::IsTyped(node));
- break;
- case IrOpcode::kLoop:
- case IrOpcode::kMerge:
- // Type is empty.
- CHECK(!NodeProperties::IsTyped(node));
- break;
- case IrOpcode::kReturn:
- // TODO(rossberg): check successor is End
- // Type is empty.
- CHECK(!NodeProperties::IsTyped(node));
- break;
- case IrOpcode::kThrow:
- // TODO(rossberg): what are the constraints on these?
- // Type is empty.
- CHECK(!NodeProperties::IsTyped(node));
- break;
+ CHECK(count_true == 1 && count_false == 1);
+ // Type is empty.
+ CheckNotTyped(node);
+ break;
+ }
+ case IrOpcode::kIfTrue:
+ case IrOpcode::kIfFalse:
+ CHECK_EQ(IrOpcode::kBranch,
+ NodeProperties::GetControlInput(node, 0)->opcode());
+ // Type is empty.
+ CheckNotTyped(node);
+ break;
+ case IrOpcode::kLoop:
+ case IrOpcode::kMerge:
+ CHECK_EQ(control_count, input_count);
+ // Type is empty.
+ CheckNotTyped(node);
+ break;
+ case IrOpcode::kReturn:
+ // TODO(rossberg): check successor is End
+ // Type is empty.
+ CheckNotTyped(node);
+ break;
+ case IrOpcode::kThrow:
+ // TODO(rossberg): what are the constraints on these?
+ // Type is empty.
+ CheckNotTyped(node);
+ break;
+ case IrOpcode::kTerminate:
+ // Type is empty.
+ CheckNotTyped(node);
+ CHECK_EQ(1, control_count);
+ CHECK_EQ(input_count, 1 + effect_count);
+ break;
- // Common operators
- // ----------------
- case IrOpcode::kParameter: {
- // Parameters have the start node as inputs.
- CHECK_EQ(1, input_count);
- CHECK_EQ(IrOpcode::kStart,
- NodeProperties::GetValueInput(node, 0)->opcode());
- // Parameter has an input that produces enough values.
- int index = OpParameter<int>(node);
- Node* input = NodeProperties::GetValueInput(node, 0);
- // Currently, parameter indices start at -1 instead of 0.
- CHECK_GT(
- OperatorProperties::GetValueOutputCount(input->op()), index +
1);
- // Type can be anything.
- CHECK(bounds(node).upper->Is(Type::Any()));
- break;
+ // Common operators
+ // ----------------
+ case IrOpcode::kParameter: {
+ // Parameters have the start node as inputs.
+ CHECK_EQ(1, input_count);
+ CHECK_EQ(IrOpcode::kStart,
+ NodeProperties::GetValueInput(node, 0)->opcode());
+ // Parameter has an input that produces enough values.
+ int index = OpParameter<int>(node);
+ Node* input = NodeProperties::GetValueInput(node, 0);
+ // Currently, parameter indices start at -1 instead of 0.
+ CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index
+ 1);
+ // Type can be anything.
+ CheckUpperIs(node, Type::Any());
+ break;
+ }
+ case IrOpcode::kInt32Constant: // TODO(rossberg): rename
Word32Constant?
+ // Constants have no inputs.
+ CHECK_EQ(0, input_count);
+ // Type is a 32 bit integer, signed or unsigned.
+ CheckUpperIs(node, Type::Integral32());
+ break;
+ case IrOpcode::kInt64Constant:
+ // Constants have no inputs.
+ CHECK_EQ(0, input_count);
+ // Type is internal.
+ // TODO(rossberg): Introduce proper Int64 type.
+ CheckUpperIs(node, Type::Internal());
+ break;
+ case IrOpcode::kFloat32Constant:
+ case IrOpcode::kFloat64Constant:
+ case IrOpcode::kNumberConstant:
+ // Constants have no inputs.
+ CHECK_EQ(0, input_count);
+ // Type is a number.
+ CheckUpperIs(node, Type::Number());
+ break;
+ case IrOpcode::kHeapConstant:
+ // Constants have no inputs.
+ CHECK_EQ(0, input_count);
+ // Type can be anything represented as a heap pointer.
+ CheckUpperIs(node, Type::TaggedPtr());
+ break;
+ case IrOpcode::kExternalConstant:
+ // Constants have no inputs.
+ CHECK_EQ(0, input_count);
+ // Type is considered internal.
+ CheckUpperIs(node, Type::Internal());
+ break;
+ case IrOpcode::kProjection: {
+ // Projection has an input that produces enough values.
+ int index = OpParameter<int>(node->op());
+ Node* input = NodeProperties::GetValueInput(node, 0);
+ CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()),
index);
+ // Type can be anything.
+ // TODO(rossberg): Introduce tuple types for this.
+ // TODO(titzer): Convince rossberg not to.
+ CheckUpperIs(node, Type::Any());
+ break;
+ }
+ case IrOpcode::kPhi: {
+ // Phi input count matches parent control node.
+ CHECK_EQ(0, effect_count);
+ CHECK_EQ(1, control_count);
+ Node* control = NodeProperties::GetControlInput(node, 0);
+ CHECK_EQ(value_count,
+ OperatorProperties::GetControlInputCount(control->op()));
+ CHECK_EQ(input_count, 1 + value_count);
+ // Type must be subsumed by all input types.
+ // TODO(rossberg): for now at least, narrowing does not really hold.
+ /*
+ for (int i = 0; i < value_count; ++i) {
+ // TODO(rossberg, jarin): Figure out what to do about lower bounds.
+ // CHECK(bounds(node).lower->Is(bounds(ValueInput(node,
i)).lower));
+ CHECK(bounds(ValueInput(node, i)).upper->Is(bounds(node).upper));
}
- case IrOpcode::kInt32Constant: // TODO(rossberg): rename
Word32Constant?
- // Constants have no inputs.
- CHECK_EQ(0, input_count);
- // Type is a 32 bit integer, signed or unsigned.
- CHECK(bounds(node).upper->Is(Type::Integral32()));
- break;
- case IrOpcode::kInt64Constant:
- // Constants have no inputs.
- CHECK_EQ(0, input_count);
- // Type is internal.
- // TODO(rossberg): Introduce proper Int64 type.
- CHECK(bounds(node).upper->Is(Type::Internal()));
- break;
- case IrOpcode::kFloat32Constant:
- case IrOpcode::kFloat64Constant:
- case IrOpcode::kNumberConstant:
- // Constants have no inputs.
- CHECK_EQ(0, input_count);
- // Type is a number.
- CHECK(bounds(node).upper->Is(Type::Number()));
- break;
- case IrOpcode::kHeapConstant:
- // Constants have no inputs.
- CHECK_EQ(0, input_count);
- // Type can be anything represented as a heap pointer.
- CHECK(bounds(node).upper->Is(Type::TaggedPtr()));
- break;
- case IrOpcode::kExternalConstant:
- // Constants have no inputs.
- CHECK_EQ(0, input_count);
- // Type is considered internal.
- CHECK(bounds(node).upper->Is(Type::Internal()));
- break;
- case IrOpcode::kProjection: {
- // Projection has an input that produces enough values.
- int index = OpParameter<int>(node->op());
- Node* input = NodeProperties::GetValueInput(node, 0);
- CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()),
index);
- // Type can be anything.
- // TODO(rossberg): Introduce tuple types for this.
- CHECK(bounds(node).upper->Is(Type::Any()));
- break;
+ */
+ break;
+ }
+ case IrOpcode::kEffectPhi: {
+ // EffectPhi input count matches parent control node.
+ CHECK_EQ(0, value_count);
+ CHECK_EQ(1, control_count);
+ Node* control = NodeProperties::GetControlInput(node, 0);
+ CHECK_EQ(effect_count,
+ OperatorProperties::GetControlInputCount(control->op()));
+ CHECK_EQ(input_count, 1 + effect_count);
+ break;
+ }
+ case IrOpcode::kValueEffect:
+ // TODO(rossberg): what are the constraints on these?
+ break;
+ case IrOpcode::kFinish: {
+ // TODO(rossberg): what are the constraints on these?
+ // Type must be subsumed by input type.
+ if (typing == TYPED) {
+ CHECK(bounds(ValueInput(node)).lower->Is(bounds(node).lower));
+ CHECK(bounds(ValueInput(node)).upper->Is(bounds(node).upper));
}
- case IrOpcode::kPhi: {
- // Phi input count matches parent control node.
- CHECK_EQ(1, control_count);
- Node* control = NodeProperties::GetControlInput(node, 0);
- CHECK_EQ(value_count,
- OperatorProperties::GetControlInputCount(control->op()));
- // Type must be subsumed by all input types.
- // TODO(rossberg): for now at least, narrowing does not really
hold.
- /*
- for (int i = 0; i < value_count; ++i) {
- // TODO(rossberg, jarin): Figure out what to do about lower
bounds.
- // CHECK(bounds(node).lower->Is(bounds(Operand(node, i)).lower));
- CHECK(bounds(Operand(node, i)).upper->Is(bounds(node).upper));
- }
- */
- break;
- }
- case IrOpcode::kEffectPhi: {
- // EffectPhi input count matches parent control node.
- CHECK_EQ(1, control_count);
- Node* control = NodeProperties::GetControlInput(node, 0);
- CHECK_EQ(effect_count,
- OperatorProperties::GetControlInputCount(control->op()));
- break;
- }
- case IrOpcode::kValueEffect:
- // TODO(rossberg): what are the constraints on these?
- break;
- case IrOpcode::kFinish: {
- // TODO(rossberg): what are the constraints on these?
- // Type must be subsumed by input type.
- CHECK(bounds(Operand(node)).lower->Is(bounds(node).lower));
- CHECK(bounds(Operand(node)).upper->Is(bounds(node).upper));
- break;
- }
- case IrOpcode::kFrameState:
- // TODO(jarin): what are the constraints on these?
- break;
- case IrOpcode::kStateValues:
- // TODO(jarin): what are the constraints on these?
- break;
- case IrOpcode::kCall:
- // TODO(rossberg): what are the constraints on these?
- break;
+ break;
+ }
+ case IrOpcode::kFrameState:
+ // TODO(jarin): what are the constraints on these?
+ break;
+ case IrOpcode::kStateValues:
+ // TODO(jarin): what are the constraints on these?
+ break;
+ case IrOpcode::kCall:
+ // TODO(rossberg): what are the constraints on these?
+ break;
- // JavaScript operators
- // --------------------
- case IrOpcode::kJSEqual:
- case IrOpcode::kJSNotEqual:
- case IrOpcode::kJSStrictEqual:
- case IrOpcode::kJSStrictNotEqual:
- case IrOpcode::kJSLessThan:
- case IrOpcode::kJSGreaterThan:
- case IrOpcode::kJSLessThanOrEqual:
- case IrOpcode::kJSGreaterThanOrEqual:
- case IrOpcode::kJSUnaryNot:
- // Type is Boolean.
- CHECK(bounds(node).upper->Is(Type::Boolean()));
- break;
+ // JavaScript operators
+ // --------------------
+ case IrOpcode::kJSEqual:
+ case IrOpcode::kJSNotEqual:
+ case IrOpcode::kJSStrictEqual:
+ case IrOpcode::kJSStrictNotEqual:
+ case IrOpcode::kJSLessThan:
+ case IrOpcode::kJSGreaterThan:
+ case IrOpcode::kJSLessThanOrEqual:
+ case IrOpcode::kJSGreaterThanOrEqual:
+ case IrOpcode::kJSUnaryNot:
+ // Type is Boolean.
+ CheckUpperIs(node, Type::Boolean());
+ break;
- case IrOpcode::kJSBitwiseOr:
- case IrOpcode::kJSBitwiseXor:
- case IrOpcode::kJSBitwiseAnd:
- case IrOpcode::kJSShiftLeft:
- case IrOpcode::kJSShiftRight:
- case IrOpcode::kJSShiftRightLogical:
- // Type is 32 bit integral.
- CHECK(bounds(node).upper->Is(Type::Integral32()));
- break;
- case IrOpcode::kJSAdd:
- // Type is Number or String.
- CHECK(bounds(node).upper->Is(Type::NumberOrString()));
- break;
- case IrOpcode::kJSSubtract:
- case IrOpcode::kJSMultiply:
- case IrOpcode::kJSDivide:
- case IrOpcode::kJSModulus:
- // Type is Number.
- CHECK(bounds(node).upper->Is(Type::Number()));
- break;
+ case IrOpcode::kJSBitwiseOr:
+ case IrOpcode::kJSBitwiseXor:
+ case IrOpcode::kJSBitwiseAnd:
+ case IrOpcode::kJSShiftLeft:
+ case IrOpcode::kJSShiftRight:
+ case IrOpcode::kJSShiftRightLogical:
+ // Type is 32 bit integral.
+ CheckUpperIs(node, Type::Integral32());
+ break;
+ case IrOpcode::kJSAdd:
+ // Type is Number or String.
+ CheckUpperIs(node, Type::NumberOrString());
+ break;
+ case IrOpcode::kJSSubtract:
+ case IrOpcode::kJSMultiply:
+ case IrOpcode::kJSDivide:
+ case IrOpcode::kJSModulus:
+ // Type is Number.
+ CheckUpperIs(node, Type::Number());
+ break;
- case IrOpcode::kJSToBoolean:
- // Type is Boolean.
- CHECK(bounds(node).upper->Is(Type::Boolean()));
- break;
- case IrOpcode::kJSToNumber:
- // Type is Number.
- CHECK(bounds(node).upper->Is(Type::Number()));
- break;
- case IrOpcode::kJSToString:
- // Type is String.
- CHECK(bounds(node).upper->Is(Type::String()));
- break;
- case IrOpcode::kJSToName:
- // Type is Name.
- CHECK(bounds(node).upper->Is(Type::Name()));
- break;
- case IrOpcode::kJSToObject:
- // Type is Receiver.
- CHECK(bounds(node).upper->Is(Type::Receiver()));
- break;
+ case IrOpcode::kJSToBoolean:
+ // Type is Boolean.
+ CheckUpperIs(node, Type::Boolean());
+ break;
+ case IrOpcode::kJSToNumber:
+ // Type is Number.
+ CheckUpperIs(node, Type::Number());
+ break;
+ case IrOpcode::kJSToString:
+ // Type is String.
+ CheckUpperIs(node, Type::String());
+ break;
+ case IrOpcode::kJSToName:
+ // Type is Name.
+ CheckUpperIs(node, Type::Name());
+ break;
+ case IrOpcode::kJSToObject:
+ // Type is Receiver.
+ CheckUpperIs(node, Type::Receiver());
+ break;
- case IrOpcode::kJSCreate:
- // Type is Object.
- CHECK(bounds(node).upper->Is(Type::Object()));
- break;
- case IrOpcode::kJSLoadProperty:
- case IrOpcode::kJSLoadNamed:
- // Type can be anything.
- CHECK(bounds(node).upper->Is(Type::Any()));
- break;
- case IrOpcode::kJSStoreProperty:
- case IrOpcode::kJSStoreNamed:
- // Type is empty.
- CHECK(!NodeProperties::IsTyped(node));
- break;
- case IrOpcode::kJSDeleteProperty:
- case IrOpcode::kJSHasProperty:
- case IrOpcode::kJSInstanceOf:
- // Type is Boolean.
- CHECK(bounds(node).upper->Is(Type::Boolean()));
- break;
- case IrOpcode::kJSTypeOf:
- // Type is String.
- CHECK(bounds(node).upper->Is(Type::String()));
- break;
+ case IrOpcode::kJSCreate:
+ // Type is Object.
+ CheckUpperIs(node, Type::Object());
+ break;
+ case IrOpcode::kJSLoadProperty:
+ case IrOpcode::kJSLoadNamed:
+ // Type can be anything.
+ CheckUpperIs(node, Type::Any());
+ break;
+ case IrOpcode::kJSStoreProperty:
+ case IrOpcode::kJSStoreNamed:
+ // Type is empty.
+ CheckNotTyped(node);
+ break;
+ case IrOpcode::kJSDeleteProperty:
+ case IrOpcode::kJSHasProperty:
+ case IrOpcode::kJSInstanceOf:
+ // Type is Boolean.
+ CheckUpperIs(node, Type::Boolean());
+ break;
+ case IrOpcode::kJSTypeOf:
+ // Type is String.
+ CheckUpperIs(node, Type::String());
+ break;
- case IrOpcode::kJSLoadContext:
- // Type can be anything.
- CHECK(bounds(node).upper->Is(Type::Any()));
- break;
- case IrOpcode::kJSStoreContext:
- // Type is empty.
- CHECK(!NodeProperties::IsTyped(node));
- break;
- case IrOpcode::kJSCreateFunctionContext:
- case IrOpcode::kJSCreateCatchContext:
- case IrOpcode::kJSCreateWithContext:
- case IrOpcode::kJSCreateBlockContext:
- case IrOpcode::kJSCreateModuleContext:
- case IrOpcode::kJSCreateGlobalContext: {
- // Type is Context, and operand is Internal.
- Bounds outer = bounds(NodeProperties::GetContextInput(node));
- // TODO(rossberg): This should really be Is(Internal), but the
typer
- // currently can't do backwards propagation.
- CHECK(outer.upper->Maybe(Type::Internal()));
- CHECK(bounds(node).upper->IsContext());
- break;
- }
+ case IrOpcode::kJSLoadContext:
+ // Type can be anything.
+ CheckUpperIs(node, Type::Any());
+ break;
+ case IrOpcode::kJSStoreContext:
+ // Type is empty.
+ CheckNotTyped(node);
+ break;
+ case IrOpcode::kJSCreateFunctionContext:
+ case IrOpcode::kJSCreateCatchContext:
+ case IrOpcode::kJSCreateWithContext:
+ case IrOpcode::kJSCreateBlockContext:
+ case IrOpcode::kJSCreateModuleContext:
+ case IrOpcode::kJSCreateGlobalContext: {
+ // Type is Context, and operand is Internal.
+ Node* context = NodeProperties::GetContextInput(node);
+ // TODO(rossberg): This should really be Is(Internal), but the typer
+ // currently can't do backwards propagation.
+ CheckUpperMaybe(context, Type::Internal());
+ if (typing == TYPED) CHECK(bounds(node).upper->IsContext());
+ break;
+ }
- case IrOpcode::kJSCallConstruct:
- // Type is Receiver.
- CHECK(bounds(node).upper->Is(Type::Receiver()));
- break;
- case IrOpcode::kJSCallFunction:
- case IrOpcode::kJSCallRuntime:
- case IrOpcode::kJSYield:
- case IrOpcode::kJSDebugger:
- // Type can be anything.
- CHECK(bounds(node).upper->Is(Type::Any()));
- break;
+ case IrOpcode::kJSCallConstruct:
+ // Type is Receiver.
+ CheckUpperIs(node, Type::Receiver());
+ break;
+ case IrOpcode::kJSCallFunction:
+ case IrOpcode::kJSCallRuntime:
+ case IrOpcode::kJSYield:
+ case IrOpcode::kJSDebugger:
+ // Type can be anything.
+ CheckUpperIs(node, Type::Any());
+ break;
- // Simplified operators
- // -------------------------------
- case IrOpcode::kBooleanNot:
- // Boolean -> Boolean
- CHECK(bounds(Operand(node)).upper->Is(Type::Boolean()));
- CHECK(bounds(node).upper->Is(Type::Boolean()));
- break;
- case IrOpcode::kBooleanToNumber:
- // Boolean -> Number
- CHECK(bounds(Operand(node)).upper->Is(Type::Boolean()));
- CHECK(bounds(node).upper->Is(Type::Number()));
- break;
- case IrOpcode::kNumberEqual:
- case IrOpcode::kNumberLessThan:
- case IrOpcode::kNumberLessThanOrEqual:
- // (Number, Number) -> Boolean
- CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number()));
- CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number()));
- CHECK(bounds(node).upper->Is(Type::Boolean()));
- break;
- case IrOpcode::kNumberAdd:
- case IrOpcode::kNumberSubtract:
- case IrOpcode::kNumberMultiply:
- case IrOpcode::kNumberDivide:
- case IrOpcode::kNumberModulus:
- // (Number, Number) -> Number
- CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number()));
- CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number()));
- // TODO(rossberg): activate once we retype after opcode changes.
- // CHECK(bounds(node).upper->Is(Type::Number()));
- break;
- case IrOpcode::kNumberToInt32:
- // Number -> Signed32
- CHECK(bounds(Operand(node)).upper->Is(Type::Number()));
- CHECK(bounds(node).upper->Is(Type::Signed32()));
- break;
- case IrOpcode::kNumberToUint32:
- // Number -> Unsigned32
- CHECK(bounds(Operand(node)).upper->Is(Type::Number()));
- CHECK(bounds(node).upper->Is(Type::Unsigned32()));
- break;
- case IrOpcode::kStringEqual:
- case IrOpcode::kStringLessThan:
- case IrOpcode::kStringLessThanOrEqual:
- // (String, String) -> Boolean
- CHECK(bounds(Operand(node, 0)).upper->Is(Type::String()));
- CHECK(bounds(Operand(node, 1)).upper->Is(Type::String()));
- CHECK(bounds(node).upper->Is(Type::Boolean()));
- break;
- case IrOpcode::kStringAdd:
- // (String, String) -> String
- CHECK(bounds(Operand(node, 0)).upper->Is(Type::String()));
- CHECK(bounds(Operand(node, 1)).upper->Is(Type::String()));
- CHECK(bounds(node).upper->Is(Type::String()));
- break;
- case IrOpcode::kReferenceEqual: {
- // (Unique, Any) -> Boolean and
- // (Any, Unique) -> Boolean
- CHECK(bounds(Operand(node, 0)).upper->Is(Type::Unique()) ||
- bounds(Operand(node, 1)).upper->Is(Type::Unique()));
- CHECK(bounds(node).upper->Is(Type::Boolean()));
- break;
+ // Simplified operators
+ // -------------------------------
+ case IrOpcode::kBooleanNot:
+ // Boolean -> Boolean
+ CheckValueInputIs(node, 0, Type::Boolean());
+ CheckUpperIs(node, Type::Boolean());
+ break;
+ case IrOpcode::kBooleanToNumber:
+ // Boolean -> Number
+ CheckValueInputIs(node, 0, Type::Boolean());
+ CheckUpperIs(node, Type::Number());
+ break;
+ case IrOpcode::kNumberEqual:
+ case IrOpcode::kNumberLessThan:
+ case IrOpcode::kNumberLessThanOrEqual:
+ // (Number, Number) -> Boolean
+ CheckValueInputIs(node, 0, Type::Number());
+ CheckValueInputIs(node, 1, Type::Number());
+ CheckUpperIs(node, Type::Boolean());
+ break;
+ case IrOpcode::kNumberAdd:
+ case IrOpcode::kNumberSubtract:
+ case IrOpcode::kNumberMultiply:
+ case IrOpcode::kNumberDivide:
+ case IrOpcode::kNumberModulus:
+ // (Number, Number) -> Number
+ CheckValueInputIs(node, 0, Type::Number());
+ CheckValueInputIs(node, 1, Type::Number());
+ // TODO(rossberg): activate once we retype after opcode changes.
+ // CheckUpperIs(node, Type::Number());
+ break;
+ case IrOpcode::kNumberToInt32:
+ // Number -> Signed32
+ CheckValueInputIs(node, 0, Type::Number());
+ CheckUpperIs(node, Type::Signed32());
+ break;
+ case IrOpcode::kNumberToUint32:
+ // Number -> Unsigned32
+ CheckValueInputIs(node, 0, Type::Number());
+ CheckUpperIs(node, Type::Unsigned32());
+ break;
+ case IrOpcode::kStringEqual:
+ case IrOpcode::kStringLessThan:
+ case IrOpcode::kStringLessThanOrEqual:
+ // (String, String) -> Boolean
+ CheckValueInputIs(node, 0, Type::String());
+ CheckValueInputIs(node, 1, Type::String());
+ CheckUpperIs(node, Type::Boolean());
+ break;
+ case IrOpcode::kStringAdd:
+ // (String, String) -> String
+ CheckValueInputIs(node, 0, Type::String());
+ CheckValueInputIs(node, 1, Type::String());
+ CheckUpperIs(node, Type::String());
+ break;
+ case IrOpcode::kReferenceEqual: {
+ // (Unique, Any) -> Boolean and
+ // (Any, Unique) -> Boolean
+ if (typing == TYPED) {
+ CHECK(bounds(ValueInput(node, 0)).upper->Is(Type::Unique()) ||
+ bounds(ValueInput(node, 1)).upper->Is(Type::Unique()));
}
- case IrOpcode::kObjectIsSmi:
- CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
- CHECK(bounds(node).upper->Is(Type::Boolean()));
- break;
- case IrOpcode::kObjectIsNonNegativeSmi:
- CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
- CHECK(bounds(node).upper->Is(Type::Boolean()));
- break;
+ CheckUpperIs(node, Type::Boolean());
+ break;
+ }
+ case IrOpcode::kObjectIsSmi:
+ CheckValueInputIs(node, 0, Type::Any());
+ CheckUpperIs(node, Type::Boolean());
+ break;
+ case IrOpcode::kObjectIsNonNegativeSmi:
+ CheckValueInputIs(node, 0, Type::Any());
+ CheckUpperIs(node, Type::Boolean());
+ break;
- case IrOpcode::kChangeTaggedToInt32: {
- // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32
- // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from = Type::Intersect(Type::Signed32(), Type::Tagged());
- // Type* to = Type::Intersect(Type::Signed32(),
Type::UntaggedInt32());
- // CHECK(bounds(Operand(node)).upper->Is(from));
- // CHECK(bounds(node).upper->Is(to));
- break;
- }
- case IrOpcode::kChangeTaggedToUint32: {
- // Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32
- // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from = Type::Intersect(Type::Unsigned32(),
Type::Tagged());
- // Type* to =Type::Intersect(Type::Unsigned32(),
Type::UntaggedInt32());
- // CHECK(bounds(Operand(node)).upper->Is(from));
- // CHECK(bounds(node).upper->Is(to));
- break;
- }
- case IrOpcode::kChangeTaggedToFloat64: {
- // Number /\ Tagged -> Number /\ UntaggedFloat64
- // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from = Type::Intersect(Type::Number(), Type::Tagged());
- // Type* to = Type::Intersect(Type::Number(),
Type::UntaggedFloat64());
- // CHECK(bounds(Operand(node)).upper->Is(from));
- // CHECK(bounds(node).upper->Is(to));
- break;
- }
- case IrOpcode::kChangeInt32ToTagged: {
- // Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged
- // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from =Type::Intersect(Type::Signed32(),
Type::UntaggedInt32());
- // Type* to = Type::Intersect(Type::Signed32(), Type::Tagged());
- // CHECK(bounds(Operand(node)).upper->Is(from));
- // CHECK(bounds(node).upper->Is(to));
- break;
- }
- case IrOpcode::kChangeUint32ToTagged: {
- // Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged
- // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type*
from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32());
- // Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged());
- // CHECK(bounds(Operand(node)).upper->Is(from));
- // CHECK(bounds(node).upper->Is(to));
- break;
- }
- case IrOpcode::kChangeFloat64ToTagged: {
- // Number /\ UntaggedFloat64 -> Number /\ Tagged
- // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from =Type::Intersect(Type::Number(),
Type::UntaggedFloat64());
- // Type* to = Type::Intersect(Type::Number(), Type::Tagged());
- // CHECK(bounds(Operand(node)).upper->Is(from));
- // CHECK(bounds(node).upper->Is(to));
- break;
- }
- case IrOpcode::kChangeBoolToBit: {
- // Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1
- // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from = Type::Intersect(Type::Boolean(),
Type::TaggedPtr());
- // Type* to = Type::Intersect(Type::Boolean(),
Type::UntaggedInt1());
- // CHECK(bounds(Operand(node)).upper->Is(from));
- // CHECK(bounds(node).upper->Is(to));
- break;
- }
- case IrOpcode::kChangeBitToBool: {
- // Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr
- // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from = Type::Intersect(Type::Boolean(),
Type::UntaggedInt1());
- // Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
- // CHECK(bounds(Operand(node)).upper->Is(from));
- // CHECK(bounds(node).upper->Is(to));
- break;
- }
+ case IrOpcode::kChangeTaggedToInt32: {
+ // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32
+ // TODO(neis): Activate once ChangeRepresentation works in typer.
+ // Type* from = Type::Intersect(Type::Signed32(), Type::Tagged());
+ // Type* to = Type::Intersect(Type::Signed32(),
Type::UntaggedInt32());
+ // CheckValueInputIs(node, 0, from));
+ // CheckUpperIs(node, to));
+ break;
+ }
+ case IrOpcode::kChangeTaggedToUint32: {
+ // Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32
+ // TODO(neis): Activate once ChangeRepresentation works in typer.
+ // Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged());
+ // Type* to =Type::Intersect(Type::Unsigned32(),
Type::UntaggedInt32());
+ // CheckValueInputIs(node, 0, from));
+ // CheckUpperIs(node, to));
+ break;
+ }
+ case IrOpcode::kChangeTaggedToFloat64: {
+ // Number /\ Tagged -> Number /\ UntaggedFloat64
+ // TODO(neis): Activate once ChangeRepresentation works in typer.
+ // Type* from = Type::Intersect(Type::Number(), Type::Tagged());
+ // Type* to = Type::Intersect(Type::Number(),
Type::UntaggedFloat64());
+ // CheckValueInputIs(node, 0, from));
+ // CheckUpperIs(node, to));
+ break;
+ }
+ case IrOpcode::kChangeInt32ToTagged: {
+ // Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged
+ // TODO(neis): Activate once ChangeRepresentation works in typer.
+ // Type* from =Type::Intersect(Type::Signed32(),
Type::UntaggedInt32());
+ // Type* to = Type::Intersect(Type::Signed32(), Type::Tagged());
+ // CheckValueInputIs(node, 0, from));
+ // CheckUpperIs(node, to));
+ break;
+ }
+ case IrOpcode::kChangeUint32ToTagged: {
+ // Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged
+ // TODO(neis): Activate once ChangeRepresentation works in typer.
+ // Type*
from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32());
+ // Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged());
+ // CheckValueInputIs(node, 0, from));
+ // CheckUpperIs(node, to));
+ break;
+ }
+ case IrOpcode::kChangeFloat64ToTagged: {
+ // Number /\ UntaggedFloat64 -> Number /\ Tagged
+ // TODO(neis): Activate once ChangeRepresentation works in typer.
+ // Type* from =Type::Intersect(Type::Number(),
Type::UntaggedFloat64());
+ // Type* to = Type::Intersect(Type::Number(), Type::Tagged());
+ // CheckValueInputIs(node, 0, from));
+ // CheckUpperIs(node, to));
+ break;
+ }
+ case IrOpcode::kChangeBoolToBit: {
+ // Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1
+ // TODO(neis): Activate once ChangeRepresentation works in typer.
+ // Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
+ // Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
+ // CheckValueInputIs(node, 0, from));
+ // CheckUpperIs(node, to));
+ break;
+ }
+ case IrOpcode::kChangeBitToBool: {
+ // Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr
+ // TODO(neis): Activate once ChangeRepresentation works in typer.
+ // Type* from = Type::Intersect(Type::Boolean(),
Type::UntaggedInt1());
+ // Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
+ // CheckValueInputIs(node, 0, from));
+ // CheckUpperIs(node, to));
+ break;
+ }
- case IrOpcode::kLoadField:
- // Object -> fieldtype
- // TODO(rossberg): activate once machine ops are typed.
- // CHECK(bounds(Operand(node)).upper->Is(Type::Object()));
- // CHECK(bounds(node).upper->Is(Field(node).type));
- break;
- case IrOpcode::kLoadElement:
- // Object -> elementtype
- // TODO(rossberg): activate once machine ops are typed.
- // CHECK(bounds(Operand(node)).upper->Is(Type::Object()));
- // CHECK(bounds(node).upper->Is(Element(node).type));
- break;
- case IrOpcode::kStoreField:
- // (Object, fieldtype) -> _|_
- // TODO(rossberg): activate once machine ops are typed.
- // CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object()));
- // CHECK(bounds(Operand(node, 1)).upper->Is(Field(node).type));
- CHECK(!NodeProperties::IsTyped(node));
- break;
- case IrOpcode::kStoreElement:
- // (Object, elementtype) -> _|_
- // TODO(rossberg): activate once machine ops are typed.
- // CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object()));
- // CHECK(bounds(Operand(node, 1)).upper->Is(Element(node).type));
- CHECK(!NodeProperties::IsTyped(node));
- break;
+ case IrOpcode::kLoadField:
+ // Object -> fieldtype
+ // TODO(rossberg): activate once machine ops are typed.
+ // CheckValueInputIs(node, 0, Type::Object());
+ // CheckUpperIs(node, Field(node).type));
+ break;
+ case IrOpcode::kLoadElement:
+ // Object -> elementtype
+ // TODO(rossberg): activate once machine ops are typed.
+ // CheckValueInputIs(node, 0, Type::Object());
+ // CheckUpperIs(node, Element(node).type));
+ break;
+ case IrOpcode::kStoreField:
+ // (Object, fieldtype) -> _|_
+ // TODO(rossberg): activate once machine ops are typed.
+ // CheckValueInputIs(node, 0, Type::Object());
+ // CheckValueInputIs(node, 1, Field(node).type));
+ CheckNotTyped(node);
+ break;
+ case IrOpcode::kStoreElement:
+ // (Object, elementtype) -> _|_
+ // TODO(rossberg): activate once machine ops are typed.
+ // CheckValueInputIs(node, 0, Type::Object());
+ // CheckValueInputIs(node, 1, Element(node).type));
+ CheckNotTyped(node);
+ break;
- // Machine operators
- // -----------------------
- case IrOpcode::kLoad:
- case IrOpcode::kStore:
- case IrOpcode::kWord32And:
- case IrOpcode::kWord32Or:
- case IrOpcode::kWord32Xor:
- case IrOpcode::kWord32Shl:
- case IrOpcode::kWord32Shr:
***The diff for this file has been truncated for email.***
=======================================
--- /trunk/src/conversions.cc Thu Sep 11 00:05:22 2014 UTC
+++ /trunk/src/conversions.cc Thu Oct 23 08:44:45 2014 UTC
@@ -483,19 +483,21 @@
}
-double StringToDouble(UnicodeCache* unicode_cache,
- String* string,
- int flags,
- double empty_string_val) {
- DisallowHeapAllocation no_gc;
- String::FlatContent flat = string->GetFlatContent();
- // ECMA-262 section 15.1.2.3, empty string is NaN
- if (flat.IsOneByte()) {
- return StringToDouble(
- unicode_cache, flat.ToOneByteVector(), flags, empty_string_val);
- } else {
- return StringToDouble(
- unicode_cache, flat.ToUC16Vector(), flags, empty_string_val);
+double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
+ int flags, double empty_string_val) {
+ Handle<String> flattened = String::Flatten(string);
+ {
+ DisallowHeapAllocation no_gc;
+ String::FlatContent flat = flattened->GetFlatContent();
+ DCHECK(flat.IsFlat());
+ // ECMA-262 section 15.1.2.3, empty string is NaN
+ if (flat.IsOneByte()) {
+ return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags,
+ empty_string_val);
+ } else {
+ return StringToDouble(unicode_cache, flat.ToUC16Vector(), flags,
+ empty_string_val);
+ }
}
}
=======================================
--- /trunk/src/conversions.h Wed Sep 24 00:05:07 2014 UTC
+++ /trunk/src/conversions.h Thu Oct 23 08:44:45 2014 UTC
@@ -198,10 +198,8 @@
}
-double StringToDouble(UnicodeCache* unicode_cache,
- String* string,
- int flags,
- double empty_string_val = 0.0);
+double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
+ int flags, double empty_string_val = 0.0);
inline bool TryNumberToSize(Isolate* isolate,
=======================================
--- /trunk/src/d8.cc Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/d8.cc Thu Oct 23 08:44:45 2014 UTC
@@ -1686,7 +1686,7 @@
}
#endif
#ifdef ENABLE_VTUNE_JIT_INTERFACE
- vTune::InitializeVtuneForV8(create_params);
+ create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
#endif
#ifndef V8_SHARED
create_params.constraints.ConfigureDefaults(
=======================================
--- /trunk/src/flag-definitions.h Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/flag-definitions.h Thu Oct 23 08:44:45 2014 UTC
@@ -157,7 +157,6 @@
#define HARMONY_FEATURES(V) \
V(harmony_scoping, "harmony block scoping") \
V(harmony_modules, "harmony modules (implies block scoping)") \
- V(harmony_strings, "harmony strings") \
V(harmony_arrays, "harmony arrays") \
V(harmony_classes, "harmony classes") \
V(harmony_object_literals, "harmony object literal extensions") \
@@ -165,7 +164,8 @@
V(harmony_arrow_functions, "harmony arrow functions") \
V(harmony_tostring, "harmony Symbol.toStringTag")
-#define STAGED_FEATURES(V) \
+#define STAGED_FEATURES(V) \
+ V(harmony_strings, "harmony strings") \
V(harmony_numeric_literals, "harmony numeric literals (0o77, 0b11)")
#define SHIPPING_FEATURES(V)
@@ -509,6 +509,8 @@
DEFINE_INT(min_semi_space_size, 0,
"min size of a semi-space (in MBytes), the new space consists
of two"
"semi-spaces")
+DEFINE_INT(target_semi_space_size, 0,
+ "target size of a semi-space (in MBytes) before triggering a
GC")
DEFINE_INT(max_semi_space_size, 0,
"max size of a semi-space (in MBytes), the new space consists
of two"
"semi-spaces")
=======================================
--- /trunk/src/harmony-tostring.js Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/harmony-tostring.js Thu Oct 23 08:44:45 2014 UTC
@@ -56,11 +56,19 @@
function HarmonyToStringExtendObjectPrototype() {
%CheckIsBootstrapping();
+ // Can't use InstallFunctions() because will fail in Debug mode.
+ // Emulate InstallFunctions() here.
+ %FunctionSetName(ObjectToStringHarmony, "toString");
+ %FunctionRemovePrototype(ObjectToStringHarmony);
+ %SetNativeFlag(ObjectToStringHarmony);
+
// Set up the non-enumerable functions on the Array prototype object.
var desc = ToPropertyDescriptor({
value: ObjectToStringHarmony
});
DefineOwnProperty($Object.prototype, "toString", desc, false);
+
+ %ToFastProperties($Object.prototype);
}
HarmonyToStringExtendObjectPrototype();
=======================================
--- /trunk/src/heap/heap.cc Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/heap/heap.cc Thu Oct 23 08:44:45 2014 UTC
@@ -61,6 +61,7 @@
reserved_semispace_size_(8 * (kPointerSize / 4) * MB),
max_semi_space_size_(8 * (kPointerSize / 4) * MB),
initial_semispace_size_(Page::kPageSize),
+ target_semispace_size_(Page::kPageSize),
max_old_generation_size_(700ul * (kPointerSize / 4) * MB),
max_executable_size_(256ul * (kPointerSize / 4) * MB),
// Variables set based on semispace_size_ and old_generation_size_ in
@@ -4944,9 +4945,9 @@
initial_semispace_size_ = max_semi_space_size_;
if (FLAG_trace_gc) {
PrintPID(
- "Min semi-space size cannot be more than the maximum"
+ "Min semi-space size cannot be more than the maximum "
"semi-space size of %d MB\n",
- max_semi_space_size_);
+ max_semi_space_size_ / MB);
}
} else {
initial_semispace_size_ = initial_semispace_size;
@@ -4955,6 +4956,31 @@
initial_semispace_size_ = Min(initial_semispace_size_,
max_semi_space_size_);
+ if (FLAG_target_semi_space_size > 0) {
+ int target_semispace_size = FLAG_target_semi_space_size * MB;
+ if (target_semispace_size < initial_semispace_size_) {
+ target_semispace_size_ = initial_semispace_size_;
+ if (FLAG_trace_gc) {
+ PrintPID(
+ "Target semi-space size cannot be less than the minimum "
+ "semi-space size of %d MB\n",
+ initial_semispace_size_ / MB);
+ }
+ } else if (target_semispace_size > max_semi_space_size_) {
+ target_semispace_size_ = max_semi_space_size_;
+ if (FLAG_trace_gc) {
+ PrintPID(
+ "Target semi-space size cannot be less than the maximum "
+ "semi-space size of %d MB\n",
+ max_semi_space_size_ / MB);
+ }
+ } else {
+ target_semispace_size_ = target_semispace_size;
+ }
+ }
+
+ target_semispace_size_ = Max(initial_semispace_size_,
target_semispace_size_);
+
// The old generation is paged and needs at least one page for each
space.
int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1;
max_old_generation_size_ =
=======================================
--- /trunk/src/heap/heap.h Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/heap/heap.h Thu Oct 23 08:44:45 2014 UTC
@@ -570,6 +570,7 @@
int MaxSemiSpaceSize() { return max_semi_space_size_; }
int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
int InitialSemiSpaceSize() { return initial_semispace_size_; }
+ int TargetSemiSpaceSize() { return target_semispace_size_; }
intptr_t MaxOldGenerationSize() { return max_old_generation_size_; }
intptr_t MaxExecutableSize() { return max_executable_size_; }
@@ -1472,6 +1473,7 @@
int reserved_semispace_size_;
int max_semi_space_size_;
int initial_semispace_size_;
+ int target_semispace_size_;
intptr_t max_old_generation_size_;
intptr_t max_executable_size_;
intptr_t maximum_committed_;
=======================================
--- /trunk/src/heap/spaces.cc Wed Oct 15 00:05:09 2014 UTC
+++ /trunk/src/heap/spaces.cc Thu Oct 23 08:44:45 2014 UTC
@@ -1195,6 +1195,8 @@
// this chunk must be a power of two and it must be aligned to its size.
int initial_semispace_capacity = heap()->InitialSemiSpaceSize();
+ int target_semispace_capacity = heap()->TargetSemiSpaceSize();
+
size_t size = 2 * reserved_semispace_capacity;
Address base =
heap()->isolate()->memory_allocator()->ReserveAlignedMemory(
size, size, &reservation_);
@@ -1223,9 +1225,10 @@
DCHECK(IsAddressAligned(chunk_base_, 2 * reserved_semispace_capacity,
0));
to_space_.SetUp(chunk_base_, initial_semispace_capacity,
- maximum_semispace_capacity);
+ target_semispace_capacity, maximum_semispace_capacity);
from_space_.SetUp(chunk_base_ + reserved_semispace_capacity,
- initial_semispace_capacity,
maximum_semispace_capacity);
+ initial_semispace_capacity, target_semispace_capacity,
+ maximum_semispace_capacity);
if (!to_space_.Commit()) {
return false;
}
@@ -1285,12 +1288,42 @@
if (!to_space_.ShrinkTo(from_space_.TotalCapacity())) {
// We are in an inconsistent state because we could not
// commit/uncommit memory from new space.
- V8::FatalProcessOutOfMemory("Failed to grow new space.");
+ CHECK(false);
}
}
}
DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
}
+
+
+bool NewSpace::GrowOnePage() {
+ if (TotalCapacity() == MaximumCapacity()) return false;
+ int new_capacity = static_cast<int>(TotalCapacity()) + Page::kPageSize;
+ if (to_space_.GrowTo(new_capacity)) {
+ // Only grow from space if we managed to grow to-space and the from
space
+ // is actually committed.
+ if (from_space_.is_committed()) {
+ if (!from_space_.GrowTo(new_capacity)) {
+ // If we managed to grow to-space but couldn't grow from-space,
+ // attempt to shrink to-space.
+ if (!to_space_.ShrinkTo(from_space_.TotalCapacity())) {
+ // We are in an inconsistent state because we could not
+ // commit/uncommit memory from new space.
+ CHECK(false);
+ }
+ return false;
+ }
+ } else {
+ if (!from_space_.SetTotalCapacity(new_capacity)) {
+ // Can't really happen, but better safe than sorry.
+ CHECK(false);
+ }
+ }
+ DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
+ return true;
+ }
+ return false;
+}
void NewSpace::Shrink() {
@@ -1306,7 +1339,7 @@
if (!to_space_.GrowTo(from_space_.TotalCapacity())) {
// We are in an inconsistent state because we could not
// commit/uncommit memory from new space.
- V8::FatalProcessOutOfMemory("Failed to shrink new space.");
+ CHECK(false);
}
}
}
@@ -1367,8 +1400,19 @@
return false;
}
if (!to_space_.AdvancePage()) {
- // Failed to get a new page in to-space.
- return false;
+ // Check if we reached the target capacity yet. If not, try to commit
a page
+ // and continue.
+ if ((to_space_.TotalCapacity() < to_space_.TargetCapacity()) &&
+ GrowOnePage()) {
+ if (!to_space_.AdvancePage()) {
+ // It doesn't make sense that we managed to commit a page, but
can't use
+ // it.
+ CHECK(false);
+ }
+ } else {
+ // Failed to get a new page in to-space.
+ return false;
+ }
}
// Clear remainder of current page.
@@ -1472,7 +1516,7 @@
//
-----------------------------------------------------------------------------
// SemiSpace implementation
-void SemiSpace::SetUp(Address start, int initial_capacity,
+void SemiSpace::SetUp(Address start, int initial_capacity, int
target_capacity,
int maximum_capacity) {
// Creates a space in the young generation. The constructor does not
// allocate memory from the OS. A SemiSpace is given a contiguous chunk
of
@@ -1481,8 +1525,11 @@
// space is used as the marking stack. It requires contiguous memory
// addresses.
DCHECK(maximum_capacity >= Page::kPageSize);
+ DCHECK(initial_capacity <= target_capacity);
+ DCHECK(target_capacity <= maximum_capacity);
initial_total_capacity_ = RoundDown(initial_capacity, Page::kPageSize);
total_capacity_ = initial_capacity;
+ target_capacity_ = RoundDown(target_capacity, Page::kPageSize);
maximum_total_capacity_ = RoundDown(maximum_capacity, Page::kPageSize);
maximum_committed_ = 0;
committed_ = false;
@@ -1609,6 +1656,17 @@
return true;
}
+
+
+bool SemiSpace::SetTotalCapacity(int new_capacity) {
+ CHECK(!is_committed());
+ if (new_capacity >= initial_total_capacity_ &&
+ new_capacity <= maximum_total_capacity_) {
+ total_capacity_ = new_capacity;
+ return true;
+ }
+ return false;
+}
void SemiSpace::FlipPages(intptr_t flags, intptr_t mask) {
=======================================
--- /trunk/src/heap/spaces.h Tue Sep 30 00:05:10 2014 UTC
+++ /trunk/src/heap/spaces.h Thu Oct 23 08:44:45 2014 UTC
@@ -2075,7 +2075,8 @@
current_page_(NULL) {}
// Sets up the semispace using the given chunk.
- void SetUp(Address start, int initial_capacity, int maximum_capacity);
+ void SetUp(Address start, int initial_capacity, int target_capacity,
+ int maximum_capacity);
// Tear down the space. Heap memory was not allocated by the space, so
it
// is not deallocated here.
@@ -2094,6 +2095,9 @@
// semispace and less than the current capacity.
bool ShrinkTo(int new_capacity);
+ // Sets the total capacity. Only possible when the space is not
committed.
+ bool SetTotalCapacity(int new_capacity);
+
// Returns the start address of the first page of the space.
Address space_start() {
DCHECK(anchor_.next_page() != &anchor_);
@@ -2167,6 +2171,9 @@
// Returns the current total capacity of the semispace.
int TotalCapacity() { return total_capacity_; }
+
+ // Returns the target for total capacity of the semispace.
+ int TargetCapacity() { return target_capacity_; }
// Returns the maximum total capacity of the semispace.
int MaximumTotalCapacity() { return maximum_total_capacity_; }
@@ -2196,6 +2203,7 @@
// The current and maximum total capacity of the space.
int total_capacity_;
+ int target_capacity_;
int maximum_total_capacity_;
int initial_total_capacity_;
@@ -2341,6 +2349,9 @@
// their maximum capacity.
void Grow();
+ // Grow the capacity of the semispaces by one page.
+ bool GrowOnePage();
+
// Shrink the capacity of the semispaces.
void Shrink();
=======================================
--- /trunk/src/hydrogen.cc Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/hydrogen.cc Thu Oct 23 08:44:45 2014 UTC
@@ -5621,6 +5621,8 @@
DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
// Fall through.
case ObjectLiteral::Property::COMPUTED:
+ // It is safe to use [[Put]] here because the boilerplate already
+ // contains computed properties with an uninitialized value.
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
CHECK_ALIVE(VisitForValue(value));
=======================================
--- /trunk/src/ia32/full-codegen-ia32.cc Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/ia32/full-codegen-ia32.cc Thu Oct 23 08:44:45 2014 UTC
@@ -1657,6 +1657,8 @@
DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
// Fall through.
case ObjectLiteral::Property::COMPUTED:
+ // It is safe to use [[Put]] here because the boilerplate already
+ // contains computed properties with an uninitialized value.
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
@@ -1684,7 +1686,7 @@
__ push(Operand(esp, 0)); // Duplicate receiver.
VisitForStackValue(value);
if (property->emit_store()) {
- __ CallRuntime(Runtime::kSetPrototype, 2);
+ __ CallRuntime(Runtime::kInternalSetPrototype, 2);
} else {
__ Drop(2);
}
=======================================
--- /trunk/src/lookup.cc Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/lookup.cc Thu Oct 23 08:44:45 2014 UTC
@@ -314,7 +314,7 @@
Handle<String> name_string = Handle<String>::cast(name());
if (name_string->length() > 0) {
double d =
- StringToDouble(isolate()->unicode_cache(), *name_string,
NO_FLAGS);
+ StringToDouble(isolate()->unicode_cache(), name_string,
NO_FLAGS);
if (!std::isnan(d)) {
if (String::Equals(isolate()->factory()->minus_zero_string(),
name_string))
=======================================
--- /trunk/src/mips/full-codegen-mips.cc Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/mips/full-codegen-mips.cc Thu Oct 23 08:44:45 2014 UTC
@@ -1711,6 +1711,8 @@
DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
// Fall through.
case ObjectLiteral::Property::COMPUTED:
+ // It is safe to use [[Put]] here because the boilerplate already
+ // contains computed properties with an uninitialized value.
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
@@ -1744,7 +1746,7 @@
__ push(a0);
VisitForStackValue(value);
if (property->emit_store()) {
- __ CallRuntime(Runtime::kSetPrototype, 2);
+ __ CallRuntime(Runtime::kInternalSetPrototype, 2);
} else {
__ Drop(2);
}
=======================================
--- /trunk/src/mips64/full-codegen-mips64.cc Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/mips64/full-codegen-mips64.cc Thu Oct 23 08:44:45 2014 UTC
@@ -1708,6 +1708,8 @@
DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
// Fall through.
case ObjectLiteral::Property::COMPUTED:
+ // It is safe to use [[Put]] here because the boilerplate already
+ // contains computed properties with an uninitialized value.
if (key->value()->IsInternalizedString()) {
if (property->emit_store()) {
VisitForAccumulatorValue(value);
@@ -1741,7 +1743,7 @@
__ push(a0);
VisitForStackValue(value);
if (property->emit_store()) {
- __ CallRuntime(Runtime::kSetPrototype, 2);
+ __ CallRuntime(Runtime::kInternalSetPrototype, 2);
} else {
__ Drop(2);
}
=======================================
--- /trunk/src/objects.cc Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/objects.cc Thu Oct 23 08:44:45 2014 UTC
@@ -11796,7 +11796,7 @@
DCHECK(new_map->prototype() == *value);
JSObject::MigrateToMap(real_receiver, new_map);
- if (!dictionary_elements_in_chain &&
+ if (from_javascript && !dictionary_elements_in_chain &&
new_map->DictionaryElementsInPrototypeChainOnly()) {
// If the prototype chain didn't previously have element callbacks,
then
// KeyedStoreICs need to be cleared to ensure any that involve this
=======================================
--- /trunk/src/runtime/runtime-numbers.cc Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/runtime/runtime-numbers.cc Thu Oct 23 08:44:45 2014 UTC
@@ -193,7 +193,7 @@
}
return *isolate->factory()->NewNumber(
- StringToDouble(isolate->unicode_cache(), *subject, flags));
+ StringToDouble(isolate->unicode_cache(), subject, flags));
}
@@ -229,8 +229,7 @@
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
- subject = String::Flatten(subject);
- double value = StringToDouble(isolate->unicode_cache(), *subject,
+ double value = StringToDouble(isolate->unicode_cache(), subject,
ALLOW_TRAILING_JUNK,
base::OS::nan_value());
return *isolate->factory()->NewNumber(value);
=======================================
--- /trunk/src/sampler.cc Fri Oct 17 20:38:26 2014 UTC
+++ /trunk/src/sampler.cc Thu Oct 23 08:44:45 2014 UTC
@@ -374,8 +374,7 @@
state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
#elif V8_HOST_ARCH_ARM
-#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
- (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
// Old GLibc ARM versions used a gregs[] array to access the register
// values from mcontext_t.
state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
@@ -385,8 +384,7 @@
state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
-#endif // defined(__GLIBC__) && !defined(__UCLIBC__) &&
- // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+#endif // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
#elif V8_HOST_ARCH_ARM64
state.pc = reinterpret_cast<Address>(mcontext.pc);
state.sp = reinterpret_cast<Address>(mcontext.sp);
=======================================
--- /trunk/src/third_party/vtune/v8-vtune.h Tue Sep 16 07:50:38 2014 UTC
+++ /trunk/src/third_party/vtune/v8-vtune.h Thu Oct 23 08:44:45 2014 UTC
@@ -62,7 +62,7 @@
namespace vTune {
-void InitializeVtuneForV8(v8::Isolate::CreateParams& params);
+v8::JitCodeEventHandler GetVtuneCodeEventHandler();
} // namespace vTune
=======================================
***Additional files exist in this changeset.***
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.