Revision: 23256
Author: [email protected]
Date: Thu Aug 21 07:23:04 2014 UTC
Log: Version 3.29.11 (based on bleeding_edge revision r23252)
Refactor ParseObjectLiteral.
Support symbol-named properties in API (issue 3394).
Suppress test262 test that tests duplicate properties.
ES6: Duplicate properties are no longer an error (issue 3498).
Expose function CheckDebugBreak in the debugger api.
Remove RegExp.$input (issue 3486).
Performance and stability improvements on all platforms.
http://code.google.com/p/v8/source/detail?r=23256
Added:
/trunk/src/compiler/js-inlining.cc
/trunk/src/compiler/js-inlining.h
/trunk/src/heap/gc-idle-time-handler.cc
/trunk/src/heap/gc-idle-time-handler.h
/trunk/test/cctest/compiler/test-run-inlining.cc
/trunk/test/mjsunit/compiler/shift-shr.js
/trunk/test/mjsunit/number-literal.js
/trunk/test/mjsunit/regress/regress-crbug-405491.js
/trunk/test/mjsunit/runtime-gen/createglobalprivateownsymbol.js
/trunk/tools/cpu.sh
Deleted:
/trunk/src/compiler-intrinsics.h
/trunk/test/mjsunit/runtime-gen/createglobalprivatesymbol.js
/trunk/test/mjsunit/runtime-gen/internalsetprototype.js
/trunk/test/preparser/duplicate-property.pyt
Modified:
/trunk/BUILD.gn
/trunk/ChangeLog
/trunk/include/v8-debug.h
/trunk/include/v8.h
/trunk/include/v8config.h
/trunk/src/accessors.cc
/trunk/src/accessors.h
/trunk/src/api.cc
/trunk/src/api.h
/trunk/src/arguments.h
/trunk/src/arm64/full-codegen-arm64.cc
/trunk/src/arm64/lithium-codegen-arm64.cc
/trunk/src/arm64/simulator-arm64.cc
/trunk/src/array-iterator.js
/trunk/src/assembler.h
/trunk/src/base/bits.h
/trunk/src/bootstrapper.cc
/trunk/src/compiler/arm/instruction-selector-arm.cc
/trunk/src/compiler/arm64/instruction-selector-arm64.cc
/trunk/src/compiler/change-lowering.cc
/trunk/src/compiler/change-lowering.h
/trunk/src/compiler/generic-graph.h
/trunk/src/compiler/generic-node.h
/trunk/src/compiler/instruction-selector.cc
/trunk/src/compiler/instruction-selector.h
/trunk/src/compiler/js-context-specialization.cc
/trunk/src/compiler/js-typed-lowering.cc
/trunk/src/compiler/machine-type.cc
/trunk/src/compiler/node-properties-inl.h
/trunk/src/compiler/node-properties.h
/trunk/src/compiler/pipeline.cc
/trunk/src/compiler/scheduler.cc
/trunk/src/compiler/scheduler.h
/trunk/src/data-flow.cc
/trunk/src/data-flow.h
/trunk/src/elements.cc
/trunk/src/elements.h
/trunk/src/flag-definitions.h
/trunk/src/frames.cc
/trunk/src/heap/heap.cc
/trunk/src/heap/heap.h
/trunk/src/heap/mark-compact.cc
/trunk/src/heap/mark-compact.h
/trunk/src/heap/spaces.cc
/trunk/src/heap-snapshot-generator.cc
/trunk/src/hydrogen-instructions.cc
/trunk/src/hydrogen-instructions.h
/trunk/src/hydrogen.cc
/trunk/src/ic.cc
/trunk/src/lookup.h
/trunk/src/macros.py
/trunk/src/math.js
/trunk/src/mips/simulator-mips.cc
/trunk/src/mips64/simulator-mips64.cc
/trunk/src/objects.cc
/trunk/src/objects.h
/trunk/src/parser.h
/trunk/src/preparser.h
/trunk/src/promise.js
/trunk/src/property.cc
/trunk/src/property.h
/trunk/src/regexp.js
/trunk/src/runtime.cc
/trunk/src/runtime.h
/trunk/src/serialize.cc
/trunk/src/string-iterator.js
/trunk/src/stub-cache.cc
/trunk/src/version.cc
/trunk/test/base-unittests/bits-unittest.cc
/trunk/test/cctest/cctest.gyp
/trunk/test/cctest/test-alloc.cc
/trunk/test/cctest/test-api.cc
/trunk/test/cctest/test-debug.cc
/trunk/test/cctest/test-heap-profiler.cc
/trunk/test/cctest/test-parsing.cc
/trunk/test/compiler-unittests/arm64/instruction-selector-arm64-unittest.cc
/trunk/test/compiler-unittests/change-lowering-unittest.cc
/trunk/test/compiler-unittests/graph-unittest.cc
/trunk/test/compiler-unittests/graph-unittest.h
/trunk/test/compiler-unittests/instruction-selector-unittest.cc
/trunk/test/compiler-unittests/instruction-selector-unittest.h
/trunk/test/heap-unittests/heap-unittest.cc
/trunk/test/mjsunit/es6/math-expm1.js
/trunk/test/mjsunit/mjsunit.status
/trunk/test/mjsunit/strict-mode.js
/trunk/test/mjsunit/string-match.js
/trunk/test/test262/test262.status
/trunk/test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt
/trunk/test/webkit/object-literal-syntax-expected.txt
/trunk/test/webkit/object-literal-syntax.js
/trunk/third_party/fdlibm/LICENSE
/trunk/third_party/fdlibm/fdlibm.cc
/trunk/third_party/fdlibm/fdlibm.h
/trunk/third_party/fdlibm/fdlibm.js
/trunk/tools/generate-runtime-tests.py
/trunk/tools/gyp/v8.gyp
/trunk/tools/whitespace.txt
=======================================
--- /dev/null
+++ /trunk/src/compiler/js-inlining.cc Thu Aug 21 07:23:04 2014 UTC
@@ -0,0 +1,329 @@
+// 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.
+
+#include "src/compiler/ast-graph-builder.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/generic-node-inl.h"
+#include "src/compiler/graph-inl.h"
+#include "src/compiler/graph-visualizer.h"
+#include "src/compiler/js-inlining.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/node-aux-data-inl.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/simplified-operator.h"
+#include "src/compiler/typer.h"
+#include "src/parser.h"
+#include "src/rewriter.h"
+#include "src/scopes.h"
+
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class InlinerVisitor : public NullNodeVisitor {
+ public:
+ explicit InlinerVisitor(JSInliner* inliner) : inliner_(inliner) {}
+
+ GenericGraphVisit::Control Post(Node* node) {
+ switch (node->opcode()) {
+ case IrOpcode::kJSCallFunction:
+ inliner_->TryInlineCall(node);
+ break;
+ default:
+ break;
+ }
+ return GenericGraphVisit::CONTINUE;
+ }
+
+ private:
+ JSInliner* inliner_;
+};
+
+
+void JSInliner::Inline() {
+ InlinerVisitor visitor(this);
+ jsgraph_->graph()->VisitNodeInputsFromEnd(&visitor);
+}
+
+
+static void MoveWithDependencies(Graph* graph, Node* node, Node* old_block,
+ Node* new_block) {
+ if (OperatorProperties::HasControlInput(node->op())) {
+ // Check if we have left the old_block.
+ if (NodeProperties::GetControlInput(node) != old_block) return;
+ // If not, move this node to the new_block.
+ NodeProperties::ReplaceControlInput(node, new_block);
+ }
+ // Independent of whether a node has a control input or not,
+ // it might have a dependency that is pinned to old_block.
+ for (InputIter iter = node->inputs().begin(); iter !=
node->inputs().end();
+ ++iter) {
+ if (NodeProperties::IsControlEdge(iter.edge())) continue;
+ MoveWithDependencies(graph, *iter, old_block, new_block);
+ }
+}
+
+
+static void MoveAllControlNodes(Node* from, Node* to) {
+ for (UseIter iter = from->uses().begin(); iter != from->uses().end();) {
+ if (NodeProperties::IsControlEdge(iter.edge())) {
+ iter.UpdateToAndIncrement(to);
+ } else {
+ ++iter;
+ }
+ }
+}
+
+
+// TODO(sigurds) Find a home for this function and reuse it everywhere
(esp. in
+// test cases, where similar code is currently duplicated).
+static void Parse(Handle<JSFunction> function, CompilationInfoWithZone*
info) {
+ CHECK(Parser::Parse(info));
+ StrictMode strict_mode = info->function()->strict_mode();
+ info->SetStrictMode(strict_mode);
+ info->SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
+ CHECK(Rewriter::Rewrite(info));
+ CHECK(Scope::Analyze(info));
+ CHECK_NE(NULL, info->scope());
+ Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope(),
info->zone());
+ info->shared_info()->set_scope_info(*scope_info);
+}
+
+
+// A facade on a JSFunction's graph to facilitate inlining. It assumes the
+// that the function graph has only one return statement, and provides
+// {UnifyReturn} to convert a function graph to that end.
+// InlineAtCall will create some new nodes using {graph}'s builders (and
hence
+// those nodes will live in {graph}'s zone.
+class Inlinee {
+ public:
+ explicit Inlinee(JSGraph* graph) : jsgraph_(graph) {}
+
+ Graph* graph() { return jsgraph_->graph(); }
+ JSGraph* jsgraph() { return jsgraph_; }
+
+ // Returns the last regular control node, that is
+ // the last control node before the end node.
+ Node* end_block() { return
NodeProperties::GetControlInput(unique_return()); }
+
+ // Return the effect output of the graph,
+ // that is the effect input of the return statement of the inlinee.
+ Node* effect_output() {
+ return NodeProperties::GetEffectInput(unique_return());
+ }
+ // Return the value output of the graph,
+ // that is the value input of the return statement of the inlinee.
+ Node* value_output() {
+ return NodeProperties::GetValueInput(unique_return(), 0);
+ }
+ // Return the unique return statement of the graph.
+ Node* unique_return() {
+ Node* unique_return =
+ NodeProperties::GetControlInput(jsgraph_->graph()->end());
+ DCHECK_EQ(IrOpcode::kReturn, unique_return->opcode());
+ return unique_return;
+ }
+ // Inline this graph at {call}, use {jsgraph} and its zone to create
+ // any new nodes.
+ void InlineAtCall(JSGraph* jsgraph, Node* call);
+ // Ensure that only a single return reaches the end node.
+ void UnifyReturn();
+
+ private:
+ JSGraph* jsgraph_;
+};
+
+
+void Inlinee::UnifyReturn() {
+ Graph* graph = jsgraph_->graph();
+
+ Node* final_merge = NodeProperties::GetControlInput(graph->end(), 0);
+ if (final_merge->opcode() == IrOpcode::kReturn) {
+ // nothing to do
+ return;
+ }
+ DCHECK_EQ(IrOpcode::kMerge, final_merge->opcode());
+
+ int predecessors =
+ OperatorProperties::GetControlInputCount(final_merge->op());
+ Operator* op_phi = jsgraph_->common()->Phi(predecessors);
+ Operator* op_ephi = jsgraph_->common()->EffectPhi(predecessors);
+
+ NodeVector values(NodeVector::allocator_type(jsgraph_->zone()));
+ NodeVector effects(NodeVector::allocator_type(jsgraph_->zone()));
+ // Iterate over all control flow predecessors,
+ // which must be return statements.
+ InputIter iter = final_merge->inputs().begin();
+ while (iter != final_merge->inputs().end()) {
+ Node* input = *iter;
+ switch (input->opcode()) {
+ case IrOpcode::kReturn:
+ values.push_back(NodeProperties::GetValueInput(input, 0));
+ effects.push_back(NodeProperties::GetEffectInput(input));
+ iter.UpdateToAndIncrement(NodeProperties::GetControlInput(input));
+ input->RemoveAllInputs();
+ break;
+ default:
+ UNREACHABLE();
+ ++iter;
+ break;
+ }
+ }
+ values.push_back(final_merge);
+ effects.push_back(final_merge);
+ Node* phi =
+ graph->NewNode(op_phi, static_cast<int>(values.size()),
&values.front());
+ Node* ephi = graph->NewNode(op_ephi, static_cast<int>(effects.size()),
+ &effects.front());
+ Node* new_return =
+ graph->NewNode(jsgraph_->common()->Return(), phi, ephi, final_merge);
+ graph->end()->ReplaceInput(0, new_return);
+}
+
+
+void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
+ MachineOperatorBuilder machine(jsgraph->zone());
+
+ Node* control = NodeProperties::GetControlInput(call);
+ // Move all the nodes to the end block.
+ MoveAllControlNodes(control, end_block());
+ // Now move the ones the call depends on back up.
+ // We have to do this back-and-forth to treat the case where the call is
+ // pinned to the start block.
+ MoveWithDependencies(graph(), call, end_block(), control);
+
+ // The inlinee uses the context from the JSFunction object. This will
+ // also be the effect dependency for the inlinee as it produces an
effect.
+ // TODO(sigurds) Use simplified load once it is ready.
+ Node* context = jsgraph->graph()->NewNode(
+ machine.Load(kMachAnyTagged), NodeProperties::GetValueInput(call, 0),
+ jsgraph->Int32Constant(JSFunction::kContextOffset - kHeapObjectTag),
+ NodeProperties::GetEffectInput(call));
+
+ // {inlinee_inputs} counts JSFunction, Receiver, arguments, context,
+ // but not effect, control.
+ int inlinee_inputs = graph()->start()->op()->OutputCount();
+ // Context is last argument.
+ int inlinee_context_index = inlinee_inputs - 1;
+ // {inliner_inputs} counts JSFunction, Receiver, arguments, but not
+ // context, effect, control.
+ int inliner_inputs = OperatorProperties::GetValueInputCount(call->op());
+ // Iterate over all uses of the start node.
+ UseIter iter = graph()->start()->uses().begin();
+ while (iter != graph()->start()->uses().end()) {
+ Node* use = *iter;
+ switch (use->opcode()) {
+ case IrOpcode::kParameter: {
+ int index = 1 +
static_cast<Operator1<int>*>(use->op())->parameter();
+ if (index < inliner_inputs && index < inlinee_context_index) {
+ // There is an input from the call, and the index is a value
+ // projection but not the context, so rewire the input.
+ NodeProperties::ReplaceWithValue(*iter, call->InputAt(index));
+ } else if (index == inlinee_context_index) {
+ // This is the context projection, rewire it to the context from
the
+ // JSFunction object.
+ NodeProperties::ReplaceWithValue(*iter, context);
+ } else if (index < inlinee_context_index) {
+ // Call has fewer arguments than required, fill with undefined.
+ NodeProperties::ReplaceWithValue(*iter,
jsgraph->UndefinedConstant());
+ } else {
+ // We got too many arguments, discard for now.
+ // TODO(sigurds): Fix to treat arguments array correctly.
+ }
+ ++iter;
+ break;
+ }
+ default:
+ if (NodeProperties::IsEffectEdge(iter.edge())) {
+ iter.UpdateToAndIncrement(context);
+ } else if (NodeProperties::IsControlEdge(iter.edge())) {
+ iter.UpdateToAndIncrement(control);
+ } else {
+ UNREACHABLE();
+ }
+ break;
+ }
+ }
+
+ // Iterate over all uses of the call node.
+ iter = call->uses().begin();
+ while (iter != call->uses().end()) {
+ if (NodeProperties::IsEffectEdge(iter.edge())) {
+ iter.UpdateToAndIncrement(effect_output());
+ } else if (NodeProperties::IsControlEdge(iter.edge())) {
+ UNREACHABLE();
+ } else {
+ DCHECK(NodeProperties::IsValueEdge(iter.edge()));
+ iter.UpdateToAndIncrement(value_output());
+ }
+ }
+ call->RemoveAllInputs();
+ DCHECK_EQ(0, call->UseCount());
+ // TODO(sigurds) Remove this once we copy.
+ unique_return()->RemoveAllInputs();
+}
+
+
+void JSInliner::TryInlineCall(Node* node) {
+ DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
+
+ ValueMatcher<Handle<JSFunction> > match(node->InputAt(0));
+ if (!match.HasValue()) {
+ return;
+ }
+
+ Handle<JSFunction> function = match.Value();
+
+ if (function->shared()->native()) {
+ if (FLAG_trace_turbo_inlining) {
+ SmartArrayPointer<char> name =
+ function->shared()->DebugName()->ToCString();
+ PrintF("Not Inlining %s into %s because inlinee is native\n",
name.get(),
+ info_->shared_info()->DebugName()->ToCString().get());
+ }
+ return;
+ }
+
+ CompilationInfoWithZone info(function);
+ Parse(function, &info);
+
+ if (info.scope()->arguments() != NULL) {
+ // For now do not inline functions that use their arguments array.
+ SmartArrayPointer<char> name =
function->shared()->DebugName()->ToCString();
+ if (FLAG_trace_turbo_inlining) {
+ PrintF(
+ "Not Inlining %s into %s because inlinee uses arguments "
+ "array\n",
+ name.get(),
info_->shared_info()->DebugName()->ToCString().get());
+ }
+ return;
+ }
+
+ if (FLAG_trace_turbo_inlining) {
+ SmartArrayPointer<char> name =
function->shared()->DebugName()->ToCString();
+ PrintF("Inlining %s into %s\n", name.get(),
+ info_->shared_info()->DebugName()->ToCString().get());
+ }
+
+ Graph graph(info_->zone());
+ graph.SetNextNodeId(jsgraph_->graph()->NextNodeID());
+
+ Typer typer(info_->zone());
+ CommonOperatorBuilder common(info_->zone());
+ JSGraph jsgraph(&graph, &common, &typer);
+
+ AstGraphBuilder graph_builder(&info, &jsgraph);
+ graph_builder.CreateGraph();
+
+ Inlinee inlinee(&jsgraph);
+ inlinee.UnifyReturn();
+ inlinee.InlineAtCall(jsgraph_, node);
+
+ jsgraph_->graph()->SetNextNodeId(inlinee.graph()->NextNodeID());
+}
+}
+}
+} // namespace v8::internal::compiler
=======================================
--- /dev/null
+++ /trunk/src/compiler/js-inlining.h Thu Aug 21 07:23:04 2014 UTC
@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef V8_COMPILER_JS_INLINING_H_
+#define V8_COMPILER_JS_INLINING_H_
+
+#include "src/compiler/js-graph.h"
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class JSInliner {
+ public:
+ JSInliner(CompilationInfo* info, JSGraph* jsgraph)
+ : info_(info), jsgraph_(jsgraph) {}
+
+ void Inline();
+ void TryInlineCall(Node* node);
+
+ private:
+ friend class InlinerVisitor;
+ CompilationInfo* info_;
+ JSGraph* jsgraph_;
+
+ static void UnifyReturn(Graph* graph);
+};
+}
+}
+} // namespace v8::internal::compiler
+
+#endif // V8_COMPILER_JS_INLINING_H_
=======================================
--- /dev/null
+++ /trunk/src/heap/gc-idle-time-handler.cc Thu Aug 21 07:23:04 2014 UTC
@@ -0,0 +1,36 @@
+// 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.
+
+#include "src/heap/gc-idle-time-handler.h"
+
+namespace v8 {
+namespace internal {
+
+
+const double GCIdleTimeHandler::kConservativeTimeRatio = 0.9;
+
+
+size_t GCIdleTimeHandler::EstimateMarkingStepSize(
+ size_t idle_time_in_ms, size_t marking_speed_in_bytes_per_ms) {
+ DCHECK(idle_time_in_ms > 0);
+
+ if (marking_speed_in_bytes_per_ms == 0) {
+ marking_speed_in_bytes_per_ms =
+ GCIdleTimeHandler::kInitialConservativeMarkingSpeed;
+ }
+
+ size_t marking_step_size = marking_speed_in_bytes_per_ms *
idle_time_in_ms;
+ if (marking_step_size / marking_speed_in_bytes_per_ms !=
idle_time_in_ms) {
+ // In the case of an overflow we return maximum marking step size.
+ return GCIdleTimeHandler::kMaximumMarkingStepSize;
+ }
+
+ if (marking_step_size > kMaximumMarkingStepSize)
+ return kMaximumMarkingStepSize;
+
+ return static_cast<size_t>(marking_step_size *
+ GCIdleTimeHandler::kConservativeTimeRatio);
+}
+}
+}
=======================================
--- /dev/null
+++ /trunk/src/heap/gc-idle-time-handler.h Thu Aug 21 07:23:04 2014 UTC
@@ -0,0 +1,38 @@
+// 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.
+
+#ifndef V8_HEAP_GC_IDLE_TIME_HANDLER_H_
+#define V8_HEAP_GC_IDLE_TIME_HANDLER_H_
+
+#include "src/globals.h"
+
+namespace v8 {
+namespace internal {
+
+// The idle time handler makes decisions about which garbage collection
+// operations are executing during IdleNotification.
+class GCIdleTimeHandler {
+ public:
+ static size_t EstimateMarkingStepSize(size_t idle_time_in_ms,
+ size_t
marking_speed_in_bytes_per_ms);
+
+ // If we haven't recorded any incremental marking events yet, we
carefully
+ // mark with a conservative lower bound for the marking speed.
+ static const size_t kInitialConservativeMarkingSpeed = 100 * KB;
+
+ // Maximum marking step size returned by EstimateMarkingStepSize.
+ static const size_t kMaximumMarkingStepSize = 700 * MB;
+
+ // We have to make sure that we finish the IdleNotification before
+ // idle_time_in_ms. Hence, we conservatively prune our workload estimate.
+ static const double kConservativeTimeRatio;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GCIdleTimeHandler);
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_HEAP_GC_IDLE_TIME_HANDLER_H_
=======================================
--- /dev/null
+++ /trunk/test/cctest/compiler/test-run-inlining.cc Thu Aug 21 07:23:04
2014 UTC
@@ -0,0 +1,184 @@
+// 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.
+
+#include "src/v8.h"
+
+#include "test/cctest/compiler/function-tester.h"
+
+#if V8_TURBOFAN_TARGET
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+// TODO(sigurds) At the moment we do not write optimization frames when
+// inlining, thus the reported stack depth changes depending on inlining.
+// AssertStackDepth checks the stack depth actually changes as a simple way
+// to ensure that inlining actually occurs.
+// Once inlining creates optimization frames, all these unit tests need to
+// check that the optimization frame is there.
+
+
+static void AssertStackDepth(const v8::FunctionCallbackInfo<v8::Value>&
args) {
+ v8::HandleScope scope(args.GetIsolate());
+ v8::Handle<v8::StackTrace> stackTrace =
v8::StackTrace::CurrentStackTrace(
+ args.GetIsolate(), 10, v8::StackTrace::kDetailed);
+ CHECK_EQ(args[0]->ToInt32()->Value(), stackTrace->GetFrameCount());
+}
+
+
+static void InstallAssertStackDepthHelper(v8::Isolate* isolate) {
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::FunctionTemplate> t =
+ v8::FunctionTemplate::New(isolate, AssertStackDepth);
+ context->Global()->Set(v8_str("AssertStackDepth"), t->GetFunction());
+}
+
+
+TEST(SimpleInlining) {
+ FLAG_turbo_inlining = true;
+ FunctionTester T(
+ "(function(){"
+ "function foo(s) { AssertStackDepth(1); return s; };"
+ "function bar(s, t) { return foo(s); };"
+ "return bar;})();");
+
+ InstallAssertStackDepthHelper(CcTest::isolate());
+ T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
+}
+
+
+TEST(SimpleInliningContext) {
+ FLAG_turbo_inlining = true;
+ FunctionTester T(
+ "(function () {"
+ "function foo(s) { AssertStackDepth(1); var x = 12; return s + x; };"
+ "function bar(s, t) { return foo(s); };"
+ "return bar;"
+ "})();");
+
+ InstallAssertStackDepthHelper(CcTest::isolate());
+ T.CheckCall(T.Val(13), T.Val(1), T.Val(2));
+}
+
+
+TEST(CaptureContext) {
+ FLAG_turbo_inlining = true;
+ FunctionTester T(
+ "var f = (function () {"
+ "var x = 42;"
+ "function bar(s) { return x + s; };"
+ "return (function (s) { return bar(s); });"
+ "})();"
+ "(function (s) { return f(s)})");
+
+ InstallAssertStackDepthHelper(CcTest::isolate());
+ T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
+}
+
+
+// TODO(sigurds) For now we do not inline any native functions. If we do at
+// some point, change this test.
+TEST(DontInlineEval) {
+ FLAG_turbo_inlining = true;
+ FunctionTester T(
+ "var x = 42;"
+ "(function () {"
+ "function bar(s, t) { return eval(\"AssertStackDepth(2); x\") };"
+ "return bar;"
+ "})();");
+
+ InstallAssertStackDepthHelper(CcTest::isolate());
+ T.CheckCall(T.Val(42), T.Val("x"), T.undefined());
+}
+
+
+TEST(InlineOmitArguments) {
+ FLAG_turbo_inlining = true;
+ FunctionTester T(
+ "(function () {"
+ "var x = 42;"
+ "function bar(s, t, u, v) { AssertStackDepth(1); return x + s; };"
+ "return (function (s,t) { return bar(s); });"
+ "})();");
+
+ InstallAssertStackDepthHelper(CcTest::isolate());
+ T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
+}
+
+
+TEST(InlineSurplusArguments) {
+ FLAG_turbo_inlining = true;
+ FunctionTester T(
+ "(function () {"
+ "var x = 42;"
+ "function foo(s) { AssertStackDepth(1); return x + s; };"
+ "function bar(s,t) { return foo(s,t,13); };"
+ "return bar;"
+ "})();");
+
+ InstallAssertStackDepthHelper(CcTest::isolate());
+ T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
+}
+
+
+TEST(InlineTwice) {
+ FLAG_turbo_inlining = true;
+ FunctionTester T(
+ "(function () {"
+ "var x = 42;"
+ "function bar(s) { AssertStackDepth(1); return x + s; };"
+ "return (function (s,t) { return bar(s) + bar(t); });"
+ "})();");
+
+ InstallAssertStackDepthHelper(CcTest::isolate());
+ T.CheckCall(T.Val(2 * 42 + 12 + 4), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineTwiceDependent) {
+ FLAG_turbo_inlining = true;
+ FunctionTester T(
+ "(function () {"
+ "var x = 42;"
+ "function foo(s) { AssertStackDepth(1); return x + s; };"
+ "function bar(s,t) { return foo(foo(s)); };"
+ "return bar;"
+ "})();");
+
+ InstallAssertStackDepthHelper(CcTest::isolate());
+ T.CheckCall(T.Val(42 + 42 + 12), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineTwiceDependentDiamond) {
+ FLAG_turbo_inlining = true;
+ FunctionTester T(
+ "(function () {"
+ "function foo(s) { if (true) {"
+ " return 12 } else { return 13; } };"
+ "function bar(s,t) { return foo(foo(1)); };"
+ "return bar;"
+ "})();");
+
+ InstallAssertStackDepthHelper(CcTest::isolate());
+ T.CheckCall(T.Val(12), T.undefined(), T.undefined());
+}
+
+
+TEST(InlineTwiceDependentDiamondReal) {
+ FLAG_turbo_inlining = true;
+ FunctionTester T(
+ "(function () {"
+ "var x = 41;"
+ "function foo(s) { AssertStackDepth(1); if (s % 2 == 0) {"
+ " return x - s } else { return x + s; } };"
+ "function bar(s,t) { return foo(foo(s)); };"
+ "return bar;"
+ "})();");
+
+ InstallAssertStackDepthHelper(CcTest::isolate());
+ T.CheckCall(T.Val(-11), T.Val(11), T.Val(4));
+}
+
+#endif // V8_TURBOFAN_TARGET
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/compiler/shift-shr.js Thu Aug 21 07:23:04 2014 UTC
@@ -0,0 +1,26 @@
+// 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.
+
+// Flags: --allow-natives-syntax --noopt-safe-uint32-operations
+
+// Check the results of `left >>> right`. The result is always unsigned
(and
+// therefore positive).
+function test_shr(left) {
+ var errors = 0;
+
+ for (var i = 1; i < 1024; i++) {
+ var temp = left >>> i;
+ if (temp < 0) {
+ errors++;
+ }
+ }
+
+ return errors;
+}
+
+assertEquals(0, test_shr(1));
+%OptimizeFunctionOnNextCall(test_shr);
+for (var i = 5; i >= -5; i--) {
+ assertEquals(0, test_shr(i));
+}
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/number-literal.js Thu Aug 21 07:23:04 2014 UTC
@@ -0,0 +1,33 @@
+// 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.
+
+function test(message, a, b, skipStrictMode) {
+ assertSame(eval(a), eval(b), message);
+ if (!skipStrictMode) {
+ (function() {
+ 'use strict';
+ assertSame(eval(a), eval(b), message);
+ })();
+ }
+}
+
+test('hex-int', '0x20', '32');
+test('oct-int', '040', '32', true); // Octals disallowed in strict mode.
+test('dec-int', '32.00', '32');
+test('dec-underflow-int', '32.00000000000000000000000000000000000000001',
'32');
+test('exp-int', '3.2e1', '32');
+test('exp-int', '3200e-2', '32');
+test('overflow-inf', '1e2000', 'Infinity');
+test('overflow-inf-exact', '1.797693134862315808e+308', 'Infinity');
+test('non-overflow-inf-exact', '1.797693134862315807e+308',
+ '1.7976931348623157e+308');
+test('underflow-0', '1e-2000', '0');
+test('underflow-0-exact', '2.4703282292062E-324', '0');
+test('non-underflow-0-exact', '2.4703282292063E-324', '5e-324');
+test('precission-loss-high', '9007199254740992', '9007199254740993');
+test('precission-loss-low', '1.9999999999999998', '1.9999999999999997');
+test('non-canonical-literal-int', '1.0', '1');
+test('non-canonical-literal-frac', '1.50', '1.5');
+test('rounding-down', '1.12512512512512452', '1.1251251251251244');
+test('rounding-up', '1.12512512512512453', '1.1251251251251246');
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-crbug-405491.js Thu Aug 21 07:23:04
2014 UTC
@@ -0,0 +1,5 @@
+// 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.
+
+// Flags: --expose-debug-as 1
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/runtime-gen/createglobalprivateownsymbol.js Thu Aug
21 07:23:04 2014 UTC
@@ -0,0 +1,5 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
+// Flags: --allow-natives-syntax --harmony --harmony-proxies
+var _name = "foo";
+%CreateGlobalPrivateOwnSymbol(_name);
=======================================
--- /dev/null
+++ /trunk/tools/cpu.sh Thu Aug 21 07:23:04 2014 UTC
@@ -0,0 +1,62 @@
+#!/bin/bash
+# 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.
+
+CPUPATH=/sys/devices/system/cpu
+
+MAXID=$(cat $CPUPATH/present | awk -F- '{print $NF}')
+
+set_governor() {
+ echo "Setting CPU frequency governor to \"$1\""
+ for (( i=0; i<=$MAXID; i++ )); do
+ echo "$1" > $CPUPATH/cpu$i/cpufreq/scaling_governor
+ done
+}
+
+dual_core() {
+ echo "Switching to dual-core mode"
+ for (( i=2; i<=$MAXID; i++ )); do
+ echo 0 > $CPUPATH/cpu$i/online
+ done
+}
+
+single_core() {
+ echo "Switching to single-core mode"
+ for (( i=1; i<=$MAXID; i++ )); do
+ echo 0 > $CPUPATH/cpu$i/online
+ done
+}
+
+
+all_cores() {
+ echo "Reactivating all CPU cores"
+ for (( i=2; i<=$MAXID; i++ )); do
+ echo 1 > $CPUPATH/cpu$i/online
+ done
+}
+
+case "$1" in
+ fast | performance)
+ set_governor "performance"
+ ;;
+ slow | powersave)
+ set_governor "powersave"
+ ;;
+ default | ondemand)
+ set_governor "ondemand"
+ ;;
+ dualcore | dual)
+ dual_core
+ ;;
+ singlecore | single)
+ single_core
+ ;;
+ allcores | all)
+ all_cores
+ ;;
+ *)
+ echo "Usage: $0 fast|slow|default|singlecore|dualcore|all"
+ exit 1
+ ;;
+esac
=======================================
--- /trunk/src/compiler-intrinsics.h Thu Jul 31 18:45:14 2014 UTC
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2006-2008 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.
-
-#ifndef V8_COMPILER_INTRINSICS_H_
-#define V8_COMPILER_INTRINSICS_H_
-
-#include "src/base/macros.h"
-
-namespace v8 {
-namespace internal {
-
-class CompilerIntrinsics {
- public:
- // Returns number of zero bits preceding least significant 1 bit.
- // Undefined for zero value.
- INLINE(static int CountTrailingZeros(uint32_t value));
-
- // Returns number of zero bits following most significant 1 bit.
- // Undefined for zero value.
- INLINE(static int CountLeadingZeros(uint32_t value));
-
- // Returns the number of bits set.
- INLINE(static int CountSetBits(uint32_t value));
-};
-
-#ifdef __GNUC__
-int CompilerIntrinsics::CountTrailingZeros(uint32_t value) {
- return __builtin_ctz(value);
-}
-
-int CompilerIntrinsics::CountLeadingZeros(uint32_t value) {
- return __builtin_clz(value);
-}
-
-int CompilerIntrinsics::CountSetBits(uint32_t value) {
- return __builtin_popcount(value);
-}
-
-#elif defined(_MSC_VER)
-
-#pragma intrinsic(_BitScanForward)
-#pragma intrinsic(_BitScanReverse)
-
-int CompilerIntrinsics::CountTrailingZeros(uint32_t value) {
- unsigned long result; //NOLINT
- _BitScanForward(&result, static_cast<long>(value)); //NOLINT
- return static_cast<int>(result);
-}
-
-int CompilerIntrinsics::CountLeadingZeros(uint32_t value) {
- unsigned long result; //NOLINT
- _BitScanReverse(&result, static_cast<long>(value)); //NOLINT
- return 31 - static_cast<int>(result);
-}
-
-int CompilerIntrinsics::CountSetBits(uint32_t value) {
- // Manually count set bits.
- value = ((value >> 1) & 0x55555555) + (value & 0x55555555);
- value = ((value >> 2) & 0x33333333) + (value & 0x33333333);
- value = ((value >> 4) & 0x0f0f0f0f) + (value & 0x0f0f0f0f);
- value = ((value >> 8) & 0x00ff00ff) + (value & 0x00ff00ff);
- value = ((value >> 16) & 0x0000ffff) + (value & 0x0000ffff);
- return value;
-}
-
-#else
-#error Unsupported compiler
-#endif
-
-} } // namespace v8::internal
-
-#endif // V8_COMPILER_INTRINSICS_H_
=======================================
--- /trunk/test/mjsunit/runtime-gen/createglobalprivatesymbol.js Fri Aug 8
15:46:17 2014 UTC
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
-// Flags: --allow-natives-syntax --harmony --harmony-proxies
-var _name = "foo";
-%CreateGlobalPrivateSymbol(_name);
=======================================
--- /trunk/test/mjsunit/runtime-gen/internalsetprototype.js Tue Aug 12
06:42:13 2014 UTC
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright 2014 the V8 project authors. All rights reserved.
-// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
-// Flags: --allow-natives-syntax --harmony --harmony-proxies
-var _obj = new Object();
-var _prototype = new Object();
-%InternalSetPrototype(_obj, _prototype);
=======================================
--- /trunk/test/preparser/duplicate-property.pyt Tue Jun 17 08:22:36 2014
UTC
+++ /dev/null
@@ -1,162 +0,0 @@
-# Copyright 2011 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.
-
-# Tests of duplicate properties in object literals.
-
-# ----------------------------------------------------------------------
-# Utility functions to generate a number of tests for each property
-# name pair.
-
-def PropertyTest(name, propa, propb, allow_strict = True):
- replacement = {"id1": propa, "id2": propb, "name": name}
-
- # Tests same test in both strict and non-strict context.
- def StrictTest(name, source, replacement, expectation):
- if (allow_strict):
- Template("strict-" + name,
- "\"use strict\";\n" + source)(replacement, expectation)
- Template(name, source)(replacement, expectation)
-
- # This one only fails in non-strict context.
- if (allow_strict):
- Template("strict-$name-data-data", """
- "use strict";
- var o = {$id1: 42, $id2: 42};
- """)(replacement, "strict_duplicate_property")
-
- Template("$name-data-data", """
- var o = {$id1: 42, $id2: 42};
- """)(replacement, None)
-
- StrictTest("$name-data-get", """
- var o = {$id1: 42, get $id2(){}};
- """, replacement, "accessor_data_property")
-
- StrictTest("$name-data-set", """
- var o = {$id1: 42, set $id2(v){}};
- """, replacement, "accessor_data_property")
-
- StrictTest("$name-get-data", """
- var o = {get $id1(){}, $id2: 42};
- """, replacement, "accessor_data_property")
-
- StrictTest("$name-set-data", """
- var o = {set $id1(v){}, $id2: 42};
- """, replacement, "accessor_data_property")
-
- StrictTest("$name-get-get", """
- var o = {get $id1(){}, get $id2(){}};
- """, replacement, "accessor_get_set")
-
- StrictTest("$name-set-set", """
- var o = {set $id1(v){}, set $id2(v){}};
- """, replacement, "accessor_get_set")
-
- StrictTest("$name-nested-get", """
- var o = {get $id1(){}, o: {get $id2(){} } };
- """, replacement, None)
-
- StrictTest("$name-nested-set", """
- var o = {set $id1(v){}, o: {set $id2(v){} } };
- """, replacement, None)
-
-
-def TestBothWays(name, propa, propb, allow_strict = True):
- PropertyTest(name + "-1", propa, propb, allow_strict)
- PropertyTest(name + "-2", propb, propa, allow_strict)
-
-def TestSame(name, prop, allow_strict = True):
- PropertyTest(name, prop, prop, allow_strict)
-
-#-----------------------------------------------------------------------
-
-# Simple identifier property
-TestSame("a", "a")
-
-# Get/set identifiers
-TestSame("get-id", "get")
-TestSame("set-id", "set")
-
-# Number properties
-TestSame("0", "0")
-TestSame("0.1", "0.1")
-TestSame("1.0", "1.0")
-TestSame("42.33", "42.33")
-TestSame("2^32-2", "4294967294")
-TestSame("2^32", "4294967296")
-TestSame("2^53", "9007199254740992")
-TestSame("Hex20", "0x20")
-TestSame("exp10", "1e10")
-TestSame("exp20", "1e20")
-TestSame("Oct40", "040", False);
-
-
-# String properties
-TestSame("str-a", '"a"')
-TestSame("str-0", '"0"')
-TestSame("str-42", '"42"')
-TestSame("str-empty", '""')
-
-# Keywords
-TestSame("if", "if")
-TestSame("case", "case")
-
-# Future reserved keywords
-TestSame("public", "public")
-TestSame("class", "class")
-
-
-# Test that numbers are converted to string correctly.
-
-TestBothWays("hex-int", "0x20", "32")
-TestBothWays("oct-int", "040", "32", False) # Octals disallowed in strict
mode.
-TestBothWays("dec-int", "32.00", "32")
-TestBothWays("dec-underflow-int",
- "32.00000000000000000000000000000000000000001", "32")
-TestBothWays("exp-int", "3.2e1", "32")
-TestBothWays("exp-int", "3200e-2", "32")
-TestBothWays("overflow-inf", "1e2000", "Infinity")
-TestBothWays("overflow-inf-exact", "1.797693134862315808e+308", "Infinity")
-TestBothWays("non-overflow-inf-exact", "1.797693134862315807e+308",
- "1.7976931348623157e+308")
-TestBothWays("underflow-0", "1e-2000", "0")
-TestBothWays("underflow-0-exact", "2.4703282292062E-324", "0")
-TestBothWays("non-underflow-0-exact", "2.4703282292063E-324", "5e-324")
-TestBothWays("precission-loss-high", "9007199254740992", "9007199254740993")
-TestBothWays("precission-loss-low", "1.9999999999999998", "1.9999999999999997")
-TestBothWays("non-canonical-literal-int", "1.0", "1")
-TestBothWays("non-canonical-literal-frac", "1.50", "1.5")
-TestBothWays("rounding-down", "1.12512512512512452", "1.1251251251251244")
-TestBothWays("rounding-up", "1.12512512512512453", "1.1251251251251246")
-
-TestBothWays("hex-int-str", "0x20", '"32"')
-TestBothWays("dec-int-str", "32.00", '"32"')
-TestBothWays("exp-int-str", "3.2e1", '"32"')
-TestBothWays("overflow-inf-str", "1e2000", '"Infinity"')
-TestBothWays("underflow-0-str", "1e-2000", '"0"')
-TestBothWays("non-canonical-literal-int-str", "1.0", '"1"')
-TestBothWays("non-canonical-literal-frac-str", "1.50", '"1.5"')
=======================================
--- /trunk/BUILD.gn Thu Aug 21 00:04:56 2014 UTC
+++ /trunk/BUILD.gn Thu Aug 21 07:23:04 2014 UTC
@@ -499,6 +499,8 @@
"src/compiler/js-generic-lowering.h",
"src/compiler/js-graph.cc",
"src/compiler/js-graph.h",
+ "src/compiler/js-inlining.cc",
+ "src/compiler/js-inlining.h",
"src/compiler/js-operator.h",
"src/compiler/js-typed-lowering.cc",
"src/compiler/js-typed-lowering.h",
@@ -509,6 +511,8 @@
"src/compiler/machine-operator-reducer.cc",
"src/compiler/machine-operator-reducer.h",
"src/compiler/machine-operator.h",
+ "src/compiler/machine-type.cc",
+ "src/compiler/machine-type.h",
"src/compiler/node-aux-data-inl.h",
"src/compiler/node-aux-data.h",
"src/compiler/node-cache.cc",
@@ -628,6 +632,8 @@
"src/heap-snapshot-generator-inl.h",
"src/heap-snapshot-generator.cc",
"src/heap-snapshot-generator.h",
+ "src/heap/gc-idle-time-handler.cc",
+ "src/heap/gc-idle-time-handler.h",
"src/heap/gc-tracer.cc",
"src/heap/gc-tracer.h",
"src/heap/heap-inl.h",
=======================================
--- /trunk/ChangeLog Thu Aug 21 00:04:56 2014 UTC
+++ /trunk/ChangeLog Thu Aug 21 07:23:04 2014 UTC
@@ -1,3 +1,20 @@
+2014-08-21: Version 3.29.11
+
+ Refactor ParseObjectLiteral.
+
+ Support symbol-named properties in API (issue 3394).
+
+ Suppress test262 test that tests duplicate properties.
+
+ ES6: Duplicate properties are no longer an error (issue 3498).
+
+ Expose function CheckDebugBreak in the debugger api.
+
+ Remove RegExp.$input (issue 3486).
+
+ Performance and stability improvements on all platforms.
+
+
2014-08-21: Version 3.29.10
ES6: Make sure we do not store -0 as the key in Map/Set (issue
3515).
=======================================
--- /trunk/include/v8-debug.h Mon Jul 7 00:05:07 2014 UTC
+++ /trunk/include/v8-debug.h Thu Aug 21 07:23:04 2014 UTC
@@ -167,6 +167,9 @@
// happened yet.
static void CancelDebugBreak(Isolate* isolate);
+ // Check if a debugger break is scheduled in the given isolate.
+ static bool CheckDebugBreak(Isolate* isolate);
+
// Break execution of JavaScript in the given isolate (this method
// can be invoked from a non-VM thread) for further client command
// execution on a VM thread. Client data is then passed in
=======================================
--- /trunk/include/v8.h Thu Aug 21 00:04:56 2014 UTC
+++ /trunk/include/v8.h Thu Aug 21 07:23:04 2014 UTC
@@ -77,6 +77,7 @@
class Int32;
class Integer;
class Isolate;
+class Name;
class Number;
class NumberObject;
class Object;
@@ -1366,6 +1367,12 @@
*/
bool IsFalse() const;
+ /**
+ * Returns true if this value is a symbol or a string.
+ * This is an experimental feature.
+ */
+ bool IsName() const;
+
/**
* Returns true if this value is an instance of the String type.
* See ECMA-262 8.4.
@@ -1598,10 +1605,21 @@
};
+/**
+ * A superclass for symbols and strings.
+ */
+class V8_EXPORT Name : public Primitive {
+ public:
+ V8_INLINE static Name* Cast(v8::Value* obj);
+ private:
+ static void CheckCast(v8::Value* obj);
+};
+
+
/**
* A JavaScript string value (ECMA-262, 4.3.17).
*/
-class V8_EXPORT String : public Primitive {
+class V8_EXPORT String : public Name {
public:
enum Encoding {
UNKNOWN_ENCODING = 0x1,
@@ -1940,7 +1958,7 @@
*
* This is an experimental feature. Use at your own risk.
*/
-class V8_EXPORT Symbol : public Primitive {
+class V8_EXPORT Symbol : public Name {
public:
// Returns the print name string of the symbol, or undefined if none.
Local<Value> Name() const;
@@ -2089,11 +2107,18 @@
typedef void (*AccessorGetterCallback)(
Local<String> property,
const PropertyCallbackInfo<Value>& info);
+typedef void (*AccessorNameGetterCallback)(
+ Local<Name> property,
+ const PropertyCallbackInfo<Value>& info);
typedef void (*AccessorSetterCallback)(
Local<String> property,
Local<Value> value,
+ const PropertyCallbackInfo<void>& info);
+typedef void (*AccessorNameSetterCallback)(
+ Local<Name> property,
+ Local<Value> value,
const PropertyCallbackInfo<void>& info);
@@ -2169,14 +2194,20 @@
Handle<Value> data = Handle<Value>(),
AccessControl settings = DEFAULT,
PropertyAttribute attribute = None);
+ bool SetAccessor(Handle<Name> name,
+ AccessorNameGetterCallback getter,
+ AccessorNameSetterCallback setter = 0,
+ Handle<Value> data = Handle<Value>(),
+ AccessControl settings = DEFAULT,
+ PropertyAttribute attribute = None);
// This function is not yet stable and should not be used at this time.
- bool SetDeclaredAccessor(Local<String> name,
+ bool SetDeclaredAccessor(Local<Name> name,
Local<DeclaredAccessorDescriptor> descriptor,
PropertyAttribute attribute = None,
AccessControl settings = DEFAULT);
- void SetAccessorProperty(Local<String> name,
+ void SetAccessorProperty(Local<Name> name,
Local<Function> getter,
Handle<Function> setter = Handle<Function>(),
PropertyAttribute attribute = None,
@@ -3178,12 +3209,12 @@
class V8_EXPORT Template : public Data {
public:
/** Adds a property to each instance created by this template.*/
- void Set(Handle<String> name, Handle<Data> value,
+ void Set(Handle<Name> name, Handle<Data> value,
PropertyAttribute attributes = None);
V8_INLINE void Set(Isolate* isolate, const char* name, Handle<Data>
value);
void SetAccessorProperty(
- Local<String> name,
+ Local<Name> name,
Local<FunctionTemplate> getter = Local<FunctionTemplate>(),
Local<FunctionTemplate> setter = Local<FunctionTemplate>(),
PropertyAttribute attribute = None,
@@ -3225,9 +3256,18 @@
Local<AccessorSignature> signature =
Local<AccessorSignature>(),
AccessControl settings = DEFAULT);
+ void SetNativeDataProperty(Local<Name> name,
+ AccessorNameGetterCallback getter,
+ AccessorNameSetterCallback setter = 0,
+ // TODO(dcarney): gcc can't handle Local below
+ Handle<Value> data = Handle<Value>(),
+ PropertyAttribute attribute = None,
+ Local<AccessorSignature> signature =
+ Local<AccessorSignature>(),
+ AccessControl settings = DEFAULT);
// This function is not yet stable and should not be used at this time.
- bool SetDeclaredAccessor(Local<String> name,
+ bool SetDeclaredAccessor(Local<Name> name,
Local<DeclaredAccessorDescriptor> descriptor,
PropertyAttribute attribute = None,
Local<AccessorSignature> signature =
@@ -3594,12 +3634,20 @@
PropertyAttribute attribute = None,
Handle<AccessorSignature> signature =
Handle<AccessorSignature>());
+ void SetAccessor(Handle<Name> name,
+ AccessorNameGetterCallback getter,
+ AccessorNameSetterCallback setter = 0,
+ Handle<Value> data = Handle<Value>(),
+ AccessControl settings = DEFAULT,
+ PropertyAttribute attribute = None,
+ Handle<AccessorSignature> signature =
+ Handle<AccessorSignature>());
/**
* Sets a named property handler on the object template.
*
- * Whenever a named property is accessed on objects created from
- * this object template, the provided callback is invoked instead of
+ * Whenever a property whose name is a string is accessed on objects
created
+ * from this object template, the provided callback is invoked instead of
* accessing the property directly on the JavaScript object.
*
* \param getter The callback to invoke when getting a property.
@@ -6346,6 +6394,14 @@
template <class T> Value* Value::Cast(T* value) {
return static_cast<Value*>(value);
}
+
+
+Name* Name::Cast(v8::Value* value) {
+#ifdef V8_ENABLE_CHECKS
+ CheckCast(value);
+#endif
+ return static_cast<Name*>(value);
+}
Symbol* Symbol::Cast(v8::Value* value) {
=======================================
--- /trunk/include/v8config.h Tue Apr 29 16:30:47 2014 UTC
+++ /trunk/include/v8config.h Thu Aug 21 07:23:04 2014 UTC
@@ -175,7 +175,10 @@
// V8_HAS_ATTRIBUTE_VISIBILITY - __attribute__((visibility))
supported
// V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT -
__attribute__((warn_unused_result))
// supported
+// V8_HAS_BUILTIN_CLZ - __builtin_clz() supported
+// V8_HAS_BUILTIN_CTZ - __builtin_ctz() supported
// V8_HAS_BUILTIN_EXPECT - __builtin_expect() supported
+// V8_HAS_BUILTIN_POPCOUNT - __builtin_popcount() supported
// V8_HAS_DECLSPEC_ALIGN - __declspec(align(n)) supported
// V8_HAS_DECLSPEC_DEPRECATED - __declspec(deprecated) supported
// V8_HAS_DECLSPEC_NOINLINE - __declspec(noinline) supported
@@ -206,7 +209,10 @@
# define V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT \
(__has_attribute(warn_unused_result))
+# define V8_HAS_BUILTIN_CLZ (__has_builtin(__builtin_clz))
+# define V8_HAS_BUILTIN_CTZ (__has_builtin(__builtin_ctz))
# define V8_HAS_BUILTIN_EXPECT (__has_builtin(__builtin_expect))
+# define V8_HAS_BUILTIN_POPCOUNT (__has_builtin(__builtin_popcount))
# define V8_HAS_CXX11_ALIGNAS (__has_feature(cxx_alignas))
# define V8_HAS_CXX11_STATIC_ASSERT (__has_feature(cxx_static_assert))
@@ -238,7 +244,10 @@
# define V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT \
(!V8_CC_INTEL && V8_GNUC_PREREQ(4, 1, 0))
+# define V8_HAS_BUILTIN_CLZ (V8_GNUC_PREREQ(3, 4, 0))
+# define V8_HAS_BUILTIN_CTZ (V8_GNUC_PREREQ(3, 4, 0))
# define V8_HAS_BUILTIN_EXPECT (V8_GNUC_PREREQ(2, 96, 0))
+# define V8_HAS_BUILTIN_POPCOUNT (V8_GNUC_PREREQ(3, 4, 0))
// g++ requires -std=c++0x or -std=gnu++0x to support C++11 functionality
// without warnings (functionality used by the macros below). These modes
=======================================
--- /trunk/src/accessors.cc Tue Aug 12 06:42:13 2014 UTC
+++ /trunk/src/accessors.cc Thu Aug 21 07:23:04 2014 UTC
@@ -23,9 +23,9 @@
Handle<AccessorInfo> Accessors::MakeAccessor(
Isolate* isolate,
- Handle<String> name,
- AccessorGetterCallback getter,
- AccessorSetterCallback setter,
+ Handle<Name> name,
+ AccessorNameGetterCallback getter,
+ AccessorNameSetterCallback setter,
PropertyAttributes attributes) {
Factory* factory = isolate->factory();
Handle<ExecutableAccessorInfo> info =
factory->NewExecutableAccessorInfo();
@@ -138,7 +138,7 @@
bool SetPropertyOnInstanceIfInherited(
Isolate* isolate, const v8::PropertyCallbackInfo<void>& info,
- v8::Local<v8::String> name, Handle<Object> value) {
+ v8::Local<v8::Name> name, Handle<Object> value) {
Handle<Object> holder = Utils::OpenHandle(*info.Holder());
Handle<Object> receiver = Utils::OpenHandle(*info.This());
if (*holder == *receiver) return false;
@@ -176,7 +176,7 @@
void Accessors::ArrayLengthGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
DisallowHeapAllocation no_allocation;
@@ -188,7 +188,7 @@
void Accessors::ArrayLengthSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> val,
const v8::PropertyCallbackInfo<void>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
@@ -244,7 +244,7 @@
//
void Accessors::StringLengthGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
DisallowHeapAllocation no_allocation;
@@ -267,7 +267,7 @@
void Accessors::StringLengthSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -290,7 +290,7 @@
void Accessors::ScriptColumnOffsetGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
DisallowHeapAllocation no_allocation;
@@ -302,7 +302,7 @@
void Accessors::ScriptColumnOffsetSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -327,7 +327,7 @@
void Accessors::ScriptIdGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
DisallowHeapAllocation no_allocation;
@@ -339,7 +339,7 @@
void Accessors::ScriptIdSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -364,7 +364,7 @@
void Accessors::ScriptNameGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
DisallowHeapAllocation no_allocation;
@@ -376,7 +376,7 @@
void Accessors::ScriptNameSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -399,7 +399,7 @@
void Accessors::ScriptSourceGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
DisallowHeapAllocation no_allocation;
@@ -411,7 +411,7 @@
void Accessors::ScriptSourceSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -434,7 +434,7 @@
void Accessors::ScriptLineOffsetGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
DisallowHeapAllocation no_allocation;
@@ -446,7 +446,7 @@
void Accessors::ScriptLineOffsetSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -471,7 +471,7 @@
void Accessors::ScriptTypeGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
DisallowHeapAllocation no_allocation;
@@ -483,7 +483,7 @@
void Accessors::ScriptTypeSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -508,7 +508,7 @@
void Accessors::ScriptCompilationTypeGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
DisallowHeapAllocation no_allocation;
@@ -521,7 +521,7 @@
void Accessors::ScriptCompilationTypeSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -546,7 +546,7 @@
void Accessors::ScriptLineEndsGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
@@ -566,7 +566,7 @@
void Accessors::ScriptLineEndsSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -591,7 +591,7 @@
void Accessors::ScriptSourceUrlGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
DisallowHeapAllocation no_allocation;
@@ -603,7 +603,7 @@
void Accessors::ScriptSourceUrlSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -626,7 +626,7 @@
void Accessors::ScriptSourceMappingUrlGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
DisallowHeapAllocation no_allocation;
@@ -639,7 +639,7 @@
void Accessors::ScriptSourceMappingUrlSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -662,7 +662,7 @@
void Accessors::ScriptContextDataGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
DisallowHeapAllocation no_allocation;
@@ -674,7 +674,7 @@
void Accessors::ScriptContextDataSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -699,7 +699,7 @@
void Accessors::ScriptEvalFromScriptGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
@@ -721,7 +721,7 @@
void Accessors::ScriptEvalFromScriptSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -746,7 +746,7 @@
void Accessors::ScriptEvalFromScriptPositionGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
@@ -767,7 +767,7 @@
void Accessors::ScriptEvalFromScriptPositionSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -792,7 +792,7 @@
void Accessors::ScriptEvalFromFunctionNameGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
@@ -813,7 +813,7 @@
void Accessors::ScriptEvalFromFunctionNameSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> value,
const v8::PropertyCallbackInfo<void>& info) {
UNREACHABLE();
@@ -884,7 +884,7 @@
void Accessors::FunctionPrototypeGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
@@ -896,7 +896,7 @@
void Accessors::FunctionPrototypeSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> val,
const v8::PropertyCallbackInfo<void>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
@@ -927,7 +927,7 @@
void Accessors::FunctionLengthGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
@@ -953,7 +953,7 @@
void Accessors::FunctionLengthSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> val,
const v8::PropertyCallbackInfo<void>& info) {
// Function length is non writable, non configurable.
@@ -977,7 +977,7 @@
void Accessors::FunctionNameGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
@@ -989,7 +989,7 @@
void Accessors::FunctionNameSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> val,
const v8::PropertyCallbackInfo<void>& info) {
// Function name is non writable, non configurable.
@@ -1114,7 +1114,7 @@
void Accessors::FunctionArgumentsGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
@@ -1126,7 +1126,7 @@
void Accessors::FunctionArgumentsSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> val,
const v8::PropertyCallbackInfo<void>& info) {
// Function arguments is non writable, non configurable.
@@ -1257,7 +1257,7 @@
void Accessors::FunctionCallerGetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
const v8::PropertyCallbackInfo<v8::Value>& info) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
HandleScope scope(isolate);
@@ -1277,7 +1277,7 @@
void Accessors::FunctionCallerSetter(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<v8::Value> val,
const v8::PropertyCallbackInfo<void>& info) {
// Function caller is non writable, non configurable.
=======================================
--- /trunk/src/accessors.h Tue Aug 12 06:42:13 2014 UTC
+++ /trunk/src/accessors.h Thu Aug 21 07:23:04 2014 UTC
@@ -43,10 +43,10 @@
// Accessor descriptors.
#define ACCESSOR_INFO_DECLARATION(name) \
static void name##Getter( \
- v8::Local<v8::String> name, \
+ v8::Local<v8::Name> name, \
const v8::PropertyCallbackInfo<v8::Value>& info); \
static void name##Setter( \
- v8::Local<v8::String> name, \
+ v8::Local<v8::Name> name, \
v8::Local<v8::Value> value, \
const v8::PropertyCallbackInfo<void>& info); \
static Handle<AccessorInfo> name##Info( \
@@ -83,9 +83,9 @@
static Handle<AccessorInfo> MakeAccessor(
Isolate* isolate,
- Handle<String> name,
- AccessorGetterCallback getter,
- AccessorSetterCallback setter,
+ Handle<Name> name,
+ AccessorNameGetterCallback getter,
+ AccessorNameSetterCallback setter,
PropertyAttributes attributes);
static Handle<ExecutableAccessorInfo> CloneAccessor(
=======================================
--- /trunk/src/api.cc Thu Aug 21 00:04:56 2014 UTC
+++ /trunk/src/api.cc Thu Aug 21 07:23:04 2014 UTC
@@ -828,7 +828,7 @@
}
-void Template::Set(v8::Handle<String> name,
+void Template::Set(v8::Handle<Name> name,
v8::Handle<Data> value,
v8::PropertyAttribute attribute) {
i::Isolate* isolate = i::Isolate::Current();
@@ -845,7 +845,7 @@
void Template::SetAccessorProperty(
- v8::Local<v8::String> name,
+ v8::Local<v8::Name> name,
v8::Local<FunctionTemplate> getter,
v8::Local<FunctionTemplate> setter,
v8::PropertyAttribute attribute,
@@ -1156,7 +1156,7 @@
static i::Handle<i::AccessorInfo> SetAccessorInfoProperties(
i::Handle<i::AccessorInfo> obj,
- v8::Handle<String> name,
+ v8::Handle<Name> name,
v8::AccessControl settings,
v8::PropertyAttribute attributes,
v8::Handle<AccessorSignature> signature) {
@@ -1173,7 +1173,7 @@
template<typename Getter, typename Setter>
static i::Handle<i::AccessorInfo> MakeAccessorInfo(
- v8::Handle<String> name,
+ v8::Handle<Name> name,
Getter getter,
Setter setter,
v8::Handle<Value> data,
@@ -1194,7 +1194,7 @@
static i::Handle<i::AccessorInfo> MakeAccessorInfo(
- v8::Handle<String> name,
+ v8::Handle<Name> name,
v8::Handle<v8::DeclaredAccessorDescriptor> descriptor,
void* setter_ignored,
void* data_ignored,
@@ -1345,10 +1345,10 @@
}
-template<typename Setter, typename Getter, typename Data, typename
Template>
+template<typename Getter, typename Setter, typename Data, typename
Template>
static bool TemplateSetAccessor(
Template* template_obj,
- v8::Local<String> name,
+ v8::Local<Name> name,
Getter getter,
Setter setter,
Data data,
@@ -1368,7 +1368,7 @@
bool Template::SetDeclaredAccessor(
- Local<String> name,
+ Local<Name> name,
Local<DeclaredAccessorDescriptor> descriptor,
PropertyAttribute attribute,
Local<AccessorSignature> signature,
@@ -1389,6 +1389,18 @@
TemplateSetAccessor(
this, name, getter, setter, data, settings, attribute, signature);
}
+
+
+void Template::SetNativeDataProperty(v8::Local<Name> name,
+ AccessorNameGetterCallback getter,
+ AccessorNameSetterCallback setter,
+ v8::Handle<Value> data,
+ PropertyAttribute attribute,
+ v8::Local<AccessorSignature>
signature,
+ AccessControl settings) {
+ TemplateSetAccessor(
+ this, name, getter, setter, data, settings, attribute, signature);
+}
void ObjectTemplate::SetAccessor(v8::Handle<String> name,
@@ -1401,6 +1413,18 @@
TemplateSetAccessor(
this, name, getter, setter, data, settings, attribute, signature);
}
+
+
+void ObjectTemplate::SetAccessor(v8::Handle<Name> name,
+ AccessorNameGetterCallback getter,
+ AccessorNameSetterCallback setter,
+ v8::Handle<Value> data,
+ AccessControl settings,
+ PropertyAttribute attribute,
+ v8::Handle<AccessorSignature> signature) {
+ TemplateSetAccessor(
+ this, name, getter, setter, data, settings, attribute, signature);
+}
void ObjectTemplate::SetNamedPropertyHandler(
@@ -2322,6 +2346,11 @@
bool Value::IsFunction() const {
return Utils::OpenHandle(this)->IsJSFunction();
}
+
+
+bool Value::IsName() const {
+ return Utils::OpenHandle(this)->IsName();
+}
bool Value::FullIsString() const {
@@ -2638,6 +2667,14 @@
"v8::Function::Cast()",
"Could not convert to function");
}
+
+
+void v8::Name::CheckCast(v8::Value* that) {
+ i::Handle<i::Object> obj = Utils::OpenHandle(that);
+ Utils::ApiCheck(obj->IsName(),
+ "v8::Name::Cast()",
+ "Could not convert to name");
+}
void v8::String::CheckCast(v8::Value* that) {
@@ -3423,11 +3460,11 @@
}
-template<typename Setter, typename Getter, typename Data>
+template<typename Getter, typename Setter, typename Data>
static inline bool ObjectSetAccessor(Object* obj,
- Handle<String> name,
- Setter getter,
- Getter setter,
+ Handle<Name> name,
+ Getter getter,
+ Setter setter,
Data data,
AccessControl settings,
PropertyAttribute attributes) {
@@ -3462,7 +3499,18 @@
}
-bool Object::SetDeclaredAccessor(Local<String> name,
+bool Object::SetAccessor(Handle<Name> name,
+ AccessorNameGetterCallback getter,
+ AccessorNameSetterCallback setter,
+ v8::Handle<Value> data,
+ AccessControl settings,
+ PropertyAttribute attributes) {
+ return ObjectSetAccessor(
+ this, name, getter, setter, data, settings, attributes);
+}
+
+
+bool Object::SetDeclaredAccessor(Local<Name> name,
Local<DeclaredAccessorDescriptor>
descriptor,
PropertyAttribute attributes,
AccessControl settings) {
@@ -3472,7 +3520,7 @@
}
-void Object::SetAccessorProperty(Local<String> name,
+void Object::SetAccessorProperty(Local<Name> name,
Local<Function> getter,
Handle<Function> setter,
PropertyAttribute attribute,
@@ -3571,7 +3619,8 @@
has_pending_exception = !i::Object::GetProperty(it).ToHandle(&result);
EXCEPTION_BAILOUT_CHECK(it->isolate(), Local<Value>());
- return Utils::ToLocal(result);
+ if (it->IsFound()) return Utils::ToLocal(result);
+ return Local<Value>();
}
@@ -6910,6 +6959,12 @@
internal_isolate->stack_guard()->ClearDebugBreak();
}
+
+bool Debug::CheckDebugBreak(Isolate* isolate) {
+ i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ return internal_isolate->stack_guard()->CheckDebugBreak();
+}
+
void Debug::DebugBreakForCommand(Isolate* isolate, ClientData* data) {
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
@@ -7630,9 +7685,9 @@
void InvokeAccessorGetterCallback(
- v8::Local<v8::String> property,
+ v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Value>& info,
- v8::AccessorGetterCallback getter) {
+ v8::AccessorNameGetterCallback getter) {
// Leaving JavaScript.
Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate());
Address getter_address =
reinterpret_cast<Address>(reinterpret_cast<intptr_t>(
=======================================
--- /trunk/src/api.h Tue Aug 5 00:05:55 2014 UTC
+++ /trunk/src/api.h Thu Aug 21 07:23:04 2014 UTC
@@ -158,6 +158,7 @@
V(Float32Array, JSTypedArray) \
V(Float64Array, JSTypedArray) \
V(DataView, JSDataView) \
+ V(Name, Name) \
V(String, String) \
V(Symbol, Symbol) \
V(Script, JSFunction) \
@@ -189,6 +190,8 @@
v8::internal::Handle<v8::internal::Object> obj);
static inline Local<Function> ToLocal(
v8::internal::Handle<v8::internal::JSFunction> obj);
+ static inline Local<Name> ToLocal(
+ v8::internal::Handle<v8::internal::Name> obj);
static inline Local<String> ToLocal(
v8::internal::Handle<v8::internal::String> obj);
static inline Local<Symbol> ToLocal(
@@ -333,6 +336,7 @@
MAKE_TO_LOCAL(ToLocal, Context, Context)
MAKE_TO_LOCAL(ToLocal, Object, Value)
MAKE_TO_LOCAL(ToLocal, JSFunction, Function)
+MAKE_TO_LOCAL(ToLocal, Name, Name)
MAKE_TO_LOCAL(ToLocal, String, String)
MAKE_TO_LOCAL(ToLocal, Symbol, Symbol)
MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp)
@@ -671,9 +675,9 @@
// Interceptor functions called from generated inline caches to notify
// CPU profiler that external callbacks are invoked.
void InvokeAccessorGetterCallback(
- v8::Local<v8::String> property,
+ v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Value>& info,
- v8::AccessorGetterCallback getter);
+ v8::AccessorNameGetterCallback getter);
void InvokeFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>&
info,
v8::FunctionCallback callback);
=======================================
--- /trunk/src/arguments.h Tue Aug 5 00:05:55 2014 UTC
+++ /trunk/src/arguments.h Thu Aug 21 07:23:04 2014 UTC
@@ -68,13 +68,13 @@
// They are used to generate the Call() functions below
// These aren't included in the list as they have duplicate signatures
// F(NamedPropertyEnumeratorCallback, ...)
-// F(NamedPropertyGetterCallback, ...)
#define FOR_EACH_CALLBACK_TABLE_MAPPING_0(F) \
F(IndexedPropertyEnumeratorCallback, v8::Array) \
#define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F) \
- F(AccessorGetterCallback, v8::Value, v8::Local<v8::String>) \
+ F(NamedPropertyGetterCallback, v8::Value, v8::Local<v8::String>) \
+ F(AccessorNameGetterCallback, v8::Value, v8::Local<v8::Name>) \
F(NamedPropertyQueryCallback, \
v8::Integer, \
v8::Local<v8::String>) \
@@ -102,9 +102,9 @@
v8::Local<v8::Value>) \
#define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \
- F(AccessorSetterCallback, \
+ F(AccessorNameSetterCallback, \
void, \
- v8::Local<v8::String>, \
+ v8::Local<v8::Name>, \
v8::Local<v8::Value>) \
=======================================
--- /trunk/src/arm64/full-codegen-arm64.cc Wed Aug 20 00:06:26 2014 UTC
+++ /trunk/src/arm64/full-codegen-arm64.cc Thu Aug 21 07:23:04 2014 UTC
@@ -2019,16 +2019,14 @@
__ Ubfx(right, right, kSmiShift, 5);
__ Lsl(result, left, right);
break;
- case Token::SHR: {
- Label right_not_zero;
- __ Cbnz(right, &right_not_zero);
- __ Tbnz(left, kXSignBit, &stub_call);
- __ Bind(&right_not_zero);
+ case Token::SHR:
+ // If `left >>> right` >= 0x80000000, the result is not
representable in a
+ // signed 32-bit smi.
__ Ubfx(right, right, kSmiShift, 5);
- __ Lsr(result, left, right);
- __ Bic(result, result, kSmiShiftMask);
+ __ Lsr(x10, left, right);
+ __ Tbnz(x10, kXSignBit, &stub_call);
+ __ Bic(result, x10, kSmiShiftMask);
break;
- }
case Token::ADD:
__ Adds(x10, left, right);
__ B(vs, &stub_call);
=======================================
--- /trunk/src/arm64/lithium-codegen-arm64.cc Thu Aug 21 00:04:56 2014 UTC
+++ /trunk/src/arm64/lithium-codegen-arm64.cc Thu Aug 21 07:23:04 2014 UTC
@@ -4891,13 +4891,12 @@
case Token::SAR: __ Asr(result, left, right); break;
case Token::SHL: __ Lsl(result, left, right); break;
case Token::SHR:
+ __ Lsr(result, left, right);
if (instr->can_deopt()) {
- Label right_not_zero;
- __ Cbnz(right, &right_not_zero);
- DeoptimizeIfNegative(left, instr->environment());
- __ Bind(&right_not_zero);
+ // If `left >>> right` >= 0x80000000, the result is not
representable
+ // in a signed 32-bit smi.
+ DeoptimizeIfNegative(result, instr->environment());
}
- __ Lsr(result, left, right);
break;
default: UNREACHABLE();
}
@@ -4952,15 +4951,14 @@
__ Lsl(result, left, result);
break;
case Token::SHR:
- if (instr->can_deopt()) {
- Label right_not_zero;
- __ Cbnz(right, &right_not_zero);
- DeoptimizeIfNegative(left, instr->environment());
- __ Bind(&right_not_zero);
- }
__ Ubfx(result, right, kSmiShift, 5);
__ Lsr(result, left, result);
__ Bic(result, result, kSmiShiftMask);
+ if (instr->can_deopt()) {
+ // If `left >>> right` >= 0x80000000, the result is not
representable
+ // in a signed 32-bit smi.
+ DeoptimizeIfNegative(result, instr->environment());
+ }
break;
default: UNREACHABLE();
}
=======================================
--- /trunk/src/arm64/simulator-arm64.cc Tue Aug 5 00:05:55 2014 UTC
+++ /trunk/src/arm64/simulator-arm64.cc Thu Aug 21 07:23:04 2014 UTC
@@ -704,7 +704,7 @@
case ExternalReference::PROFILING_GETTER_CALL: {
// void f(Local<String> property, PropertyCallbackInfo& info,
- // AccessorGetterCallback callback)
+ // AccessorNameGetterCallback callback)
TraceSim("Type: PROFILING_GETTER_CALL\n");
SimulatorRuntimeProfilingGetterCall target =
reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(
=======================================
--- /trunk/src/array-iterator.js Tue Jul 15 00:04:47 2014 UTC
+++ /trunk/src/array-iterator.js Thu Aug 21 07:23:04 2014 UTC
@@ -50,7 +50,7 @@
function ArrayIteratorNext() {
var iterator = ToObject(this);
- if (!HAS_PRIVATE(iterator, arrayIteratorObjectSymbol)) {
+ if (!HAS_DEFINED_PRIVATE(iterator, arrayIteratorNextIndexSymbol)) {
throw MakeTypeError('incompatible_method_receiver',
['Array Iterator.prototype.next']);
}
=======================================
--- /trunk/src/assembler.h Thu Aug 7 08:39:21 2014 UTC
+++ /trunk/src/assembler.h Thu Aug 21 07:23:04 2014 UTC
@@ -774,12 +774,12 @@
PROFILING_API_CALL,
// Direct call to accessor getter callback.
- // void f(Local<String> property, PropertyCallbackInfo& info)
+ // void f(Local<Name> property, PropertyCallbackInfo& info)
DIRECT_GETTER_CALL,
// Call to accessor getter callback via InvokeAccessorGetterCallback.
- // void f(Local<String> property, PropertyCallbackInfo& info,
- // AccessorGetterCallback callback)
+ // void f(Local<Name> property, PropertyCallbackInfo& info,
+ // AccessorNameGetterCallback callback)
PROFILING_GETTER_CALL
};
=======================================
--- /trunk/src/base/bits.h Wed Aug 20 00:06:26 2014 UTC
+++ /trunk/src/base/bits.h Thu Aug 21 07:23:04 2014 UTC
@@ -6,6 +6,9 @@
#define V8_BASE_BITS_H_
#include "include/v8stdint.h"
+#if V8_CC_MSVC
+#include <intrin.h>
+#endif
#if V8_OS_WIN32
#include "src/base/win32-headers.h"
#endif
@@ -14,6 +17,61 @@
namespace base {
namespace bits {
+// CountSetBits32(value) returns the number of bits set in |value|.
+inline uint32_t CountSetBits32(uint32_t value) {
+#if V8_HAS_BUILTIN_POPCOUNT
+ return __builtin_popcount(value);
+#else
+ value = ((value >> 1) & 0x55555555) + (value & 0x55555555);
+ value = ((value >> 2) & 0x33333333) + (value & 0x33333333);
+ value = ((value >> 4) & 0x0f0f0f0f) + (value & 0x0f0f0f0f);
+ value = ((value >> 8) & 0x00ff00ff) + (value & 0x00ff00ff);
+ value = ((value >> 16) & 0x0000ffff) + (value & 0x0000ffff);
+ return value;
+#endif
+}
+
+
+// CountLeadingZeros32(value) returns the number of zero bits following
the most
+// significant 1 bit in |value| if |value| is non-zero, otherwise it
returns 32.
+inline uint32_t CountLeadingZeros32(uint32_t value) {
+#if V8_HAS_BUILTIN_CLZ
+ return value ? __builtin_clz(value) : 32;
+#elif V8_CC_MSVC
+ unsigned long result; // NOLINT(runtime/int)
+ if (!_BitScanReverse(&result, value)) return 32;
+ return static_cast<uint32_t>(31 - result);
+#else
+ value = value | (value >> 1);
+ value = value | (value >> 2);
+ value = value | (value >> 4);
+ value = value | (value >> 8);
+ value = value | (value >> 16);
+ return CountSetBits32(~value);
+#endif
+}
+
+
+// CountTrailingZeros32(value) returns the number of zero bits preceding
the
+// least significant 1 bit in |value| if |value| is non-zero, otherwise it
+// returns 32.
+inline uint32_t CountTrailingZeros32(uint32_t value) {
+#if V8_HAS_BUILTIN_CTZ
+ return value ? __builtin_ctz(value) : 32;
+#elif V8_CC_MSVC
+ unsigned long result; // NOLINT(runtime/int)
+ if (!_BitScanForward(&result, value)) return 32;
+ return static_cast<uint32_t>(result);
+#else
+ if (value == 0) return 32;
+ unsigned count = 0;
+ for (value ^= value - 1; value >>= 1; ++count)
+ ;
+ return count;
+#endif
+}
+
+
inline uint32_t RotateRight32(uint32_t value, uint32_t shift) {
if (shift == 0) return value;
return (value >> shift) | (value << (32 - shift));
=======================================
--- /trunk/src/bootstrapper.cc Wed Aug 20 00:06:26 2014 UTC
+++ /trunk/src/bootstrapper.cc Thu Aug 21 07:23:04 2014 UTC
@@ -2204,6 +2204,8 @@
debug_context->set_security_token(native_context->security_token());
Handle<String> debug_string =
factory->InternalizeUtf8String(FLAG_expose_debug_as);
+ uint32_t index;
+ if (debug_string->AsArrayIndex(&index)) return true;
Handle<Object> global_proxy(debug_context->global_proxy(), isolate);
JSObject::AddProperty(global, debug_string, global_proxy, DONT_ENUM);
}
@@ -2445,11 +2447,10 @@
break;
}
case CALLBACKS: {
- LookupResult result(isolate());
- Handle<Name> key(Name::cast(descs->GetKey(i)), isolate());
- to->LookupOwn(key, &result);
+ Handle<Name> key(descs->GetKey(i));
+ LookupIterator it(to, key, LookupIterator::CHECK_PROPERTY);
// If the property is already there we skip it
- if (result.IsFound()) continue;
+ if (it.IsFound() && it.HasProperty()) continue;
HandleScope inner(isolate());
DCHECK(!to->HasFastProperties());
// Add to dictionary.
@@ -2478,10 +2479,9 @@
if (properties->IsKey(raw_key)) {
DCHECK(raw_key->IsName());
// If the property is already there we skip it.
- LookupResult result(isolate());
Handle<Name> key(Name::cast(raw_key));
- to->LookupOwn(key, &result);
- if (result.IsFound()) continue;
+ LookupIterator it(to, key, LookupIterator::CHECK_PROPERTY);
+ if (it.IsFound() && it.HasProperty()) continue;
// Set the property.
Handle<Object> value = Handle<Object>(properties->ValueAt(i),
isolate());
=======================================
--- /trunk/src/compiler/arm/instruction-selector-arm.cc Thu Aug 21 00:04:56
2014 UTC
+++ /trunk/src/compiler/arm/instruction-selector-arm.cc Thu Aug 21 07:23:04
2014 UTC
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "src/base/bits.h"
#include "src/compiler/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
-#include "src/compiler-intrinsics.h"
namespace v8 {
namespace internal {
@@ -423,10 +423,10 @@
}
if (IsSupported(ARMv7) && m.right().HasValue()) {
uint32_t value = m.right().Value();
- uint32_t width = CompilerIntrinsics::CountSetBits(value);
- uint32_t msb = CompilerIntrinsics::CountLeadingZeros(value);
+ uint32_t width = base::bits::CountSetBits32(value);
+ uint32_t msb = base::bits::CountLeadingZeros32(value);
if (width != 0 && msb + width == 32) {
- DCHECK_EQ(0, CompilerIntrinsics::CountTrailingZeros(value));
+ DCHECK_EQ(0, base::bits::CountTrailingZeros32(value));
if (m.left().IsWord32Shr()) {
Int32BinopMatcher mleft(m.left().node());
if (mleft.right().IsInRange(0, 31)) {
@@ -442,8 +442,8 @@
}
// Try to interpret this AND as BFC.
width = 32 - width;
- msb = CompilerIntrinsics::CountLeadingZeros(~value);
- uint32_t lsb = CompilerIntrinsics::CountTrailingZeros(~value);
+ msb = base::bits::CountLeadingZeros32(~value);
+ uint32_t lsb = base::bits::CountTrailingZeros32(~value);
if (msb + width + lsb == 32) {
Emit(kArmBfc, g.DefineSameAsFirst(node),
g.UseRegister(m.left().node()),
g.TempImmediate(lsb), g.TempImmediate(width));
@@ -536,10 +536,10 @@
Int32BinopMatcher mleft(m.left().node());
if (mleft.right().HasValue()) {
uint32_t value = (mleft.right().Value() >> lsb) << lsb;
- uint32_t width = CompilerIntrinsics::CountSetBits(value);
- uint32_t msb = CompilerIntrinsics::CountLeadingZeros(value);
+ uint32_t width = base::bits::CountSetBits32(value);
+ uint32_t msb = base::bits::CountLeadingZeros32(value);
if (msb + width + lsb == 32) {
- DCHECK_EQ(lsb, CompilerIntrinsics::CountTrailingZeros(value));
+ DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value));
Emit(kArmUbfx, g.DefineAsRegister(node),
g.UseRegister(mleft.left().node()), g.TempImmediate(lsb),
g.TempImmediate(width));
=======================================
--- /trunk/src/compiler/arm64/instruction-selector-arm64.cc Wed Aug 20
00:06:26 2014 UTC
+++ /trunk/src/compiler/arm64/instruction-selector-arm64.cc Thu Aug 21
07:23:04 2014 UTC
@@ -57,9 +57,9 @@
// TODO(dcarney): -values can be handled by instruction swapping
return Assembler::IsImmAddSub(value);
case kShift32Imm:
- return 0 <= value && value < 31;
+ return 0 <= value && value < 32;
case kShift64Imm:
- return 0 <= value && value < 63;
+ return 0 <= value && value < 64;
case kLoadStoreImm:
return (0 <= value && value < (1 << 9)) ||
(-(1 << 6) <= value && value < (1 << 6));
=======================================
--- /trunk/src/compiler/change-lowering.cc Thu Aug 21 00:04:56 2014 UTC
+++ /trunk/src/compiler/change-lowering.cc Thu Aug 21 07:23:04 2014 UTC
@@ -27,7 +27,14 @@
case IrOpcode::kChangeTaggedToFloat64:
return ChangeTaggedToFloat64(node->InputAt(0), control);
case IrOpcode::kChangeTaggedToInt32:
+ case IrOpcode::kChangeTaggedToUint32:
+ // ToInt32 and ToUint32 perform exactly the same operation, just the
+ // interpretation of the resulting 32 bit value is different, so we
can
+ // use the same subgraph for both operations.
+ // See ECMA-262 9.5: ToInt32 and ECMA-262 9.6: ToUint32.
return ChangeTaggedToInt32(node->InputAt(0), control);
+ case IrOpcode::kChangeUint32ToTagged:
+ return ChangeUint32ToTagged(node->InputAt(0), control);
default:
return NoChange();
}
@@ -42,6 +49,20 @@
((HeapNumber::kValueOffset / kPointerSize) * (machine()->is64() ?
8 : 4));
return jsgraph()->Int32Constant(heap_number_value_offset -
kHeapObjectTag);
}
+
+
+Node* ChangeLowering::SmiMaxValueConstant() {
+ // TODO(turbofan): Work-around for weird GCC 4.6 linker issue:
+ // src/compiler/change-lowering.cc:46: undefined reference to
+ // `v8::internal::SmiTagging<4u>::kSmiValueSize'
+ // src/compiler/change-lowering.cc:46: undefined reference to
+ // `v8::internal::SmiTagging<8u>::kSmiValueSize'
+ STATIC_ASSERT(SmiTagging<4>::kSmiValueSize == 31);
+ STATIC_ASSERT(SmiTagging<8>::kSmiValueSize == 32);
+ const int smi_value_size = machine()->is64() ? 32 : 31;
+ return jsgraph()->Int32Constant(
+ -(static_cast<int>(0xffffffffu << (smi_value_size - 1)) + 1));
+}
Node* ChangeLowering::SmiShiftBitsConstant() {
@@ -55,6 +76,43 @@
const int smi_shift_size = machine()->is64() ? 31 : 0;
return jsgraph()->Int32Constant(smi_shift_size + kSmiTagSize);
}
+
+
+Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node*
control) {
+ // The AllocateHeapNumber() runtime function does not use the context,
so we
+ // can safely pass in Smi zero here.
+ Node* context = jsgraph()->ZeroConstant();
+ Node* effect = graph()->NewNode(common()->ValueEffect(1), value);
+ const Runtime::Function* function =
+ Runtime::FunctionForId(Runtime::kAllocateHeapNumber);
+ DCHECK_EQ(0, function->nargs);
+ CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
+ function->function_id, 0, Operator::kNoProperties);
+ Node* heap_number = graph()->NewNode(
+ common()->Call(desc), jsgraph()->CEntryStubConstant(),
+ jsgraph()->ExternalConstant(ExternalReference(function, isolate())),
+ jsgraph()->Int32Constant(function->nargs), context, effect, control);
+ Node* store = graph()->NewNode(
+ machine()->Store(kMachFloat64, kNoWriteBarrier), heap_number,
+ HeapNumberValueIndexConstant(), value, heap_number, control);
+ return graph()->NewNode(common()->Finish(1), heap_number, store);
+}
+
+
+Node* ChangeLowering::ChangeSmiToInt32(Node* value) {
+ value = graph()->NewNode(machine()->WordSar(), value,
SmiShiftBitsConstant());
+ if (machine()->is64()) {
+ value = graph()->NewNode(machine()->TruncateInt64ToInt32(), value);
+ }
+ return value;
+}
+
+
+Node* ChangeLowering::LoadHeapNumberValue(Node* value, Node* control) {
+ return graph()->NewNode(machine()->Load(kMachFloat64), value,
+ HeapNumberValueIndexConstant(),
+ graph()->NewNode(common()->ControlEffect(),
control));
+}
Reduction ChangeLowering::ChangeBitToBool(Node* val, Node* control) {
@@ -121,18 +179,11 @@
Node* branch = graph()->NewNode(common()->Branch(), tag, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* load = graph()->NewNode(
- machine()->Load(kMachFloat64), val, HeapNumberValueIndexConstant(),
- graph()->NewNode(common()->ControlEffect(), if_true));
- Node* change = graph()->NewNode(machine()->TruncateFloat64ToInt32(),
load);
+ Node* change = graph()->NewNode(machine()->TruncateFloat64ToInt32(),
+ LoadHeapNumberValue(val, if_true));
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* integer =
- graph()->NewNode(machine()->WordSar(), val, SmiShiftBitsConstant());
- Node* number =
- machine()->is64()
- ? graph()->NewNode(machine()->TruncateInt64ToInt32(), integer)
- : integer;
+ Node* number = ChangeSmiToInt32(val);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
Node* phi = graph()->NewNode(common()->Phi(2), change, number, merge);
@@ -150,21 +201,41 @@
Node* branch = graph()->NewNode(common()->Branch(), tag, control);
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
- Node* load = graph()->NewNode(
- machine()->Load(kMachFloat64), val, HeapNumberValueIndexConstant(),
- graph()->NewNode(common()->ControlEffect(), if_true));
+ Node* load = LoadHeapNumberValue(val, if_true);
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
- Node* integer =
- graph()->NewNode(machine()->WordSar(), val, SmiShiftBitsConstant());
- Node* number = graph()->NewNode(
- machine()->ChangeInt32ToFloat64(),
+ Node* number = graph()->NewNode(machine()->ChangeInt32ToFloat64(),
+ ChangeSmiToInt32(val));
+
+ Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+ Node* phi = graph()->NewNode(common()->Phi(2), load, number, merge);
+
+ return Replace(phi);
+}
+
+
+Reduction ChangeLowering::ChangeUint32ToTagged(Node* val, Node* control) {
+ STATIC_ASSERT(kSmiTag == 0);
+ STATIC_ASSERT(kSmiTagMask == 1);
+
+ Node* cmp = graph()->NewNode(machine()->Uint32LessThanOrEqual(), val,
+ SmiMaxValueConstant());
+ Node* branch = graph()->NewNode(common()->Branch(), cmp, control);
+
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Node* smi = graph()->NewNode(
+ machine()->WordShl(),
machine()->is64()
- ? graph()->NewNode(machine()->TruncateInt64ToInt32(), integer)
- : integer);
+ ? graph()->NewNode(machine()->ChangeUint32ToUint64(), val)
+ : val,
+ SmiShiftBitsConstant());
+
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+ Node* heap_number = AllocateHeapNumberWithValue(
+ graph()->NewNode(machine()->ChangeUint32ToFloat64(), val), if_false);
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
- Node* phi = graph()->NewNode(common()->Phi(2), load, number, merge);
+ Node* phi = graph()->NewNode(common()->Phi(2), smi, heap_number, merge);
return Replace(phi);
}
@@ -179,27 +250,6 @@
CommonOperatorBuilder* ChangeLowering::common() const {
return jsgraph()->common();
}
-
-
-Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node*
control) {
- // The AllocateHeapNumber() runtime function does not use the context,
so we
- // can safely pass in Smi zero here.
- Node* context = jsgraph()->ZeroConstant();
- Node* effect = graph()->NewNode(common()->ValueEffect(1), value);
- const Runtime::Function* function =
- Runtime::FunctionForId(Runtime::kAllocateHeapNumber);
- DCHECK_EQ(0, function->nargs);
- CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
- function->function_id, 0, Operator::kNoProperties);
- Node* heap_number = graph()->NewNode(
- common()->Call(desc), jsgraph()->CEntryStubConstant(),
- jsgraph()->ExternalConstant(ExternalReference(function, isolate())),
- jsgraph()->Int32Constant(function->nargs), context, effect, control);
- Node* store = graph()->NewNode(
- machine()->Store(kMachFloat64, kNoWriteBarrier), heap_number,
- HeapNumberValueIndexConstant(), value, heap_number, control);
- return graph()->NewNode(common()->Finish(1), heap_number, store);
-}
} // namespace compiler
} // namespace internal
=======================================
--- /trunk/src/compiler/change-lowering.h Wed Aug 20 00:06:26 2014 UTC
+++ /trunk/src/compiler/change-lowering.h Thu Aug 21 07:23:04 2014 UTC
@@ -26,16 +26,22 @@
virtual Reduction Reduce(Node* node) V8_OVERRIDE;
- protected:
+ private:
Node* HeapNumberValueIndexConstant();
+ Node* SmiMaxValueConstant();
Node* SmiShiftBitsConstant();
+ Node* AllocateHeapNumberWithValue(Node* value, Node* control);
+ Node* ChangeSmiToInt32(Node* value);
+ Node* LoadHeapNumberValue(Node* value, Node* control);
+
Reduction ChangeBitToBool(Node* val, Node* control);
Reduction ChangeBoolToBit(Node* val);
Reduction ChangeFloat64ToTagged(Node* val, Node* control);
Reduction ChangeInt32ToTagged(Node* val, Node* control);
Reduction ChangeTaggedToFloat64(Node* val, Node* control);
Reduction ChangeTaggedToInt32(Node* val, Node* control);
+ Reduction ChangeUint32ToTagged(Node* val, Node* control);
Graph* graph() const;
Isolate* isolate() const;
@@ -43,9 +49,6 @@
Linkage* linkage() const { return linkage_; }
CommonOperatorBuilder* common() const;
MachineOperatorBuilder* machine() const { return machine_; }
-
- private:
- Node* AllocateHeapNumberWithValue(Node* value, Node* control);
JSGraph* jsgraph_;
Linkage* linkage_;
=======================================
--- /trunk/src/compiler/generic-graph.h Thu Jul 31 18:45:14 2014 UTC
+++ /trunk/src/compiler/generic-graph.h Thu Aug 21 07:23:04 2014 UTC
@@ -22,6 +22,7 @@
NodeId NextNodeID() { return next_node_id_++; }
NodeId NodeCount() const { return next_node_id_; }
+ void SetNextNodeId(NodeId next) { next_node_id_ = next; }
private:
Zone* zone_;
=======================================
--- /trunk/src/compiler/generic-node.h Tue Aug 5 00:05:55 2014 UTC
+++ /trunk/src/compiler/generic-node.h Thu Aug 21 07:23:04 2014 UTC
@@ -204,6 +204,12 @@
++index_;
return *this;
}
+ iterator& UpdateToAndIncrement(GenericNode<B, S>* new_to) {
+ typename GenericNode<B, S>::Input* input = GetInput();
+ input->Update(new_to);
+ index_++;
+ return *this;
+ }
int index() { return index_; }
private:
=======================================
--- /trunk/src/compiler/instruction-selector.cc Thu Aug 21 00:04:56 2014 UTC
+++ /trunk/src/compiler/instruction-selector.cc Thu Aug 21 07:23:04 2014 UTC
@@ -199,12 +199,18 @@
DCHECK(!IsReference(node));
sequence()->MarkAsDouble(node->id());
- // Propagate "doubleness" throughout phis.
+ // Propagate "doubleness" throughout Finish/Phi nodes.
for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) {
Node* user = *i;
- if (user->opcode() != IrOpcode::kPhi) continue;
- if (IsDouble(user)) continue;
- MarkAsDouble(user);
+ switch (user->opcode()) {
+ case IrOpcode::kFinish:
+ case IrOpcode::kPhi:
+ if (IsDouble(user)) continue;
+ MarkAsDouble(user);
+ break;
+ default:
+ break;
+ }
}
}
@@ -220,12 +226,18 @@
DCHECK(!IsDouble(node));
sequence()->MarkAsReference(node->id());
- // Propagate "referenceness" throughout phis.
+ // Propagate "referenceness" throughout Finish/Phi nodes.
for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) {
Node* user = *i;
- if (user->opcode() != IrOpcode::kPhi) continue;
- if (IsReference(user)) continue;
- MarkAsReference(user);
+ switch (user->opcode()) {
+ case IrOpcode::kFinish:
+ case IrOpcode::kPhi:
+ if (IsReference(user)) continue;
+ MarkAsReference(user);
+ break;
+ default:
+ break;
+ }
}
}
@@ -464,13 +476,12 @@
case IrOpcode::kContinuation:
// No code needed for these graph artifacts.
return;
+ case IrOpcode::kFinish:
+ return VisitFinish(node);
case IrOpcode::kParameter: {
- int index = OpParameter<int>(node);
- MachineType rep = linkage()
- ->GetIncomingDescriptor()
- ->GetInputLocation(index)
- .representation();
- MarkAsRepresentation(rep, node);
+ LinkageLocation location =
+ linkage()->GetParameterLocation(OpParameter<int>(node));
+ MarkAsRepresentation(location.representation(), node);
return VisitParameter(node);
}
case IrOpcode::kPhi:
@@ -797,6 +808,13 @@
#endif // V8_TARGET_ARCH_32_BIT || !V8_TURBOFAN_BACKEND
+void InstructionSelector::VisitFinish(Node* node) {
+ OperandGenerator g(this);
+ Node* value = node->InputAt(0);
+ Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
+}
+
+
void InstructionSelector::VisitParameter(Node* node) {
OperandGenerator g(this);
Emit(kArchNop, g.DefineAsLocation(node, linkage()->GetParameterLocation(
=======================================
--- /trunk/src/compiler/instruction-selector.h Tue Aug 12 06:42:13 2014 UTC
+++ /trunk/src/compiler/instruction-selector.h Thu Aug 21 07:23:04 2014 UTC
@@ -169,6 +169,7 @@
void VisitWord64Compare(Node* node, FlagsContinuation* cont);
void VisitFloat64Compare(Node* node, FlagsContinuation* cont);
+ void VisitFinish(Node* node);
void VisitParameter(Node* node);
void VisitPhi(Node* node);
void VisitProjection(Node* node);
=======================================
--- /trunk/src/compiler/js-context-specialization.cc Fri Aug 8 15:46:17
2014 UTC
+++ /trunk/src/compiler/js-context-specialization.cc Thu Aug 21 07:23:04
2014 UTC
@@ -15,26 +15,6 @@
namespace internal {
namespace compiler {
-// TODO(titzer): factor this out to a common routine with
js-typed-lowering.
-static void ReplaceEffectfulWithValue(Node* node, Node* value) {
- Node* effect = NULL;
- if (OperatorProperties::HasEffectInput(node->op())) {
- effect = NodeProperties::GetEffectInput(node);
- }
-
- // Requires distinguishing between value and effect edges.
- UseIter iter = node->uses().begin();
- while (iter != node->uses().end()) {
- if (NodeProperties::IsEffectEdge(iter.edge())) {
- DCHECK_NE(NULL, effect);
- iter = iter.UpdateToAndIncrement(effect);
- } else {
- iter = iter.UpdateToAndIncrement(value);
- }
- }
-}
-
-
class ContextSpecializationVisitor : public NullNodeVisitor {
public:
explicit ContextSpecializationVisitor(JSContextSpecializer* spec)
@@ -45,14 +25,16 @@
case IrOpcode::kJSLoadContext: {
Reduction r = spec_->ReduceJSLoadContext(node);
if (r.Changed() && r.replacement() != node) {
- ReplaceEffectfulWithValue(node, r.replacement());
+ NodeProperties::ReplaceWithValue(node, r.replacement());
+ node->RemoveAllInputs();
}
break;
}
case IrOpcode::kJSStoreContext: {
Reduction r = spec_->ReduceJSStoreContext(node);
if (r.Changed() && r.replacement() != node) {
- ReplaceEffectfulWithValue(node, r.replacement());
+ NodeProperties::ReplaceWithValue(node, r.replacement());
+ node->RemoveAllInputs();
}
break;
}
@@ -68,7 +50,8 @@
void JSContextSpecializer::SpecializeToContext() {
- ReplaceEffectfulWithValue(context_,
jsgraph_->Constant(info_->context()));
+ NodeProperties::ReplaceWithValue(context_,
+ jsgraph_->Constant(info_->context()));
ContextSpecializationVisitor visitor(this);
jsgraph_->graph()->VisitNodeInputsFromEnd(&visitor);
=======================================
--- /trunk/src/compiler/js-typed-lowering.cc Tue Aug 5 00:05:55 2014 UTC
+++ /trunk/src/compiler/js-typed-lowering.cc Thu Aug 21 07:23:04 2014 UTC
@@ -17,39 +17,18 @@
// - relax effects from generic but not-side-effecting operations
// - relax effects for ToNumber(mixed)
-// Replace value uses of {node} with {value} and effect uses of {node} with
-// {effect}. If {effect == NULL}, then use the effect input to {node}.
-// TODO(titzer): move into a GraphEditor?
-static void ReplaceUses(Node* node, Node* value, Node* effect) {
- if (value == effect) {
- // Effect and value updates are the same; no special iteration needed.
- if (value != node) node->ReplaceUses(value);
- return;
- }
-
- if (effect == NULL) effect = NodeProperties::GetEffectInput(node);
-
- // The iteration requires distinguishing between value and effect edges.
- UseIter iter = node->uses().begin();
- while (iter != node->uses().end()) {
- if (NodeProperties::IsEffectEdge(iter.edge())) {
- iter = iter.UpdateToAndIncrement(effect);
- } else {
- iter = iter.UpdateToAndIncrement(value);
- }
- }
-}
-
// Relax the effects of {node} by immediately replacing effect uses of
{node}
// with the effect input to {node}.
// TODO(turbofan): replace the effect input to {node} with
{graph->start()}.
// TODO(titzer): move into a GraphEditor?
-static void RelaxEffects(Node* node) { ReplaceUses(node, node, NULL); }
+static void RelaxEffects(Node* node) {
+ NodeProperties::ReplaceWithValue(node, node, NULL);
+}
Reduction JSTypedLowering::ReplaceEagerly(Node* old, Node* node) {
- ReplaceUses(old, node, node);
+ NodeProperties::ReplaceWithValue(old, node, node);
return Reducer::Changed(node);
}
@@ -522,7 +501,7 @@
static Reduction ReplaceWithReduction(Node* node, Reduction reduction) {
if (reduction.Changed()) {
- ReplaceUses(node, reduction.replacement(), NULL);
+ NodeProperties::ReplaceWithValue(node, reduction.replacement());
return reduction;
}
return Reducer::NoChange();
@@ -573,13 +552,13 @@
// !x => BooleanNot(x)
value =
graph()->NewNode(simplified()->BooleanNot(),
result.replacement());
- ReplaceUses(node, value, NULL);
+ NodeProperties::ReplaceWithValue(node, value);
return Changed(value);
} else {
// !x => BooleanNot(JSToBoolean(x))
value = graph()->NewNode(simplified()->BooleanNot(), node);
node->set_op(javascript()->ToBoolean());
- ReplaceUses(node, value, node);
+ NodeProperties::ReplaceWithValue(node, value, node);
// Note: ReplaceUses() smashes all uses, so smash it back here.
value->ReplaceInput(0, node);
return ReplaceWith(value);
=======================================
--- /trunk/src/compiler/machine-type.cc Wed Aug 20 00:06:26 2014 UTC
+++ /trunk/src/compiler/machine-type.cc Thu Aug 21 07:23:04 2014 UTC
@@ -11,7 +11,7 @@
#define PRINT(bit) \
if (type & bit) { \
- if (before) os << "|"; \
+ if (before) os << "+"; \
os << #bit; \
before = true; \
}
=======================================
--- /trunk/src/compiler/node-properties-inl.h Wed Aug 20 00:06:26 2014 UTC
+++ /trunk/src/compiler/node-properties-inl.h Thu Aug 21 07:23:04 2014 UTC
@@ -146,6 +146,28 @@
inline void NodeProperties::RemoveNonValueInputs(Node* node) {
node->TrimInputCount(OperatorProperties::GetValueInputCount(node->op()));
}
+
+
+// Replace value uses of {node} with {value} and effect uses of {node} with
+// {effect}. If {effect == NULL}, then use the effect input to {node}.
+inline void NodeProperties::ReplaceWithValue(Node* node, Node* value,
+ Node* effect) {
+ DCHECK(!OperatorProperties::HasControlOutput(node->op()));
+ if (effect == NULL && OperatorProperties::HasEffectInput(node->op())) {
+ effect = NodeProperties::GetEffectInput(node);
+ }
+
+ // Requires distinguishing between value and effect edges.
+ UseIter iter = node->uses().begin();
+ while (iter != node->uses().end()) {
+ if (NodeProperties::IsEffectEdge(iter.edge())) {
+ DCHECK_NE(NULL, effect);
+ iter = iter.UpdateToAndIncrement(effect);
+ } else {
+ iter = iter.UpdateToAndIncrement(value);
+ }
+ }
+}
//
-----------------------------------------------------------------------------
=======================================
--- /trunk/src/compiler/node-properties.h Wed Aug 20 00:06:26 2014 UTC
+++ /trunk/src/compiler/node-properties.h Thu Aug 21 07:23:04 2014 UTC
@@ -33,6 +33,8 @@
static inline void ReplaceEffectInput(Node* node, Node* effect,
int index = 0);
static inline void RemoveNonValueInputs(Node* node);
+ static inline void ReplaceWithValue(Node* node, Node* value,
+ Node* effect = NULL);
static inline Bounds GetBounds(Node* node);
static inline void SetBounds(Node* node, Bounds bounds);
=======================================
--- /trunk/src/compiler/pipeline.cc Wed Aug 20 00:06:26 2014 UTC
+++ /trunk/src/compiler/pipeline.cc Thu Aug 21 07:23:04 2014 UTC
@@ -13,6 +13,7 @@
#include "src/compiler/instruction-selector.h"
#include "src/compiler/js-context-specialization.h"
#include "src/compiler/js-generic-lowering.h"
+#include "src/compiler/js-inlining.h"
#include "src/compiler/js-typed-lowering.h"
#include "src/compiler/phi-reducer.h"
#include "src/compiler/register-allocator.h"
@@ -186,13 +187,21 @@
VerifyAndPrintGraph(&graph, "Initial untyped");
if (FLAG_context_specialization) {
- SourcePositionTable::Scope pos_(&source_positions,
- SourcePosition::Unknown());
+ SourcePositionTable::Scope pos(&source_positions,
+ SourcePosition::Unknown());
// Specialize the code to the context as aggressively as possible.
JSContextSpecializer spec(info(), &jsgraph, context_node);
spec.SpecializeToContext();
VerifyAndPrintGraph(&graph, "Context specialized");
}
+
+ if (FLAG_turbo_inlining) {
+ SourcePositionTable::Scope pos(&source_positions,
+ SourcePosition::Unknown());
+ JSInliner inliner(info(), &jsgraph);
+ inliner.Inline();
+ VerifyAndPrintGraph(&graph, "Inlined");
+ }
// Print a replay of the initial graph.
if (FLAG_print_turbo_replay) {
=======================================
--- /trunk/src/compiler/scheduler.cc Wed Aug 20 00:06:26 2014 UTC
+++ /trunk/src/compiler/scheduler.cc Thu Aug 21 07:23:04 2014 UTC
@@ -15,15 +15,198 @@
namespace internal {
namespace compiler {
+static inline void Trace(const char* msg, ...) {
+ if (FLAG_trace_turbo_scheduler) {
+ va_list arguments;
+ va_start(arguments, msg);
+ base::OS::VPrint(msg, arguments);
+ va_end(arguments);
+ }
+}
+
+
+// Internal class to build a control flow graph (i.e the basic blocks and
edges
+// between them within a Schedule) from the node graph.
+// Visits the graph backwards from end, following control and data edges.
+class CFGBuilder : public NullNodeVisitor {
+ public:
+ Schedule* schedule_;
+
+ explicit CFGBuilder(Schedule* schedule) : schedule_(schedule) {}
+
+ // Create the blocks for the schedule in pre-order.
+ void PreEdge(Node* from, int index, Node* node) {
+ switch (node->opcode()) {
+ case IrOpcode::kLoop:
+ case IrOpcode::kMerge:
+ BuildBlockForNode(node);
+ break;
+ case IrOpcode::kBranch:
+ BuildBlocksForSuccessors(node, IrOpcode::kIfTrue,
IrOpcode::kIfFalse);
+ break;
+ case IrOpcode::kCall:
+ if (OperatorProperties::CanLazilyDeoptimize(node->op())) {
+ BuildBlocksForSuccessors(node, IrOpcode::kContinuation,
+ IrOpcode::kLazyDeoptimization);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Connect the blocks after nodes have been visited in post-order.
+ GenericGraphVisit::Control Post(Node* node) {
+ switch (node->opcode()) {
+ case IrOpcode::kLoop:
+ case IrOpcode::kMerge:
+ ConnectMerge(node);
+ break;
+ case IrOpcode::kBranch:
+ ConnectBranch(node);
+ break;
+ case IrOpcode::kDeoptimize:
+ ConnectDeoptimize(node);
+ case IrOpcode::kCall:
+ if (OperatorProperties::CanLazilyDeoptimize(node->op())) {
+ ConnectCall(node);
+ }
+ break;
+ case IrOpcode::kReturn:
+ ConnectReturn(node);
+ break;
+ default:
+ break;
+ }
+ return GenericGraphVisit::CONTINUE;
+ }
+
+ void BuildBlockForNode(Node* node) {
+ if (schedule_->block(node) == NULL) {
+ BasicBlock* block = schedule_->NewBasicBlock();
+ Trace("Create block B%d for node %d (%s)\n", block->id(), node->id(),
+ IrOpcode::Mnemonic(node->opcode()));
+ schedule_->AddNode(block, node);
+ }
+ }
+
+ void BuildBlocksForSuccessors(Node* node, IrOpcode::Value a,
+ IrOpcode::Value b) {
+ Node* successors[2];
+ CollectSuccessorProjections(node, successors, a, b);
+ BuildBlockForNode(successors[0]);
+ BuildBlockForNode(successors[1]);
+ }
+
+ // Collect the branch-related projections from a node, such as IfTrue,
+ // IfFalse, Continuation, and LazyDeoptimization.
+ // TODO(titzer): consider moving this to node.h
+ void CollectSuccessorProjections(Node* node, Node** buffer,
+ IrOpcode::Value true_opcode,
+ IrOpcode::Value false_opcode) {
+ buffer[0] = NULL;
+ buffer[1] = NULL;
+ for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) {
+ if ((*i)->opcode() == true_opcode) {
+ DCHECK_EQ(NULL, buffer[0]);
+ buffer[0] = *i;
+ }
+ if ((*i)->opcode() == false_opcode) {
+ DCHECK_EQ(NULL, buffer[1]);
+ buffer[1] = *i;
+ }
+ }
+ DCHECK_NE(NULL, buffer[0]);
+ DCHECK_NE(NULL, buffer[1]);
+ }
+
+ void CollectSuccessorBlocks(Node* node, BasicBlock** buffer,
+ IrOpcode::Value true_opcode,
+ IrOpcode::Value false_opcode) {
+ Node* successors[2];
+ CollectSuccessorProjections(node, successors, true_opcode,
false_opcode);
+ buffer[0] = schedule_->block(successors[0]);
+ buffer[1] = schedule_->block(successors[1]);
+ }
+
+ void ConnectBranch(Node* branch) {
+ Node* branch_block_node = NodeProperties::GetControlInput(branch);
+ BasicBlock* branch_block = schedule_->block(branch_block_node);
+ DCHECK(branch_block != NULL);
+
+ BasicBlock* successor_blocks[2];
+ CollectSuccessorBlocks(branch, successor_blocks, IrOpcode::kIfTrue,
+ IrOpcode::kIfFalse);
+
+ TraceConnect(branch, branch_block, successor_blocks[0]);
+ TraceConnect(branch, branch_block, successor_blocks[1]);
+
+ schedule_->AddBranch(branch_block, branch, successor_blocks[0],
+ successor_blocks[1]);
+ }
+
+ void ConnectMerge(Node* merge) {
+ BasicBlock* block = schedule_->block(merge);
+ DCHECK(block != NULL);
+ // For all of the merge's control inputs, add a goto at the end to the
+ // merge's basic block.
+ for (InputIter j = merge->inputs().begin(); j != merge->inputs().end();
+ ++j) {
+ BasicBlock* predecessor_block = schedule_->block(*j);
+ if ((*j)->opcode() != IrOpcode::kReturn &&
+ (*j)->opcode() != IrOpcode::kDeoptimize) {
+ TraceConnect(merge, predecessor_block, block);
+ schedule_->AddGoto(predecessor_block, block);
+ }
+ }
+ }
+
+ void ConnectDeoptimize(Node* deopt) {
+ Node* deopt_block_node = NodeProperties::GetControlInput(deopt);
+ BasicBlock* deopt_block = schedule_->block(deopt_block_node);
+ TraceConnect(deopt, deopt_block, NULL);
+ schedule_->AddDeoptimize(deopt_block, deopt);
+ }
+
+ void ConnectReturn(Node* ret) {
+ Node* return_block_node = NodeProperties::GetControlInput(ret);
+ BasicBlock* return_block = schedule_->block(return_block_node);
+ TraceConnect(ret, return_block, NULL);
+ schedule_->AddReturn(return_block, ret);
+ }
+
+ void ConnectCall(Node* call) {
+ Node* call_block_node = NodeProperties::GetControlInput(call);
+ BasicBlock* call_block = schedule_->block(call_block_node);
+
+ BasicBlock* successor_blocks[2];
+ CollectSuccessorBlocks(call, successor_blocks, IrOpcode::kContinuation,
+ IrOpcode::kLazyDeoptimization);
+
+ TraceConnect(call, call_block, successor_blocks[0]);
+ TraceConnect(call, call_block, successor_blocks[1]);
+
+ schedule_->AddCall(call_block, call, successor_blocks[0],
+ successor_blocks[1]);
+ }
+
+ void TraceConnect(Node* node, BasicBlock* block, BasicBlock* succ) {
+ DCHECK_NE(NULL, block);
+ if (succ == NULL) {
+ Trace("node %d (%s) in block %d -> end\n", node->id(),
+ IrOpcode::Mnemonic(node->opcode()), block->id());
+ } else {
+ Trace("node %d (%s) in block %d -> block %d\n", node->id(),
+ IrOpcode::Mnemonic(node->opcode()), block->id(), succ->id());
+ }
+ }
+};
+
+
Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule)
: zone_(zone),
graph_(graph),
schedule_(schedule),
- branches_(NodeVector::allocator_type(zone)),
- calls_(NodeVector::allocator_type(zone)),
- deopts_(NodeVector::allocator_type(zone)),
- returns_(NodeVector::allocator_type(zone)),
- loops_and_merges_(NodeVector::allocator_type(zone)),
unscheduled_uses_(IntVector::allocator_type(zone)),
scheduled_nodes_(NodeVectorVector::allocator_type(zone)),
schedule_root_nodes_(NodeVector::allocator_type(zone)),
@@ -33,13 +216,13 @@
Schedule* Scheduler::ComputeSchedule(Graph* graph) {
Zone tmp_zone(graph->zone()->isolate());
Schedule* schedule = new (graph->zone()) Schedule(graph->zone());
+
+ Scheduler::ComputeCFG(graph, schedule);
+
Scheduler scheduler(&tmp_zone, graph, schedule);
- schedule->AddNode(schedule->end(), graph->end());
-
scheduler.PrepareAuxiliaryNodeData();
- scheduler.CreateBlocks();
- scheduler.WireBlocks();
+
scheduler.PrepareAuxiliaryBlockData();
Scheduler::ComputeSpecialRPO(schedule);
@@ -56,9 +239,6 @@
bool Scheduler::IsBasicBlockBegin(Node* node) {
return OperatorProperties::IsBasicBlockBegin(node->op());
}
-
-
-bool Scheduler::CanBeScheduled(Node* node) { return true; }
bool Scheduler::HasFixedSchedulePosition(Node* node) {
@@ -76,77 +256,12 @@
}
-class CreateBlockVisitor : public NullNodeVisitor {
- public:
- explicit CreateBlockVisitor(Scheduler* scheduler) :
scheduler_(scheduler) {}
-
- GenericGraphVisit::Control Post(Node* node) {
- Schedule* schedule = scheduler_->schedule_;
- switch (node->opcode()) {
- case IrOpcode::kIfTrue:
- case IrOpcode::kIfFalse:
- case IrOpcode::kContinuation:
- case IrOpcode::kLazyDeoptimization: {
- BasicBlock* block = schedule->NewBasicBlock();
- schedule->AddNode(block, node);
- break;
- }
- case IrOpcode::kLoop:
- case IrOpcode::kMerge: {
- BasicBlock* block = schedule->NewBasicBlock();
- schedule->AddNode(block, node);
- scheduler_->loops_and_merges_.push_back(node);
- break;
- }
- case IrOpcode::kBranch: {
- scheduler_->branches_.push_back(node);
- break;
- }
- case IrOpcode::kDeoptimize: {
- scheduler_->deopts_.push_back(node);
- break;
- }
- case IrOpcode::kCall: {
- if (OperatorProperties::CanLazilyDeoptimize(node->op())) {
- scheduler_->calls_.push_back(node);
- }
- break;
- }
- case IrOpcode::kReturn:
- scheduler_->returns_.push_back(node);
- break;
- default:
- break;
- }
-
- return GenericGraphVisit::CONTINUE;
- }
-
- private:
- Scheduler* scheduler_;
-};
-
-
-void Scheduler::CreateBlocks() {
- CreateBlockVisitor create_blocks(this);
- if (FLAG_trace_turbo_scheduler) {
- PrintF("---------------- CREATING BLOCKS ------------------\n");
- }
- schedule_->AddNode(schedule_->start(), graph_->start());
- graph_->VisitNodeInputsFromEnd(&create_blocks);
-}
-
-
-void Scheduler::WireBlocks() {
- if (FLAG_trace_turbo_scheduler) {
- PrintF("----------------- WIRING BLOCKS -------------------\n");
- }
- AddSuccessorsForBranches();
- AddSuccessorsForReturns();
- AddSuccessorsForCalls();
- AddSuccessorsForDeopts();
- AddPredecessorsForLoopsAndMerges();
- // TODO(danno): Handle Throw, et al.
+void Scheduler::ComputeCFG(Graph* graph, Schedule* schedule) {
+ CFGBuilder cfg_builder(schedule);
+ Trace("---------------- CREATING CFG ------------------\n");
+ schedule->AddNode(schedule->start(), graph->start());
+ graph->VisitNodeInputsFromEnd(&cfg_builder);
+ schedule->AddNode(schedule->end(), graph->end());
}
@@ -162,151 +277,6 @@
NodeVector(NodeVector::allocator_type(zone)));
schedule_->immediate_dominator_.resize(schedule_->BasicBlockCount(),
NULL);
}
-
-
-void Scheduler::AddPredecessorsForLoopsAndMerges() {
- for (NodeVectorIter i = loops_and_merges_.begin();
- i != loops_and_merges_.end(); ++i) {
- Node* merge_or_loop = *i;
- BasicBlock* block = schedule_->block(merge_or_loop);
- DCHECK(block != NULL);
- // For all of the merge's control inputs, add a goto at the end to the
- // merge's basic block.
- for (InputIter j = (*i)->inputs().begin(); j != (*i)->inputs().end();
++j) {
- if (IsBasicBlockBegin((*i))) {
- BasicBlock* predecessor_block = schedule_->block(*j);
- if ((*j)->opcode() != IrOpcode::kReturn &&
- (*j)->opcode() != IrOpcode::kDeoptimize) {
- DCHECK(predecessor_block != NULL);
- if (FLAG_trace_turbo_scheduler) {
- IrOpcode::Value opcode = (*i)->opcode();
- PrintF("node %d (%s) in block %d -> block %d\n", (*i)->id(),
- IrOpcode::Mnemonic(opcode), predecessor_block->id(),
- block->id());
- }
- schedule_->AddGoto(predecessor_block, block);
- }
- }
- }
- }
-}
-
-
-void Scheduler::AddSuccessorsForCalls() {
- for (NodeVectorIter i = calls_.begin(); i != calls_.end(); ++i) {
- Node* call = *i;
- DCHECK(call->opcode() == IrOpcode::kCall);
- DCHECK(OperatorProperties::CanLazilyDeoptimize(call->op()));
-
- Node* lazy_deopt_node = NULL;
- Node* cont_node = NULL;
- // Find the continuation and lazy-deopt nodes among the uses.
- for (UseIter use_iter = call->uses().begin();
- use_iter != call->uses().end(); ++use_iter) {
- switch ((*use_iter)->opcode()) {
- case IrOpcode::kContinuation: {
- DCHECK(cont_node == NULL);
- cont_node = *use_iter;
- break;
- }
- case IrOpcode::kLazyDeoptimization: {
- DCHECK(lazy_deopt_node == NULL);
- lazy_deopt_node = *use_iter;
- break;
- }
- default:
- break;
- }
- }
- DCHECK(lazy_deopt_node != NULL);
- DCHECK(cont_node != NULL);
- BasicBlock* cont_successor_block = schedule_->block(cont_node);
- BasicBlock* deopt_successor_block = schedule_->block(lazy_deopt_node);
- Node* call_block_node = NodeProperties::GetControlInput(call);
- BasicBlock* call_block = schedule_->block(call_block_node);
- if (FLAG_trace_turbo_scheduler) {
- IrOpcode::Value opcode = call->opcode();
- PrintF("node %d (%s) in block %d -> block %d\n", call->id(),
- IrOpcode::Mnemonic(opcode), call_block->id(),
- cont_successor_block->id());
- PrintF("node %d (%s) in block %d -> block %d\n", call->id(),
- IrOpcode::Mnemonic(opcode), call_block->id(),
- deopt_successor_block->id());
- }
- schedule_->AddCall(call_block, call, cont_successor_block,
- deopt_successor_block);
- }
-}
-
-
-void Scheduler::AddSuccessorsForDeopts() {
- for (NodeVectorIter i = deopts_.begin(); i != deopts_.end(); ++i) {
- Node* deopt_block_node = NodeProperties::GetControlInput(*i);
- BasicBlock* deopt_block = schedule_->block(deopt_block_node);
- DCHECK(deopt_block != NULL);
- if (FLAG_trace_turbo_scheduler) {
- IrOpcode::Value opcode = (*i)->opcode();
- PrintF("node %d (%s) in block %d -> end\n", (*i)->id(),
- IrOpcode::Mnemonic(opcode), deopt_block->id());
- }
- schedule_->AddDeoptimize(deopt_block, *i);
- }
-}
-
-
-void Scheduler::AddSuccessorsForBranches() {
- for (NodeVectorIter i = branches_.begin(); i != branches_.end(); ++i) {
- Node* branch = *i;
- DCHECK(branch->opcode() == IrOpcode::kBranch);
- Node* branch_block_node = NodeProperties::GetControlInput(branch);
- BasicBlock* branch_block = schedule_->block(branch_block_node);
- DCHECK(branch_block != NULL);
- UseIter use_iter = branch->uses().begin();
- Node* first_successor = *use_iter;
- ++use_iter;
- DCHECK(use_iter != branch->uses().end());
- Node* second_successor = *use_iter;
- DCHECK(++use_iter == branch->uses().end());
- Node* true_successor_node = first_successor->opcode() ==
IrOpcode::kIfTrue
- ? first_successor
- : second_successor;
- Node* false_successor_node = first_successor->opcode() ==
IrOpcode::kIfTrue
- ? second_successor
- : first_successor;
- DCHECK(true_successor_node->opcode() == IrOpcode::kIfTrue);
- DCHECK(false_successor_node->opcode() == IrOpcode::kIfFalse);
- BasicBlock* true_successor_block =
schedule_->block(true_successor_node);
- BasicBlock* false_successor_block =
schedule_->block(false_successor_node);
- DCHECK(true_successor_block != NULL);
- DCHECK(false_successor_block != NULL);
- if (FLAG_trace_turbo_scheduler) {
- IrOpcode::Value opcode = branch->opcode();
- PrintF("node %d (%s) in block %d -> block %d\n", branch->id(),
- IrOpcode::Mnemonic(opcode), branch_block->id(),
- true_successor_block->id());
- PrintF("node %d (%s) in block %d -> block %d\n", branch->id(),
- IrOpcode::Mnemonic(opcode), branch_block->id(),
- false_successor_block->id());
- }
- schedule_->AddBranch(branch_block, branch, true_successor_block,
- false_successor_block);
- }
-}
-
-
-void Scheduler::AddSuccessorsForReturns() {
- for (NodeVectorIter i = returns_.begin(); i != returns_.end(); ++i) {
- Node* return_block_node = NodeProperties::GetControlInput(*i);
- BasicBlock* return_block = schedule_->block(return_block_node);
- DCHECK(return_block != NULL);
- if (FLAG_trace_turbo_scheduler) {
- IrOpcode::Value opcode = (*i)->opcode();
- PrintF("node %d (%s) in block %d -> end\n", (*i)->id(),
- IrOpcode::Mnemonic(opcode), return_block->id());
- }
- schedule_->AddReturn(return_block, *i);
- }
-}
BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
@@ -327,9 +297,7 @@
void Scheduler::GenerateImmediateDominatorTree() {
// Build the dominator graph. TODO(danno): consider using Lengauer &
Tarjan's
// if this becomes really slow.
- if (FLAG_trace_turbo_scheduler) {
- PrintF("------------ IMMEDIATE BLOCK DOMINATORS -----------\n");
- }
+ Trace("------------ IMMEDIATE BLOCK DOMINATORS -----------\n");
for (size_t i = 0; i < schedule_->rpo_order_.size(); i++) {
BasicBlock* current_rpo = schedule_->rpo_order_[i];
if (current_rpo != schedule_->start()) {
@@ -352,9 +320,7 @@
++current_pred;
}
schedule_->immediate_dominator_[current_rpo->id()] = dominator;
- if (FLAG_trace_turbo_scheduler) {
- PrintF("Block %d's idom is %d\n", current_rpo->id(),
dominator->id());
- }
+ Trace("Block %d's idom is %d\n", current_rpo->id(), dominator->id());
}
}
}
@@ -371,7 +337,7 @@
int id = node->id();
int max_rpo = 0;
// Fixed nodes already know their schedule early position.
- if (IsFixedNode(node)) {
+ if (scheduler_->HasFixedSchedulePosition(node)) {
BasicBlock* block = schedule_->block(node);
DCHECK(block != NULL);
max_rpo = block->rpo_number_;
@@ -379,9 +345,7 @@
has_changed_rpo_constraints_ = true;
}
scheduler_->schedule_early_rpo_index_[id] = max_rpo;
- if (FLAG_trace_turbo_scheduler) {
- PrintF("Node %d pre-scheduled early at rpo limit %d\n", id,
max_rpo);
- }
+ Trace("Node %d pre-scheduled early at rpo limit %d\n", id, max_rpo);
}
return GenericGraphVisit::CONTINUE;
}
@@ -390,8 +354,7 @@
int id = node->id();
int max_rpo = 0;
// Otherwise, the minimum rpo for the node is the max of all of the
inputs.
- if (!IsFixedNode(node)) {
- DCHECK(!scheduler_->IsBasicBlockBegin(node));
+ if (!scheduler_->HasFixedSchedulePosition(node)) {
for (InputIter i = node->inputs().begin(); i != node->inputs().end();
++i) {
int control_rpo =
scheduler_->schedule_early_rpo_index_[(*i)->id()];
@@ -403,17 +366,10 @@
has_changed_rpo_constraints_ = true;
}
scheduler_->schedule_early_rpo_index_[id] = max_rpo;
- if (FLAG_trace_turbo_scheduler) {
- PrintF("Node %d post-scheduled early at rpo limit %d\n", id,
max_rpo);
- }
+ Trace("Node %d post-scheduled early at rpo limit %d\n", id, max_rpo);
}
return GenericGraphVisit::CONTINUE;
}
-
- bool IsFixedNode(Node* node) {
- return scheduler_->HasFixedSchedulePosition(node) ||
- !scheduler_->CanBeScheduled(node);
- }
// TODO(mstarzinger): Dirty hack to unblock others, schedule early
should be
// rewritten to use a pre-order traversal from the start instead.
@@ -426,9 +382,7 @@
void Scheduler::ScheduleEarly() {
- if (FLAG_trace_turbo_scheduler) {
- PrintF("------------------- SCHEDULE EARLY ----------------\n");
- }
+ Trace("------------------- SCHEDULE EARLY ----------------\n");
int fixpoint_count = 0;
ScheduleEarlyNodeVisitor visitor(this);
@@ -438,9 +392,7 @@
fixpoint_count++;
}
- if (FLAG_trace_turbo_scheduler) {
- PrintF("It took %d iterations to determine fixpoint\n",
fixpoint_count);
- }
+ Trace("It took %d iterations to determine fixpoint\n", fixpoint_count);
}
@@ -455,10 +407,8 @@
// to schedule them.
if (!schedule_->IsScheduled(node) &&
scheduler_->HasFixedSchedulePosition(node)) {
- if (FLAG_trace_turbo_scheduler) {
- PrintF("Fixed position node %d is unscheduled, scheduling now\n",
- node->id());
- }
+ Trace("Fixed position node %d is unscheduled, scheduling now\n",
+ node->id());
IrOpcode::Value opcode = node->opcode();
BasicBlock* block =
opcode == IrOpcode::kParameter
@@ -479,13 +429,11 @@
// If the edge is from an unscheduled node, then tally it in the use
count
// for all of its inputs. The same criterion will be used in
ScheduleLate
// for decrementing use counts.
- if (!schedule_->IsScheduled(from) && scheduler_->CanBeScheduled(from))
{
+ if (!schedule_->IsScheduled(from)) {
DCHECK(!scheduler_->HasFixedSchedulePosition(from));
++scheduler_->unscheduled_uses_[to->id()];
- if (FLAG_trace_turbo_scheduler) {
- PrintF("Incrementing uses of node %d from %d to %d\n", to->id(),
- from->id(), scheduler_->unscheduled_uses_[to->id()]);
- }
+ Trace("Incrementing uses of node %d from %d to %d\n", to->id(),
+ from->id(), scheduler_->unscheduled_uses_[to->id()]);
}
}
@@ -496,9 +444,7 @@
void Scheduler::PrepareUses() {
- if (FLAG_trace_turbo_scheduler) {
- PrintF("------------------- PREPARE USES ------------------\n");
- }
+ Trace("------------------- PREPARE USES ------------------\n");
// Count the uses of every node, it will be used to ensure that all of a
// node's uses are scheduled before the node itself.
PrepareUsesVisitor prepare_uses(this);
@@ -512,8 +458,8 @@
: scheduler_(scheduler), schedule_(scheduler_->schedule_) {}
GenericGraphVisit::Control Pre(Node* node) {
- // Don't schedule nodes that cannot be scheduled or are already
scheduled.
- if (!scheduler_->CanBeScheduled(node) || schedule_->IsScheduled(node))
{
+ // Don't schedule nodes that are already scheduled.
+ if (schedule_->IsScheduled(node)) {
return GenericGraphVisit::CONTINUE;
}
DCHECK(!scheduler_->HasFixedSchedulePosition(node));
@@ -521,10 +467,8 @@
// If all the uses of a node have been scheduled, then the node itself
can
// be scheduled.
bool eligible = scheduler_->unscheduled_uses_[node->id()] == 0;
- if (FLAG_trace_turbo_scheduler) {
- PrintF("Testing for schedule eligibility for node %d -> %s\n",
node->id(),
- eligible ? "true" : "false");
- }
+ Trace("Testing for schedule eligibility for node %d -> %s\n",
node->id(),
+ eligible ? "true" : "false");
if (!eligible) return GenericGraphVisit::DEFER;
// Determine the dominating block for all of the uses of this node. It
is
@@ -541,12 +485,10 @@
DCHECK(block != NULL);
int min_rpo = scheduler_->schedule_early_rpo_index_[node->id()];
- if (FLAG_trace_turbo_scheduler) {
- PrintF(
- "Schedule late conservative for node %d is block %d at "
- "loop depth %d, min rpo = %d\n",
- node->id(), block->id(), block->loop_depth_, min_rpo);
- }
+ Trace(
+ "Schedule late conservative for node %d is block %d at "
+ "loop depth %d, min rpo = %d\n",
+ node->id(), block->id(), block->loop_depth_, min_rpo);
// Hoist nodes out of loops if possible. Nodes can be hoisted
iteratively
// into enlcosing loop pre-headers until they would preceed their
// ScheduleEarly position.
@@ -554,9 +496,7 @@
while (hoist_block != NULL && hoist_block->rpo_number_ >= min_rpo) {
if (hoist_block->loop_depth_ < block->loop_depth_) {
block = hoist_block;
- if (FLAG_trace_turbo_scheduler) {
- PrintF("Hoisting node %d to block %d\n", node->id(),
block->id());
- }
+ Trace("Hoisting node %d to block %d\n", node->id(), block->id());
}
// Try to hoist to the pre-header of the loop header.
hoist_block = hoist_block->loop_header();
@@ -564,12 +504,10 @@
BasicBlock* pre_header = schedule_->dominator(hoist_block);
DCHECK(pre_header == NULL ||
*hoist_block->predecessors().begin() == pre_header);
- if (FLAG_trace_turbo_scheduler) {
- PrintF(
- "Try hoist to pre-header block %d of loop header block %d,"
- " depth would be %d\n",
- pre_header->id(), hoist_block->id(),
pre_header->loop_depth_);
- }
+ Trace(
+ "Try hoist to pre-header block %d of loop header block %d,"
+ " depth would be %d\n",
+ pre_header->id(), hoist_block->id(), pre_header->loop_depth_);
hoist_block = pre_header;
}
}
@@ -587,9 +525,7 @@
// corresponding to the phi's input.
if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) {
int index = edge.index();
- if (FLAG_trace_turbo_scheduler) {
- PrintF("Use %d is input %d to a phi\n", use->id(), index);
- }
+ Trace("Use %d is input %d to a phi\n", use->id(), index);
use = NodeProperties::GetControlInput(use, 0);
opcode = use->opcode();
DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop);
@@ -597,9 +533,7 @@
}
BasicBlock* result = schedule_->block(use);
if (result == NULL) return NULL;
- if (FLAG_trace_turbo_scheduler) {
- PrintF("Must dominate use %d in block %d\n", use->id(),
result->id());
- }
+ Trace("Must dominate use %d in block %d\n", use->id(), result->id());
return result;
}
@@ -613,11 +547,11 @@
DCHECK(scheduler_->unscheduled_uses_[(*i)->id()] > 0);
--scheduler_->unscheduled_uses_[(*i)->id()];
if (FLAG_trace_turbo_scheduler) {
- PrintF("Decrementing use count for node %d from node %d
(now %d)\n",
- (*i)->id(), i.edge().from()->id(),
- scheduler_->unscheduled_uses_[(*i)->id()]);
+ Trace("Decrementing use count for node %d from node %d (now %d)\n",
+ (*i)->id(), i.edge().from()->id(),
+ scheduler_->unscheduled_uses_[(*i)->id()]);
if (scheduler_->unscheduled_uses_[(*i)->id()] == 0) {
- PrintF("node %d is now eligible for scheduling\n", (*i)->id());
+ Trace("node %d is now eligible for scheduling\n", (*i)->id());
}
}
}
@@ -629,9 +563,7 @@
void Scheduler::ScheduleLate() {
- if (FLAG_trace_turbo_scheduler) {
- PrintF("------------------- SCHEDULE LATE -----------------\n");
- }
+ Trace("------------------- SCHEDULE LATE -----------------\n");
// Schedule: Places nodes in dominator block of all their uses.
ScheduleLateNodeVisitor schedule_late_visitor(this);
@@ -865,9 +797,7 @@
BasicBlockVector* Scheduler::ComputeSpecialRPO(Schedule* schedule) {
Zone tmp_zone(schedule->zone()->isolate());
Zone* zone = &tmp_zone;
- if (FLAG_trace_turbo_scheduler) {
- PrintF("------------- COMPUTING SPECIAL RPO ---------------\n");
- }
+ Trace("------------- COMPUTING SPECIAL RPO ---------------\n");
// RPO should not have been computed for this schedule yet.
CHECK_EQ(kBlockUnvisited1, schedule->start()->rpo_number_);
CHECK_EQ(0, static_cast<int>(schedule->rpo_order_.size()));
@@ -1027,10 +957,8 @@
current->loop_end_ = end == NULL ?
static_cast<int>(final_order->size())
: end->block->rpo_number_;
current_header = current_loop->header;
- if (FLAG_trace_turbo_scheduler) {
- PrintF("Block %d is a loop header, increment loop depth to %d\n",
- current->id(), loop_depth);
- }
+ Trace("Block %d is a loop header, increment loop depth to %d\n",
+ current->id(), loop_depth);
} else {
while (current_header != NULL &&
current->rpo_number_ >= current_header->loop_end_) {
@@ -1042,16 +970,9 @@
}
}
current->loop_depth_ = loop_depth;
- if (FLAG_trace_turbo_scheduler) {
- if (current->loop_header_ == NULL) {
- PrintF("Block %d's loop header is NULL, loop depth %d\n",
current->id(),
- current->loop_depth_);
- } else {
- PrintF("Block %d's loop header is block %d, loop depth %d\n",
- current->id(), current->loop_header_->id(),
- current->loop_depth_);
- }
- }
+ Trace("Block %d's loop header is block %d, loop depth %d\n",
current->id(),
+ current->loop_header_ == NULL ? -1 : current->loop_header_->id(),
+ current->loop_depth_);
}
#if DEBUG
=======================================
--- /trunk/src/compiler/scheduler.h Wed Aug 20 00:06:26 2014 UTC
+++ /trunk/src/compiler/scheduler.h Thu Aug 21 07:23:04 2014 UTC
@@ -22,21 +22,21 @@
// ordering the basic blocks in the special RPO order.
class Scheduler {
public:
- // Create a new schedule and place all computations from the graph in it.
+ // The complete scheduling algorithm.
+ // Create a new schedule and place all nodes from the graph into it.
static Schedule* ComputeSchedule(Graph* graph);
// Compute the RPO of blocks in an existing schedule.
static BasicBlockVector* ComputeSpecialRPO(Schedule* schedule);
+ // (Exposed for testing only)
+ // Build and connect the CFG for a node graph, but don't schedule nodes.
+ static void ComputeCFG(Graph* graph, Schedule* schedule);
+
private:
Zone* zone_;
Graph* graph_;
Schedule* schedule_;
- NodeVector branches_;
- NodeVector calls_;
- NodeVector deopts_;
- NodeVector returns_;
- NodeVector loops_and_merges_;
IntVector unscheduled_uses_;
NodeVectorVector scheduled_nodes_;
NodeVector schedule_root_nodes_;
@@ -45,7 +45,6 @@
Scheduler(Zone* zone, Graph* graph, Schedule* schedule);
bool IsBasicBlockBegin(Node* node);
- bool CanBeScheduled(Node* node);
bool HasFixedSchedulePosition(Node* node);
bool IsScheduleRoot(Node* node);
@@ -59,17 +58,6 @@
void PrepareAuxiliaryNodeData();
void PrepareAuxiliaryBlockData();
- friend class CreateBlockVisitor;
- void CreateBlocks();
-
- void WireBlocks();
-
- void AddPredecessorsForLoopsAndMerges();
- void AddSuccessorsForBranches();
- void AddSuccessorsForReturns();
- void AddSuccessorsForCalls();
- void AddSuccessorsForDeopts();
-
void GenerateImmediateDominatorTree();
BasicBlock* GetCommonDominator(BasicBlock* b1, BasicBlock* b2);
=======================================
--- /trunk/src/data-flow.cc Wed Jun 4 00:06:13 2014 UTC
+++ /trunk/src/data-flow.cc Thu Aug 21 07:23:04 2014 UTC
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "src/v8.h"
+#include "src/data-flow.h"
-#include "src/data-flow.h"
+#include "src/base/bits.h"
#include "src/scopes.h"
namespace v8 {
@@ -40,4 +40,15 @@
current_value_ = val >> 1;
}
-} } // namespace v8::internal
+
+int BitVector::Count() const {
+ int count = 0;
+ for (int i = 0; i < data_length_; i++) {
+ int data = data_[i];
+ if (data != 0) count += base::bits::CountSetBits32(data);
+ }
+ return count;
+}
+
+} // namespace internal
+} // namespace v8
=======================================
--- /trunk/src/data-flow.h Tue Aug 5 00:05:55 2014 UTC
+++ /trunk/src/data-flow.h Thu Aug 21 07:23:04 2014 UTC
@@ -164,14 +164,7 @@
return true;
}
- int Count() const {
- int count = 0;
- for (int i = 0; i < data_length_; i++) {
- int data = data_[i];
- if (data != 0) count += CompilerIntrinsics::CountSetBits(data);
- }
- return count;
- }
+ int Count() const;
int length() const { return length_; }
@@ -185,6 +178,7 @@
uint32_t* data_;
};
+
class GrowableBitVector BASE_EMBEDDED {
public:
class Iterator BASE_EMBEDDED {
@@ -241,8 +235,7 @@
BitVector* bits_;
};
-
-} } // namespace v8::internal
-
+} // namespace internal
+} // namespace v8
#endif // V8_DATAFLOW_H_
=======================================
--- /trunk/src/elements.cc Wed Aug 6 00:06:29 2014 UTC
+++ /trunk/src/elements.cc Thu Aug 21 07:23:04 2014 UTC
@@ -652,28 +652,6 @@
Handle<BackingStore>::cast(backing_store)->is_the_hole(key)
? ABSENT : NONE;
}
-
- MUST_USE_RESULT virtual PropertyType GetType(
- Handle<Object> receiver,
- Handle<JSObject> holder,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) V8_FINAL V8_OVERRIDE {
- return ElementsAccessorSubclass::GetTypeImpl(
- receiver, holder, key, backing_store);
- }
-
- MUST_USE_RESULT static PropertyType GetTypeImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) {
- if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
- return NONEXISTENT;
- }
- return
- Handle<BackingStore>::cast(backing_store)->is_the_hole(key)
- ? NONEXISTENT : FIELD;
- }
MUST_USE_RESULT virtual MaybeHandle<AccessorPair> GetAccessorPair(
Handle<Object> receiver,
@@ -1309,16 +1287,6 @@
key < AccessorClass::GetCapacityImpl(backing_store)
? NONE : ABSENT;
}
-
- MUST_USE_RESULT static PropertyType GetTypeImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> backing_store) {
- return
- key < AccessorClass::GetCapacityImpl(backing_store)
- ? FIELD : NONEXISTENT;
- }
MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl(
Handle<JSObject> obj,
@@ -1529,20 +1497,6 @@
}
return ABSENT;
}
-
- MUST_USE_RESULT static PropertyType GetTypeImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> store) {
- Handle<SeededNumberDictionary> backing_store =
- Handle<SeededNumberDictionary>::cast(store);
- int entry = backing_store->FindEntry(key);
- if (entry != SeededNumberDictionary::kNotFound) {
- return backing_store->DetailsAt(entry).type();
- }
- return NONEXISTENT;
- }
MUST_USE_RESULT static MaybeHandle<AccessorPair> GetAccessorPairImpl(
Handle<Object> receiver,
@@ -1647,23 +1601,6 @@
receiver, obj, key, arguments);
}
}
-
- MUST_USE_RESULT static PropertyType GetTypeImpl(
- Handle<Object> receiver,
- Handle<JSObject> obj,
- uint32_t key,
- Handle<FixedArrayBase> parameters) {
- Handle<FixedArray> parameter_map =
Handle<FixedArray>::cast(parameters);
- Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
- if (!probe->IsTheHole()) {
- return FIELD;
- } else {
- // If not aliased, check the arguments.
- Handle<FixedArray>
arguments(FixedArray::cast(parameter_map->get(1)));
- return ElementsAccessor::ForArray(arguments)->GetType(
- receiver, obj, key, arguments);
- }
- }
MUST_USE_RESULT static MaybeHandle<AccessorPair> GetAccessorPairImpl(
Handle<Object> receiver,
=======================================
***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.