diff options
author | Chris Dickinson <christopher.s.dickinson@gmail.com> | 2015-05-05 13:48:55 -0700 |
---|---|---|
committer | Rod Vagg <rod@vagg.org> | 2015-08-04 11:56:09 -0700 |
commit | d58e780504bdba6c5897c48428fd984c5b5f96fe (patch) | |
tree | 033f1568ae3f9f077aceb843b42eb1ed1739ce0f /deps/v8/test | |
parent | 21d31c08e7d0b6865e52452750b20b05e6dca443 (diff) | |
download | node-new-d58e780504bdba6c5897c48428fd984c5b5f96fe.tar.gz |
deps: update v8 to 4.3.61.21
* @indutny's SealHandleScope patch (484bebc38319fc7c622478037922ad73b2edcbf9)
has been cherry picked onto the top of V8 to make it compile.
* There's some test breakage in contextify.
* This was merged at the request of the TC.
PR-URL: https://github.com/iojs/io.js/pull/1632
Diffstat (limited to 'deps/v8/test')
275 files changed, 12207 insertions, 4349 deletions
diff --git a/deps/v8/test/cctest/cctest.gyp b/deps/v8/test/cctest/cctest.gyp index 1b851e44cf..60536a4420 100644 --- a/deps/v8/test/cctest/cctest.gyp +++ b/deps/v8/test/cctest/cctest.gyp @@ -86,6 +86,7 @@ 'compiler/test-run-machops.cc', 'compiler/test-run-properties.cc', 'compiler/test-run-stackcheck.cc', + 'compiler/test-run-stubs.cc', 'compiler/test-run-variables.cc', 'compiler/test-simplified-lowering.cc', 'cctest.cc', @@ -99,6 +100,7 @@ 'test-api.cc', 'test-api.h', 'test-api-interceptors.cc', + 'test-array-list.cc', 'test-ast.cc', 'test-atomicops.cc', 'test-bignum.cc', @@ -156,6 +158,7 @@ 'test-thread-termination.cc', 'test-threads.cc', 'test-transitions.cc', + 'test-typedarrays.cc', 'test-types.cc', 'test-unbound-queue.cc', 'test-unboxed-doubles.cc', @@ -270,6 +273,9 @@ }, }, }], + ['OS=="aix"', { + 'ldflags': [ '-Wl,-bbigtoc' ], + }], ['component=="shared_library"', { # cctest can't be built against a shared library, so we need to # depend on the underlying static target in that case. diff --git a/deps/v8/test/cctest/cctest.h b/deps/v8/test/cctest/cctest.h index e111438cdf..08877c8268 100644 --- a/deps/v8/test/cctest/cctest.h +++ b/deps/v8/test/cctest/cctest.h @@ -558,6 +558,9 @@ static inline void SimulateIncrementalMarking(i::Heap* heap) { CHECK(marking->IsMarking()); while (!marking->IsComplete()) { marking->Step(i::MB, i::IncrementalMarking::NO_GC_VIA_STACK_GUARD); + if (marking->IsReadyToOverApproximateWeakClosure()) { + marking->MarkObjectGroups(); + } } CHECK(marking->IsComplete()); } diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index c58b1f0204..d7f72495ae 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -64,9 +64,6 @@ # are actually 13 * 38 * 5 * 128 = 316160 individual tests hidden here. 'test-parsing/ParserSync': [PASS, NO_VARIANTS], - # Modules are busted - 'test-parsing/ExportsMaybeAssigned': [SKIP], - # This tests only the type system, so there is no point in running several # variants. 'test-hydrogen-types/*': [PASS, NO_VARIANTS], @@ -75,13 +72,25 @@ # The cpu profiler tests are notoriously flaky. # BUG(2999). (test/cpu-profiler/CollectCpuProfile) # BUG(3287). (test-cpu-profiler/SampleWhenFrameIsNotSetup) - 'test-cpu-profiler/*': [PASS, FLAKY], - 'test-cpu-profiler/*': [SKIP], + 'test-cpu-profiler/CollectCpuProfile': [SKIP], + 'test-cpu-profiler/CollectCpuProfileSamples': [SKIP], + 'test-cpu-profiler/FunctionApplySample': [SKIP], + 'test-cpu-profiler/FunctionCallSample': [SKIP], + 'test-cpu-profiler/SampleWhenFrameIsNotSetup': [SKIP], + 'test-cpu-profiler/HotDeoptNoFrameEntry': [SKIP], + 'test-cpu-profiler/BoundFunctionCall': [SKIP], + 'test-cpu-profiler/CpuProfileDeepStack': [SKIP], + 'test-cpu-profiler/JsNativeJsSample': [SKIP], + 'test-cpu-profiler/JsNativeJsRuntimeJsSample': [SKIP], + 'test-cpu-profiler/JsNative1JsNative2JsSample': [SKIP], # BUG(3525). Test crashes flakily. 'test-debug/RecursiveBreakpoints': [PASS, FLAKY], 'test-debug/RecursiveBreakpointsGlobal': [PASS, FLAKY], + # Fails sometimes. + 'test-debug/ProcessDebugMessagesThreaded': [PASS, FLAKY], + ############################################################################## # TurboFan compiler failures. @@ -94,14 +103,15 @@ # BUG(3742). 'test-mark-compact/MarkCompactCollector': [PASS, ['arch==arm', NO_VARIANTS]], - # TODO(jarin/mstarzinger): Investigate debugger issues with TurboFan. - 'test-debug/DebugStepNatives': [PASS, NO_VARIANTS], - 'test-debug/DebugStepFunctionApply': [PASS, NO_VARIANTS], - 'test-debug/DebugStepFunctionCall': [PASS, NO_VARIANTS], + # TODO(jarin): Cannot lazy-deoptimize from conversions before comparisons. + 'test-js-typed-lowering/OrderCompareEffects': [SKIP], # TODO(jochen): Reenable after we removed the CHECK() from the marking queue. 'test-mark-compact/MarkingDeque': [SKIP], + 'test-heap/TestInternalWeakLists': [PASS, ['arch==arm', NO_VARIANTS]], + 'test-heap/TestInternalWeakListsTraverseWithGC': [PASS, ['arch==arm', NO_VARIANTS]], + ############################################################################ # Slow tests. 'test-api/Threading1': [PASS, ['mode == debug', SLOW]], @@ -114,15 +124,14 @@ ############################################################################## ['arch == arm64', { + 'test-cpu-profiler/CollectDeoptEvents': [PASS, FAIL], + 'test-api/Bug618': [PASS], # BUG(v8:3385). 'test-serialize/DeserializeFromSecondSerialization': [PASS, FAIL], 'test-serialize/DeserializeFromSecondSerializationAndRunScript2': [PASS, FAIL], - # BUG(v8:2999). - 'test-cpu-profiler/CollectCpuProfile': [PASS, FAIL], - # BUG(v8:3154). 'test-heap/ReleaseOverReservedPages': [PASS, FAIL], @@ -180,18 +189,12 @@ ############################################################################## ['system == windows', { - # BUG(2999). - 'test-cpu-profiler/CollectCpuProfile': [PASS, FAIL], - # BUG(3005). 'test-alloc/CodeRange': [PASS, FAIL], # BUG(3331). Fails on windows. 'test-heap/NoWeakHashTableLeakWithIncrementalMarking': [SKIP], - # BUG(v8:3433). Crashes on windows. - 'test-cpu-profiler/FunctionApplySample': [SKIP], - }], # 'system == windows' ############################################################################## @@ -206,6 +209,8 @@ ############################################################################## ['arch == arm', { + 'test-cpu-profiler/CollectDeoptEvents': [PASS, FAIL], + # BUG(355): Test crashes on ARM. 'test-log/ProfLazyMode': [SKIP], @@ -229,20 +234,13 @@ ############################################################################## ['arch == mipsel or arch == mips', { - - # BUG(2657): Test sometimes times out on MIPS simulator. - 'test-thread-termination/TerminateMultipleV8ThreadsDefaultIsolate': [PASS, TIMEOUT], + 'test-cpu-profiler/CollectDeoptEvents': [PASS, FAIL], # BUG(1075): Unresolved crashes on MIPS also. 'test-serialize/Deserialize': [SKIP], 'test-serialize/DeserializeFromSecondSerializationAndRunScript2': [SKIP], 'test-serialize/DeserializeAndRunScript2': [SKIP], 'test-serialize/DeserializeFromSecondSerialization': [SKIP], - - # Test requires turbofan: - 'test-simplified-lowering/LowerStringOps_to_call_and_compare': [SKIP], - 'codegen-tester/CompareWrapper': [SKIP], - 'codegen-tester/ParametersEqual': [SKIP], }], # 'arch == mipsel or arch == mips' ############################################################################## @@ -260,9 +258,7 @@ ############################################################################## ['arch == mips64el', { - - # BUG(2657): Test sometimes times out on MIPS simulator. - 'test-thread-termination/TerminateMultipleV8ThreadsDefaultIsolate': [PASS, TIMEOUT], + 'test-cpu-profiler/CollectDeoptEvents': [PASS, FAIL], # BUG(v8:3154). 'test-heap/ReleaseOverReservedPages': [PASS, FAIL], @@ -272,11 +268,6 @@ 'test-serialize/DeserializeFromSecondSerializationAndRunScript2': [SKIP], 'test-serialize/DeserializeAndRunScript2': [SKIP], 'test-serialize/DeserializeFromSecondSerialization': [SKIP], - - # Test requires turbofan: - 'test-simplified-lowering/LowerStringOps_to_call_and_compare': [SKIP], - 'codegen-tester/CompareWrapper': [SKIP], - 'codegen-tester/ParametersEqual': [SKIP], }], # 'arch == mips64el' ############################################################################## @@ -286,6 +277,7 @@ 'codegen-tester/CompareWrapper': [SKIP], 'codegen-tester/ParametersEqual': [SKIP], 'test-simplified-lowering/LowerStringOps_to_call_and_compare': [SKIP], + 'test-serialize/SerializeInternalReference': [FAIL], }], # 'arch == x87' ############################################################################## @@ -402,8 +394,13 @@ }], # 'arch == nacl_ia32 or arch == nacl_x64' -['arch == ppc64', { - #issue 2857 - 'test-log/EquivalenceOfLoggingAndTraversal' : [SKIP], -}], # 'arch == ppc64' +############################################################################## +['arch == ppc and simulator_run == True or arch == ppc64 and simulator_run == True', { + + # Pass but take too long with the simulator. + 'test-api/Threading1': [PASS, SLOW], + 'test-api/Threading2': [PASS, SLOW], + 'test-api/ExternalArrays': [PASS, SLOW], + +}], # 'arch == ppc64 and simulator_run == True' ] diff --git a/deps/v8/test/cctest/compiler/call-tester.h b/deps/v8/test/cctest/compiler/call-tester.h index ffafaf0803..30bbe1e8aa 100644 --- a/deps/v8/test/cctest/compiler/call-tester.h +++ b/deps/v8/test/cctest/compiler/call-tester.h @@ -128,6 +128,20 @@ struct ParameterTraits<T*> { static uintptr_t Cast(void* r) { return reinterpret_cast<uintptr_t>(r); } }; +// Additional template specialization required for mips64 to sign-extend +// parameters defined by calling convention. +template <> +struct ParameterTraits<int32_t> { + static int64_t Cast(int32_t r) { return static_cast<int64_t>(r); } +}; + +template <> +struct ParameterTraits<uint32_t> { + static int64_t Cast(uint32_t r) { + return static_cast<int64_t>(static_cast<int32_t>(r)); + } +}; + class CallHelper { public: explicit CallHelper(Isolate* isolate, MachineSignature* machine_sig) @@ -214,6 +228,7 @@ class CallHelper { return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4)); } + template <typename R, typename F> R DoCall(F* f) { return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f))); diff --git a/deps/v8/test/cctest/compiler/function-tester.h b/deps/v8/test/cctest/compiler/function-tester.h index 440043cb94..20efd1e304 100644 --- a/deps/v8/test/cctest/compiler/function-tester.h +++ b/deps/v8/test/cctest/compiler/function-tester.h @@ -34,6 +34,7 @@ class FunctionTester : public InitializedHandleScope { flags_(flags) { Compile(function); const uint32_t supported_flags = CompilationInfo::kContextSpecializing | + CompilationInfo::kBuiltinInliningEnabled | CompilationInfo::kInliningEnabled | CompilationInfo::kTypingEnabled; CHECK_EQ(0u, flags_ & ~supported_flags); @@ -60,7 +61,6 @@ class FunctionTester : public InitializedHandleScope { CHECK(isolate->has_pending_exception()); CHECK(try_catch.HasCaught()); CHECK(no_result.is_null()); - // TODO(mstarzinger): Temporary workaround for issue chromium:362388. isolate->OptionalRescheduleException(true); } @@ -71,10 +71,8 @@ class FunctionTester : public InitializedHandleScope { CHECK(isolate->has_pending_exception()); CHECK(try_catch.HasCaught()); CHECK(no_result.is_null()); - // TODO(mstarzinger): Calling OptionalRescheduleException is a dirty hack, - // it's the only way to make Message() not to assert because an external - // exception has been caught by the try_catch. isolate->OptionalRescheduleException(true); + CHECK(!try_catch.Message().IsEmpty()); return try_catch.Message(); } @@ -152,9 +150,11 @@ class FunctionTester : public InitializedHandleScope { Handle<JSFunction> Compile(Handle<JSFunction> function) { // TODO(titzer): make this method private. #if V8_TURBOFAN_TARGET - CompilationInfoWithZone info(function); + Zone zone; + ParseInfo parse_info(&zone, function); + CompilationInfo info(&parse_info); - CHECK(Parser::ParseStatic(&info)); + CHECK(Parser::ParseStatic(info.parse_info())); info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code())); if (flags_ & CompilationInfo::kContextSpecializing) { info.MarkAsContextSpecializing(); @@ -165,7 +165,7 @@ class FunctionTester : public InitializedHandleScope { if (flags_ & CompilationInfo::kTypingEnabled) { info.MarkAsTypingEnabled(); } - CHECK(Compiler::Analyze(&info)); + CHECK(Compiler::Analyze(info.parse_info())); CHECK(Compiler::EnsureDeoptimizationSupport(&info)); Pipeline pipeline(&info); @@ -208,12 +208,14 @@ class FunctionTester : public InitializedHandleScope { // and replace the JSFunction's code with the result. Handle<JSFunction> CompileGraph(Graph* graph) { CHECK(Pipeline::SupportedTarget()); - CompilationInfoWithZone info(function); + Zone zone; + ParseInfo parse_info(&zone, function); + CompilationInfo info(&parse_info); - CHECK(Parser::ParseStatic(&info)); + CHECK(Parser::ParseStatic(info.parse_info())); info.SetOptimizing(BailoutId::None(), Handle<Code>(function->shared()->code())); - CHECK(Compiler::Analyze(&info)); + CHECK(Compiler::Analyze(info.parse_info())); CHECK(Compiler::EnsureDeoptimizationSupport(&info)); Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, graph); diff --git a/deps/v8/test/cctest/compiler/simplified-graph-builder.cc b/deps/v8/test/cctest/compiler/simplified-graph-builder.cc index e65ba2e0df..6afdc0a211 100644 --- a/deps/v8/test/cctest/compiler/simplified-graph-builder.cc +++ b/deps/v8/test/cctest/compiler/simplified-graph-builder.cc @@ -48,7 +48,7 @@ Node* SimplifiedGraphBuilder::MakeNode(const Operator* op, DCHECK(op->ValueInputCount() == value_input_count); DCHECK(!OperatorProperties::HasContextInput(op)); - DCHECK(!OperatorProperties::HasFrameStateInput(op)); + DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op)); bool has_control = op->ControlInputCount() == 1; bool has_effect = op->EffectInputCount() == 1; diff --git a/deps/v8/test/cctest/compiler/test-codegen-deopt.cc b/deps/v8/test/cctest/compiler/test-codegen-deopt.cc index a90e4025dc..0b59308216 100644 --- a/deps/v8/test/cctest/compiler/test-codegen-deopt.cc +++ b/deps/v8/test/cctest/compiler/test-codegen-deopt.cc @@ -44,11 +44,14 @@ class DeoptCodegenTester { explicit DeoptCodegenTester(HandleAndZoneScope* scope, const char* src) : scope_(scope), function(NewFunction(src)), - info(function, scope->main_zone()), - bailout_id(-1) { - CHECK(Parser::ParseStatic(&info)); + parse_info(scope->main_zone(), function), + info(&parse_info), + bailout_id(-1), + tagged_type(1, kMachAnyTagged, zone()), + empty_types(zone()) { + CHECK(Parser::ParseStatic(&parse_info)); info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code())); - CHECK(Compiler::Analyze(&info)); + CHECK(Compiler::Analyze(&parse_info)); CHECK(Compiler::EnsureDeoptimizationSupport(&info)); DCHECK(info.shared_info()->has_deoptimization_support()); @@ -76,11 +79,14 @@ class DeoptCodegenTester { HandleAndZoneScope* scope_; Handle<JSFunction> function; + ParseInfo parse_info; CompilationInfo info; BailoutId bailout_id; Handle<Code> result_code; TestInstrSeq* code; Graph* graph; + ZoneVector<MachineType> tagged_type; + ZoneVector<MachineType> empty_types; }; @@ -118,9 +124,10 @@ class TrivialDeoptCodegenTester : public DeoptCodegenTester { m.NewNode(common.HeapConstant(caller_context_constant)); bailout_id = GetCallBailoutId(); - Node* parameters = m.NewNode(common.StateValues(1), m.UndefinedConstant()); - Node* locals = m.NewNode(common.StateValues(0)); - Node* stack = m.NewNode(common.StateValues(0)); + Node* parameters = + m.NewNode(common.TypedStateValues(&tagged_type), m.UndefinedConstant()); + Node* locals = m.NewNode(common.TypedStateValues(&empty_types)); + Node* stack = m.NewNode(common.TypedStateValues(&empty_types)); Node* state_node = m.NewNode( common.FrameState(JS_FRAME, bailout_id, @@ -233,9 +240,10 @@ class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester { Node* context_node = m.NewNode(common.HeapConstant(context_constant)); bailout_id = GetCallBailoutId(); - Node* parameters = m.NewNode(common.StateValues(1), m.UndefinedConstant()); - Node* locals = m.NewNode(common.StateValues(0)); - Node* stack = m.NewNode(common.StateValues(0)); + Node* parameters = + m.NewNode(common.TypedStateValues(&tagged_type), m.UndefinedConstant()); + Node* locals = m.NewNode(common.TypedStateValues(&empty_types)); + Node* stack = m.NewNode(common.TypedStateValues(&empty_types)); Node* state_node = m.NewNode( common.FrameState(JS_FRAME, bailout_id, diff --git a/deps/v8/test/cctest/compiler/test-control-reducer.cc b/deps/v8/test/cctest/compiler/test-control-reducer.cc index 827dcfdaa8..c2b225ab00 100644 --- a/deps/v8/test/cctest/compiler/test-control-reducer.cc +++ b/deps/v8/test/cctest/compiler/test-control-reducer.cc @@ -8,7 +8,7 @@ #include "src/base/bits.h" #include "src/compiler/common-operator.h" #include "src/compiler/control-reducer.h" -#include "src/compiler/graph-inl.h" +#include "src/compiler/graph.h" #include "src/compiler/js-graph.h" #include "src/compiler/node-properties.h" @@ -694,9 +694,9 @@ TEST(CMergeReduce_none1) { TEST(CMergeReduce_none2) { ControlReducerTester R; - Node* t = R.graph.NewNode(R.common.IfTrue(), R.start); - Node* f = R.graph.NewNode(R.common.IfFalse(), R.start); - Node* merge = R.graph.NewNode(R.common.Merge(2), t, f); + Node* t1 = R.graph.NewNode(R.common.IfTrue(), R.start); + Node* t2 = R.graph.NewNode(R.common.IfTrue(), R.start); + Node* merge = R.graph.NewNode(R.common.Merge(2), t1, t2); R.ReduceMerge(merge, merge); } @@ -744,7 +744,7 @@ TEST(CMergeReduce_dead_rm1b) { ControlReducerTester R; Node* t = R.graph.NewNode(R.common.IfTrue(), R.start); - Node* f = R.graph.NewNode(R.common.IfFalse(), R.start); + Node* f = R.graph.NewNode(R.common.IfTrue(), R.start); for (int i = 0; i < 2; i++) { Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead); for (int j = i + 1; j < 3; j++) { @@ -1118,7 +1118,7 @@ TEST(CChainedDiamondsReduce_x_false) { Diamond d2(R, R.zero); d2.chain(d1); - R.ReduceMergeIterative(d1.merge, d2.merge); + R.ReduceMergeIterative(R.start, d2.merge); } @@ -1128,8 +1128,7 @@ TEST(CChainedDiamondsReduce_false_x) { Diamond d2(R, R.p0); d2.chain(d1); - R.ReduceMergeIterative(d2.merge, d2.merge); - CheckInputs(d2.branch, R.p0, R.start); + R.ReduceMergeIterative(R.start, d2.merge); } @@ -1190,6 +1189,28 @@ TEST(CNestedDiamonds_xyz) { } +TEST(CUnusedDiamond1) { + ControlReducerTester R; + // if (p0) { } else { } + Node* branch = R.graph.NewNode(R.common.Branch(), R.p0, R.start); + Node* if_true = R.graph.NewNode(R.common.IfTrue(), branch); + Node* if_false = R.graph.NewNode(R.common.IfFalse(), branch); + Node* merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false); + R.ReduceMergeIterative(R.start, merge); +} + + +TEST(CUnusedDiamond2) { + ControlReducerTester R; + // if (p0) { } else { } + Node* branch = R.graph.NewNode(R.common.Branch(), R.p0, R.start); + Node* if_true = R.graph.NewNode(R.common.IfTrue(), branch); + Node* if_false = R.graph.NewNode(R.common.IfFalse(), branch); + Node* merge = R.graph.NewNode(R.common.Merge(2), if_false, if_true); + R.ReduceMergeIterative(R.start, merge); +} + + TEST(CDeadLoop1) { ControlReducerTester R; @@ -1329,9 +1350,7 @@ TEST(Return_nested_diamonds1) { CheckInputs(ret, d1.phi, R.start, d1.merge); CheckInputs(d1.phi, R.one, R.zero, d1.merge); - CheckInputs(d1.merge, d2.merge, d3.merge); - CheckLiveDiamond(d2); - CheckLiveDiamond(d3); + CheckInputs(d1.merge, d1.if_true, d1.if_false); } @@ -1348,11 +1367,7 @@ TEST(Return_nested_diamonds_true1) { R.ReduceGraph(); // d1 gets folded true. - CheckInputs(ret, R.one, R.start, d2.merge); - CheckInputs(d2.branch, R.p0, R.start); - CheckDeadDiamond(d1); - CheckLiveDiamond(d2); - CheckDeadDiamond(d3); + CheckInputs(ret, R.one, R.start, R.start); } @@ -1369,11 +1384,7 @@ TEST(Return_nested_diamonds_false1) { R.ReduceGraph(); // d1 gets folded false. - CheckInputs(ret, R.zero, R.start, d3.merge); - CheckInputs(d3.branch, R.p0, R.start); - CheckDeadDiamond(d1); - CheckDeadDiamond(d2); - CheckLiveDiamond(d3); + CheckInputs(ret, R.zero, R.start, R.start); } diff --git a/deps/v8/test/cctest/compiler/test-instruction.cc b/deps/v8/test/cctest/compiler/test-instruction.cc index 85cc870e9d..22d46e7e39 100644 --- a/deps/v8/test/cctest/compiler/test-instruction.cc +++ b/deps/v8/test/cctest/compiler/test-instruction.cc @@ -27,20 +27,14 @@ typedef v8::internal::compiler::InstructionSequence TestInstrSeq; class InstructionTester : public HandleAndZoneScope { public: // We're all friends here. InstructionTester() - : isolate(main_isolate()), - graph(zone()), + : graph(zone()), schedule(zone()), - fake_stub(main_isolate()), - info(&fake_stub, main_isolate()), common(zone()), machine(zone()), code(NULL) {} - Isolate* isolate; Graph graph; Schedule schedule; - FakeStubForTesting fake_stub; - CompilationInfoWithZone info; CommonOperatorBuilder common; MachineOperatorBuilder machine; TestInstrSeq* code; @@ -93,8 +87,12 @@ class InstructionTester : public HandleAndZoneScope { return UnallocatedOperand(UnallocatedOperand::ANY, vreg).Copy(zone()); } + RpoNumber RpoFor(BasicBlock* block) { + return RpoNumber::FromInt(block->rpo_number()); + } + InstructionBlock* BlockAt(BasicBlock* block) { - return code->InstructionBlockAt(block->GetRpoNumber()); + return code->InstructionBlockAt(RpoFor(block)); } BasicBlock* GetBasicBlock(int instruction_index) { const InstructionBlock* block = @@ -131,7 +129,6 @@ TEST(InstructionBasic) { for (auto block : *blocks) { CHECK_EQ(block->rpo_number(), R.BlockAt(block)->rpo_number().ToInt()); - CHECK_EQ(block->id().ToInt(), R.BlockAt(block)->id().ToInt()); CHECK(!block->loop_end()); } } @@ -151,23 +148,23 @@ TEST(InstructionGetBasicBlock) { R.allocCode(); - R.code->StartBlock(b0->GetRpoNumber()); + R.code->StartBlock(R.RpoFor(b0)); int i0 = R.NewInstr(); int i1 = R.NewInstr(); - R.code->EndBlock(b0->GetRpoNumber()); - R.code->StartBlock(b1->GetRpoNumber()); + R.code->EndBlock(R.RpoFor(b0)); + R.code->StartBlock(R.RpoFor(b1)); int i2 = R.NewInstr(); int i3 = R.NewInstr(); int i4 = R.NewInstr(); int i5 = R.NewInstr(); - R.code->EndBlock(b1->GetRpoNumber()); - R.code->StartBlock(b2->GetRpoNumber()); + R.code->EndBlock(R.RpoFor(b1)); + R.code->StartBlock(R.RpoFor(b2)); int i6 = R.NewInstr(); int i7 = R.NewInstr(); int i8 = R.NewInstr(); - R.code->EndBlock(b2->GetRpoNumber()); - R.code->StartBlock(b3->GetRpoNumber()); - R.code->EndBlock(b3->GetRpoNumber()); + R.code->EndBlock(R.RpoFor(b2)); + R.code->StartBlock(R.RpoFor(b3)); + R.code->EndBlock(R.RpoFor(b3)); CHECK_EQ(b0, R.GetBasicBlock(i0)); CHECK_EQ(b0, R.GetBasicBlock(i1)); @@ -203,11 +200,11 @@ TEST(InstructionIsGapAt) { R.allocCode(); TestInstr* i0 = TestInstr::New(R.zone(), 100); - TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl(); - R.code->StartBlock(b0->GetRpoNumber()); + TestInstr* g = TestInstr::New(R.zone(), 103); + R.code->StartBlock(R.RpoFor(b0)); R.code->AddInstruction(i0); R.code->AddInstruction(g); - R.code->EndBlock(b0->GetRpoNumber()); + R.code->EndBlock(R.RpoFor(b0)); CHECK(R.code->instructions().size() == 4); for (size_t i = 0; i < R.code->instructions().size(); ++i) { @@ -226,18 +223,18 @@ TEST(InstructionIsGapAt2) { R.allocCode(); TestInstr* i0 = TestInstr::New(R.zone(), 100); - TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl(); - R.code->StartBlock(b0->GetRpoNumber()); + TestInstr* g = TestInstr::New(R.zone(), 103); + R.code->StartBlock(R.RpoFor(b0)); R.code->AddInstruction(i0); R.code->AddInstruction(g); - R.code->EndBlock(b0->GetRpoNumber()); + R.code->EndBlock(R.RpoFor(b0)); TestInstr* i1 = TestInstr::New(R.zone(), 102); - TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl(); - R.code->StartBlock(b1->GetRpoNumber()); + TestInstr* g1 = TestInstr::New(R.zone(), 104); + R.code->StartBlock(R.RpoFor(b1)); R.code->AddInstruction(i1); R.code->AddInstruction(g1); - R.code->EndBlock(b1->GetRpoNumber()); + R.code->EndBlock(R.RpoFor(b1)); CHECK(R.code->instructions().size() == 8); for (size_t i = 0; i < R.code->instructions().size(); ++i) { @@ -254,11 +251,11 @@ TEST(InstructionAddGapMove) { R.allocCode(); TestInstr* i0 = TestInstr::New(R.zone(), 100); - TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl(); - R.code->StartBlock(b0->GetRpoNumber()); + TestInstr* g = TestInstr::New(R.zone(), 103); + R.code->StartBlock(R.RpoFor(b0)); R.code->AddInstruction(i0); R.code->AddInstruction(g); - R.code->EndBlock(b0->GetRpoNumber()); + R.code->EndBlock(R.RpoFor(b0)); CHECK(R.code->instructions().size() == 4); for (size_t i = 0; i < R.code->instructions().size(); ++i) { diff --git a/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc b/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc index f4531d3e83..cc4b2bdef2 100644 --- a/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc +++ b/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "src/compiler/graph-inl.h" #include "src/compiler/js-graph.h" #include "src/compiler/js-typed-lowering.h" #include "src/compiler/machine-operator.h" @@ -68,7 +67,7 @@ class JSTypedLoweringTester : public HandleAndZoneScope { Node* stack = graph.NewNode(common.StateValues(0)); Node* state_node = - graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0), + graph.NewNode(common.FrameState(JS_FRAME, BailoutId::None(), OutputFrameStateCombine::Ignore()), parameters, locals, stack, context, UndefinedConstant()); @@ -114,9 +113,13 @@ class JSTypedLoweringTester : public HandleAndZoneScope { Node* Binop(const Operator* op, Node* left, Node* right) { // JS binops also require context, effect, and control - if (OperatorProperties::HasFrameStateInput(op)) { + if (OperatorProperties::GetFrameStateInputCount(op) == 1) { return graph.NewNode(op, left, right, context(), EmptyFrameState(context()), start(), control()); + } else if (OperatorProperties::GetFrameStateInputCount(op) == 2) { + return graph.NewNode(op, left, right, context(), + EmptyFrameState(context()), + EmptyFrameState(context()), start(), control()); } else { return graph.NewNode(op, left, right, context(), start(), control()); } @@ -124,7 +127,8 @@ class JSTypedLoweringTester : public HandleAndZoneScope { Node* Unop(const Operator* op, Node* input) { // JS unops also require context, effect, and control - if (OperatorProperties::HasFrameStateInput(op)) { + if (OperatorProperties::GetFrameStateInputCount(op) > 0) { + DCHECK(OperatorProperties::GetFrameStateInputCount(op) == 1); return graph.NewNode(op, input, context(), EmptyFrameState(context()), start(), control()); } else { @@ -134,7 +138,10 @@ class JSTypedLoweringTester : public HandleAndZoneScope { Node* UseForEffect(Node* node) { // TODO(titzer): use EffectPhi after fixing EffectCount - if (OperatorProperties::HasFrameStateInput(javascript.ToNumber())) { + if (OperatorProperties::GetFrameStateInputCount(javascript.ToNumber()) > + 0) { + DCHECK(OperatorProperties::GetFrameStateInputCount( + javascript.ToNumber()) == 1); return graph.NewNode(javascript.ToNumber(), node, context(), EmptyFrameState(context()), node, control()); } else { @@ -500,42 +507,6 @@ TEST(JSToNumberOfNumberOrOtherPrimitive) { } -TEST(JSToBoolean) { - JSTypedLoweringTester R; - const Operator* op = R.javascript.ToBoolean(); - - { // ToBoolean(undefined) - Node* r = R.ReduceUnop(op, Type::Undefined()); - R.CheckFalse(r); - } - - { // ToBoolean(null) - Node* r = R.ReduceUnop(op, Type::Null()); - R.CheckFalse(r); - } - - { // ToBoolean(boolean) - Node* r = R.ReduceUnop(op, Type::Boolean()); - CHECK_EQ(IrOpcode::kParameter, r->opcode()); - } - - { // ToBoolean(object) - Node* r = R.ReduceUnop(op, Type::DetectableObject()); - R.CheckTrue(r); - } - - { // ToBoolean(undetectable) - Node* r = R.ReduceUnop(op, Type::Undetectable()); - R.CheckFalse(r); - } - - { // ToBoolean(object) - Node* r = R.ReduceUnop(op, Type::Object()); - CHECK_EQ(IrOpcode::kAnyToBoolean, r->opcode()); - } -} - - TEST(JSToString1) { JSTypedLoweringTester R; @@ -717,24 +688,6 @@ TEST(MixedComparison1) { } -TEST(UnaryNot) { - JSTypedLoweringTester R; - const Operator* opnot = R.javascript.UnaryNot(); - - for (size_t i = 0; i < arraysize(kJSTypes); i++) { - Node* orig = R.Unop(opnot, R.Parameter(kJSTypes[i])); - Node* r = R.reduce(orig); - - if (r == orig && orig->opcode() == IrOpcode::kJSToBoolean) { - // The original node was turned into a ToBoolean. - CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode()); - } else if (r->opcode() != IrOpcode::kHeapConstant) { - CHECK_EQ(IrOpcode::kBooleanNot, r->opcode()); - } - } -} - - TEST(RemoveToNumberEffects) { FLAG_turbo_deoptimization = true; @@ -749,8 +702,9 @@ TEST(RemoveToNumberEffects) { switch (i) { case 0: - // TODO(jarin) Replace with a query of FLAG_turbo_deoptimization. - if (OperatorProperties::HasFrameStateInput(R.javascript.ToNumber())) { + if (FLAG_turbo_deoptimization) { + DCHECK(OperatorProperties::GetFrameStateInputCount( + R.javascript.ToNumber()) == 1); effect_use = R.graph.NewNode(R.javascript.ToNumber(), p0, R.context(), frame_state, ton, R.start()); } else { @@ -759,8 +713,9 @@ TEST(RemoveToNumberEffects) { } break; case 1: - // TODO(jarin) Replace with a query of FLAG_turbo_deoptimization. - if (OperatorProperties::HasFrameStateInput(R.javascript.ToNumber())) { + if (FLAG_turbo_deoptimization) { + DCHECK(OperatorProperties::GetFrameStateInputCount( + R.javascript.ToNumber()) == 1); effect_use = R.graph.NewNode(R.javascript.ToNumber(), ton, R.context(), frame_state, ton, R.start()); @@ -773,11 +728,11 @@ TEST(RemoveToNumberEffects) { effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start()); case 3: effect_use = R.graph.NewNode(R.javascript.Add(), ton, ton, R.context(), - frame_state, ton, R.start()); + frame_state, frame_state, ton, R.start()); break; case 4: effect_use = R.graph.NewNode(R.javascript.Add(), p0, p0, R.context(), - frame_state, ton, R.start()); + frame_state, frame_state, ton, R.start()); break; case 5: effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start()); diff --git a/deps/v8/test/cctest/compiler/test-jump-threading.cc b/deps/v8/test/cctest/compiler/test-jump-threading.cc index d9de18efad..b2d3008aa9 100644 --- a/deps/v8/test/cctest/compiler/test-jump-threading.cc +++ b/deps/v8/test/cctest/compiler/test-jump-threading.cc @@ -13,8 +13,6 @@ namespace v8 { namespace internal { namespace compiler { -typedef BasicBlock::RpoNumber RpoNumber; - class TestCode : public HandleAndZoneScope { public: TestCode() @@ -32,8 +30,8 @@ class TestCode : public HandleAndZoneScope { int Jump(int target) { Start(); InstructionOperand ops[] = {UseRpo(target)}; - sequence_.AddInstruction(Instruction::New(main_zone(), kArchJmp, 0, NULL, 1, - ops, 0, NULL)->MarkAsControl()); + sequence_.AddInstruction( + Instruction::New(main_zone(), kArchJmp, 0, NULL, 1, ops, 0, NULL)); int pos = static_cast<int>(sequence_.instructions().size() - 1); End(); return pos; @@ -47,8 +45,8 @@ class TestCode : public HandleAndZoneScope { InstructionOperand ops[] = {UseRpo(ttarget), UseRpo(ftarget)}; InstructionCode code = 119 | FlagsModeField::encode(kFlags_branch) | FlagsConditionField::encode(kEqual); - sequence_.AddInstruction(Instruction::New(main_zone(), code, 0, NULL, 2, - ops, 0, NULL)->MarkAsControl()); + sequence_.AddInstruction( + Instruction::New(main_zone(), code, 0, NULL, 2, ops, 0, NULL)); int pos = static_cast<int>(sequence_.instructions().size() - 1); End(); return pos; @@ -87,9 +85,9 @@ class TestCode : public HandleAndZoneScope { } void Start(bool deferred = false) { if (current_ == NULL) { - current_ = new (main_zone()) InstructionBlock( - main_zone(), BasicBlock::Id::FromInt(rpo_number_.ToInt()), - rpo_number_, RpoNumber::Invalid(), RpoNumber::Invalid(), deferred); + current_ = new (main_zone()) + InstructionBlock(main_zone(), rpo_number_, RpoNumber::Invalid(), + RpoNumber::Invalid(), deferred); blocks_.push_back(current_); sequence_.StartBlock(rpo_number_); } diff --git a/deps/v8/test/cctest/compiler/test-linkage.cc b/deps/v8/test/cctest/compiler/test-linkage.cc index 13695b2e0b..212ff3a8f2 100644 --- a/deps/v8/test/cctest/compiler/test-linkage.cc +++ b/deps/v8/test/cctest/compiler/test-linkage.cc @@ -6,6 +6,7 @@ #include "src/code-stubs.h" #include "src/compiler.h" +#include "src/parser.h" #include "src/zone.h" #include "src/compiler/common-operator.h" @@ -33,7 +34,7 @@ static Handle<JSFunction> Compile(const char* source) { ->NewStringFromUtf8(CStrVector(source)) .ToHandleChecked(); Handle<SharedFunctionInfo> shared_function = Compiler::CompileScript( - source_code, Handle<String>(), 0, 0, false, false, + source_code, Handle<String>(), 0, 0, false, false, Handle<Object>(), Handle<Context>(isolate->native_context()), NULL, NULL, v8::ScriptCompiler::kNoCompileOptions, NOT_NATIVES_CODE, false); return isolate->factory()->NewFunctionFromSharedFunctionInfo( @@ -42,25 +43,25 @@ static Handle<JSFunction> Compile(const char* source) { TEST(TestLinkageCreate) { - InitializedHandleScope handles; + HandleAndZoneScope handles; Handle<JSFunction> function = Compile("a + b"); - CompilationInfoWithZone info(function); + ParseInfo parse_info(handles.main_zone(), function); + CompilationInfo info(&parse_info); CallDescriptor* descriptor = Linkage::ComputeIncoming(info.zone(), &info); CHECK(descriptor); } TEST(TestLinkageJSFunctionIncoming) { - InitializedHandleScope handles; - const char* sources[] = {"(function() { })", "(function(a) { })", "(function(a,b) { })", "(function(a,b,c) { })"}; for (int i = 0; i < 3; i++) { - i::HandleScope handles(CcTest::i_isolate()); + HandleAndZoneScope handles; Handle<JSFunction> function = v8::Utils::OpenHandle( *v8::Handle<v8::Function>::Cast(CompileRun(sources[i]))); - CompilationInfoWithZone info(function); + ParseInfo parse_info(handles.main_zone(), function); + CompilationInfo info(&parse_info); CallDescriptor* descriptor = Linkage::ComputeIncoming(info.zone(), &info); CHECK(descriptor); @@ -74,9 +75,10 @@ TEST(TestLinkageJSFunctionIncoming) { TEST(TestLinkageCodeStubIncoming) { Isolate* isolate = CcTest::InitIsolateOnce(); + Zone zone; ToNumberStub stub(isolate); - CompilationInfoWithZone info(&stub, isolate); - CallDescriptor* descriptor = Linkage::ComputeIncoming(info.zone(), &info); + CompilationInfo info(&stub, isolate, &zone); + CallDescriptor* descriptor = Linkage::ComputeIncoming(&zone, &info); CHECK(descriptor); CHECK_EQ(1, static_cast<int>(descriptor->JSParameterCount())); CHECK_EQ(1, static_cast<int>(descriptor->ReturnCount())); @@ -88,7 +90,8 @@ TEST(TestLinkageCodeStubIncoming) { TEST(TestLinkageJSCall) { HandleAndZoneScope handles; Handle<JSFunction> function = Compile("a + c"); - CompilationInfoWithZone info(function); + ParseInfo parse_info(handles.main_zone(), function); + CompilationInfo info(&parse_info); for (int i = 0; i < 32; i++) { CallDescriptor* descriptor = Linkage::GetJSCallDescriptor( diff --git a/deps/v8/test/cctest/compiler/test-loop-assignment-analysis.cc b/deps/v8/test/cctest/compiler/test-loop-assignment-analysis.cc index 7513307bab..5f9820c72a 100644 --- a/deps/v8/test/cctest/compiler/test-loop-assignment-analysis.cc +++ b/deps/v8/test/cctest/compiler/test-loop-assignment-analysis.cc @@ -29,14 +29,15 @@ struct TestHelper : public HandleAndZoneScope { void CheckLoopAssignedCount(int expected, const char* var_name) { // TODO(titzer): don't scope analyze every single time. - CompilationInfo info(function, main_zone()); + ParseInfo parse_info(main_zone(), function); + CompilationInfo info(&parse_info); - CHECK(Parser::ParseStatic(&info)); - CHECK(Rewriter::Rewrite(&info)); - CHECK(Scope::Analyze(&info)); + CHECK(Parser::ParseStatic(&parse_info)); + CHECK(Rewriter::Rewrite(&parse_info)); + CHECK(Scope::Analyze(&parse_info)); Scope* scope = info.function()->scope(); - AstValueFactory* factory = info.ast_value_factory(); + AstValueFactory* factory = parse_info.ast_value_factory(); CHECK(scope); if (result == NULL) { diff --git a/deps/v8/test/cctest/compiler/test-machine-operator-reducer.cc b/deps/v8/test/cctest/compiler/test-machine-operator-reducer.cc index 7ee5751875..beedc459e7 100644 --- a/deps/v8/test/cctest/compiler/test-machine-operator-reducer.cc +++ b/deps/v8/test/cctest/compiler/test-machine-operator-reducer.cc @@ -6,7 +6,6 @@ #include "src/base/utils/random-number-generator.h" #include "src/codegen.h" -#include "src/compiler/graph-inl.h" #include "src/compiler/js-graph.h" #include "src/compiler/machine-operator-reducer.h" #include "src/compiler/operator-properties.h" diff --git a/deps/v8/test/cctest/compiler/test-node-algorithm.cc b/deps/v8/test/cctest/compiler/test-node-algorithm.cc index 842d18272e..0cb77011aa 100644 --- a/deps/v8/test/cctest/compiler/test-node-algorithm.cc +++ b/deps/v8/test/cctest/compiler/test-node-algorithm.cc @@ -9,7 +9,6 @@ #include "graph-tester.h" #include "src/compiler/common-operator.h" #include "src/compiler/graph.h" -#include "src/compiler/graph-inl.h" #include "src/compiler/graph-visualizer.h" #include "src/compiler/node.h" #include "src/compiler/operator.h" @@ -20,45 +19,6 @@ using namespace v8::internal::compiler; static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite, "dummy", 0, 0, 0, 1, 0, 0); -class PreNodeVisitor : public NullNodeVisitor { - public: - void Pre(Node* node) { - printf("NODE ID: %d\n", node->id()); - nodes_.push_back(node); - } - std::vector<Node*> nodes_; -}; - - -class PostNodeVisitor : public NullNodeVisitor { - public: - void Post(Node* node) { - printf("NODE ID: %d\n", node->id()); - nodes_.push_back(node); - } - std::vector<Node*> nodes_; -}; - - -TEST(TestInputNodePreOrderVisitSimple) { - GraphWithStartNodeTester graph; - Node* n2 = graph.NewNode(&dummy_operator, graph.start()); - Node* n3 = graph.NewNode(&dummy_operator, n2); - Node* n4 = graph.NewNode(&dummy_operator, n2, n3); - Node* n5 = graph.NewNode(&dummy_operator, n4, n2); - graph.SetEnd(n5); - - PreNodeVisitor node_visitor; - graph.VisitNodeInputsFromEnd(&node_visitor); - CHECK_EQ(5, static_cast<int>(node_visitor.nodes_.size())); - CHECK(n5->id() == node_visitor.nodes_[0]->id()); - CHECK(n4->id() == node_visitor.nodes_[1]->id()); - CHECK(n2->id() == node_visitor.nodes_[2]->id()); - CHECK(graph.start()->id() == node_visitor.nodes_[3]->id()); - CHECK(n3->id() == node_visitor.nodes_[4]->id()); -} - - TEST(TestPrintNodeGraphToNodeGraphviz) { GraphWithStartNodeTester graph; Node* n2 = graph.NewNode(&dummy_operator, graph.start()); diff --git a/deps/v8/test/cctest/compiler/test-node.cc b/deps/v8/test/cctest/compiler/test-node.cc index 2c51e26f86..5bb21f585d 100644 --- a/deps/v8/test/cctest/compiler/test-node.cc +++ b/deps/v8/test/cctest/compiler/test-node.cc @@ -13,32 +13,143 @@ using namespace v8::internal; using namespace v8::internal::compiler; +#define NONE reinterpret_cast<Node*>(1) + static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite, "dummy", 0, 0, 0, 1, 0, 0); +#define CHECK_USES(node, ...) \ + do { \ + Node* __array[] = {__VA_ARGS__}; \ + int __size = \ + __array[0] != NONE ? static_cast<int>(arraysize(__array)) : 0; \ + CheckUseChain(node, __array, __size); \ + } while (false) + + +typedef std::multiset<Node*, std::less<Node*>> NodeMSet; + +static void CheckUseChain(Node* node, Node** uses, int use_count) { + // Check ownership. + if (use_count == 1) CHECK(node->OwnedBy(uses[0])); + if (use_count > 1) { + for (int i = 0; i < use_count; i++) { + CHECK(!node->OwnedBy(uses[i])); + } + } + + // Check the self-reported use count. + CHECK_EQ(use_count, node->UseCount()); + + // Build the expectation set. + NodeMSet expect_set; + for (int i = 0; i < use_count; i++) { + expect_set.insert(uses[i]); + } + + { + // Check that iterating over the uses gives the right counts. + NodeMSet use_set; + for (auto use : node->uses()) { + use_set.insert(use); + } + CHECK(expect_set == use_set); + } + + { + // Check that iterating over the use edges gives the right counts, + // input indices, from(), and to() pointers. + NodeMSet use_set; + for (auto edge : node->use_edges()) { + CHECK_EQ(node, edge.to()); + CHECK_EQ(node, edge.from()->InputAt(edge.index())); + use_set.insert(edge.from()); + } + CHECK(expect_set == use_set); + } + + { + // Check the use nodes actually have the node as inputs. + for (Node* use : node->uses()) { + size_t count = 0; + for (Node* input : use->inputs()) { + if (input == node) count++; + } + CHECK_EQ(count, expect_set.count(use)); + } + } +} + + +#define CHECK_INPUTS(node, ...) \ + do { \ + Node* __array[] = {__VA_ARGS__}; \ + int __size = \ + __array[0] != NONE ? static_cast<int>(arraysize(__array)) : 0; \ + CheckInputs(node, __array, __size); \ + } while (false) + + +static void CheckInputs(Node* node, Node** inputs, int input_count) { + CHECK_EQ(input_count, node->InputCount()); + // Check InputAt(). + for (int i = 0; i < static_cast<int>(input_count); i++) { + CHECK_EQ(inputs[i], node->InputAt(i)); + } + + // Check input iterator. + int index = 0; + for (Node* input : node->inputs()) { + CHECK_EQ(inputs[index], input); + index++; + } + + // Check use lists of inputs. + for (int i = 0; i < static_cast<int>(input_count); i++) { + Node* input = inputs[i]; + if (!input) continue; // skip null inputs + bool found = false; + // Check regular use list. + for (Node* use : input->uses()) { + if (use == node) { + found = true; + break; + } + } + CHECK(found); + int count = 0; + // Check use edge list. + for (auto edge : input->use_edges()) { + if (edge.from() == node && edge.to() == input && edge.index() == i) { + count++; + } + } + CHECK_EQ(1, count); + } +} + + TEST(NodeUseIteratorReplaceUses) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0); Node* n3 = graph.NewNode(&dummy_operator); - auto i1(n0->uses().begin()); - CHECK_EQ(n1, *i1); - ++i1; - CHECK_EQ(n2, *i1); + + CHECK_USES(n0, n1, n2); + + CHECK_INPUTS(n1, n0); + CHECK_INPUTS(n2, n0); + n0->ReplaceUses(n3); - auto i2(n3->uses().begin()); - CHECK_EQ(n1, *i2); - ++i2; - CHECK_EQ(n2, *i2); - auto i3(n1->inputs().begin()); - CHECK_EQ(n3, *i3); - ++i3; - CHECK(n1->inputs().end() == i3); - auto i4(n2->inputs().begin()); - CHECK_EQ(n3, *i4); - ++i4; - CHECK(n2->inputs().end() == i4); + + CHECK_USES(n0, NONE); + CHECK_USES(n1, NONE); + CHECK_USES(n2, NONE); + CHECK_USES(n3, n1, n2); + + CHECK_INPUTS(n1, n3); + CHECK_INPUTS(n2, n3); } @@ -46,21 +157,22 @@ TEST(NodeUseIteratorReplaceUsesSelf) { GraphTester graph; Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); - Node* n3 = graph.NewNode(&dummy_operator); + + CHECK_USES(n0, n1); + CHECK_USES(n1, NONE); n1->ReplaceInput(0, n1); // Create self-reference. - auto i1(n1->uses().begin()); - CHECK_EQ(n1, *i1); + CHECK_USES(n0, NONE); + CHECK_USES(n1, n1); - n1->ReplaceUses(n3); + Node* n2 = graph.NewNode(&dummy_operator); - CHECK(n1->uses().begin() == n1->uses().end()); + n1->ReplaceUses(n2); - auto i2(n3->uses().begin()); - CHECK_EQ(n1, *i2); - ++i2; - CHECK(n1->uses().end() == i2); + CHECK_USES(n0, NONE); + CHECK_USES(n1, NONE); + CHECK_USES(n2, n1); } @@ -70,48 +182,22 @@ TEST(ReplaceInput) { Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator); Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2); - auto i1(n3->inputs().begin()); - CHECK(n0 == *i1); - CHECK_EQ(n0, n3->InputAt(0)); - ++i1; - CHECK_EQ(n1, *i1); - CHECK_EQ(n1, n3->InputAt(1)); - ++i1; - CHECK_EQ(n2, *i1); - CHECK_EQ(n2, n3->InputAt(2)); - ++i1; - CHECK(i1 == n3->inputs().end()); - - auto i2(n1->uses().begin()); - CHECK_EQ(n3, *i2); - ++i2; - CHECK(i2 == n1->uses().end()); - Node* n4 = graph.NewNode(&dummy_operator); - auto i3(n4->uses().begin()); - CHECK(i3 == n4->uses().end()); + + CHECK_USES(n0, n3); + CHECK_USES(n1, n3); + CHECK_USES(n2, n3); + CHECK_USES(n3, NONE); + CHECK_USES(n4, NONE); + + CHECK_INPUTS(n3, n0, n1, n2); n3->ReplaceInput(1, n4); - auto i4(n1->uses().begin()); - CHECK(i4 == n1->uses().end()); - - auto i5(n4->uses().begin()); - CHECK_EQ(n3, *i5); - ++i5; - CHECK(i5 == n4->uses().end()); - - auto i6(n3->inputs().begin()); - CHECK(n0 == *i6); - CHECK_EQ(n0, n3->InputAt(0)); - ++i6; - CHECK_EQ(n4, *i6); - CHECK_EQ(n4, n3->InputAt(1)); - ++i6; - CHECK_EQ(n2, *i6); - CHECK_EQ(n2, n3->InputAt(2)); - ++i6; - CHECK(i6 == n3->inputs().end()); + CHECK_USES(n1, NONE); + CHECK_USES(n4, n3); + + CHECK_INPUTS(n3, n0, n4, n2); } @@ -169,16 +255,19 @@ TEST(Uses) { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); - CHECK_EQ(1, n0->UseCount()); - printf("A: %d vs %d\n", n0->UseAt(0)->id(), n1->id()); - CHECK(n0->UseAt(0) == n1); + + CHECK_USES(n0, n1); + CHECK_USES(n1, NONE); + Node* n2 = graph.NewNode(&dummy_operator, n0); - CHECK_EQ(2, n0->UseCount()); - printf("B: %d vs %d\n", n0->UseAt(1)->id(), n2->id()); - CHECK(n0->UseAt(1) == n2); + + CHECK_USES(n0, n1, n2); + CHECK_USES(n2, NONE); + Node* n3 = graph.NewNode(&dummy_operator, n0); - CHECK_EQ(3, n0->UseCount()); - CHECK(n0->UseAt(2) == n3); + + CHECK_USES(n0, n1, n2, n3); + CHECK_USES(n3, NONE); } @@ -189,39 +278,23 @@ TEST(Inputs) { Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0); Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2); - CHECK_EQ(3, n3->InputCount()); - CHECK(n3->InputAt(0) == n0); - CHECK(n3->InputAt(1) == n1); - CHECK(n3->InputAt(2) == n2); + + CHECK_INPUTS(n3, n0, n1, n2); + Node* n4 = graph.NewNode(&dummy_operator, n0, n1, n2); n3->AppendInput(graph.zone(), n4); - CHECK_EQ(4, n3->InputCount()); - CHECK(n3->InputAt(0) == n0); - CHECK(n3->InputAt(1) == n1); - CHECK(n3->InputAt(2) == n2); - CHECK(n3->InputAt(3) == n4); - Node* n5 = graph.NewNode(&dummy_operator, n4); + + CHECK_INPUTS(n3, n0, n1, n2, n4); + CHECK_USES(n4, n3); + n3->AppendInput(graph.zone(), n4); - CHECK_EQ(5, n3->InputCount()); - CHECK(n3->InputAt(0) == n0); - CHECK(n3->InputAt(1) == n1); - CHECK(n3->InputAt(2) == n2); - CHECK(n3->InputAt(3) == n4); - CHECK(n3->InputAt(4) == n4); - - // Make sure uses have been hooked op correctly. - Node::Uses uses(n4->uses()); - auto current = uses.begin(); - CHECK(current != uses.end()); - CHECK(*current == n3); - ++current; - CHECK(current != uses.end()); - CHECK(*current == n5); - ++current; - CHECK(current != uses.end()); - CHECK(*current == n3); - ++current; - CHECK(current == uses.end()); + + CHECK_INPUTS(n3, n0, n1, n2, n4, n4); + CHECK_USES(n4, n3, n3); + + Node* n5 = graph.NewNode(&dummy_operator, n4); + + CHECK_USES(n4, n3, n3, n5); } @@ -232,17 +305,25 @@ TEST(RemoveInput) { Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); + CHECK_INPUTS(n0, NONE); + CHECK_INPUTS(n1, n0); + CHECK_INPUTS(n2, n0, n1); + CHECK_USES(n0, n1, n2); + n1->RemoveInput(0); - CHECK_EQ(0, n1->InputCount()); - CHECK_EQ(1, n0->UseCount()); + CHECK_INPUTS(n1, NONE); + CHECK_USES(n0, n2); n2->RemoveInput(0); - CHECK_EQ(1, n2->InputCount()); - CHECK_EQ(0, n0->UseCount()); - CHECK_EQ(1, n1->UseCount()); + CHECK_INPUTS(n2, n1); + CHECK_USES(n0, NONE); + CHECK_USES(n1, n2); n2->RemoveInput(0); - CHECK_EQ(0, n2->InputCount()); + CHECK_INPUTS(n2, NONE); + CHECK_USES(n0, NONE); + CHECK_USES(n1, NONE); + CHECK_USES(n2, NONE); } @@ -253,33 +334,17 @@ TEST(AppendInputsAndIterator) { Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); - Node::InputEdges inputs(n2->input_edges()); - Node::InputEdges::iterator current = inputs.begin(); - CHECK(current != inputs.end()); - CHECK((*current).to() == n0); - ++current; - CHECK(current != inputs.end()); - CHECK((*current).to() == n1); - ++current; - CHECK(current == inputs.end()); + CHECK_INPUTS(n0, NONE); + CHECK_INPUTS(n1, n0); + CHECK_INPUTS(n2, n0, n1); + CHECK_USES(n0, n1, n2); Node* n3 = graph.NewNode(&dummy_operator); + n2->AppendInput(graph.zone(), n3); - inputs = n2->input_edges(); - current = inputs.begin(); - CHECK(current != inputs.end()); - CHECK((*current).to() == n0); - CHECK_EQ(0, (*current).index()); - ++current; - CHECK(current != inputs.end()); - CHECK((*current).to() == n1); - CHECK_EQ(1, (*current).index()); - ++current; - CHECK(current != inputs.end()); - CHECK((*current).to() == n3); - CHECK_EQ(2, (*current).index()); - ++current; - CHECK(current == inputs.end()); + + CHECK_INPUTS(n2, n0, n1, n3); + CHECK_USES(n3, n2); } @@ -289,15 +354,23 @@ TEST(NullInputsSimple) { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); - CHECK_EQ(2, n2->InputCount()); - - CHECK(n0 == n2->InputAt(0)); - CHECK(n1 == n2->InputAt(1)); - CHECK_EQ(2, n0->UseCount()); - n2->ReplaceInput(0, NULL); - CHECK(NULL == n2->InputAt(0)); - CHECK(n1 == n2->InputAt(1)); - CHECK_EQ(1, n0->UseCount()); + + CHECK_INPUTS(n0, NONE); + CHECK_INPUTS(n1, n0); + CHECK_INPUTS(n2, n0, n1); + CHECK_USES(n0, n1, n2); + + n2->ReplaceInput(0, nullptr); + + CHECK_INPUTS(n2, NULL, n1); + + CHECK_USES(n0, n1); + + n2->ReplaceInput(1, nullptr); + + CHECK_INPUTS(n2, NULL, NULL); + + CHECK_USES(n1, NONE); } @@ -310,17 +383,16 @@ TEST(NullInputsAppended) { Node* n3 = graph.NewNode(&dummy_operator, n0); n3->AppendInput(graph.zone(), n1); n3->AppendInput(graph.zone(), n2); - CHECK_EQ(3, n3->InputCount()); - CHECK(n0 == n3->InputAt(0)); - CHECK(n1 == n3->InputAt(1)); - CHECK(n2 == n3->InputAt(2)); - CHECK_EQ(1, n1->UseCount()); + CHECK_INPUTS(n3, n0, n1, n2); + CHECK_USES(n0, n1, n2, n3); + CHECK_USES(n1, n3); + CHECK_USES(n2, n3); + n3->ReplaceInput(1, NULL); - CHECK(n0 == n3->InputAt(0)); - CHECK(NULL == n3->InputAt(1)); - CHECK(n2 == n3->InputAt(2)); - CHECK_EQ(0, n1->UseCount()); + CHECK_USES(n1, NONE); + + CHECK_INPUTS(n3, n0, NULL, n2); } @@ -331,26 +403,23 @@ TEST(ReplaceUsesFromAppendedInputs) { Node* n1 = graph.NewNode(&dummy_operator, n0); Node* n2 = graph.NewNode(&dummy_operator, n0); Node* n3 = graph.NewNode(&dummy_operator); + + CHECK_INPUTS(n2, n0); + n2->AppendInput(graph.zone(), n1); + CHECK_INPUTS(n2, n0, n1); + CHECK_USES(n1, n2); + n2->AppendInput(graph.zone(), n0); - CHECK_EQ(0, n3->UseCount()); - CHECK_EQ(3, n0->UseCount()); + CHECK_INPUTS(n2, n0, n1, n0); + CHECK_USES(n1, n2); + CHECK_USES(n0, n2, n1, n2); + n0->ReplaceUses(n3); - CHECK_EQ(0, n0->UseCount()); - CHECK_EQ(3, n3->UseCount()); - - Node::Uses uses(n3->uses()); - auto current = uses.begin(); - CHECK(current != uses.end()); - CHECK(*current == n1); - ++current; - CHECK(current != uses.end()); - CHECK(*current == n2); - ++current; - CHECK(current != uses.end()); - CHECK(*current == n2); - ++current; - CHECK(current == uses.end()); + + CHECK_USES(n0, NONE); + CHECK_INPUTS(n2, n3, n1, n3); + CHECK_USES(n3, n2, n1, n2); } @@ -378,17 +447,16 @@ TEST(TrimInputCountInline) { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); n1->TrimInputCount(1); - CHECK_EQ(1, n1->InputCount()); - CHECK_EQ(n0, n1->InputAt(0)); - CHECK_EQ(1, n0->UseCount()); + CHECK_INPUTS(n1, n0); + CHECK_USES(n0, n1); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator, n0); n1->TrimInputCount(0); - CHECK_EQ(0, n1->InputCount()); - CHECK_EQ(0, n0->UseCount()); + CHECK_INPUTS(n1, NONE); + CHECK_USES(n0, NONE); } { @@ -396,10 +464,9 @@ TEST(TrimInputCountInline) { Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); n2->TrimInputCount(2); - CHECK_EQ(2, n2->InputCount()); - CHECK_EQ(1, n0->UseCount()); - CHECK_EQ(1, n1->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, n0, n1); + CHECK_USES(n0, n2); + CHECK_USES(n1, n2); } { @@ -407,10 +474,9 @@ TEST(TrimInputCountInline) { Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); n2->TrimInputCount(1); - CHECK_EQ(1, n2->InputCount()); - CHECK_EQ(1, n0->UseCount()); - CHECK_EQ(0, n1->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, n0); + CHECK_USES(n0, n2); + CHECK_USES(n1, NONE); } { @@ -418,28 +484,25 @@ TEST(TrimInputCountInline) { Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0, n1); n2->TrimInputCount(0); - CHECK_EQ(0, n2->InputCount()); - CHECK_EQ(0, n0->UseCount()); - CHECK_EQ(0, n1->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, NONE); + CHECK_USES(n0, NONE); + CHECK_USES(n1, NONE); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0, n0); n2->TrimInputCount(1); - CHECK_EQ(1, n2->InputCount()); - CHECK_EQ(1, n0->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, n0); + CHECK_USES(n0, n2); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0, n0); n2->TrimInputCount(0); - CHECK_EQ(0, n2->InputCount()); - CHECK_EQ(0, n0->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, NONE); + CHECK_USES(n0, NONE); } } @@ -451,10 +514,12 @@ TEST(TrimInputCountOutOfLine1) { Node* n0 = graph.NewNode(&dummy_operator); Node* n1 = graph.NewNode(&dummy_operator); n1->AppendInput(graph.zone(), n0); + CHECK_INPUTS(n1, n0); + CHECK_USES(n0, n1); + n1->TrimInputCount(1); - CHECK_EQ(1, n1->InputCount()); - CHECK_EQ(n0, n1->InputAt(0)); - CHECK_EQ(1, n0->UseCount()); + CHECK_INPUTS(n1, n0); + CHECK_USES(n0, n1); } { @@ -473,14 +538,12 @@ TEST(TrimInputCountOutOfLine1) { Node* n2 = graph.NewNode(&dummy_operator); n2->AppendInput(graph.zone(), n0); n2->AppendInput(graph.zone(), n1); - CHECK_EQ(2, n2->InputCount()); + CHECK_INPUTS(n2, n0, n1); n2->TrimInputCount(2); - CHECK_EQ(2, n2->InputCount()); - CHECK_EQ(n0, n2->InputAt(0)); - CHECK_EQ(n1, n2->InputAt(1)); - CHECK_EQ(1, n0->UseCount()); - CHECK_EQ(1, n1->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, n0, n1); + CHECK_USES(n0, n2); + CHECK_USES(n1, n2); + CHECK_USES(n2, NONE); } { @@ -489,13 +552,12 @@ TEST(TrimInputCountOutOfLine1) { Node* n2 = graph.NewNode(&dummy_operator); n2->AppendInput(graph.zone(), n0); n2->AppendInput(graph.zone(), n1); - CHECK_EQ(2, n2->InputCount()); + CHECK_INPUTS(n2, n0, n1); n2->TrimInputCount(1); - CHECK_EQ(1, n2->InputCount()); - CHECK_EQ(n0, n2->InputAt(0)); - CHECK_EQ(1, n0->UseCount()); - CHECK_EQ(0, n1->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, n0); + CHECK_USES(n0, n2); + CHECK_USES(n1, NONE); + CHECK_USES(n2, NONE); } { @@ -504,12 +566,12 @@ TEST(TrimInputCountOutOfLine1) { Node* n2 = graph.NewNode(&dummy_operator); n2->AppendInput(graph.zone(), n0); n2->AppendInput(graph.zone(), n1); - CHECK_EQ(2, n2->InputCount()); + CHECK_INPUTS(n2, n0, n1); n2->TrimInputCount(0); - CHECK_EQ(0, n2->InputCount()); - CHECK_EQ(0, n0->UseCount()); - CHECK_EQ(0, n1->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, NONE); + CHECK_USES(n0, NONE); + CHECK_USES(n1, NONE); + CHECK_USES(n2, NONE); } { @@ -517,12 +579,11 @@ TEST(TrimInputCountOutOfLine1) { Node* n2 = graph.NewNode(&dummy_operator); n2->AppendInput(graph.zone(), n0); n2->AppendInput(graph.zone(), n0); - CHECK_EQ(2, n2->InputCount()); - CHECK_EQ(2, n0->UseCount()); + CHECK_INPUTS(n2, n0, n0); + CHECK_USES(n0, n2, n2); n2->TrimInputCount(1); - CHECK_EQ(1, n2->InputCount()); - CHECK_EQ(1, n0->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, n0); + CHECK_USES(n0, n2); } { @@ -530,12 +591,11 @@ TEST(TrimInputCountOutOfLine1) { Node* n2 = graph.NewNode(&dummy_operator); n2->AppendInput(graph.zone(), n0); n2->AppendInput(graph.zone(), n0); - CHECK_EQ(2, n2->InputCount()); - CHECK_EQ(2, n0->UseCount()); + CHECK_INPUTS(n2, n0, n0); + CHECK_USES(n0, n2, n2); n2->TrimInputCount(0); - CHECK_EQ(0, n2->InputCount()); - CHECK_EQ(0, n0->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, NONE); + CHECK_USES(n0, NONE); } } @@ -548,14 +608,12 @@ TEST(TrimInputCountOutOfLine2) { Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0); n2->AppendInput(graph.zone(), n1); - CHECK_EQ(2, n2->InputCount()); + CHECK_INPUTS(n2, n0, n1); n2->TrimInputCount(2); - CHECK_EQ(2, n2->InputCount()); - CHECK_EQ(n0, n2->InputAt(0)); - CHECK_EQ(n1, n2->InputAt(1)); - CHECK_EQ(1, n0->UseCount()); - CHECK_EQ(1, n1->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, n0, n1); + CHECK_USES(n0, n2); + CHECK_USES(n1, n2); + CHECK_USES(n2, NONE); } { @@ -563,13 +621,12 @@ TEST(TrimInputCountOutOfLine2) { Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0); n2->AppendInput(graph.zone(), n1); - CHECK_EQ(2, n2->InputCount()); + CHECK_INPUTS(n2, n0, n1); n2->TrimInputCount(1); - CHECK_EQ(1, n2->InputCount()); - CHECK_EQ(n0, n2->InputAt(0)); - CHECK_EQ(1, n0->UseCount()); - CHECK_EQ(0, n1->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, n0); + CHECK_USES(n0, n2); + CHECK_USES(n1, NONE); + CHECK_USES(n2, NONE); } { @@ -577,24 +634,24 @@ TEST(TrimInputCountOutOfLine2) { Node* n1 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0); n2->AppendInput(graph.zone(), n1); - CHECK_EQ(2, n2->InputCount()); + CHECK_INPUTS(n2, n0, n1); n2->TrimInputCount(0); - CHECK_EQ(0, n2->InputCount()); - CHECK_EQ(0, n0->UseCount()); - CHECK_EQ(0, n1->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, NONE); + CHECK_USES(n0, NONE); + CHECK_USES(n1, NONE); + CHECK_USES(n2, NONE); } { Node* n0 = graph.NewNode(&dummy_operator); Node* n2 = graph.NewNode(&dummy_operator, n0); n2->AppendInput(graph.zone(), n0); - CHECK_EQ(2, n2->InputCount()); - CHECK_EQ(2, n0->UseCount()); + CHECK_INPUTS(n2, n0, n0); + CHECK_USES(n0, n2, n2); n2->TrimInputCount(1); - CHECK_EQ(1, n2->InputCount()); - CHECK_EQ(1, n0->UseCount()); - CHECK_EQ(0, n2->UseCount()); + CHECK_INPUTS(n2, n0); + CHECK_USES(n0, n2); + CHECK_USES(n2, NONE); } { @@ -611,7 +668,7 @@ TEST(TrimInputCountOutOfLine2) { } -TEST(RemoveAllInputs) { +TEST(NullAllInputs) { GraphTester graph; for (int i = 0; i < 2; i++) { @@ -620,27 +677,27 @@ TEST(RemoveAllInputs) { Node* n2; if (i == 0) { n2 = graph.NewNode(&dummy_operator, n0, n1); + CHECK_INPUTS(n2, n0, n1); } else { n2 = graph.NewNode(&dummy_operator, n0); + CHECK_INPUTS(n2, n0); n2->AppendInput(graph.zone(), n1); // with out-of-line input. + CHECK_INPUTS(n2, n0, n1); } - n0->RemoveAllInputs(); - CHECK_EQ(0, n0->InputCount()); + n0->NullAllInputs(); + CHECK_INPUTS(n0, NONE); - CHECK_EQ(2, n0->UseCount()); - n1->RemoveAllInputs(); - CHECK_EQ(1, n1->InputCount()); - CHECK_EQ(1, n0->UseCount()); - CHECK(!n1->InputAt(0)); + CHECK_USES(n0, n1, n2); + n1->NullAllInputs(); + CHECK_INPUTS(n1, NULL); + CHECK_INPUTS(n2, n0, n1); + CHECK_USES(n0, n2); - CHECK_EQ(1, n1->UseCount()); - n2->RemoveAllInputs(); - CHECK_EQ(2, n2->InputCount()); - CHECK_EQ(0, n0->UseCount()); - CHECK_EQ(0, n1->UseCount()); - CHECK(!n2->InputAt(0)); - CHECK(!n2->InputAt(1)); + n2->NullAllInputs(); + CHECK_INPUTS(n1, NULL); + CHECK_INPUTS(n2, NULL, NULL); + CHECK_USES(n0, NONE); } { @@ -648,11 +705,53 @@ TEST(RemoveAllInputs) { Node* n1 = graph.NewNode(&dummy_operator, n0); n1->ReplaceInput(0, n1); // self-reference. - CHECK_EQ(0, n0->UseCount()); - CHECK_EQ(1, n1->UseCount()); - n1->RemoveAllInputs(); - CHECK_EQ(1, n1->InputCount()); - CHECK_EQ(0, n1->UseCount()); - CHECK(!n1->InputAt(0)); + CHECK_INPUTS(n0, NONE); + CHECK_INPUTS(n1, n1); + CHECK_USES(n0, NONE); + CHECK_USES(n1, n1); + n1->NullAllInputs(); + + CHECK_INPUTS(n0, NONE); + CHECK_INPUTS(n1, NULL); + CHECK_USES(n0, NONE); + CHECK_USES(n1, NONE); + } +} + + +TEST(AppendAndTrim) { + GraphTester graph; + + Node* nodes[] = { + graph.NewNode(&dummy_operator), graph.NewNode(&dummy_operator), + graph.NewNode(&dummy_operator), graph.NewNode(&dummy_operator), + graph.NewNode(&dummy_operator)}; + + int max = static_cast<int>(arraysize(nodes)); + + Node* last = graph.NewNode(&dummy_operator); + + for (int i = 0; i < max; i++) { + last->AppendInput(graph.zone(), nodes[i]); + CheckInputs(last, nodes, i + 1); + + for (int j = 0; j < max; j++) { + if (j <= i) CHECK_USES(nodes[j], last); + if (j > i) CHECK_USES(nodes[j], NONE); + } + + CHECK_USES(last, NONE); + } + + for (int i = max; i >= 0; i--) { + last->TrimInputCount(i); + CheckInputs(last, nodes, i); + + for (int j = 0; j < i; j++) { + if (j < i) CHECK_USES(nodes[j], last); + if (j >= i) CHECK_USES(nodes[j], NONE); + } + + CHECK_USES(last, NONE); } } diff --git a/deps/v8/test/cctest/compiler/test-osr.cc b/deps/v8/test/cctest/compiler/test-osr.cc index e3963901a5..d2171188f8 100644 --- a/deps/v8/test/cctest/compiler/test-osr.cc +++ b/deps/v8/test/cctest/compiler/test-osr.cc @@ -36,6 +36,8 @@ static int CheckInputs(Node* node, Node* i0 = NULL, Node* i1 = NULL, static Operator kIntLt(IrOpcode::kInt32LessThan, Operator::kPure, "Int32LessThan", 2, 0, 0, 1, 0, 0); +static Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0, + 0, 1, 0, 0); static const int kMaxOsrValues = 10; @@ -122,7 +124,12 @@ class OsrDeconstructorTester : public HandleAndZoneScope { CHECK(!nodes.IsLive(osr_normal_entry)); CHECK(!nodes.IsLive(osr_loop_entry)); // No dangling nodes should be left over. - CHECK_EQ(0u, nodes.gray.size()); + for (Node* const node : nodes.live) { + for (Node* const use : node->uses()) { + CHECK(std::find(nodes.live.begin(), nodes.live.end(), use) != + nodes.live.end()); + } + } } }; @@ -484,3 +491,105 @@ TEST(Deconstruct_osr_nested2) { CheckInputs(new_outer_phi, new_entry_phi, new_inner_phi, T.jsgraph.ZeroConstant(), new_outer_loop); } + + +Node* MakeCounter(JSGraph* jsgraph, Node* start, Node* loop) { + int count = loop->InputCount(); + NodeVector tmp_inputs(jsgraph->graph()->zone()); + for (int i = 0; i < count; i++) { + tmp_inputs.push_back(start); + } + tmp_inputs.push_back(loop); + + Node* phi = jsgraph->graph()->NewNode( + jsgraph->common()->Phi(kMachInt32, count), count + 1, &tmp_inputs[0]); + Node* inc = jsgraph->graph()->NewNode(&kIntAdd, phi, jsgraph->OneConstant()); + + for (int i = 1; i < count; i++) { + phi->ReplaceInput(i, inc); + } + return phi; +} + + +TEST(Deconstruct_osr_nested3) { + OsrDeconstructorTester T(1); + + // outermost loop. + While loop0(T, T.p0, false, 1); + Node* loop0_cntr = MakeCounter(&T.jsgraph, T.p0, loop0.loop); + loop0.branch->ReplaceInput(0, loop0_cntr); + + // middle loop. + Node* loop1 = T.graph.NewNode(T.common.Loop(2), loop0.if_true, T.self); + loop1->ReplaceInput(0, loop0.if_true); + Node* loop1_phi = + T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), loop0_cntr, loop0_cntr); + + // innermost (OSR) loop. + While loop2(T, T.p0, true, 1); + loop2.loop->ReplaceInput(0, loop1); + + Node* loop2_cntr = MakeCounter(&T.jsgraph, loop1_phi, loop2.loop); + loop2_cntr->ReplaceInput(1, T.osr_values[0]); + Node* osr_phi = loop2_cntr; + Node* loop2_inc = loop2_cntr->InputAt(2); + loop2.branch->ReplaceInput(0, loop2_cntr); + + loop1_phi->ReplaceInput(1, loop2_cntr); + loop0_cntr->ReplaceInput(1, loop2_cntr); + + // Branch to either the outer or middle loop. + Node* branch = T.graph.NewNode(T.common.Branch(), loop2_cntr, loop2.exit); + Node* if_true = T.graph.NewNode(T.common.IfTrue(), branch); + Node* if_false = T.graph.NewNode(T.common.IfFalse(), branch); + + loop0.loop->ReplaceInput(1, if_true); + loop1->ReplaceInput(1, if_false); + + Node* ret = + T.graph.NewNode(T.common.Return(), loop0_cntr, T.start, loop0.exit); + Node* end = T.graph.NewNode(T.common.End(), ret); + T.graph.SetEnd(end); + + T.DeconstructOsr(); + + // Check structure of deconstructed graph. + // Check loop2 (OSR loop) is directly connected to start. + CheckInputs(loop2.loop, T.start, loop2.if_true); + CheckInputs(osr_phi, T.osr_values[0], loop2_inc, loop2.loop); + CheckInputs(loop2.branch, osr_phi, loop2.loop); + CheckInputs(loop2.if_true, loop2.branch); + CheckInputs(loop2.exit, loop2.branch); + CheckInputs(branch, osr_phi, loop2.exit); + CheckInputs(if_true, branch); + CheckInputs(if_false, branch); + + // Check structure of new_loop1. + Node* new_loop1_loop = FindSuccessor(if_false, IrOpcode::kLoop); + // TODO(titzer): check the internal copy of loop2. + USE(new_loop1_loop); + + // Check structure of new_loop0. + Node* new_loop0_loop_entry = FindSuccessor(if_true, IrOpcode::kMerge); + Node* new_loop0_loop = FindSuccessor(new_loop0_loop_entry, IrOpcode::kLoop); + // TODO(titzer): check the internal copies of loop1 and loop2. + + Node* new_loop0_branch = FindSuccessor(new_loop0_loop, IrOpcode::kBranch); + Node* new_loop0_if_true = FindSuccessor(new_loop0_branch, IrOpcode::kIfTrue); + Node* new_loop0_exit = FindSuccessor(new_loop0_branch, IrOpcode::kIfFalse); + + USE(new_loop0_if_true); + + Node* new_ret = T.graph.end()->InputAt(0); + CHECK_EQ(IrOpcode::kReturn, new_ret->opcode()); + + Node* new_loop0_phi = new_ret->InputAt(0); + CHECK_EQ(IrOpcode::kPhi, new_loop0_phi->opcode()); + CHECK_EQ(new_loop0_loop, NodeProperties::GetControlInput(new_loop0_phi)); + CHECK_EQ(new_loop0_phi, FindSuccessor(new_loop0_loop, IrOpcode::kPhi)); + + // Check that the return returns the phi from the OSR loop and control + // depends on the copy of the outer loop0. + CheckInputs(new_ret, new_loop0_phi, T.graph.start(), new_loop0_exit); +} diff --git a/deps/v8/test/cctest/compiler/test-pipeline.cc b/deps/v8/test/cctest/compiler/test-pipeline.cc index 98b0baeefd..b67af6ecf7 100644 --- a/deps/v8/test/cctest/compiler/test-pipeline.cc +++ b/deps/v8/test/cctest/compiler/test-pipeline.cc @@ -17,13 +17,13 @@ using namespace v8::internal; using namespace v8::internal::compiler; TEST(PipelineAdd) { - InitializedHandleScope handles; + HandleAndZoneScope handles; const char* source = "(function(a,b) { return a + b; })"; Handle<JSFunction> function = v8::Utils::OpenHandle( *v8::Handle<v8::Function>::Cast(CompileRun(source))); - CompilationInfoWithZone info(function); - - CHECK(Compiler::ParseAndAnalyze(&info)); + ParseInfo parse_info(handles.main_zone(), function); + CHECK(Compiler::ParseAndAnalyze(&parse_info)); + CompilationInfo info(&parse_info); Pipeline pipeline(&info); #if V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/test-run-inlining.cc b/deps/v8/test/cctest/compiler/test-run-inlining.cc index 19b96bad50..a6d76e4d57 100644 --- a/deps/v8/test/cctest/compiler/test-run-inlining.cc +++ b/deps/v8/test/cctest/compiler/test-run-inlining.cc @@ -11,9 +11,11 @@ using namespace v8::internal; using namespace v8::internal::compiler; +namespace { + // Helper to determine inline count via JavaScriptFrame::GetInlineCount. // Note that a count of 1 indicates that no inlining has occured. -static void AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value>& args) { +void AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value>& args) { StackTraceFrameIterator it(CcTest::i_isolate()); int frames_seen = 0; JavaScriptFrame* topmost = it.frame(); @@ -30,7 +32,7 @@ static void AssertInlineCount(const v8::FunctionCallbackInfo<v8::Value>& args) { } -static void InstallAssertInlineCountHelper(v8::Isolate* isolate) { +void InstallAssertInlineCountHelper(v8::Isolate* isolate) { v8::Local<v8::Context> context = isolate->GetCurrentContext(); v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate, AssertInlineCount); @@ -38,9 +40,15 @@ static void InstallAssertInlineCountHelper(v8::Isolate* isolate) { } -static uint32_t kInlineFlags = CompilationInfo::kInliningEnabled | - CompilationInfo::kContextSpecializing | - CompilationInfo::kTypingEnabled; +const uint32_t kBuiltinInlineFlags = CompilationInfo::kBuiltinInliningEnabled | + CompilationInfo::kContextSpecializing | + CompilationInfo::kTypingEnabled; + +const uint32_t kInlineFlags = CompilationInfo::kInliningEnabled | + CompilationInfo::kContextSpecializing | + CompilationInfo::kTypingEnabled; + +} // namespace TEST(SimpleInlining) { @@ -320,6 +328,53 @@ TEST(InlineLoopGuardedTwice) { } +TEST(InlineLoopUnguardedEmpty) { + FLAG_turbo_deoptimization = true; + FunctionTester T( + "(function () {" + " function foo(s) { AssertInlineCount(2); while (s); return s; };" + " function bar(s, t) { return foo(s); };" + " return bar;" + "})();", + kInlineFlags); + + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4)); +} + + +TEST(InlineLoopUnguardedOnce) { + FLAG_turbo_deoptimization = true; + FunctionTester T( + "(function () {" + " function foo(s) { AssertInlineCount(2); while (s) {" + " s = s - 1; }; return s; };" + " function bar(s, t) { return foo(s); };" + " return bar;" + "})();", + kInlineFlags); + + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4)); +} + + +TEST(InlineLoopUnguardedTwice) { + FLAG_turbo_deoptimization = true; + FunctionTester T( + "(function () {" + " function foo(s) { AssertInlineCount(2); while (s > 0) {" + " s = s - 1; }; return s; };" + " function bar(s,t) { return foo(foo(s,t),t); };" + " return bar;" + "})();", + kInlineFlags); + + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4)); +} + + TEST(InlineStrictIntoNonStrict) { FLAG_turbo_deoptimization = true; FunctionTester T( @@ -437,4 +492,38 @@ TEST(InlineWithArguments) { T.CheckCall(T.true_value(), T.Val(12), T.Val(14)); } + +TEST(InlineBuiltin) { + FLAG_turbo_deoptimization = true; + FunctionTester T( + "(function () {" + " function foo(s,t,u) { AssertInlineCount(2); return true; }" + " function bar() { return foo(); };" + " %SetInlineBuiltinFlag(foo);" + " return bar;" + "})();", + kBuiltinInlineFlags); + + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.true_value()); +} + + +TEST(InlineNestedBuiltin) { + FLAG_turbo_deoptimization = true; + FunctionTester T( + "(function () {" + " function foo(s,t,u) { AssertInlineCount(3); return true; }" + " function baz(s,t,u) { return foo(s,t,u); }" + " function bar() { return baz(); };" + " %SetInlineBuiltinFlag(foo);" + " %SetInlineBuiltinFlag(baz);" + " return bar;" + "})();", + kBuiltinInlineFlags); + + InstallAssertInlineCountHelper(CcTest::isolate()); + T.CheckCall(T.true_value()); +} + #endif // V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/test-run-intrinsics.cc b/deps/v8/test/cctest/compiler/test-run-intrinsics.cc index bd4038ed91..7fc5cc9758 100644 --- a/deps/v8/test/cctest/compiler/test-run-intrinsics.cc +++ b/deps/v8/test/cctest/compiler/test-run-intrinsics.cc @@ -10,29 +10,98 @@ using namespace v8::internal; using namespace v8::internal::compiler; uint32_t flags = CompilationInfo::kInliningEnabled; -TEST(IsSmi) { + +TEST(CallFunction) { FLAG_turbo_deoptimization = true; - FunctionTester T("(function(a) { return %_IsSmi(a); })", flags); + FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })", + flags); + CompileRun("function f(a,b,c) { return a + b + c + this.d; }"); - T.CheckTrue(T.Val(1)); - T.CheckFalse(T.Val(1.1)); - T.CheckFalse(T.Val(-0.0)); - T.CheckTrue(T.Val(-2)); - T.CheckFalse(T.Val(-2.3)); + T.CheckCall(T.Val(129), T.NewObject("({d:123})"), T.NewObject("f")); + T.CheckCall(T.Val("6x"), T.NewObject("({d:'x'})"), T.NewObject("f")); +} + + +TEST(ClassOf) { + FLAG_turbo_deoptimization = true; + FunctionTester T("(function(a) { return %_ClassOf(a); })", flags); + + T.CheckCall(T.Val("Function"), T.NewObject("(function() {})")); + T.CheckCall(T.Val("Array"), T.NewObject("([1])")); + T.CheckCall(T.Val("Object"), T.NewObject("({})")); + T.CheckCall(T.Val("RegExp"), T.NewObject("(/x/)")); + T.CheckCall(T.null(), T.undefined()); + T.CheckCall(T.null(), T.null()); + T.CheckCall(T.null(), T.Val("x")); + T.CheckCall(T.null(), T.Val(1)); +} + + +TEST(HeapObjectGetMap) { + FLAG_turbo_deoptimization = true; + FunctionTester T("(function(a) { return %_HeapObjectGetMap(a); })", flags); + + Factory* factory = T.main_isolate()->factory(); + T.CheckCall(factory->null_map(), T.null()); + T.CheckCall(factory->undefined_map(), T.undefined()); + T.CheckCall(factory->heap_number_map(), T.Val(3.1415)); + T.CheckCall(factory->symbol_map(), factory->NewSymbol()); +} + + +#define COUNTER_NAME "hurz" + +static int* LookupCounter(const char* name) { + static int counter = 1234; + return strcmp(name, COUNTER_NAME) == 0 ? &counter : nullptr; +} + + +TEST(IncrementStatsCounter) { + FLAG_turbo_deoptimization = true; + FLAG_native_code_counters = true; + reinterpret_cast<v8::Isolate*>(CcTest::InitIsolateOnce()) + ->SetCounterFunction(LookupCounter); + FunctionTester T( + "(function() { %_IncrementStatsCounter('" COUNTER_NAME "'); })", flags); + StatsCounter counter(T.main_isolate(), COUNTER_NAME); + if (!counter.Enabled()) return; + + int old_value = *counter.GetInternalPointer(); + T.CheckCall(T.undefined()); + CHECK_EQ(old_value + 1, *counter.GetInternalPointer()); +} + +#undef COUNTER_NAME + + +TEST(IsArray) { + FLAG_turbo_deoptimization = true; + FunctionTester T("(function(a) { return %_IsArray(a); })", flags); + + T.CheckFalse(T.NewObject("(function() {})")); + T.CheckTrue(T.NewObject("([1])")); + T.CheckFalse(T.NewObject("({})")); + T.CheckFalse(T.NewObject("(/x/)")); T.CheckFalse(T.undefined()); + T.CheckFalse(T.null()); + T.CheckFalse(T.Val("x")); + T.CheckFalse(T.Val(1)); } -TEST(IsNonNegativeSmi) { +TEST(IsFunction) { FLAG_turbo_deoptimization = true; - FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags); + FunctionTester T("(function(a) { return %_IsFunction(a); })", flags); - T.CheckTrue(T.Val(1)); - T.CheckFalse(T.Val(1.1)); - T.CheckFalse(T.Val(-0.0)); - T.CheckFalse(T.Val(-2)); - T.CheckFalse(T.Val(-2.3)); + T.CheckTrue(T.NewObject("(function() {})")); + T.CheckFalse(T.NewObject("([1])")); + T.CheckFalse(T.NewObject("({})")); + T.CheckFalse(T.NewObject("(/x/)")); T.CheckFalse(T.undefined()); + T.CheckFalse(T.null()); + T.CheckFalse(T.Val("x")); + T.CheckFalse(T.Val(1)); } @@ -49,18 +118,16 @@ TEST(IsMinusZero) { } -TEST(IsArray) { +TEST(IsNonNegativeSmi) { FLAG_turbo_deoptimization = true; - FunctionTester T("(function(a) { return %_IsArray(a); })", flags); + FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags); - T.CheckFalse(T.NewObject("(function() {})")); - T.CheckTrue(T.NewObject("([1])")); - T.CheckFalse(T.NewObject("({})")); - T.CheckFalse(T.NewObject("(/x/)")); + T.CheckTrue(T.Val(1)); + T.CheckFalse(T.Val(1.1)); + T.CheckFalse(T.Val(-0.0)); + T.CheckFalse(T.Val(-2)); + T.CheckFalse(T.Val(-2.3)); T.CheckFalse(T.undefined()); - T.CheckFalse(T.null()); - T.CheckFalse(T.Val("x")); - T.CheckFalse(T.Val(1)); } @@ -79,14 +146,14 @@ TEST(IsObject) { } -TEST(IsFunction) { +TEST(IsRegExp) { FLAG_turbo_deoptimization = true; - FunctionTester T("(function(a) { return %_IsFunction(a); })", flags); + FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags); - T.CheckTrue(T.NewObject("(function() {})")); + T.CheckFalse(T.NewObject("(function() {})")); T.CheckFalse(T.NewObject("([1])")); T.CheckFalse(T.NewObject("({})")); - T.CheckFalse(T.NewObject("(/x/)")); + T.CheckTrue(T.NewObject("(/x/)")); T.CheckFalse(T.undefined()); T.CheckFalse(T.null()); T.CheckFalse(T.Val("x")); @@ -94,33 +161,30 @@ TEST(IsFunction) { } -TEST(IsRegExp) { +TEST(IsSmi) { FLAG_turbo_deoptimization = true; - FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags); + FunctionTester T("(function(a) { return %_IsSmi(a); })", flags); - T.CheckFalse(T.NewObject("(function() {})")); - T.CheckFalse(T.NewObject("([1])")); - T.CheckFalse(T.NewObject("({})")); - T.CheckTrue(T.NewObject("(/x/)")); + T.CheckTrue(T.Val(1)); + T.CheckFalse(T.Val(1.1)); + T.CheckFalse(T.Val(-0.0)); + T.CheckTrue(T.Val(-2)); + T.CheckFalse(T.Val(-2.3)); T.CheckFalse(T.undefined()); - T.CheckFalse(T.null()); - T.CheckFalse(T.Val("x")); - T.CheckFalse(T.Val(1)); } -TEST(ClassOf) { +TEST(MapGetInstanceType) { FLAG_turbo_deoptimization = true; - FunctionTester T("(function(a) { return %_ClassOf(a); })", flags); - - T.CheckCall(T.Val("Function"), T.NewObject("(function() {})")); - T.CheckCall(T.Val("Array"), T.NewObject("([1])")); - T.CheckCall(T.Val("Object"), T.NewObject("({})")); - T.CheckCall(T.Val("RegExp"), T.NewObject("(/x/)")); - T.CheckCall(T.null(), T.undefined()); - T.CheckCall(T.null(), T.null()); - T.CheckCall(T.null(), T.Val("x")); - T.CheckCall(T.null(), T.Val(1)); + FunctionTester T( + "(function(a) { return %_MapGetInstanceType(%_HeapObjectGetMap(a)); })", + flags); + + Factory* factory = T.main_isolate()->factory(); + T.CheckCall(T.Val(ODDBALL_TYPE), T.null()); + T.CheckCall(T.Val(ODDBALL_TYPE), T.undefined()); + T.CheckCall(T.Val(HEAP_NUMBER_TYPE), T.Val(3.1415)); + T.CheckCall(T.Val(SYMBOL_TYPE), factory->NewSymbol()); } @@ -138,14 +202,48 @@ TEST(ObjectEquals) { } -TEST(ValueOf) { +TEST(OneByteSeqStringGetChar) { FLAG_turbo_deoptimization = true; - FunctionTester T("(function(a) { return %_ValueOf(a); })", flags); + FunctionTester T("(function(a,b) { return %_OneByteSeqStringGetChar(a,b); })", + flags); - T.CheckCall(T.Val("a"), T.Val("a")); - T.CheckCall(T.Val("b"), T.NewObject("(new String('b'))")); - T.CheckCall(T.Val(123), T.Val(123)); - T.CheckCall(T.Val(456), T.NewObject("(new Number(456))")); + Handle<SeqOneByteString> string = + T.main_isolate()->factory()->NewRawOneByteString(3).ToHandleChecked(); + string->SeqOneByteStringSet(0, 'b'); + string->SeqOneByteStringSet(1, 'a'); + string->SeqOneByteStringSet(2, 'r'); + T.CheckCall(T.Val('b'), string, T.Val(0.0)); + T.CheckCall(T.Val('a'), string, T.Val(1)); + T.CheckCall(T.Val('r'), string, T.Val(2)); +} + + +TEST(OneByteSeqStringSetChar) { + FLAG_turbo_deoptimization = true; + FunctionTester T("(function(a,b) { %_OneByteSeqStringSetChar(a,88,b); })", + flags); + + Handle<SeqOneByteString> string = + T.main_isolate()->factory()->NewRawOneByteString(3).ToHandleChecked(); + string->SeqOneByteStringSet(0, 'b'); + string->SeqOneByteStringSet(1, 'a'); + string->SeqOneByteStringSet(2, 'r'); + T.Call(T.Val(1), string); + CHECK_EQ('b', string->SeqOneByteStringGet(0)); + CHECK_EQ('X', string->SeqOneByteStringGet(1)); + CHECK_EQ('r', string->SeqOneByteStringGet(2)); +} + + +TEST(NewConsString) { + FLAG_turbo_deoptimization = true; + FunctionTester T( + "(function() { " + " return %_NewConsString(14, true, 'abcdefghi', 'jklmn');" + " })", + flags); + + T.CheckCall(T.Val("abcdefghijklmn")); } @@ -159,13 +257,13 @@ TEST(SetValueOf) { } -TEST(StringCharFromCode) { +TEST(StringAdd) { FLAG_turbo_deoptimization = true; - FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags); + FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags); - T.CheckCall(T.Val("a"), T.Val(97)); - T.CheckCall(T.Val("\xE2\x9D\x8A"), T.Val(0x274A)); - T.CheckCall(T.Val(""), T.undefined()); + T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb")); + T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val("")); + T.CheckCall(T.Val("bbb"), T.Val(""), T.Val("bbb")); } @@ -190,17 +288,27 @@ TEST(StringCharCodeAt) { } -TEST(StringAdd) { +TEST(StringCharFromCode) { FLAG_turbo_deoptimization = true; - FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags); + FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags); - T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb")); - T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val("")); - T.CheckCall(T.Val("bbb"), T.Val(""), T.Val("bbb")); + T.CheckCall(T.Val("a"), T.Val(97)); + T.CheckCall(T.Val("\xE2\x9D\x8A"), T.Val(0x274A)); + T.CheckCall(T.Val(""), T.undefined()); +} + + +TEST(StringCompare) { + FLAG_turbo_deoptimization = true; + FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })", flags); + + T.CheckCall(T.Val(-1), T.Val("aaa"), T.Val("bbb")); + T.CheckCall(T.Val(0.0), T.Val("bbb"), T.Val("bbb")); + T.CheckCall(T.Val(+1), T.Val("ccc"), T.Val("bbb")); } -TEST(StringSubString) { +TEST(SubString) { FLAG_turbo_deoptimization = true; FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })", flags); @@ -210,22 +318,45 @@ TEST(StringSubString) { } -TEST(StringCompare) { +TEST(TwoByteSeqStringGetChar) { FLAG_turbo_deoptimization = true; - FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })", flags); + FunctionTester T("(function(a,b) { return %_TwoByteSeqStringGetChar(a,b); })", + flags); - T.CheckCall(T.Val(-1), T.Val("aaa"), T.Val("bbb")); - T.CheckCall(T.Val(0.0), T.Val("bbb"), T.Val("bbb")); - T.CheckCall(T.Val(+1), T.Val("ccc"), T.Val("bbb")); + Handle<SeqTwoByteString> string = + T.main_isolate()->factory()->NewRawTwoByteString(3).ToHandleChecked(); + string->SeqTwoByteStringSet(0, 'b'); + string->SeqTwoByteStringSet(1, 'a'); + string->SeqTwoByteStringSet(2, 'r'); + T.CheckCall(T.Val('b'), string, T.Val(0.0)); + T.CheckCall(T.Val('a'), string, T.Val(1)); + T.CheckCall(T.Val('r'), string, T.Val(2)); } -TEST(CallFunction) { +TEST(TwoByteSeqStringSetChar) { FLAG_turbo_deoptimization = true; - FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })", + FunctionTester T("(function(a,b) { %_TwoByteSeqStringSetChar(a,88,b); })", flags); - CompileRun("function f(a,b,c) { return a + b + c + this.d; }"); - T.CheckCall(T.Val(129), T.NewObject("({d:123})"), T.NewObject("f")); - T.CheckCall(T.Val("6x"), T.NewObject("({d:'x'})"), T.NewObject("f")); + Handle<SeqTwoByteString> string = + T.main_isolate()->factory()->NewRawTwoByteString(3).ToHandleChecked(); + string->SeqTwoByteStringSet(0, 'b'); + string->SeqTwoByteStringSet(1, 'a'); + string->SeqTwoByteStringSet(2, 'r'); + T.Call(T.Val(1), string); + CHECK_EQ('b', string->SeqTwoByteStringGet(0)); + CHECK_EQ('X', string->SeqTwoByteStringGet(1)); + CHECK_EQ('r', string->SeqTwoByteStringGet(2)); +} + + +TEST(ValueOf) { + FLAG_turbo_deoptimization = true; + FunctionTester T("(function(a) { return %_ValueOf(a); })", flags); + + T.CheckCall(T.Val("a"), T.Val("a")); + T.CheckCall(T.Val("b"), T.NewObject("(new String('b'))")); + T.CheckCall(T.Val(123), T.Val(123)); + T.CheckCall(T.Val(456), T.NewObject("(new Number(456))")); } diff --git a/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc b/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc index 74990daac9..f06dc5f315 100644 --- a/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc +++ b/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc @@ -18,7 +18,8 @@ TEST(Throw) { } -TEST(ThrowSourcePosition) { +TEST(ThrowMessagePosition) { + i::FLAG_turbo_exceptions = true; static const char* src = "(function(a, b) { \n" " if (a == 1) throw 1; \n" @@ -30,22 +31,57 @@ TEST(ThrowSourcePosition) { v8::Handle<v8::Message> message; message = T.CheckThrowsReturnMessage(T.Val(1), T.undefined()); - CHECK(!message.IsEmpty()); CHECK_EQ(2, message->GetLineNumber()); CHECK_EQ(40, message->GetStartPosition()); message = T.CheckThrowsReturnMessage(T.Val(2), T.undefined()); - CHECK(!message.IsEmpty()); CHECK_EQ(3, message->GetLineNumber()); CHECK_EQ(67, message->GetStartPosition()); message = T.CheckThrowsReturnMessage(T.Val(3), T.undefined()); - CHECK(!message.IsEmpty()); CHECK_EQ(4, message->GetLineNumber()); CHECK_EQ(95, message->GetStartPosition()); } +TEST(ThrowMessageDirectly) { + i::FLAG_turbo_exceptions = true; + static const char* src = + "(function(a, b) {" + " if (a) { throw b; } else { throw new Error(b); }" + "})"; + FunctionTester T(src); + v8::Handle<v8::Message> message; + + message = T.CheckThrowsReturnMessage(T.false_value(), T.Val("Wat?")); + CHECK(message->Get()->Equals(v8_str("Uncaught Error: Wat?"))); + + message = T.CheckThrowsReturnMessage(T.true_value(), T.Val("Kaboom!")); + CHECK(message->Get()->Equals(v8_str("Uncaught Kaboom!"))); +} + + +TEST(ThrowMessageIndirectly) { + i::FLAG_turbo_exceptions = true; + static const char* src = + "(function(a, b) {" + " try {" + " if (a) { throw b; } else { throw new Error(b); }" + " } finally {" + " try { throw 'clobber'; } catch (e) { 'unclobber'; }" + " }" + "})"; + FunctionTester T(src); + v8::Handle<v8::Message> message; + + message = T.CheckThrowsReturnMessage(T.false_value(), T.Val("Wat?")); + CHECK(message->Get()->Equals(v8_str("Uncaught Error: Wat?"))); + + message = T.CheckThrowsReturnMessage(T.true_value(), T.Val("Kaboom!")); + CHECK(message->Get()->Equals(v8_str("Uncaught Kaboom!"))); +} + + // TODO(mstarzinger): Increase test coverage by having similar tests within the // mjsunit suite to also test integration with other components (e.g. OSR). @@ -118,6 +154,28 @@ TEST(CatchBreak) { } +TEST(CatchCall) { + i::FLAG_turbo_exceptions = true; + const char* src = + "(function(fun) {" + " var r = '-';" + " try {" + " r += 'A-';" + " return r + 'B-' + fun();" + " } catch (e) {" + " r += e;" + " }" + " return r;" + "})"; + FunctionTester T(src); + + CompileRun("function thrower() { throw 'T-'; }"); + T.CheckCall(T.Val("-A-T-"), T.NewFunction("thrower")); + CompileRun("function returner() { return 'R-'; }"); + T.CheckCall(T.Val("-A-B-R-"), T.NewFunction("returner")); +} + + TEST(Finally) { i::FLAG_turbo_exceptions = true; const char* src = @@ -158,3 +216,76 @@ TEST(FinallyBreak) { T.CheckCall(T.Val("-A-B-D-"), T.false_value(), T.true_value()); T.CheckCall(T.Val("-A-B-C-D-"), T.false_value(), T.false_value()); } + + +TEST(DeoptTry) { + i::FLAG_turbo_exceptions = true; + i::FLAG_turbo_deoptimization = true; + const char* src = + "(function f(a) {" + " try {" + " %DeoptimizeFunction(f);" + " throw a;" + " } catch (e) {" + " return e + 1;" + " }" + "})"; + FunctionTester T(src); + + T.CheckCall(T.Val(2), T.Val(1)); +} + + +TEST(DeoptCatch) { + i::FLAG_turbo_exceptions = true; + i::FLAG_turbo_deoptimization = true; + const char* src = + "(function f(a) {" + " try {" + " throw a;" + " } catch (e) {" + " %DeoptimizeFunction(f);" + " return e + 1;" + " }" + "})"; + FunctionTester T(src); + + T.CheckCall(T.Val(2), T.Val(1)); +} + + +TEST(DeoptFinallyReturn) { + i::FLAG_turbo_exceptions = true; + i::FLAG_turbo_deoptimization = true; + const char* src = + "(function f(a) {" + " try {" + " throw a;" + " } finally {" + " %DeoptimizeFunction(f);" + " return a + 1;" + " }" + "})"; + FunctionTester T(src); + + T.CheckCall(T.Val(2), T.Val(1)); +} + + +TEST(DeoptFinallyReThrow) { + i::FLAG_turbo_exceptions = true; + i::FLAG_turbo_deoptimization = true; + const char* src = + "(function f(a) {" + " try {" + " throw a;" + " } finally {" + " %DeoptimizeFunction(f);" + " }" + "})"; + FunctionTester T(src); + +#if 0 // TODO(mstarzinger): Enable once we can. + T.CheckThrows(T.NewObject("new Error"), T.Val(1)); +#endif +} diff --git a/deps/v8/test/cctest/compiler/test-run-jsops.cc b/deps/v8/test/cctest/compiler/test-run-jsops.cc index bb7c239a59..032db82db3 100644 --- a/deps/v8/test/cctest/compiler/test-run-jsops.cc +++ b/deps/v8/test/cctest/compiler/test-run-jsops.cc @@ -451,7 +451,6 @@ TEST(LookupStore) { TEST(BlockLoadStore) { - FLAG_harmony_scoping = true; FunctionTester T("(function(a) { 'use strict'; { let x = a+a; return x; }})"); T.CheckCall(T.Val(46), T.Val(23)); @@ -460,7 +459,6 @@ TEST(BlockLoadStore) { TEST(BlockLoadStoreNested) { - FLAG_harmony_scoping = true; const char* src = "(function(a,b) {" "'use strict';" diff --git a/deps/v8/test/cctest/compiler/test-run-machops.cc b/deps/v8/test/cctest/compiler/test-run-machops.cc index 5a55ce6e23..102e6d8ad4 100644 --- a/deps/v8/test/cctest/compiler/test-run-machops.cc +++ b/deps/v8/test/cctest/compiler/test-run-machops.cc @@ -4436,6 +4436,26 @@ TEST(RunInt32SubWithOverflowInBranchP) { } +TEST(RunWord64EqualInBranchP) { + int64_t input; + MLabel blocka, blockb; + RawMachineAssemblerTester<int64_t> m; + if (!m.machine()->Is64()) return; + Node* value = m.LoadFromPointer(&input, kMachInt64); + m.Branch(m.Word64Equal(value, m.Int64Constant(0)), &blocka, &blockb); + m.Bind(&blocka); + m.Return(m.Int32Constant(1)); + m.Bind(&blockb); + m.Return(m.Int32Constant(2)); + input = V8_INT64_C(0); + CHECK_EQ(1, m.Call()); + input = V8_INT64_C(1); + CHECK_EQ(2, m.Call()); + input = V8_INT64_C(0x100000000); + CHECK_EQ(2, m.Call()); +} + + TEST(RunChangeInt32ToInt64P) { if (kPointerSize < 8) return; int64_t actual = -1; @@ -4627,6 +4647,72 @@ TEST(RunFloat32Constant) { } +TEST(RunFloat64ExtractLowWord32) { + uint64_t input = 0; + RawMachineAssemblerTester<int32_t> m; + m.Return(m.Float64ExtractLowWord32(m.LoadFromPointer(&input, kMachFloat64))); + FOR_FLOAT64_INPUTS(i) { + input = bit_cast<uint64_t>(*i); + int32_t expected = bit_cast<int32_t>(static_cast<uint32_t>(input)); + CHECK_EQ(expected, m.Call()); + } +} + + +TEST(RunFloat64ExtractHighWord32) { + uint64_t input = 0; + RawMachineAssemblerTester<int32_t> m; + m.Return(m.Float64ExtractHighWord32(m.LoadFromPointer(&input, kMachFloat64))); + FOR_FLOAT64_INPUTS(i) { + input = bit_cast<uint64_t>(*i); + int32_t expected = bit_cast<int32_t>(static_cast<uint32_t>(input >> 32)); + CHECK_EQ(expected, m.Call()); + } +} + + +TEST(RunFloat64InsertLowWord32) { + uint64_t input = 0; + uint64_t result = 0; + RawMachineAssemblerTester<int32_t> m(kMachInt32); + m.StoreToPointer( + &result, kMachFloat64, + m.Float64InsertLowWord32(m.LoadFromPointer(&input, kMachFloat64), + m.Parameter(0))); + m.Return(m.Int32Constant(0)); + FOR_FLOAT64_INPUTS(i) { + FOR_INT32_INPUTS(j) { + input = bit_cast<uint64_t>(*i); + uint64_t expected = (input & ~(V8_UINT64_C(0xFFFFFFFF))) | + (static_cast<uint64_t>(bit_cast<uint32_t>(*j))); + CHECK_EQ(0, m.Call(*j)); + CHECK_EQ(expected, result); + } + } +} + + +TEST(RunFloat64InsertHighWord32) { + uint64_t input = 0; + uint64_t result = 0; + RawMachineAssemblerTester<int32_t> m(kMachInt32); + m.StoreToPointer( + &result, kMachFloat64, + m.Float64InsertHighWord32(m.LoadFromPointer(&input, kMachFloat64), + m.Parameter(0))); + m.Return(m.Int32Constant(0)); + FOR_FLOAT64_INPUTS(i) { + FOR_INT32_INPUTS(j) { + input = bit_cast<uint64_t>(*i); + uint64_t expected = (input & ~(V8_UINT64_C(0xFFFFFFFF) << 32)) | + (static_cast<uint64_t>(bit_cast<uint32_t>(*j)) << 32); + CHECK_EQ(0, m.Call(*j)); + CHECK_EQ(expected, result); + } + } +} + + static double two_30 = 1 << 30; // 2^30 is a smi boundary. static double two_52 = two_30 * (1 << 22); // 2^52 is a precision boundary. static double kValues[] = {0.1, @@ -4725,13 +4811,13 @@ static double kValues[] = {0.1, -two_52 + 1 - 0.7}; -TEST(RunFloat64Floor) { +TEST(RunFloat64RoundDown1) { double input = -1.0; double result = 0.0; RawMachineAssemblerTester<int32_t> m; - if (!m.machine()->HasFloat64Floor()) return; + if (!m.machine()->HasFloat64RoundDown()) return; m.StoreToPointer(&result, kMachFloat64, - m.Float64Floor(m.LoadFromPointer(&input, kMachFloat64))); + m.Float64RoundDown(m.LoadFromPointer(&input, kMachFloat64))); m.Return(m.Int32Constant(0)); for (size_t i = 0; i < arraysize(kValues); ++i) { input = kValues[i]; @@ -4742,13 +4828,16 @@ TEST(RunFloat64Floor) { } -TEST(RunFloat64Ceil) { +TEST(RunFloat64RoundDown2) { double input = -1.0; double result = 0.0; RawMachineAssemblerTester<int32_t> m; - if (!m.machine()->HasFloat64Ceil()) return; + if (!m.machine()->HasFloat64RoundDown()) return; m.StoreToPointer(&result, kMachFloat64, - m.Float64Ceil(m.LoadFromPointer(&input, kMachFloat64))); + m.Float64Sub(m.Float64Constant(-0.0), + m.Float64RoundDown(m.Float64Sub( + m.Float64Constant(-0.0), + m.LoadFromPointer(&input, kMachFloat64))))); m.Return(m.Int32Constant(0)); for (size_t i = 0; i < arraysize(kValues); ++i) { input = kValues[i]; @@ -4763,7 +4852,7 @@ TEST(RunFloat64RoundTruncate) { double input = -1.0; double result = 0.0; RawMachineAssemblerTester<int32_t> m; - if (!m.machine()->HasFloat64Ceil()) return; + if (!m.machine()->HasFloat64RoundTruncate()) return; m.StoreToPointer( &result, kMachFloat64, m.Float64RoundTruncate(m.LoadFromPointer(&input, kMachFloat64))); @@ -4793,4 +4882,5 @@ TEST(RunFloat64RoundTiesAway) { CHECK_EQ(expected, result); } } + #endif // V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/test-run-stubs.cc b/deps/v8/test/cctest/compiler/test-run-stubs.cc new file mode 100644 index 0000000000..daf9a461b1 --- /dev/null +++ b/deps/v8/test/cctest/compiler/test-run-stubs.cc @@ -0,0 +1,106 @@ +// Copyright 2015 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/bootstrapper.h" +#include "src/code-stubs.h" +#include "src/compiler/common-operator.h" +#include "src/compiler/graph.h" +#include "src/compiler/linkage.h" +#include "src/compiler/pipeline.h" +#include "src/parser.h" +#include "test/cctest/compiler/function-tester.h" + +#if V8_TURBOFAN_TARGET + +using namespace v8::internal; +using namespace v8::internal::compiler; + + +static Handle<JSFunction> GetFunction(Isolate* isolate, const char* name) { + v8::ExtensionConfiguration no_extensions; + Handle<Context> ctx = isolate->bootstrapper()->CreateEnvironment( + MaybeHandle<JSGlobalProxy>(), v8::Handle<v8::ObjectTemplate>(), + &no_extensions); + Handle<JSBuiltinsObject> builtins = handle(ctx->builtins()); + MaybeHandle<Object> fun = Object::GetProperty(isolate, builtins, name); + Handle<JSFunction> function = Handle<JSFunction>::cast(fun.ToHandleChecked()); + // Just to make sure nobody calls this... + function->set_code(isolate->builtins()->builtin(Builtins::kIllegal)); + return function; +} + + +class StringLengthStubTF : public CodeStub { + public: + explicit StringLengthStubTF(Isolate* isolate) : CodeStub(isolate) {} + + StringLengthStubTF(uint32_t key, Isolate* isolate) : CodeStub(key, isolate) {} + + CallInterfaceDescriptor GetCallInterfaceDescriptor() OVERRIDE { + return LoadDescriptor(isolate()); + }; + + Handle<Code> GenerateCode() OVERRIDE { + Zone zone; + // Build a "hybrid" CompilationInfo for a JSFunction/CodeStub pair. + ParseInfo parse_info(&zone, GetFunction(isolate(), "STRING_LENGTH_STUB")); + CompilationInfo info(&parse_info); + info.SetStub(this); + // Run a "mini pipeline", extracted from compiler.cc. + CHECK(Parser::ParseStatic(info.parse_info())); + CHECK(Compiler::Analyze(info.parse_info())); + return Pipeline(&info).GenerateCode(); + } + + Major MajorKey() const OVERRIDE { return StringLength; }; + Code::Kind GetCodeKind() const OVERRIDE { return Code::HANDLER; } + InlineCacheState GetICState() const OVERRIDE { return MONOMORPHIC; } + ExtraICState GetExtraICState() const OVERRIDE { return Code::LOAD_IC; } + Code::StubType GetStubType() const OVERRIDE { return Code::FAST; } + + private: + DISALLOW_COPY_AND_ASSIGN(StringLengthStubTF); +}; + + +TEST(RunStringLengthStubTF) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + // Create code and an accompanying descriptor. + StringLengthStubTF stub(isolate); + Handle<Code> code = stub.GenerateCode(); + CompilationInfo info(&stub, isolate, zone); + CallDescriptor* descriptor = Linkage::ComputeIncoming(zone, &info); + + // Create a function to call the code using the descriptor. + Graph graph(zone); + CommonOperatorBuilder common(zone); + // FunctionTester (ab)uses a 2-argument function + Node* start = graph.NewNode(common.Start(2)); + // Parameter 0 is the receiver + Node* receiverParam = graph.NewNode(common.Parameter(1), start); + Node* nameParam = graph.NewNode(common.Parameter(2), start); + Unique<HeapObject> u = Unique<HeapObject>::CreateImmovable(code); + Node* theCode = graph.NewNode(common.HeapConstant(u)); + Node* dummyContext = graph.NewNode(common.NumberConstant(0.0)); + Node* call = graph.NewNode(common.Call(descriptor), theCode, receiverParam, + nameParam, dummyContext, start, start); + Node* ret = graph.NewNode(common.Return(), call, call, start); + Node* end = graph.NewNode(common.End(), ret); + graph.SetStart(start); + graph.SetEnd(end); + FunctionTester ft(&graph); + + // Actuall call through to the stub, verifying its result. + const char* testString = "Und das Lamm schrie HURZ!"; + Handle<JSReceiver> receiverArg = + Object::ToObject(isolate, ft.Val(testString)).ToHandleChecked(); + Handle<String> nameArg = ft.Val("length"); + Handle<Object> result = ft.Call(receiverArg, nameArg).ToHandleChecked(); + CHECK_EQ(static_cast<int>(strlen(testString)), Smi::cast(*result)->value()); +} + +#endif // V8_TURBOFAN_TARGET diff --git a/deps/v8/test/cctest/compiler/test-run-variables.cc b/deps/v8/test/cctest/compiler/test-run-variables.cc index bf86e0d42c..4e5fd181f4 100644 --- a/deps/v8/test/cctest/compiler/test-run-variables.cc +++ b/deps/v8/test/cctest/compiler/test-run-variables.cc @@ -49,7 +49,6 @@ static const char* bind_tests[] = { static void RunVariableTests(const char* source, const char* tests[]) { - FLAG_harmony_scoping = true; EmbeddedVector<char, 512> buffer; for (int i = 0; tests[i] != NULL; i += 3) { diff --git a/deps/v8/test/cctest/compiler/test-simplified-lowering.cc b/deps/v8/test/cctest/compiler/test-simplified-lowering.cc index 6e2480e51e..634483bf24 100644 --- a/deps/v8/test/cctest/compiler/test-simplified-lowering.cc +++ b/deps/v8/test/cctest/compiler/test-simplified-lowering.cc @@ -790,25 +790,6 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders { }; -#if V8_TURBOFAN_TARGET - -TEST(LowerAnyToBoolean_tagged_tagged) { - // AnyToBoolean(x: kRepTagged) used as kRepTagged - TestingGraph t(Type::Any()); - Node* x = t.p0; - Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x); - Node* use = t.Use(cnv, kRepTagged); - t.Return(use); - t.Lower(); - CHECK_EQ(IrOpcode::kCall, cnv->opcode()); - CHECK_EQ(IrOpcode::kHeapConstant, cnv->InputAt(0)->opcode()); - CHECK_EQ(x, cnv->InputAt(1)); - CHECK_EQ(t.jsgraph.NoContextConstant(), cnv->InputAt(2)); -} - -#endif - - TEST(LowerBooleanNot_bit_bit) { // BooleanNot(x: kRepBit) used as kRepBit TestingGraph t(Type::Boolean()); @@ -1441,27 +1422,43 @@ TEST(LowerLoadField_to_load) { TEST(LowerStoreField_to_store) { - TestingGraph t(Type::Any(), Type::Signed32()); + { + TestingGraph t(Type::Any(), Type::Signed32()); - for (size_t i = 0; i < arraysize(kMachineReps); i++) { - FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, - Handle<Name>::null(), Type::Any(), kMachineReps[i]}; + for (size_t i = 0; i < arraysize(kMachineReps); i++) { + FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, + Handle<Name>::null(), Type::Any(), kMachineReps[i]}; - Node* val = t.ExampleWithOutput(kMachineReps[i]); + Node* val = t.ExampleWithOutput(kMachineReps[i]); + Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0, + val, t.start, t.start); + t.Effect(store); + t.Lower(); + CHECK_EQ(IrOpcode::kStore, store->opcode()); + CHECK_EQ(val, store->InputAt(2)); + CheckFieldAccessArithmetic(access, store); + + StoreRepresentation rep = OpParameter<StoreRepresentation>(store); + if (kMachineReps[i] & kRepTagged) { + CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind()); + } + CHECK_EQ(kMachineReps[i], rep.machine_type()); + } + } + { + TestingGraph t(Type::Any(), + Type::Intersect(Type::SignedSmall(), Type::TaggedSigned())); + FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, + Handle<Name>::null(), Type::Any(), kMachAnyTagged}; Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0, - val, t.start, t.start); + t.p1, t.start, t.start); t.Effect(store); t.Lower(); CHECK_EQ(IrOpcode::kStore, store->opcode()); - CHECK_EQ(val, store->InputAt(2)); - CheckFieldAccessArithmetic(access, store); - + CHECK_EQ(t.p1, store->InputAt(2)); StoreRepresentation rep = OpParameter<StoreRepresentation>(store); - if (kMachineReps[i] & kRepTagged) { - CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind()); - } - CHECK_EQ(kMachineReps[i], rep.machine_type()); + CHECK_EQ(kNoWriteBarrier, rep.write_barrier_kind()); } } @@ -1489,26 +1486,42 @@ TEST(LowerLoadElement_to_load) { TEST(LowerStoreElement_to_store) { - TestingGraph t(Type::Any(), Type::Signed32()); + { + TestingGraph t(Type::Any(), Type::Signed32()); - for (size_t i = 0; i < arraysize(kMachineReps); i++) { - ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, - Type::Any(), kMachineReps[i]}; + for (size_t i = 0; i < arraysize(kMachineReps); i++) { + ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, + Type::Any(), kMachineReps[i]}; + + Node* val = t.ExampleWithOutput(kMachineReps[i]); + Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), + t.p0, t.p1, val, t.start, t.start); + t.Effect(store); + t.Lower(); + CHECK_EQ(IrOpcode::kStore, store->opcode()); + CHECK_EQ(val, store->InputAt(2)); + CheckElementAccessArithmetic(access, store); - Node* val = t.ExampleWithOutput(kMachineReps[i]); + StoreRepresentation rep = OpParameter<StoreRepresentation>(store); + if (kMachineReps[i] & kRepTagged) { + CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind()); + } + CHECK_EQ(kMachineReps[i], rep.machine_type()); + } + } + { + TestingGraph t(Type::Any(), Type::Signed32(), + Type::Intersect(Type::SignedSmall(), Type::TaggedSigned())); + ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, + Type::Any(), kMachAnyTagged}; Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, - t.p1, val, t.start, t.start); + t.p1, t.p2, t.start, t.start); t.Effect(store); t.Lower(); CHECK_EQ(IrOpcode::kStore, store->opcode()); - CHECK_EQ(val, store->InputAt(2)); - CheckElementAccessArithmetic(access, store); - + CHECK_EQ(t.p2, store->InputAt(2)); StoreRepresentation rep = OpParameter<StoreRepresentation>(store); - if (kMachineReps[i] & kRepTagged) { - CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind()); - } - CHECK_EQ(kMachineReps[i], rep.machine_type()); + CHECK_EQ(kNoWriteBarrier, rep.write_barrier_kind()); } } @@ -1938,10 +1951,10 @@ TEST(NumberModulus_TruncatingToUint32) { Node* k = t.jsgraph.Constant(constants[i]); Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod); - Node* ret = t.Return(trunc); + t.Return(trunc); t.Lower(); - CHECK_EQ(IrOpcode::kUint32Mod, ret->InputAt(0)->opcode()); + CHECK_EQ(IrOpcode::kUint32Mod, t.ret->InputAt(0)->InputAt(0)->opcode()); } } diff --git a/deps/v8/test/cctest/test-accessors.cc b/deps/v8/test/cctest/test-accessors.cc index bbb74c0a71..be69111364 100644 --- a/deps/v8/test/cctest/test-accessors.cc +++ b/deps/v8/test/cctest/test-accessors.cc @@ -605,3 +605,86 @@ THREADED_TEST(Regress433458) { "Object.defineProperty(obj, 'prop', { writable: false });" "Object.defineProperty(obj, 'prop', { writable: true });"); } + + +static bool security_check_value = false; + + +static bool SecurityTestCallback(Local<v8::Object> global, Local<Value> name, + v8::AccessType type, Local<Value> data) { + return security_check_value; +} + + +TEST(PrototypeGetterAccessCheck) { + i::FLAG_allow_natives_syntax = true; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + auto fun_templ = v8::FunctionTemplate::New(isolate); + auto getter_templ = v8::FunctionTemplate::New(isolate, handle_property); + getter_templ->SetAcceptAnyReceiver(false); + fun_templ->InstanceTemplate()->SetAccessorProperty(v8_str("foo"), + getter_templ); + auto obj_templ = v8::ObjectTemplate::New(isolate); + obj_templ->SetAccessCheckCallbacks(SecurityTestCallback, nullptr); + env->Global()->Set(v8_str("Fun"), fun_templ->GetFunction()); + env->Global()->Set(v8_str("obj"), obj_templ->NewInstance()); + env->Global()->Set(v8_str("obj2"), obj_templ->NewInstance()); + + security_check_value = true; + CompileRun("var proto = new Fun();"); + CompileRun("obj.__proto__ = proto;"); + ExpectInt32("proto.foo", 907); + + // Test direct. + security_check_value = true; + ExpectInt32("obj.foo", 907); + security_check_value = false; + { + v8::TryCatch try_catch(isolate); + CompileRun("obj.foo"); + CHECK(try_catch.HasCaught()); + } + + // Test through call. + security_check_value = true; + ExpectInt32("proto.__lookupGetter__('foo').call(obj)", 907); + security_check_value = false; + { + v8::TryCatch try_catch(isolate); + CompileRun("proto.__lookupGetter__('foo').call(obj)"); + CHECK(try_catch.HasCaught()); + } + + // Test ics. + CompileRun( + "function f() {" + " var x;" + " for (var i = 0; i < 4; i++) {" + " x = obj.foo;" + " }" + " return x;" + "}"); + + security_check_value = true; + ExpectInt32("f()", 907); + security_check_value = false; + { + v8::TryCatch try_catch(isolate); + CompileRun("f();"); + CHECK(try_catch.HasCaught()); + } + + // Test crankshaft. + CompileRun("%OptimizeFunctionOnNextCall(f);"); + + security_check_value = true; + ExpectInt32("f()", 907); + security_check_value = false; + { + v8::TryCatch try_catch(isolate); + CompileRun("f();"); + CHECK(try_catch.HasCaught()); + } +} diff --git a/deps/v8/test/cctest/test-alloc.cc b/deps/v8/test/cctest/test-alloc.cc index 79ba4a486e..0ec9934644 100644 --- a/deps/v8/test/cctest/test-alloc.cc +++ b/deps/v8/test/cctest/test-alloc.cc @@ -63,7 +63,7 @@ static AllocationResult AllocateAfterFailures() { heap->AllocateFixedArray(10000, TENURED).ToObjectChecked(); // Large object space. - static const int kLargeObjectSpaceFillerLength = 300000; + static const int kLargeObjectSpaceFillerLength = 3 * (Page::kPageSize / 10); static const int kLargeObjectSpaceFillerSize = FixedArray::SizeFor( kLargeObjectSpaceFillerLength); DCHECK(kLargeObjectSpaceFillerSize > heap->old_pointer_space()->AreaSize()); @@ -210,7 +210,7 @@ TEST(CodeRange) { // Geometrically distributed sizes, greater than // Page::kMaxRegularHeapObjectSize (which is greater than code page area). // TODO(gc): instead of using 3 use some contant based on code_range_size - // kMaxHeapObjectSize. + // kMaxRegularHeapObjectSize. size_t requested = (Page::kMaxRegularHeapObjectSize << (Pseudorandom() % 3)) + Pseudorandom() % 5000 + 1; diff --git a/deps/v8/test/cctest/test-api-interceptors.cc b/deps/v8/test/cctest/test-api-interceptors.cc index a2acb24d76..e3bee15318 100644 --- a/deps/v8/test/cctest/test-api-interceptors.cc +++ b/deps/v8/test/cctest/test-api-interceptors.cc @@ -15,7 +15,6 @@ #include "src/objects.h" #include "src/parser.h" #include "src/smart-pointers.h" -#include "src/snapshot.h" #include "src/unicode-inl.h" #include "src/utils.h" #include "src/vm-state.h" @@ -2934,16 +2933,8 @@ struct AccessCheckData { }; -bool SimpleNamedAccessChecker(Local<v8::Object> global, Local<Value> name, - v8::AccessType type, Local<Value> data) { - auto access_check_data = GetWrappedObject<AccessCheckData>(data); - access_check_data->count++; - return access_check_data->result; -} - - -bool SimpleIndexedAccessChecker(Local<v8::Object> global, uint32_t index, - v8::AccessType type, Local<Value> data) { +bool SimpleAccessChecker(Local<v8::Object> global, Local<Value> name, + v8::AccessType type, Local<Value> data) { auto access_check_data = GetWrappedObject<AccessCheckData>(data); access_check_data->count++; return access_check_data->result; @@ -3015,7 +3006,7 @@ THREADED_TEST(NamedAllCanReadInterceptor) { auto checked = v8::ObjectTemplate::New(isolate); checked->SetAccessCheckCallbacks( - SimpleNamedAccessChecker, nullptr, + SimpleAccessChecker, nullptr, BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false); context->Global()->Set(v8_str("intercepted_0"), intercepted_0->NewInstance()); @@ -3032,15 +3023,27 @@ THREADED_TEST(NamedAllCanReadInterceptor) { access_check_data.result = true; ExpectInt32("checked.whatever", 17); - CHECK_EQ(1, access_check_data.count); + CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')") + ->IsUndefined()); + CHECK_EQ(2, access_check_data.count); access_check_data.result = false; ExpectInt32("checked.whatever", intercept_data_0.value); - CHECK_EQ(2, access_check_data.count); + { + v8::TryCatch try_catch(isolate); + CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')"); + CHECK(try_catch.HasCaught()); + } + CHECK_EQ(4, access_check_data.count); intercept_data_1.should_intercept = true; ExpectInt32("checked.whatever", intercept_data_1.value); - CHECK_EQ(3, access_check_data.count); + { + v8::TryCatch try_catch(isolate); + CompileRun("Object.getOwnPropertyDescriptor(checked, 'whatever')"); + CHECK(try_catch.HasCaught()); + } + CHECK_EQ(6, access_check_data.count); } @@ -3081,7 +3084,7 @@ THREADED_TEST(IndexedAllCanReadInterceptor) { auto checked = v8::ObjectTemplate::New(isolate); checked->SetAccessCheckCallbacks( - nullptr, SimpleIndexedAccessChecker, + SimpleAccessChecker, nullptr, BuildWrappedObject<AccessCheckData>(isolate, &access_check_data), false); context->Global()->Set(v8_str("intercepted_0"), intercepted_0->NewInstance()); @@ -3098,13 +3101,211 @@ THREADED_TEST(IndexedAllCanReadInterceptor) { access_check_data.result = true; ExpectInt32("checked[15]", 17); - CHECK_EQ(1, access_check_data.count); + CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')") + ->IsUndefined()); + CHECK_EQ(3, access_check_data.count); access_check_data.result = false; ExpectInt32("checked[15]", intercept_data_0.value); - CHECK_EQ(2, access_check_data.count); + // Note: this should throw but without a LookupIterator it's complicated. + CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')") + ->IsUndefined()); + CHECK_EQ(6, access_check_data.count); intercept_data_1.should_intercept = true; ExpectInt32("checked[15]", intercept_data_1.value); - CHECK_EQ(3, access_check_data.count); + // Note: this should throw but without a LookupIterator it's complicated. + CHECK(!CompileRun("Object.getOwnPropertyDescriptor(checked, '15')") + ->IsUndefined()); + CHECK_EQ(9, access_check_data.count); +} + + +THREADED_TEST(NonMaskingInterceptorOwnProperty) { + auto isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext context; + + ShouldInterceptData intercept_data; + intercept_data.value = 239; + intercept_data.should_intercept = true; + + auto interceptor_templ = v8::ObjectTemplate::New(isolate); + v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor); + conf.flags = v8::PropertyHandlerFlags::kNonMasking; + conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data); + interceptor_templ->SetHandler(conf); + + auto interceptor = interceptor_templ->NewInstance(); + context->Global()->Set(v8_str("obj"), interceptor); + + ExpectInt32("obj.whatever", 239); + + CompileRun("obj.whatever = 4;"); + ExpectInt32("obj.whatever", 4); + + CompileRun("delete obj.whatever;"); + ExpectInt32("obj.whatever", 239); +} + + +THREADED_TEST(NonMaskingInterceptorPrototypeProperty) { + auto isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext context; + + ShouldInterceptData intercept_data; + intercept_data.value = 239; + intercept_data.should_intercept = true; + + auto interceptor_templ = v8::ObjectTemplate::New(isolate); + v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor); + conf.flags = v8::PropertyHandlerFlags::kNonMasking; + conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data); + interceptor_templ->SetHandler(conf); + + auto interceptor = interceptor_templ->NewInstance(); + context->Global()->Set(v8_str("obj"), interceptor); + + ExpectInt32("obj.whatever", 239); + + CompileRun("obj.__proto__ = {'whatever': 4};"); + ExpectInt32("obj.whatever", 4); + + CompileRun("delete obj.__proto__.whatever;"); + ExpectInt32("obj.whatever", 239); +} + + +THREADED_TEST(NonMaskingInterceptorPrototypePropertyIC) { + auto isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext context; + + ShouldInterceptData intercept_data; + intercept_data.value = 239; + intercept_data.should_intercept = true; + + auto interceptor_templ = v8::ObjectTemplate::New(isolate); + v8::NamedPropertyHandlerConfiguration conf(ShouldNamedInterceptor); + conf.flags = v8::PropertyHandlerFlags::kNonMasking; + conf.data = BuildWrappedObject<ShouldInterceptData>(isolate, &intercept_data); + interceptor_templ->SetHandler(conf); + + auto interceptor = interceptor_templ->NewInstance(); + context->Global()->Set(v8_str("obj"), interceptor); + + CompileRun( + "outer = {};" + "outer.__proto__ = obj;" + "function f(obj) {" + " var x;" + " for (var i = 0; i < 4; i++) {" + " x = obj.whatever;" + " }" + " return x;" + "}"); + + // Receiver == holder. + CompileRun("obj.__proto__ = null;"); + ExpectInt32("f(obj)", 239); + ExpectInt32("f(outer)", 239); + + // Receiver != holder. + CompileRun("Object.setPrototypeOf(obj, {});"); + ExpectInt32("f(obj)", 239); + ExpectInt32("f(outer)", 239); + + // Masked value on prototype. + CompileRun("obj.__proto__.whatever = 4;"); + CompileRun("obj.__proto__.__proto__ = { 'whatever' : 5 };"); + ExpectInt32("f(obj)", 4); + ExpectInt32("f(outer)", 4); + + // Masked value on prototype prototype. + CompileRun("delete obj.__proto__.whatever;"); + ExpectInt32("f(obj)", 5); + ExpectInt32("f(outer)", 5); + + // Reset. + CompileRun("delete obj.__proto__.__proto__.whatever;"); + ExpectInt32("f(obj)", 239); + ExpectInt32("f(outer)", 239); + + // Masked value on self. + CompileRun("obj.whatever = 4;"); + ExpectInt32("f(obj)", 4); + ExpectInt32("f(outer)", 4); + + // Reset. + CompileRun("delete obj.whatever;"); + ExpectInt32("f(obj)", 239); + ExpectInt32("f(outer)", 239); + + CompileRun("outer.whatever = 4;"); + ExpectInt32("f(obj)", 239); + ExpectInt32("f(outer)", 4); +} + + +namespace { + +void DatabaseGetter(Local<Name> name, + const v8::PropertyCallbackInfo<Value>& info) { + ApiTestFuzzer::Fuzz(); + auto context = info.GetIsolate()->GetCurrentContext(); + Local<v8::Object> db = info.Holder() + ->GetRealNamedProperty(context, v8_str("db")) + .ToLocalChecked() + .As<v8::Object>(); + if (!db->Has(context, name).FromJust()) return; + info.GetReturnValue().Set(db->Get(context, name).ToLocalChecked()); +} + + +void DatabaseSetter(Local<Name> name, Local<Value> value, + const v8::PropertyCallbackInfo<Value>& info) { + ApiTestFuzzer::Fuzz(); + auto context = info.GetIsolate()->GetCurrentContext(); + if (name->Equals(v8_str("db"))) return; + Local<v8::Object> db = info.Holder() + ->GetRealNamedProperty(context, v8_str("db")) + .ToLocalChecked() + .As<v8::Object>(); + db->Set(context, name, value).FromJust(); + info.GetReturnValue().Set(value); +} +} + + +THREADED_TEST(NonMaskingInterceptorGlobalEvalRegression) { + auto isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext context; + + auto interceptor_templ = v8::ObjectTemplate::New(isolate); + v8::NamedPropertyHandlerConfiguration conf(DatabaseGetter, DatabaseSetter); + conf.flags = v8::PropertyHandlerFlags::kNonMasking; + interceptor_templ->SetHandler(conf); + + context->Global()->Set(v8_str("intercepted_1"), + interceptor_templ->NewInstance()); + context->Global()->Set(v8_str("intercepted_2"), + interceptor_templ->NewInstance()); + + // Init dbs. + CompileRun( + "intercepted_1.db = {};" + "intercepted_2.db = {};"); + + ExpectInt32( + "var obj = intercepted_1;" + "obj.x = 4;" + "eval('obj.x');" + "eval('obj.x');" + "eval('obj.x');" + "obj = intercepted_2;" + "obj.x = 9;" + "eval('obj.x');", + 9); } diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index afb70ffeee..8432cbfba1 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -45,7 +45,6 @@ #include "src/objects.h" #include "src/parser.h" #include "src/smart-pointers.h" -#include "src/snapshot.h" #include "src/unicode-inl.h" #include "src/utils.h" #include "src/vm-state.h" @@ -61,12 +60,15 @@ using ::v8::FunctionTemplate; using ::v8::Handle; using ::v8::HandleScope; using ::v8::Local; -using ::v8::Name; +using ::v8::Maybe; using ::v8::Message; using ::v8::MessageCallback; +using ::v8::Name; +using ::v8::None; using ::v8::Object; using ::v8::ObjectTemplate; using ::v8::Persistent; +using ::v8::PropertyAttribute; using ::v8::Script; using ::v8::StackTrace; using ::v8::String; @@ -691,28 +693,23 @@ class RandomLengthOneByteResource THREADED_TEST(NewExternalForVeryLongString) { + auto isolate = CcTest::isolate(); { - LocalContext env; - v8::HandleScope scope(env->GetIsolate()); + v8::HandleScope scope(isolate); v8::TryCatch try_catch; RandomLengthOneByteResource r(1 << 30); - v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r); + v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r); CHECK(str.IsEmpty()); - CHECK(try_catch.HasCaught()); - String::Utf8Value exception_value(try_catch.Exception()); - CHECK_EQ(0, strcmp("RangeError: Invalid string length", *exception_value)); + CHECK(!try_catch.HasCaught()); } { - LocalContext env; - v8::HandleScope scope(env->GetIsolate()); + v8::HandleScope scope(isolate); v8::TryCatch try_catch; RandomLengthResource r(1 << 30); - v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r); + v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r); CHECK(str.IsEmpty()); - CHECK(try_catch.HasCaught()); - String::Utf8Value exception_value(try_catch.Exception()); - CHECK_EQ(0, strcmp("RangeError: Invalid string length", *exception_value)); + CHECK(!try_catch.HasCaught()); } } @@ -733,8 +730,8 @@ THREADED_TEST(ScavengeExternalString) { CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring)); CHECK_EQ(0, dispose_count); } - CcTest::heap()->CollectGarbage( - in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE); + CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE + : i::OLD_DATA_SPACE); CHECK_EQ(1, dispose_count); } @@ -756,8 +753,8 @@ THREADED_TEST(ScavengeExternalOneByteString) { CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring)); CHECK_EQ(0, dispose_count); } - CcTest::heap()->CollectGarbage( - in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE); + CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE + : i::OLD_DATA_SPACE); CHECK_EQ(1, dispose_count); } @@ -2124,7 +2121,7 @@ THREADED_TEST(InternalFieldsAlignedPointers) { void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); CheckAlignedPointerInInternalField(obj, huge); - v8::UniquePersistent<v8::Object> persistent(isolate, obj); + v8::Global<v8::Object> persistent(isolate, obj); CHECK_EQ(1, Object::InternalFieldCount(persistent)); CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0)); } @@ -3035,20 +3032,20 @@ THREADED_TEST(ResettingGlobalHandleToEmpty) { template <class T> -static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) { +static v8::Global<T> PassUnique(v8::Global<T> unique) { return unique.Pass(); } template <class T> -static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate, - const v8::Persistent<T>& global) { - v8::UniquePersistent<String> unique(isolate, global); +static v8::Global<T> ReturnUnique(v8::Isolate* isolate, + const v8::Persistent<T>& global) { + v8::Global<String> unique(isolate, global); return unique.Pass(); } -THREADED_TEST(UniquePersistent) { +THREADED_TEST(Global) { v8::Isolate* isolate = CcTest::isolate(); v8::Persistent<String> global; { @@ -3059,11 +3056,11 @@ THREADED_TEST(UniquePersistent) { reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); int initial_handle_count = global_handles->global_handles_count(); { - v8::UniquePersistent<String> unique(isolate, global); + v8::Global<String> unique(isolate, global); CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); // Test assignment via Pass { - v8::UniquePersistent<String> copy = unique.Pass(); + v8::Global<String> copy = unique.Pass(); CHECK(unique.IsEmpty()); CHECK(copy == global); CHECK_EQ(initial_handle_count + 1, @@ -3072,7 +3069,7 @@ THREADED_TEST(UniquePersistent) { } // Test ctor via Pass { - v8::UniquePersistent<String> copy(unique.Pass()); + v8::Global<String> copy(unique.Pass()); CHECK(unique.IsEmpty()); CHECK(copy == global); CHECK_EQ(initial_handle_count + 1, @@ -3081,7 +3078,7 @@ THREADED_TEST(UniquePersistent) { } // Test pass through function call { - v8::UniquePersistent<String> copy = PassUnique(unique.Pass()); + v8::Global<String> copy = PassUnique(unique.Pass()); CHECK(unique.IsEmpty()); CHECK(copy == global); CHECK_EQ(initial_handle_count + 1, @@ -3092,7 +3089,7 @@ THREADED_TEST(UniquePersistent) { } // Test pass from function call { - v8::UniquePersistent<String> unique = ReturnUnique(isolate, global); + v8::Global<String> unique = ReturnUnique(isolate, global); CHECK(unique == global); CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); } @@ -3101,6 +3098,123 @@ THREADED_TEST(UniquePersistent) { } +namespace { + +class TwoPassCallbackData; +void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data); +void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data); + + +class TwoPassCallbackData { + public: + TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter) + : first_pass_called_(false), + second_pass_called_(false), + trigger_gc_(false), + instance_counter_(instance_counter) { + HandleScope scope(isolate); + i::ScopedVector<char> buffer(40); + i::SNPrintF(buffer, "%p", static_cast<void*>(this)); + auto string = + v8::String::NewFromUtf8(isolate, buffer.start(), + v8::NewStringType::kNormal).ToLocalChecked(); + cell_.Reset(isolate, string); + (*instance_counter_)++; + } + + ~TwoPassCallbackData() { + CHECK(first_pass_called_); + CHECK(second_pass_called_); + CHECK(cell_.IsEmpty()); + (*instance_counter_)--; + } + + void FirstPass() { + CHECK(!first_pass_called_); + CHECK(!second_pass_called_); + CHECK(!cell_.IsEmpty()); + cell_.Reset(); + first_pass_called_ = true; + } + + void SecondPass() { + CHECK(first_pass_called_); + CHECK(!second_pass_called_); + CHECK(cell_.IsEmpty()); + second_pass_called_ = true; + delete this; + } + + void SetWeak() { + cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter); + } + + void MarkTriggerGc() { trigger_gc_ = true; } + bool trigger_gc() { return trigger_gc_; } + + int* instance_counter() { return instance_counter_; } + + private: + bool first_pass_called_; + bool second_pass_called_; + bool trigger_gc_; + v8::Global<v8::String> cell_; + int* instance_counter_; +}; + + +void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) { + ApiTestFuzzer::Fuzz(); + bool trigger_gc = data.GetParameter()->trigger_gc(); + int* instance_counter = data.GetParameter()->instance_counter(); + data.GetParameter()->SecondPass(); + if (!trigger_gc) return; + auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter); + data_2->SetWeak(); + CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); +} + + +void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) { + data.GetParameter()->FirstPass(); + data.SetSecondPassCallback(SecondPassCallback); +} + +} // namespace + + +TEST(TwoPassPhantomCallbacks) { + auto isolate = CcTest::isolate(); + const size_t kLength = 20; + int instance_counter = 0; + for (size_t i = 0; i < kLength; ++i) { + auto data = new TwoPassCallbackData(isolate, &instance_counter); + data->SetWeak(); + } + CHECK_EQ(static_cast<int>(kLength), instance_counter); + CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); + CHECK_EQ(0, instance_counter); +} + + +TEST(TwoPassPhantomCallbacksNestedGc) { + auto isolate = CcTest::isolate(); + const size_t kLength = 20; + TwoPassCallbackData* array[kLength]; + int instance_counter = 0; + for (size_t i = 0; i < kLength; ++i) { + array[i] = new TwoPassCallbackData(isolate, &instance_counter); + array[i]->SetWeak(); + } + array[5]->MarkTriggerGc(); + array[10]->MarkTriggerGc(); + array[15]->MarkTriggerGc(); + CHECK_EQ(static_cast<int>(kLength), instance_counter); + CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); + CHECK_EQ(0, instance_counter); +} + + template <typename K, typename V> class WeakStdMapTraits : public v8::StdMapTraits<K, V> { public: @@ -3126,8 +3240,7 @@ class WeakStdMapTraits : public v8::StdMapTraits<K, V> { return data.GetParameter()->key; } static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; } - static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value, - K key) {} + static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {} }; @@ -3153,7 +3266,7 @@ static void TestPersistentValueMap() { typename Map::PersistentValueReference ref = map.GetReference(7); CHECK(expected->Equals(ref.NewLocal(isolate))); } - v8::UniquePersistent<v8::Object> removed = map.Remove(7); + v8::Global<v8::Object> removed = map.Remove(7); CHECK_EQ(0, static_cast<int>(map.Size())); CHECK(expected == removed); removed = map.Remove(7); @@ -3165,8 +3278,7 @@ static void TestPersistentValueMap() { { typename Map::PersistentValueReference ref; Local<v8::Object> expected2 = v8::Object::New(isolate); - removed = map.Set(8, v8::UniquePersistent<v8::Object>(isolate, expected2), - &ref); + removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref); CHECK_EQ(1, static_cast<int>(map.Size())); CHECK(expected == removed); CHECK(expected2->Equals(ref.NewLocal(isolate))); @@ -3197,6 +3309,126 @@ TEST(PersistentValueMap) { } +namespace { + +void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); } + + +Local<v8::Object> NewObjectForIntKey( + v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ, + int key) { + auto local = Local<v8::ObjectTemplate>::New(isolate, templ); + auto obj = local->NewInstance(); + obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key)); + return obj; +} + + +template <typename K, typename V> +class PhantomStdMapTraits : public v8::StdMapTraits<K, V> { + public: + typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType; + static const v8::PersistentContainerCallbackType kCallbackType = + v8::kWeakWithInternalFields; + struct WeakCallbackDataType { + MapType* map; + K key; + }; + static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key, + Local<V> value) { + WeakCallbackDataType* data = new WeakCallbackDataType; + data->map = map; + data->key = key; + return data; + } + static MapType* MapFromWeakCallbackInfo( + const v8::WeakCallbackInfo<WeakCallbackDataType>& data) { + return data.GetParameter()->map; + } + static K KeyFromWeakCallbackInfo( + const v8::WeakCallbackInfo<WeakCallbackDataType>& data) { + return data.GetParameter()->key; + } + static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; } + static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) { + CHECK_EQ(IntKeyToVoidPointer(key), + v8::Object::GetAlignedPointerFromInternalField(value, 0)); + } + static void DisposeWeak( + v8::Isolate* isolate, + const v8::WeakCallbackInfo<WeakCallbackDataType>& info, K key) { + CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0)); + DisposeCallbackData(info.GetParameter()); + } +}; + +} // namespace + + +TEST(GlobalValueMap) { + typedef v8::GlobalValueMap<int, v8::Object, + PhantomStdMapTraits<int, v8::Object>> Map; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::Global<ObjectTemplate> templ; + { + HandleScope scope(isolate); + auto t = ObjectTemplate::New(isolate); + t->SetInternalFieldCount(1); + templ.Reset(isolate, t); + } + Map map(isolate); + v8::internal::GlobalHandles* global_handles = + reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); + int initial_handle_count = global_handles->global_handles_count(); + CHECK_EQ(0, static_cast<int>(map.Size())); + { + HandleScope scope(isolate); + Local<v8::Object> obj = map.Get(7); + CHECK(obj.IsEmpty()); + Local<v8::Object> expected = v8::Object::New(isolate); + map.Set(7, expected); + CHECK_EQ(1, static_cast<int>(map.Size())); + obj = map.Get(7); + CHECK(expected->Equals(obj)); + { + Map::PersistentValueReference ref = map.GetReference(7); + CHECK(expected->Equals(ref.NewLocal(isolate))); + } + v8::Global<v8::Object> removed = map.Remove(7); + CHECK_EQ(0, static_cast<int>(map.Size())); + CHECK(expected == removed); + removed = map.Remove(7); + CHECK(removed.IsEmpty()); + map.Set(8, expected); + CHECK_EQ(1, static_cast<int>(map.Size())); + map.Set(8, expected); + CHECK_EQ(1, static_cast<int>(map.Size())); + { + Map::PersistentValueReference ref; + Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8); + removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref); + CHECK_EQ(1, static_cast<int>(map.Size())); + CHECK(expected == removed); + CHECK(expected2->Equals(ref.NewLocal(isolate))); + } + } + CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count()); + CcTest::i_isolate()->heap()->CollectAllGarbage( + i::Heap::kAbortIncrementalMarkingMask); + CHECK_EQ(0, static_cast<int>(map.Size())); + CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); + { + HandleScope scope(isolate); + Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9); + map.Set(9, value); + map.Clear(); + } + CHECK_EQ(0, static_cast<int>(map.Size())); + CHECK_EQ(initial_handle_count, global_handles->global_handles_count()); +} + + TEST(PersistentValueVector) { LocalContext env; v8::Isolate* isolate = env->GetIsolate(); @@ -3209,7 +3441,7 @@ TEST(PersistentValueVector) { Local<v8::Object> obj1 = v8::Object::New(isolate); Local<v8::Object> obj2 = v8::Object::New(isolate); - v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate)); + v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate)); CHECK(vector.IsEmpty()); CHECK_EQ(0, static_cast<int>(vector.Size())); @@ -3891,6 +4123,7 @@ static void check_message_3(v8::Handle<v8::Message> message, CHECK(message->GetScriptOrigin().ResourceIsSharedCrossOrigin()->Value()); CHECK(message->GetScriptOrigin().ResourceIsEmbedderDebugScript()->Value()); CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue()); + CHECK_EQ(7.40, message->GetScriptOrigin().SourceMapUrl()->NumberValue()); message_received = true; } @@ -3902,10 +4135,10 @@ TEST(MessageHandler3) { CHECK(!message_received); v8::V8::AddMessageListener(check_message_3); LocalContext context; - v8::ScriptOrigin origin = - v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1), - v8::Integer::New(isolate, 2), v8::True(isolate), - Handle<v8::Integer>(), v8::True(isolate)); + v8::ScriptOrigin origin = v8::ScriptOrigin( + v8_str("6.75"), v8::Integer::New(isolate, 1), + v8::Integer::New(isolate, 2), v8::True(isolate), Handle<v8::Integer>(), + v8::True(isolate), v8_str("7.40")); v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), &origin); script->Run(); @@ -6266,12 +6499,13 @@ THREADED_TEST(ErrorWithMissingScriptInfo) { struct FlagAndPersistent { bool flag; - v8::Persistent<v8::Object> handle; + v8::Global<v8::Object> handle; }; -static void SetFlag(const v8::PhantomCallbackData<FlagAndPersistent>& data) { +static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) { data.GetParameter()->flag = true; + data.GetParameter()->handle.Reset(); } @@ -6309,8 +6543,10 @@ static void IndependentWeakHandle(bool global_gc, bool interlinked) { object_a.flag = false; object_b.flag = false; - object_a.handle.SetPhantom(&object_a, &SetFlag); - object_b.handle.SetPhantom(&object_b, &SetFlag); + object_a.handle.SetWeak(&object_a, &SetFlag, + v8::WeakCallbackType::kParameter); + object_b.handle.SetWeak(&object_b, &SetFlag, + v8::WeakCallbackType::kParameter); CHECK(!object_b.handle.IsIndependent()); object_a.handle.MarkIndependent(); object_b.handle.MarkIndependent(); @@ -6365,7 +6601,7 @@ class Trivial2 { void CheckInternalFields( - const v8::PhantomCallbackData<v8::Persistent<v8::Object>>& data) { + const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) { v8::Persistent<v8::Object>* handle = data.GetParameter(); handle->Reset(); Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField1()); @@ -6405,8 +6641,8 @@ void InternalFieldCallback(bool global_gc) { reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1)); CHECK_EQ(103, t2->x()); - handle.SetPhantom<v8::Persistent<v8::Object>>(&handle, CheckInternalFields, - 0, 1); + handle.SetWeak<v8::Persistent<v8::Object>>( + &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields); if (!global_gc) { handle.MarkIndependent(); } @@ -7673,30 +7909,9 @@ TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) { // For use within the TestSecurityHandler() test. static bool g_security_callback_result = false; -static bool NamedSecurityTestCallback(Local<v8::Object> global, - Local<Value> name, - v8::AccessType type, - Local<Value> data) { +static bool SecurityTestCallback(Local<v8::Object> global, Local<Value> name, + v8::AccessType type, Local<Value> data) { printf("a\n"); - // Always allow read access. - if (type == v8::ACCESS_GET) - return true; - - // Sometimes allow other access. - return g_security_callback_result; -} - - -static bool IndexedSecurityTestCallback(Local<v8::Object> global, - uint32_t key, - v8::AccessType type, - Local<Value> data) { - printf("b\n"); - // Always allow read access. - if (type == v8::ACCESS_GET) - return true; - - // Sometimes allow other access. return g_security_callback_result; } @@ -7707,8 +7922,7 @@ TEST(SecurityHandler) { v8::HandleScope scope0(isolate); v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); - global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback, - IndexedSecurityTestCallback); + global_template->SetAccessCheckCallbacks(SecurityTestCallback, NULL); // Create an environment v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template); context0->Enter(); @@ -7735,6 +7949,7 @@ TEST(SecurityHandler) { v8::Handle<Script> script1 = v8_compile("othercontext.foo = 222; othercontext[0] = 888;"); script1->Run(); + g_security_callback_result = true; // This read will pass the security check. v8::Handle<Value> foo1 = global0->Get(v8_str("foo")); CHECK_EQ(111, foo1->Int32Value()); @@ -7743,7 +7958,7 @@ TEST(SecurityHandler) { CHECK_EQ(999, z1->Int32Value()); // Create another environment, should pass security checks. - { g_security_callback_result = true; // allow security handler to pass. + { v8::HandleScope scope2(isolate); LocalContext context2; v8::Handle<v8::Object> global2 = context2->Global(); @@ -7866,26 +8081,13 @@ THREADED_TEST(SecurityChecksForPrototypeChain) { } -static bool named_security_check_with_gc_called; +static bool security_check_with_gc_called; -static bool NamedSecurityCallbackWithGC(Local<v8::Object> global, - Local<Value> name, - v8::AccessType type, - Local<Value> data) { +static bool SecurityTestCallbackWithGC(Local<v8::Object> global, + Local<v8::Value> name, + v8::AccessType type, Local<Value> data) { CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); - named_security_check_with_gc_called = true; - return true; -} - - -static bool indexed_security_check_with_gc_called; - -static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global, - uint32_t key, - v8::AccessType type, - Local<Value> data) { - CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); - indexed_security_check_with_gc_called = true; + security_check_with_gc_called = true; return true; } @@ -7895,29 +8097,20 @@ TEST(SecurityTestGCAllowed) { v8::HandleScope handle_scope(isolate); v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate); - object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC, - IndexedSecurityTestCallbackWithGC); + object_template->SetAccessCheckCallbacks(SecurityTestCallbackWithGC, NULL); v8::Handle<Context> context = Context::New(isolate); v8::Context::Scope context_scope(context); context->Global()->Set(v8_str("obj"), object_template->NewInstance()); - named_security_check_with_gc_called = false; - CompileRun("obj.foo = new String(1001);"); - CHECK(named_security_check_with_gc_called); - - indexed_security_check_with_gc_called = false; + security_check_with_gc_called = false; CompileRun("obj[0] = new String(1002);"); - CHECK(indexed_security_check_with_gc_called); - - named_security_check_with_gc_called = false; - CHECK(CompileRun("obj.foo")->ToString(isolate)->Equals(v8_str("1001"))); - CHECK(named_security_check_with_gc_called); + CHECK(security_check_with_gc_called); - indexed_security_check_with_gc_called = false; + security_check_with_gc_called = false; CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002"))); - CHECK(indexed_security_check_with_gc_called); + CHECK(security_check_with_gc_called); } @@ -8275,22 +8468,11 @@ TEST(DetachedAccesses) { } -static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false }; -static bool NamedAccessBlocker(Local<v8::Object> global, - Local<Value> name, - v8::AccessType type, - Local<Value> data) { +static bool allowed_access = false; +static bool AccessBlocker(Local<v8::Object> global, Local<Value> name, + v8::AccessType type, Local<Value> data) { return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) || - allowed_access_type[type]; -} - - -static bool IndexedAccessBlocker(Local<v8::Object> global, - uint32_t key, - v8::AccessType type, - Local<Value> data) { - return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) || - allowed_access_type[type]; + allowed_access; } @@ -8338,8 +8520,7 @@ TEST(AccessControl) { v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); - global_template->SetAccessCheckCallbacks(NamedAccessBlocker, - IndexedAccessBlocker); + global_template->SetAccessCheckCallbacks(AccessBlocker, NULL); // Add an accessor accessible by cross-domain JS code. global_template->SetAccessor( @@ -8413,15 +8594,10 @@ TEST(AccessControl) { CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty()); CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty()); - // Enable ACCESS_HAS - allowed_access_type[v8::ACCESS_HAS] = true; - CHECK(CompileRun("other[239]").IsEmpty()); - // ... and now we can get the descriptor... - CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value") - .IsEmpty()); - // ... and enumerate the property. + allowed_access = true; + // Now we can enumerate the property. ExpectTrue("propertyIsEnumerable.call(other, '239')"); - allowed_access_type[v8::ACCESS_HAS] = false; + allowed_access = false; // Access a property with JS accessor. CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty()); @@ -8430,9 +8606,7 @@ TEST(AccessControl) { CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')") .IsEmpty()); - // Enable both ACCESS_HAS and ACCESS_GET. - allowed_access_type[v8::ACCESS_HAS] = true; - allowed_access_type[v8::ACCESS_GET] = true; + allowed_access = true; ExpectString("other.js_accessor_p", "getter"); ExpectObject( @@ -8442,8 +8616,7 @@ TEST(AccessControl) { ExpectUndefined( "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); - allowed_access_type[v8::ACCESS_HAS] = false; - allowed_access_type[v8::ACCESS_GET] = false; + allowed_access = false; // Access an element with JS accessor. CHECK(CompileRun("other[42] = 2").IsEmpty()); @@ -8451,17 +8624,14 @@ TEST(AccessControl) { CHECK(CompileRun("other[42]").IsEmpty()); CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty()); - // Enable both ACCESS_HAS and ACCESS_GET. - allowed_access_type[v8::ACCESS_HAS] = true; - allowed_access_type[v8::ACCESS_GET] = true; + allowed_access = true; ExpectString("other[42]", "el_getter"); ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); - allowed_access_type[v8::ACCESS_HAS] = false; - allowed_access_type[v8::ACCESS_GET] = false; + allowed_access = false; v8::Handle<Value> value; @@ -8514,8 +8684,7 @@ TEST(AccessControlES5) { v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); - global_template->SetAccessCheckCallbacks(NamedAccessBlocker, - IndexedAccessBlocker); + global_template->SetAccessCheckCallbacks(AccessBlocker, NULL); // Add accessible accessor. global_template->SetAccessor( @@ -8578,14 +8747,9 @@ TEST(AccessControlES5) { } -static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name, - v8::AccessType type, Local<Value> data) { - return false; -} - - -static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key, - v8::AccessType type, Local<Value> data) { +static bool AccessAlwaysBlocked(Local<v8::Object> global, Local<Value> name, + v8::AccessType type, Local<Value> data) { + i::PrintF("Access blocked.\n"); return false; } @@ -8597,8 +8761,7 @@ THREADED_TEST(AccessControlGetOwnPropertyNames) { v8::ObjectTemplate::New(isolate); obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42)); - obj_template->SetAccessCheckCallbacks(BlockEverythingNamed, - BlockEverythingIndexed); + obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL); // Create an environment v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template); @@ -8641,8 +8804,7 @@ TEST(SuperAccessControl) { v8::HandleScope handle_scope(isolate); v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate); - obj_template->SetAccessCheckCallbacks(BlockEverythingNamed, - BlockEverythingIndexed); + obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL); LocalContext env; env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance()); @@ -8690,6 +8852,32 @@ TEST(SuperAccessControl) { } +TEST(Regress470113) { + i::FLAG_harmony_classes = true; + i::FLAG_harmony_object_literals = true; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + v8::Handle<v8::ObjectTemplate> obj_template = + v8::ObjectTemplate::New(isolate); + obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL); + LocalContext env; + env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance()); + + { + v8::TryCatch try_catch; + CompileRun( + "'use strict';\n" + "class C extends Object {\n" + " m() { super.powned = 'Powned!'; }\n" + "}\n" + "let c = new C();\n" + "c.m.call(prohibited)"); + + CHECK(try_catch.HasCaught()); + } +} + + static void ConstTenGetter(Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { info.GetReturnValue().Set(v8_num(10)); @@ -8749,31 +8937,18 @@ THREADED_TEST(CrossDomainAccessors) { } -static int named_access_count = 0; -static int indexed_access_count = 0; +static int access_count = 0; -static bool NamedAccessCounter(Local<v8::Object> global, - Local<Value> name, - v8::AccessType type, - Local<Value> data) { - named_access_count++; - return true; -} - - -static bool IndexedAccessCounter(Local<v8::Object> global, - uint32_t key, - v8::AccessType type, - Local<Value> data) { - indexed_access_count++; +static bool AccessCounter(Local<v8::Object> global, Local<Value> name, + v8::AccessType type, Local<Value> data) { + access_count++; return true; } // This one is too easily disturbed by other tests. TEST(AccessControlIC) { - named_access_count = 0; - indexed_access_count = 0; + access_count = 0; v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope handle_scope(isolate); @@ -8786,8 +8961,7 @@ TEST(AccessControlIC) { // called for cross-domain access. v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate); - object_template->SetAccessCheckCallbacks(NamedAccessCounter, - IndexedAccessCounter); + object_template->SetAccessCheckCallbacks(AccessCounter, NULL); Local<v8::Object> object = object_template->NewInstance(); v8::HandleScope scope1(isolate); @@ -8811,7 +8985,7 @@ TEST(AccessControlIC) { value = CompileRun("testProp(obj)"); CHECK(value->IsNumber()); CHECK_EQ(1, value->Int32Value()); - CHECK_EQ(21, named_access_count); + CHECK_EQ(21, access_count); // Check that the named access-control function is called every time. CompileRun("var p = 'prop';" @@ -8825,16 +8999,18 @@ TEST(AccessControlIC) { value = CompileRun("testKeyed(obj)"); CHECK(value->IsNumber()); CHECK_EQ(1, value->Int32Value()); - CHECK_EQ(42, named_access_count); + CHECK_EQ(42, access_count); // Force the inline caches into generic state and try again. CompileRun("testKeyed({ a: 0 })"); CompileRun("testKeyed({ b: 0 })"); value = CompileRun("testKeyed(obj)"); CHECK(value->IsNumber()); CHECK_EQ(1, value->Int32Value()); - CHECK_EQ(63, named_access_count); + CHECK_EQ(63, access_count); // Check that the indexed access-control function is called every time. + access_count = 0; + CompileRun("function testIndexed(obj) {" " for (var i = 0; i < 10; i++) obj[0] = 1;" " for (var j = 0; j < 10; j++) obj[0];" @@ -8843,15 +9019,16 @@ TEST(AccessControlIC) { value = CompileRun("testIndexed(obj)"); CHECK(value->IsNumber()); CHECK_EQ(1, value->Int32Value()); - CHECK_EQ(21, indexed_access_count); + CHECK_EQ(21, access_count); // Force the inline caches into generic state. CompileRun("testIndexed(new Array(1))"); // Test that the indexed access check is called. value = CompileRun("testIndexed(obj)"); CHECK(value->IsNumber()); CHECK_EQ(1, value->Int32Value()); - CHECK_EQ(42, indexed_access_count); + CHECK_EQ(42, access_count); + access_count = 0; // Check that the named access check is called when invoking // functions on an object that requires access checks. CompileRun("obj.f = function() {}"); @@ -8859,7 +9036,8 @@ TEST(AccessControlIC) { " for (var i = 0; i < 10; i++) obj.f();" "}"); CompileRun("testCallNormal(obj)"); - CHECK_EQ(74, named_access_count); + printf("%i\n", access_count); + CHECK_EQ(11, access_count); // Force obj into slow case. value = CompileRun("delete obj.prop"); @@ -8870,89 +9048,14 @@ TEST(AccessControlIC) { value = CompileRun("testProp(obj);"); CHECK(value->IsNumber()); CHECK_EQ(1, value->Int32Value()); - CHECK_EQ(96, named_access_count); + CHECK_EQ(33, access_count); // Force the call inline cache into dictionary probing mode. CompileRun("o.f = function() {}; testCallNormal(o)"); // Test that the named access check is still called for each // invocation of the function. value = CompileRun("testCallNormal(obj)"); - CHECK_EQ(106, named_access_count); - - context1->Exit(); - context0->Exit(); -} - - -static bool NamedAccessFlatten(Local<v8::Object> global, - Local<Value> name, - v8::AccessType type, - Local<Value> data) { - char buf[100]; - int len; - - CHECK(name->IsString()); - - memset(buf, 0x1, sizeof(buf)); - len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); - CHECK_EQ(4, len); - - uint16_t buf2[100]; - - memset(buf, 0x1, sizeof(buf)); - len = name.As<String>()->Write(buf2); - CHECK_EQ(4, len); - - return true; -} - - -static bool IndexedAccessFlatten(Local<v8::Object> global, - uint32_t key, - v8::AccessType type, - Local<Value> data) { - return true; -} - - -// Regression test. In access checks, operations that may cause -// garbage collection are not allowed. It used to be the case that -// using the Write operation on a string could cause a garbage -// collection due to flattening of the string. This is no longer the -// case. -THREADED_TEST(AccessControlFlatten) { - named_access_count = 0; - indexed_access_count = 0; - - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope handle_scope(isolate); - - // Create an environment. - v8::Local<Context> context0 = Context::New(isolate); - context0->Enter(); - - // Create an object that requires access-check functions to be - // called for cross-domain access. - v8::Handle<v8::ObjectTemplate> object_template = - v8::ObjectTemplate::New(isolate); - object_template->SetAccessCheckCallbacks(NamedAccessFlatten, - IndexedAccessFlatten); - Local<v8::Object> object = object_template->NewInstance(); - - v8::HandleScope scope1(isolate); - - // Create another environment. - v8::Local<Context> context1 = Context::New(isolate); - context1->Enter(); - - // Make easy access to the object from the other environment. - v8::Handle<v8::Object> global1 = context1->Global(); - global1->Set(v8_str("obj"), object); - - v8::Handle<Value> value; - - value = v8_compile("var p = 'as' + 'df';")->Run(); - value = v8_compile("obj[p];")->Run(); + CHECK_EQ(43, access_count); context1->Exit(); context0->Exit(); @@ -10869,16 +10972,29 @@ THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) { try_catch.Reset(); CHECK(result.IsEmpty()); + Maybe<PropertyAttribute> attr = + instance->GetRealNamedPropertyAttributes(v8_str("f")); + CHECK(!try_catch.HasCaught()); + CHECK(Just(None) == attr); + result = another->GetRealNamedProperty(v8_str("f")); CHECK(try_catch.HasCaught()); try_catch.Reset(); CHECK(result.IsEmpty()); + attr = another->GetRealNamedPropertyAttributes(v8_str("f")); + CHECK(!try_catch.HasCaught()); + CHECK(Just(None) == attr); + result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f")); CHECK(try_catch.HasCaught()); try_catch.Reset(); CHECK(result.IsEmpty()); + attr = another->GetRealNamedPropertyAttributesInPrototypeChain(v8_str("f")); + CHECK(!try_catch.HasCaught()); + CHECK(Just(None) == attr); + result = another->Get(v8_str("f")); CHECK(try_catch.HasCaught()); try_catch.Reset(); @@ -10889,6 +11005,10 @@ THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) { try_catch.Reset(); CHECK(result.IsEmpty()); + attr = with_js_getter->GetRealNamedPropertyAttributes(v8_str("f")); + CHECK(!try_catch.HasCaught()); + CHECK(Just(None) == attr); + result = with_js_getter->Get(v8_str("f")); CHECK(try_catch.HasCaught()); try_catch.Reset(); @@ -12676,61 +12796,13 @@ THREADED_TEST(PropertyEnumeration2) { } } -static bool NamedSetAccessBlocker(Local<v8::Object> obj, - Local<Value> name, - v8::AccessType type, - Local<Value> data) { - return type != v8::ACCESS_SET; -} - - -static bool IndexedSetAccessBlocker(Local<v8::Object> obj, - uint32_t key, - v8::AccessType type, - Local<Value> data) { - return type != v8::ACCESS_SET; -} - - -THREADED_TEST(DisableAccessChecksWhileConfiguring) { - LocalContext context; - v8::Isolate* isolate = context->GetIsolate(); - v8::HandleScope scope(isolate); - Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); - templ->SetAccessCheckCallbacks(NamedSetAccessBlocker, - IndexedSetAccessBlocker); - templ->Set(v8_str("x"), v8::True(isolate)); - Local<v8::Object> instance = templ->NewInstance(); - context->Global()->Set(v8_str("obj"), instance); - Local<Value> value = CompileRun("obj.x"); - CHECK(value->BooleanValue()); -} - - -static bool NamedGetAccessBlocker(Local<v8::Object> obj, - Local<Value> name, - v8::AccessType type, - Local<Value> data) { - return false; -} - - -static bool IndexedGetAccessBlocker(Local<v8::Object> obj, - uint32_t key, - v8::AccessType type, - Local<Value> data) { - return false; -} - - THREADED_TEST(AccessChecksReenabledCorrectly) { LocalContext context; v8::Isolate* isolate = context->GetIsolate(); v8::HandleScope scope(isolate); Local<ObjectTemplate> templ = ObjectTemplate::New(isolate); - templ->SetAccessCheckCallbacks(NamedGetAccessBlocker, - IndexedGetAccessBlocker); + templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL); templ->Set(v8_str("a"), v8_str("a")); // Add more than 8 (see kMaxFastProperties) properties // so that the constructor will force copying map. @@ -12762,27 +12834,6 @@ THREADED_TEST(AccessChecksReenabledCorrectly) { } -// This tests that access check information remains on the global -// object template when creating contexts. -THREADED_TEST(AccessControlRepeatedContextCreation) { - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope handle_scope(isolate); - v8::Handle<v8::ObjectTemplate> global_template = - v8::ObjectTemplate::New(isolate); - global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker, - IndexedSetAccessBlocker); - i::Handle<i::ObjectTemplateInfo> internal_template = - v8::Utils::OpenHandle(*global_template); - CHECK(!internal_template->constructor()->IsUndefined()); - i::Handle<i::FunctionTemplateInfo> constructor( - i::FunctionTemplateInfo::cast(internal_template->constructor())); - CHECK(!constructor->access_check_info()->IsUndefined()); - v8::Local<Context> context0(Context::New(isolate, NULL, global_template)); - CHECK(!context0.IsEmpty()); - CHECK(!constructor->access_check_info()->IsUndefined()); -} - - THREADED_TEST(TurnOnAccessCheck) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope handle_scope(isolate); @@ -12791,10 +12842,8 @@ THREADED_TEST(TurnOnAccessCheck) { // default. v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); - global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, - IndexedGetAccessBlocker, - v8::Handle<v8::Value>(), - false); + global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL, + v8::Handle<v8::Value>(), false); v8::Local<Context> context = Context::New(isolate, NULL, global_template); Context::Scope context_scope(context); @@ -12850,109 +12899,6 @@ THREADED_TEST(TurnOnAccessCheck) { } -static const char* kPropertyA = "a"; -static const char* kPropertyH = "h"; - -static bool NamedGetAccessBlockAandH(Local<v8::Object> obj, - Local<Value> name, - v8::AccessType type, - Local<Value> data) { - if (!name->IsString()) return false; - i::Handle<i::String> name_handle = - v8::Utils::OpenHandle(String::Cast(*name)); - return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA)) - && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH)); -} - - -THREADED_TEST(TurnOnAccessCheckAndRecompile) { - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope handle_scope(isolate); - - // Create an environment with access check to the global object disabled by - // default. When the registered access checker will block access to properties - // a and h. - v8::Handle<v8::ObjectTemplate> global_template = - v8::ObjectTemplate::New(isolate); - global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH, - IndexedGetAccessBlocker, - v8::Handle<v8::Value>(), - false); - v8::Local<Context> context = Context::New(isolate, NULL, global_template); - Context::Scope context_scope(context); - - // Set up a property and a number of functions. - context->Global()->Set(v8_str("a"), v8_num(1)); - static const char* source = "function f1() {return a;}" - "function f2() {return a;}" - "function g1() {return h();}" - "function g2() {return h();}" - "function h() {return 1;}"; - - CompileRun(source); - Local<Function> f1; - Local<Function> f2; - Local<Function> g1; - Local<Function> g2; - Local<Function> h; - f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); - f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); - g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); - g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); - h = Local<Function>::Cast(context->Global()->Get(v8_str("h"))); - - // Get the global object. - v8::Handle<v8::Object> global = context->Global(); - - // Call f1 one time and f2 a number of times. This will ensure that f1 still - // uses the runtime system to retreive property a whereas f2 uses global load - // inline cache. - CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1))); - for (int i = 0; i < 4; i++) { - CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1))); - } - - // Same for g1 and g2. - CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1))); - for (int i = 0; i < 4; i++) { - CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1))); - } - - // Detach the global and turn on access check now blocking access to property - // a and function h. - Local<Object> hidden_global = Local<Object>::Cast( - context->Global()->GetPrototype()); - context->DetachGlobal(); - hidden_global->TurnOnAccessCheck(); - - // Failing access check results in exception. - CHECK(f1->Call(global, 0, NULL).IsEmpty()); - CHECK(f2->Call(global, 0, NULL).IsEmpty()); - CHECK(g1->Call(global, 0, NULL).IsEmpty()); - CHECK(g2->Call(global, 0, NULL).IsEmpty()); - - // No failing access check when just returning a constant. - CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1))); - - // Now compile the source again. And get the newly compiled functions, except - // for h for which access is blocked. - CompileRun(source); - f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1"))); - f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2"))); - g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1"))); - g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2"))); - CHECK(hidden_global->Get(v8_str("h")).IsEmpty()); - - // Failing access check results in exception. - v8::Local<v8::Value> result = f1->Call(global, 0, NULL); - CHECK(result.IsEmpty()); - CHECK(f1->Call(global, 0, NULL).IsEmpty()); - CHECK(f2->Call(global, 0, NULL).IsEmpty()); - CHECK(g1->Call(global, 0, NULL).IsEmpty()); - CHECK(g2->Call(global, 0, NULL).IsEmpty()); -} - - // Tests that ScriptData can be serialized and deserialized. TEST(PreCompileSerialization) { v8::V8::Initialize(); @@ -15223,6 +15169,54 @@ TEST(CaptureStackTraceForUncaughtExceptionAndSetters) { } +static void StackTraceFunctionNameListener(v8::Handle<v8::Message> message, + v8::Handle<Value>) { + v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); + CHECK_EQ(5, stack_trace->GetFrameCount()); + checkStackFrame("origin", "foo:0", 4, 7, false, false, + stack_trace->GetFrame(0)); + checkStackFrame("origin", "foo:1", 5, 27, false, false, + stack_trace->GetFrame(1)); + checkStackFrame("origin", "foo", 5, 27, false, false, + stack_trace->GetFrame(2)); + checkStackFrame("origin", "foo", 5, 27, false, false, + stack_trace->GetFrame(3)); + checkStackFrame("origin", "", 1, 14, false, false, stack_trace->GetFrame(4)); +} + + +TEST(GetStackTraceContainsFunctionsWithFunctionName) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + + CompileRunWithOrigin( + "function gen(name, counter) {\n" + " var f = function foo() {\n" + " if (counter === 0)\n" + " throw 1;\n" + " gen(name, counter - 1)();\n" + " };\n" + " if (counter == 3) {\n" + " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n" + " } else {\n" + " Object.defineProperty(f, 'name', {writable:true});\n" + " if (counter == 2)\n" + " f.name = 42;\n" + " else\n" + " f.name = name + ':' + counter;\n" + " }\n" + " return f;\n" + "};", + "origin"); + + v8::V8::AddMessageListener(StackTraceFunctionNameListener); + v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); + CompileRunWithOrigin("gen('foo', 3)();", "origin"); + v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); + v8::V8::RemoveMessageListeners(StackTraceFunctionNameListener); +} + + static void RethrowStackTraceHandler(v8::Handle<v8::Message> message, v8::Handle<v8::Value> data) { // Use the frame where JavaScript is called from. @@ -15991,30 +15985,10 @@ static void CreateGarbageInOldSpace() { } -// Test that idle notification can be handled and eventually returns true. -TEST(IdleNotification) { - const intptr_t MB = 1024 * 1024; - const int IdlePauseInMs = 1000; - LocalContext env; - v8::HandleScope scope(env->GetIsolate()); - intptr_t initial_size = CcTest::heap()->SizeOfObjects(); - CreateGarbageInOldSpace(); - intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); - CHECK_GT(size_with_garbage, initial_size + MB); - bool finished = false; - for (int i = 0; i < 200 && !finished; i++) { - finished = env->GetIsolate()->IdleNotification(IdlePauseInMs); - } - intptr_t final_size = CcTest::heap()->SizeOfObjects(); - CHECK(finished); - CHECK_LT(final_size, initial_size + 1); -} - - // Test that idle notification can be handled and eventually collects garbage. -TEST(IdleNotificationWithSmallHint) { +TEST(TestIdleNotification) { const intptr_t MB = 1024 * 1024; - const int IdlePauseInMs = 900; + const double IdlePauseInSeconds = 1.0; LocalContext env; v8::HandleScope scope(env->GetIsolate()); intptr_t initial_size = CcTest::heap()->SizeOfObjects(); @@ -16023,27 +15997,10 @@ TEST(IdleNotificationWithSmallHint) { CHECK_GT(size_with_garbage, initial_size + MB); bool finished = false; for (int i = 0; i < 200 && !finished; i++) { - finished = env->GetIsolate()->IdleNotification(IdlePauseInMs); - } - intptr_t final_size = CcTest::heap()->SizeOfObjects(); - CHECK(finished); - CHECK_LT(final_size, initial_size + 1); -} - - -// Test that idle notification can be handled and eventually collects garbage. -TEST(IdleNotificationWithLargeHint) { - const intptr_t MB = 1024 * 1024; - const int IdlePauseInMs = 900; - LocalContext env; - v8::HandleScope scope(env->GetIsolate()); - intptr_t initial_size = CcTest::heap()->SizeOfObjects(); - CreateGarbageInOldSpace(); - intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects(); - CHECK_GT(size_with_garbage, initial_size + MB); - bool finished = false; - for (int i = 0; i < 200 && !finished; i++) { - finished = env->GetIsolate()->IdleNotification(IdlePauseInMs); + finished = env->GetIsolate()->IdleNotificationDeadline( + (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() / + static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) + + IdlePauseInSeconds); } intptr_t final_size = CcTest::heap()->SizeOfObjects(); CHECK(finished); @@ -16188,7 +16145,7 @@ TEST(ExternalizeOldSpaceTwoByteCons) { CHECK(v8::Utils::OpenHandle(*cons)->IsConsString()); CcTest::heap()->CollectAllAvailableGarbage(); CHECK(CcTest::heap()->old_pointer_space()->Contains( - *v8::Utils::OpenHandle(*cons))); + *v8::Utils::OpenHandle(*cons))); TestResource* resource = new TestResource( AsciiToTwoByteString("Romeo Montague Juliet Capulet")); @@ -16211,7 +16168,7 @@ TEST(ExternalizeOldSpaceOneByteCons) { CHECK(v8::Utils::OpenHandle(*cons)->IsConsString()); CcTest::heap()->CollectAllAvailableGarbage(); CHECK(CcTest::heap()->old_pointer_space()->Contains( - *v8::Utils::OpenHandle(*cons))); + *v8::Utils::OpenHandle(*cons))); TestOneByteResource* resource = new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet")); @@ -16501,6 +16458,7 @@ THREADED_TEST(SpaghettiStackReThrow) { TEST(Regress528) { v8::V8::Initialize(); v8::Isolate* isolate = CcTest::isolate(); + i::FLAG_retain_maps_for_n_gc = 0; v8::HandleScope scope(isolate); v8::Local<Context> other_context; int gc_count; @@ -16593,7 +16551,8 @@ THREADED_TEST(ScriptOrigin) { v8::String::NewFromUtf8(env->GetIsolate(), "test"), v8::Integer::New(env->GetIsolate(), 1), v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()), - v8::Handle<v8::Integer>(), v8::True(env->GetIsolate())); + v8::Handle<v8::Integer>(), v8::True(env->GetIsolate()), + v8::String::NewFromUtf8(env->GetIsolate(), "http://sourceMapUrl")); v8::Handle<v8::String> script = v8::String::NewFromUtf8( env->GetIsolate(), "function f() {}\n\nfunction g() {}"); v8::Script::Compile(script, &origin)->Run(); @@ -16608,6 +16567,10 @@ THREADED_TEST(ScriptOrigin) { CHECK_EQ(1, script_origin_f.ResourceLineOffset()->Int32Value()); CHECK(script_origin_f.ResourceIsSharedCrossOrigin()->Value()); CHECK(script_origin_f.ResourceIsEmbedderDebugScript()->Value()); + printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined()); + + CHECK_EQ(0, strcmp("http://sourceMapUrl", + *v8::String::Utf8Value(script_origin_f.SourceMapUrl()))); v8::ScriptOrigin script_origin_g = g->GetScriptOrigin(); CHECK_EQ(0, strcmp("test", @@ -16615,6 +16578,8 @@ THREADED_TEST(ScriptOrigin) { CHECK_EQ(1, script_origin_g.ResourceLineOffset()->Int32Value()); CHECK(script_origin_g.ResourceIsSharedCrossOrigin()->Value()); CHECK(script_origin_g.ResourceIsEmbedderDebugScript()->Value()); + CHECK_EQ(0, strcmp("http://sourceMapUrl", + *v8::String::Utf8Value(script_origin_g.SourceMapUrl()))); } @@ -17457,10 +17422,8 @@ TEST(GCInFailedAccessCheckCallback) { // check callbacks that will block access. v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); - global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, - IndexedGetAccessBlocker, - v8::Handle<v8::Value>(), - false); + global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL, + v8::Handle<v8::Value>(), false); // Create a context and set an x property on it's global object. LocalContext context0(NULL, global_template); @@ -18230,18 +18193,22 @@ THREADED_TEST(CreationContext) { instance2 = func2->NewInstance(); } - CHECK(object1->CreationContext() == context1); - CheckContextId(object1, 1); - CHECK(func1->CreationContext() == context1); - CheckContextId(func1, 1); - CHECK(instance1->CreationContext() == context1); - CheckContextId(instance1, 1); - CHECK(object2->CreationContext() == context2); - CheckContextId(object2, 2); - CHECK(func2->CreationContext() == context2); - CheckContextId(func2, 2); - CHECK(instance2->CreationContext() == context2); - CheckContextId(instance2, 2); + { + Handle<Context> other_context = Context::New(isolate); + Context::Scope scope(other_context); + CHECK(object1->CreationContext() == context1); + CheckContextId(object1, 1); + CHECK(func1->CreationContext() == context1); + CheckContextId(func1, 1); + CHECK(instance1->CreationContext() == context1); + CheckContextId(instance1, 1); + CHECK(object2->CreationContext() == context2); + CheckContextId(object2, 2); + CHECK(func2->CreationContext() == context2); + CheckContextId(func2, 2); + CHECK(instance2->CreationContext() == context2); + CheckContextId(instance2, 2); + } { Context::Scope scope(context1); @@ -18288,6 +18255,8 @@ THREADED_TEST(CreationContextOfJsFunction) { function = CompileRun("function foo() {}; foo").As<Object>(); } + Handle<Context> other_context = Context::New(CcTest::isolate()); + Context::Scope scope(other_context); CHECK(function->CreationContext() == context); CheckContextId(function, 1); } @@ -18596,33 +18565,13 @@ THREADED_TEST(Regress1516) { } -static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global, - Local<Value> name, - v8::AccessType type, - Local<Value> data) { - // Only block read access to __proto__. - if (type == v8::ACCESS_GET && name->IsString() && - name.As<v8::String>()->Length() == 9 && - name.As<v8::String>()->Utf8Length() == 9) { - char buffer[10]; - CHECK_EQ(10, name.As<v8::String>()->WriteUtf8(buffer)); - return strncmp(buffer, "__proto__", 9) != 0; - } - - return true; -} - - THREADED_TEST(Regress93759) { v8::Isolate* isolate = CcTest::isolate(); HandleScope scope(isolate); // Template for object with security check. Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate); - // We don't do indexing, so any callback can be used for that. - no_proto_template->SetAccessCheckCallbacks( - BlockProtoNamedSecurityTestCallback, - IndexedSecurityTestCallback); + no_proto_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL); // Templates for objects with hidden prototypes and possibly security check. Local<FunctionTemplate> hidden_proto_template = @@ -18632,8 +18581,7 @@ THREADED_TEST(Regress93759) { Local<FunctionTemplate> protected_hidden_proto_template = v8::FunctionTemplate::New(isolate); protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks( - BlockProtoNamedSecurityTestCallback, - IndexedSecurityTestCallback); + AccessAlwaysBlocked, NULL); protected_hidden_proto_template->SetHiddenPrototype(true); // Context for "foreign" objects used in test. @@ -18644,12 +18592,10 @@ THREADED_TEST(Regress93759) { Local<Object> simple_object = Object::New(isolate); // Object with explicit security check. - Local<Object> protected_object = - no_proto_template->NewInstance(); + Local<Object> protected_object = no_proto_template->NewInstance(); // JSGlobalProxy object, always have security check. - Local<Object> proxy_object = - context->Global(); + Local<Object> proxy_object = context->Global(); // Global object, the prototype of proxy_object. No security checks. Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate); @@ -19815,24 +19761,6 @@ THREADED_TEST(SemaphoreInterruption) { #endif // V8_OS_POSIX -static bool NamedAccessAlwaysBlocked(Local<v8::Object> global, - Local<Value> name, - v8::AccessType type, - Local<Value> data) { - i::PrintF("Named access blocked.\n"); - return false; -} - - -static bool IndexAccessAlwaysBlocked(Local<v8::Object> global, - uint32_t key, - v8::AccessType type, - Local<Value> data) { - i::PrintF("Indexed access blocked.\n"); - return false; -} - - void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { CHECK(false); } @@ -19847,8 +19775,7 @@ TEST(JSONStringifyAccessCheck) { // check callbacks that will block access. v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); - global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked, - IndexAccessAlwaysBlocked); + global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL); // Create a context and set an x property on it's global object. LocalContext context0(NULL, global_template); @@ -19946,8 +19873,7 @@ TEST(AccessCheckThrows) { // check callbacks that will block access. v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); - global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked, - IndexAccessAlwaysBlocked); + global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL); // Create a context and set an x property on it's global object. LocalContext context0(NULL, global_template); @@ -20100,6 +20026,7 @@ class RequestInterruptTestWithFunctionCall isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)); env_->Global()->Set(v8_str("ShouldContinue"), func); + i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops. CompileRun("while (ShouldContinue()) { }"); } }; @@ -20115,6 +20042,7 @@ class RequestInterruptTestWithMethodCall isolate_, ShouldContinueCallback, v8::External::New(isolate_, this))); env_->Global()->Set(v8_str("Klass"), t->GetFunction()); + i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops. CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }"); } }; @@ -20130,6 +20058,7 @@ class RequestInterruptTestWithAccessor isolate_, ShouldContinueCallback, v8::External::New(isolate_, this))); env_->Global()->Set(v8_str("Klass"), t->GetFunction()); + i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops. CompileRun("var obj = new Klass; while (obj.shouldContinue) { }"); } }; @@ -20147,6 +20076,7 @@ class RequestInterruptTestWithNativeAccessor v8::External::New(isolate_, this)); env_->Global()->Set(v8_str("Klass"), t->GetFunction()); + i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops. CompileRun("var obj = new Klass; while (obj.shouldContinue) { }"); } @@ -20176,6 +20106,7 @@ class RequestInterruptTestWithMethodCallAndInterceptor env_->Global()->Set(v8_str("Klass"), t->GetFunction()); + i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops. CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }"); } @@ -20200,6 +20131,7 @@ class RequestInterruptTestWithMathAbs v8::External::New(isolate_, this))); i::FLAG_allow_natives_syntax = true; + i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops. CompileRun("function loopish(o) {" " var pre = 10;" " while (o.abs(1) > 0) {" @@ -20283,6 +20215,7 @@ class RequestMultipleInterrupts : public RequestInterruptTestBase { isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)); env_->Global()->Set(v8_str("ShouldContinue"), func); + i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops. CompileRun("while (ShouldContinue()) { }"); } @@ -21002,42 +20935,42 @@ TEST(Regress354123) { v8::HandleScope scope(isolate); v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); - templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter); + templ->SetAccessCheckCallbacks(AccessCounter, NULL); current->Global()->Set(v8_str("friend"), templ->NewInstance()); // Test access using __proto__ from the prototype chain. - named_access_count = 0; + access_count = 0; CompileRun("friend.__proto__ = {};"); - CHECK_EQ(2, named_access_count); + CHECK_EQ(2, access_count); CompileRun("friend.__proto__;"); - CHECK_EQ(4, named_access_count); + CHECK_EQ(4, access_count); // Test access using __proto__ as a hijacked function (A). - named_access_count = 0; + access_count = 0; CompileRun("var p = Object.prototype;" "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;" "f.call(friend, {});"); - CHECK_EQ(1, named_access_count); + CHECK_EQ(1, access_count); CompileRun("var p = Object.prototype;" "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;" "f.call(friend);"); - CHECK_EQ(2, named_access_count); + CHECK_EQ(2, access_count); // Test access using __proto__ as a hijacked function (B). - named_access_count = 0; + access_count = 0; CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');" "f.call(friend, {});"); - CHECK_EQ(1, named_access_count); + CHECK_EQ(1, access_count); CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');" "f.call(friend);"); - CHECK_EQ(2, named_access_count); + CHECK_EQ(2, access_count); // Test access using Object.setPrototypeOf reflective method. - named_access_count = 0; + access_count = 0; CompileRun("Object.setPrototypeOf(friend, {});"); - CHECK_EQ(1, named_access_count); + CHECK_EQ(1, access_count); CompileRun("Object.getPrototypeOf(friend);"); - CHECK_EQ(2, named_access_count); + CHECK_EQ(2, access_count); } @@ -21192,8 +21125,7 @@ TEST(Regress411877) { v8::HandleScope handle_scope(isolate); v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate); - object_template->SetAccessCheckCallbacks(NamedAccessCounter, - IndexedAccessCounter); + object_template->SetAccessCheckCallbacks(AccessCounter, NULL); v8::Handle<Context> context = Context::New(isolate); v8::Context::Scope context_scope(context); @@ -21208,8 +21140,7 @@ TEST(GetHiddenPropertyTableAfterAccessCheck) { v8::HandleScope handle_scope(isolate); v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate); - object_template->SetAccessCheckCallbacks(NamedAccessCounter, - IndexedAccessCounter); + object_template->SetAccessCheckCallbacks(AccessCounter, NULL); v8::Handle<Context> context = Context::New(isolate); v8::Context::Scope context_scope(context); @@ -21227,8 +21158,7 @@ TEST(Regress411793) { v8::HandleScope handle_scope(isolate); v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(isolate); - object_template->SetAccessCheckCallbacks(NamedAccessCounter, - IndexedAccessCounter); + object_template->SetAccessCheckCallbacks(AccessCounter, NULL); v8::Handle<Context> context = Context::New(isolate); v8::Context::Scope context_scope(context); @@ -21806,6 +21736,7 @@ TEST(TurboAsmDisablesNeuter) { "Module(this, {}, buffer).load();" "buffer"; + i::FLAG_turbo_osr = false; // TODO(titzer): test requires eager TF. v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>(); CHECK_EQ(should_be_neuterable, result->IsNeuterable()); @@ -21820,6 +21751,7 @@ TEST(TurboAsmDisablesNeuter) { "Module(this, {}, buffer).store();" "buffer"; + i::FLAG_turbo_osr = false; // TODO(titzer): test requires eager TF. result = CompileRun(store).As<v8::ArrayBuffer>(); CHECK_EQ(should_be_neuterable, result->IsNeuterable()); } @@ -21833,8 +21765,7 @@ TEST(GetPrototypeAccessControl) { v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(isolate); - obj_template->SetAccessCheckCallbacks(BlockEverythingNamed, - BlockEverythingIndexed); + obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL); env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance()); @@ -21917,7 +21848,6 @@ TEST(StreamingScriptWithSourceMappingURLInTheMiddle) { TEST(NewStringRangeError) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope handle_scope(isolate); - LocalContext env; const int length = i::String::kMaxLength + 1; const int buffer_size = length * sizeof(uint16_t); void* buffer = malloc(buffer_size); @@ -21928,21 +21858,21 @@ TEST(NewStringRangeError) { char* data = reinterpret_cast<char*>(buffer); CHECK(v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString, length).IsEmpty()); - CHECK(try_catch.HasCaught()); + CHECK(!try_catch.HasCaught()); } { v8::TryCatch try_catch; uint8_t* data = reinterpret_cast<uint8_t*>(buffer); CHECK(v8::String::NewFromOneByte(isolate, data, v8::String::kNormalString, length).IsEmpty()); - CHECK(try_catch.HasCaught()); + CHECK(!try_catch.HasCaught()); } { v8::TryCatch try_catch; uint16_t* data = reinterpret_cast<uint16_t*>(buffer); CHECK(v8::String::NewFromTwoByte(isolate, data, v8::String::kNormalString, length).IsEmpty()); - CHECK(try_catch.HasCaught()); + CHECK(!try_catch.HasCaught()); } free(buffer); } diff --git a/deps/v8/test/cctest/test-array-list.cc b/deps/v8/test/cctest/test-array-list.cc new file mode 100644 index 0000000000..2852043b2f --- /dev/null +++ b/deps/v8/test/cctest/test-array-list.cc @@ -0,0 +1,41 @@ +// 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 <stdlib.h> + +#include "src/v8.h" + +#include "src/factory.h" +#include "test/cctest/cctest.h" + +namespace { + +using namespace v8::internal; + + +TEST(ArrayList) { + LocalContext context; + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + Handle<ArrayList> array( + ArrayList::cast(isolate->heap()->empty_fixed_array())); + CHECK_EQ(0, array->Length()); + array = ArrayList::Add(array, handle(Smi::FromInt(100), isolate)); + CHECK_EQ(1, array->Length()); + CHECK_EQ(100, Smi::cast(array->Get(0))->value()); + array = ArrayList::Add(array, handle(Smi::FromInt(200), isolate), + handle(Smi::FromInt(300), isolate)); + CHECK_EQ(3, array->Length()); + CHECK_EQ(100, Smi::cast(array->Get(0))->value()); + CHECK_EQ(200, Smi::cast(array->Get(1))->value()); + CHECK_EQ(300, Smi::cast(array->Get(2))->value()); + array->Set(2, Smi::FromInt(400)); + CHECK_EQ(400, Smi::cast(array->Get(2))->value()); + array->Clear(2, isolate->heap()->undefined_value()); + array->SetLength(2); + CHECK_EQ(2, array->Length()); + CHECK_EQ(100, Smi::cast(array->Get(0))->value()); + CHECK_EQ(200, Smi::cast(array->Get(1))->value()); +} +} diff --git a/deps/v8/test/cctest/test-assembler-arm64.cc b/deps/v8/test/cctest/test-assembler-arm64.cc index df8477ba9f..e54c4894b7 100644 --- a/deps/v8/test/cctest/test-assembler-arm64.cc +++ b/deps/v8/test/cctest/test-assembler-arm64.cc @@ -11223,3 +11223,173 @@ TEST(pool_size) { TEARDOWN(); } + + +TEST(jump_tables_forward) { + // Test jump tables with forward jumps. + const int kNumCases = 512; + + INIT_V8(); + SETUP_SIZE(kNumCases * 5 * kInstructionSize + 8192); + START(); + + int32_t values[kNumCases]; + isolate->random_number_generator()->NextBytes(values, sizeof(values)); + int32_t results[kNumCases]; + memset(results, 0, sizeof(results)); + uintptr_t results_ptr = reinterpret_cast<uintptr_t>(results); + + Label loop; + Label labels[kNumCases]; + Label done; + + const Register& index = x0; + STATIC_ASSERT(sizeof(results[0]) == 4); + const Register& value = w1; + const Register& target = x2; + + __ Mov(index, 0); + __ Mov(target, results_ptr); + __ Bind(&loop); + + { + Assembler::BlockPoolsScope block_pools(&masm); + Label base; + + __ Adr(x10, &base); + __ Ldr(x11, MemOperand(x10, index, LSL, kPointerSizeLog2)); + __ Br(x11); + __ Bind(&base); + for (int i = 0; i < kNumCases; ++i) { + __ dcptr(&labels[i]); + } + } + + for (int i = 0; i < kNumCases; ++i) { + __ Bind(&labels[i]); + __ Mov(value, values[i]); + __ B(&done); + } + + __ Bind(&done); + __ Str(value, MemOperand(target, 4, PostIndex)); + __ Add(index, index, 1); + __ Cmp(index, kNumCases); + __ B(ne, &loop); + + END(); + + RUN(); + + for (int i = 0; i < kNumCases; ++i) { + CHECK_EQ(values[i], results[i]); + } + + TEARDOWN(); +} + + +TEST(jump_tables_backward) { + // Test jump tables with backward jumps. + const int kNumCases = 512; + + INIT_V8(); + SETUP_SIZE(kNumCases * 5 * kInstructionSize + 8192); + START(); + + int32_t values[kNumCases]; + isolate->random_number_generator()->NextBytes(values, sizeof(values)); + int32_t results[kNumCases]; + memset(results, 0, sizeof(results)); + uintptr_t results_ptr = reinterpret_cast<uintptr_t>(results); + + Label loop; + Label labels[kNumCases]; + Label done; + + const Register& index = x0; + STATIC_ASSERT(sizeof(results[0]) == 4); + const Register& value = w1; + const Register& target = x2; + + __ Mov(index, 0); + __ Mov(target, results_ptr); + __ B(&loop); + + for (int i = 0; i < kNumCases; ++i) { + __ Bind(&labels[i]); + __ Mov(value, values[i]); + __ B(&done); + } + + __ Bind(&loop); + { + Assembler::BlockPoolsScope block_pools(&masm); + Label base; + + __ Adr(x10, &base); + __ Ldr(x11, MemOperand(x10, index, LSL, kPointerSizeLog2)); + __ Br(x11); + __ Bind(&base); + for (int i = 0; i < kNumCases; ++i) { + __ dcptr(&labels[i]); + } + } + + __ Bind(&done); + __ Str(value, MemOperand(target, 4, PostIndex)); + __ Add(index, index, 1); + __ Cmp(index, kNumCases); + __ B(ne, &loop); + + END(); + + RUN(); + + for (int i = 0; i < kNumCases; ++i) { + CHECK_EQ(values[i], results[i]); + } + + TEARDOWN(); +} + + +TEST(internal_reference_linked) { + // Test internal reference when they are linked in a label chain. + + INIT_V8(); + SETUP(); + START(); + + Label done; + + __ Mov(x0, 0); + __ Cbnz(x0, &done); + + { + Assembler::BlockPoolsScope block_pools(&masm); + Label base; + + __ Adr(x10, &base); + __ Ldr(x11, MemOperand(x10)); + __ Br(x11); + __ Bind(&base); + __ dcptr(&done); + } + + // Dead code, just to extend the label chain. + __ B(&done); + __ dcptr(&done); + __ Tbz(x0, 1, &done); + + __ Bind(&done); + __ Mov(x0, 1); + + END(); + + RUN(); + + CHECK_EQUAL_64(0x1, x0); + + TEARDOWN(); +} diff --git a/deps/v8/test/cctest/test-assembler-ia32.cc b/deps/v8/test/cctest/test-assembler-ia32.cc index 46592a05d1..5a7ad0294a 100644 --- a/deps/v8/test/cctest/test-assembler-ia32.cc +++ b/deps/v8/test/cctest/test-assembler-ia32.cc @@ -34,7 +34,6 @@ #include "src/factory.h" #include "src/macro-assembler.h" #include "src/ostreams.h" -#include "src/serialize.h" #include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-assembler-mips64.cc b/deps/v8/test/cctest/test-assembler-mips64.cc index d4cabbcf72..e55fb24282 100644 --- a/deps/v8/test/cctest/test-assembler-mips64.cc +++ b/deps/v8/test/cctest/test-assembler-mips64.cc @@ -1585,7 +1585,7 @@ TEST(jump_tables3) { __ bind(&done); __ ld(ra, MemOperand(sp)); - __ addiu(sp, sp, 8); + __ daddiu(sp, sp, 8); __ jr(ra); __ nop(); @@ -1594,7 +1594,7 @@ TEST(jump_tables3) { Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT -// code->Print(std::cout); + code->Print(std::cout); #endif F1 f = FUNCTION_CAST<F1>(code->entry()); for (int i = 0; i < kNumCases; ++i) { diff --git a/deps/v8/test/cctest/test-assembler-x64.cc b/deps/v8/test/cctest/test-assembler-x64.cc index f5d59ded9b..ca88309bb6 100644 --- a/deps/v8/test/cctest/test-assembler-x64.cc +++ b/deps/v8/test/cctest/test-assembler-x64.cc @@ -34,7 +34,6 @@ #include "src/factory.h" #include "src/macro-assembler.h" #include "src/ostreams.h" -#include "src/serialize.h" #include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-assembler-x87.cc b/deps/v8/test/cctest/test-assembler-x87.cc index c07be845b9..f83bbbd0d8 100644 --- a/deps/v8/test/cctest/test-assembler-x87.cc +++ b/deps/v8/test/cctest/test-assembler-x87.cc @@ -34,7 +34,6 @@ #include "src/factory.h" #include "src/macro-assembler.h" #include "src/ostreams.h" -#include "src/serialize.h" #include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-compiler.cc b/deps/v8/test/cctest/test-compiler.cc index faf533239e..ed8b1c6d99 100644 --- a/deps/v8/test/cctest/test-compiler.cc +++ b/deps/v8/test/cctest/test-compiler.cc @@ -60,7 +60,7 @@ static Handle<JSFunction> Compile(const char* source) { Handle<String> source_code = isolate->factory()->NewStringFromUtf8( CStrVector(source)).ToHandleChecked(); Handle<SharedFunctionInfo> shared_function = Compiler::CompileScript( - source_code, Handle<String>(), 0, 0, false, false, + source_code, Handle<String>(), 0, 0, false, false, Handle<Object>(), Handle<Context>(isolate->native_context()), NULL, NULL, v8::ScriptCompiler::kNoCompileOptions, NOT_NATIVES_CODE, false); return isolate->factory()->NewFunctionFromSharedFunctionInfo( diff --git a/deps/v8/test/cctest/test-constantpool.cc b/deps/v8/test/cctest/test-constantpool.cc index 453657609e..8b9b2cf73a 100644 --- a/deps/v8/test/cctest/test-constantpool.cc +++ b/deps/v8/test/cctest/test-constantpool.cc @@ -284,8 +284,9 @@ TEST(ConstantPoolCompacting) { Page* first_page = heap->old_data_space()->anchor()->next_page(); { HandleScope scope(isolate); + int dummy_array_size = Page::kMaxRegularHeapObjectSize - 92 * KB; Handle<HeapObject> temp = - factory->NewFixedDoubleArray(900 * KB / kDoubleSize, TENURED); + factory->NewFixedDoubleArray(dummy_array_size / kDoubleSize, TENURED); CHECK(heap->InOldDataSpace(temp->address())); Handle<HeapObject> heap_ptr = factory->NewHeapNumber(5.0, IMMUTABLE, TENURED); diff --git a/deps/v8/test/cctest/test-conversions.cc b/deps/v8/test/cctest/test-conversions.cc index b7881edcf6..789425119d 100644 --- a/deps/v8/test/cctest/test-conversions.cc +++ b/deps/v8/test/cctest/test-conversions.cc @@ -362,3 +362,58 @@ TEST(BitField64) { CHECK(x == MiddleBits::encode(3)); CHECK_EQ(3, MiddleBits::decode(x)); } + + +static void CheckNonArrayIndex(bool expected, const char* chars) { + auto isolate = CcTest::i_isolate(); + auto string = isolate->factory()->NewStringFromAsciiChecked(chars); + CHECK_EQ(expected, IsNonArrayIndexInteger(*string)); +} + + +TEST(NonArrayIndexParsing) { + auto isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + CheckNonArrayIndex(false, ""); + CheckNonArrayIndex(false, "-"); + CheckNonArrayIndex(false, "0"); + CheckNonArrayIndex(false, "01"); + CheckNonArrayIndex(false, "-01"); + CheckNonArrayIndex(false, "4294967295"); + CheckNonArrayIndex(false, "429496.7295"); + CheckNonArrayIndex(false, "43s3"); + CheckNonArrayIndex(true, "-0"); + CheckNonArrayIndex(true, "-1"); + CheckNonArrayIndex(true, "4294967296"); + CheckNonArrayIndex(true, "-4294967296"); + CheckNonArrayIndex( + true, + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296"); + CheckNonArrayIndex( + true, + "-429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296" + "429496729642949672964294967296429496729642949672964294967296"); +} diff --git a/deps/v8/test/cctest/test-cpu-profiler.cc b/deps/v8/test/cctest/test-cpu-profiler.cc index e2b6db0b96..a8cbdd505c 100644 --- a/deps/v8/test/cctest/test-cpu-profiler.cc +++ b/deps/v8/test/cctest/test-cpu-profiler.cc @@ -56,6 +56,16 @@ static v8::Local<v8::Function> GetFunction(v8::Context* env, const char* name) { } +static int offset(const char* src, const char* substring) { + return static_cast<int>(strstr(src, substring) - src); +} + + +static const char* reason(const i::Deoptimizer::DeoptReason reason) { + return i::Deoptimizer::GetDeoptReason(reason); +} + + TEST(StartStop) { i::Isolate* isolate = CcTest::i_isolate(); CpuProfilesCollection profiles(isolate->heap()); @@ -433,8 +443,7 @@ static v8::CpuProfile* RunProfiler( static bool ContainsString(v8::Handle<v8::String> string, const Vector<v8::Handle<v8::String> >& vector) { for (int i = 0; i < vector.length(); i++) { - if (string->Equals(vector[i])) - return true; + if (string->Equals(vector[i])) return true; } return false; } @@ -445,18 +454,31 @@ static void CheckChildrenNames(const v8::CpuProfileNode* node, int count = node->GetChildrenCount(); for (int i = 0; i < count; i++) { v8::Handle<v8::String> name = node->GetChild(i)->GetFunctionName(); - CHECK(ContainsString(name, names)); + if (!ContainsString(name, names)) { + char buffer[100]; + i::SNPrintF(Vector<char>(buffer, arraysize(buffer)), + "Unexpected child '%s' found in '%s'", + *v8::String::Utf8Value(name), + *v8::String::Utf8Value(node->GetFunctionName())); + FATAL(buffer); + } // Check that there are no duplicates. for (int j = 0; j < count; j++) { if (j == i) continue; - CHECK(!name->Equals(node->GetChild(j)->GetFunctionName())); + if (name->Equals(node->GetChild(j)->GetFunctionName())) { + char buffer[100]; + i::SNPrintF(Vector<char>(buffer, arraysize(buffer)), + "Second child with the same name '%s' found in '%s'", + *v8::String::Utf8Value(name), + *v8::String::Utf8Value(node->GetFunctionName())); + FATAL(buffer); + } } } } -static const v8::CpuProfileNode* FindChild(v8::Isolate* isolate, - const v8::CpuProfileNode* node, +static const v8::CpuProfileNode* FindChild(const v8::CpuProfileNode* node, const char* name) { int count = node->GetChildrenCount(); v8::Handle<v8::String> nameHandle = v8_str(name); @@ -468,10 +490,9 @@ static const v8::CpuProfileNode* FindChild(v8::Isolate* isolate, } -static const v8::CpuProfileNode* GetChild(v8::Isolate* isolate, - const v8::CpuProfileNode* node, +static const v8::CpuProfileNode* GetChild(const v8::CpuProfileNode* node, const char* name) { - const v8::CpuProfileNode* result = FindChild(isolate, node, name); + const v8::CpuProfileNode* result = FindChild(node, name); if (!result) { char buffer[100]; i::SNPrintF(Vector<char>(buffer, arraysize(buffer)), @@ -482,26 +503,24 @@ static const v8::CpuProfileNode* GetChild(v8::Isolate* isolate, } -static void CheckSimpleBranch(v8::Isolate* isolate, - const v8::CpuProfileNode* node, +static void CheckSimpleBranch(const v8::CpuProfileNode* node, const char* names[], int length) { for (int i = 0; i < length; i++) { const char* name = names[i]; - node = GetChild(isolate, node, name); + node = GetChild(node, name); int expectedChildrenCount = (i == length - 1) ? 0 : 1; CHECK_EQ(expectedChildrenCount, node->GetChildrenCount()); } } -static const v8::CpuProfileNode* GetSimpleBranch(v8::Isolate* isolate, - const v8::CpuProfileNode* node, - const char* names[], - int length) { +static const ProfileNode* GetSimpleBranch(v8::CpuProfile* profile, + const char* names[], int length) { + const v8::CpuProfileNode* node = profile->GetTopDownRoot(); for (int i = 0; i < length; i++) { - node = GetChild(isolate, node, names[i]); + node = GetChild(node, names[i]); } - return node; + return reinterpret_cast<const ProfileNode*>(node); } @@ -577,23 +596,18 @@ TEST(CollectCpuProfile) { names[2] = v8_str("start"); CheckChildrenNames(root, names); - const v8::CpuProfileNode* startNode = - GetChild(env->GetIsolate(), root, "start"); + const v8::CpuProfileNode* startNode = GetChild(root, "start"); CHECK_EQ(1, startNode->GetChildrenCount()); - const v8::CpuProfileNode* fooNode = - GetChild(env->GetIsolate(), startNode, "foo"); + const v8::CpuProfileNode* fooNode = GetChild(startNode, "foo"); CHECK_EQ(3, fooNode->GetChildrenCount()); const char* barBranch[] = { "bar", "delay", "loop" }; - CheckSimpleBranch(env->GetIsolate(), fooNode, barBranch, - arraysize(barBranch)); + CheckSimpleBranch(fooNode, barBranch, arraysize(barBranch)); const char* bazBranch[] = { "baz", "delay", "loop" }; - CheckSimpleBranch(env->GetIsolate(), fooNode, bazBranch, - arraysize(bazBranch)); + CheckSimpleBranch(fooNode, bazBranch, arraysize(bazBranch)); const char* delayBranch[] = { "delay", "loop" }; - CheckSimpleBranch(env->GetIsolate(), fooNode, delayBranch, - arraysize(delayBranch)); + CheckSimpleBranch(fooNode, delayBranch, arraysize(delayBranch)); profile->Delete(); } @@ -650,11 +664,10 @@ TEST(HotDeoptNoFrameEntry) { names[2] = v8_str("start"); CheckChildrenNames(root, names); - const v8::CpuProfileNode* startNode = - GetChild(env->GetIsolate(), root, "start"); + const v8::CpuProfileNode* startNode = GetChild(root, "start"); CHECK_EQ(1, startNode->GetChildrenCount()); - GetChild(env->GetIsolate(), startNode, "foo"); + GetChild(startNode, "foo"); profile->Delete(); } @@ -736,17 +749,15 @@ TEST(SampleWhenFrameIsNotSetup) { names[2] = v8_str("start"); CheckChildrenNames(root, names); - const v8::CpuProfileNode* startNode = - FindChild(env->GetIsolate(), root, "start"); + const v8::CpuProfileNode* startNode = FindChild(root, "start"); // On slow machines there may be no meaningfull samples at all, skip the // check there. if (startNode && startNode->GetChildrenCount() > 0) { CHECK_EQ(1, startNode->GetChildrenCount()); - const v8::CpuProfileNode* delayNode = - GetChild(env->GetIsolate(), startNode, "delay"); + const v8::CpuProfileNode* delayNode = GetChild(startNode, "delay"); if (delayNode->GetChildrenCount() > 0) { CHECK_EQ(1, delayNode->GetChildrenCount()); - GetChild(env->GetIsolate(), delayNode, "loop"); + GetChild(delayNode, "loop"); } } @@ -842,10 +853,9 @@ TEST(NativeAccessorUninitializedIC) { RunProfiler(env.local(), function, args, arraysize(args), 180); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - const v8::CpuProfileNode* startNode = - GetChild(isolate, root, "start"); - GetChild(isolate, startNode, "get foo"); - GetChild(isolate, startNode, "set foo"); + const v8::CpuProfileNode* startNode = GetChild(root, "start"); + GetChild(startNode, "get foo"); + GetChild(startNode, "set foo"); profile->Delete(); } @@ -894,10 +904,9 @@ TEST(NativeAccessorMonomorphicIC) { RunProfiler(env.local(), function, args, arraysize(args), 200); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - const v8::CpuProfileNode* startNode = - GetChild(isolate, root, "start"); - GetChild(isolate, startNode, "get foo"); - GetChild(isolate, startNode, "set foo"); + const v8::CpuProfileNode* startNode = GetChild(root, "start"); + GetChild(startNode, "get foo"); + GetChild(startNode, "set foo"); profile->Delete(); } @@ -944,9 +953,8 @@ TEST(NativeMethodUninitializedIC) { RunProfiler(env.local(), function, args, arraysize(args), 100); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - const v8::CpuProfileNode* startNode = - GetChild(isolate, root, "start"); - GetChild(isolate, startNode, "fooMethod"); + const v8::CpuProfileNode* startNode = GetChild(root, "start"); + GetChild(startNode, "fooMethod"); profile->Delete(); } @@ -997,10 +1005,9 @@ TEST(NativeMethodMonomorphicIC) { RunProfiler(env.local(), function, args, arraysize(args), 100); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - GetChild(isolate, root, "start"); - const v8::CpuProfileNode* startNode = - GetChild(isolate, root, "start"); - GetChild(isolate, startNode, "fooMethod"); + GetChild(root, "start"); + const v8::CpuProfileNode* startNode = GetChild(root, "start"); + GetChild(startNode, "fooMethod"); profile->Delete(); } @@ -1034,9 +1041,8 @@ TEST(BoundFunctionCall) { // Don't allow |foo| node to be at the top level. CheckChildrenNames(root, names); - const v8::CpuProfileNode* startNode = - GetChild(env->GetIsolate(), root, "start"); - GetChild(env->GetIsolate(), startNode, "foo"); + const v8::CpuProfileNode* startNode = GetChild(root, "start"); + GetChild(startNode, "foo"); profile->Delete(); } @@ -1086,10 +1092,10 @@ TEST(TickLines) { CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap()); profiles->StartProfiling("", false); ProfileGenerator generator(profiles); - ProfilerEventsProcessor* processor = new ProfilerEventsProcessor( - &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100)); + SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor( + &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100))); processor->Start(); - CpuProfiler profiler(isolate, profiles, &generator, processor); + CpuProfiler profiler(isolate, profiles, &generator, processor.get()); // Enqueue code creation events. i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name); @@ -1099,7 +1105,7 @@ TEST(TickLines) { *str, line, column); // Enqueue a tick event to enable code events processing. - EnqueueTickSampleEvent(processor, code_address); + EnqueueTickSampleEvent(processor.get(), code_address); processor->StopSynchronously(); @@ -1197,8 +1203,7 @@ TEST(FunctionCallSample) { // won't be |start| node in the profiles. bool is_gc_stress_testing = (i::FLAG_gc_interval != -1) || i::FLAG_stress_compaction; - const v8::CpuProfileNode* startNode = - FindChild(env->GetIsolate(), root, "start"); + const v8::CpuProfileNode* startNode = FindChild(root, "start"); CHECK(is_gc_stress_testing || startNode); if (startNode) { ScopedVector<v8::Handle<v8::String> > names(2); @@ -1207,8 +1212,8 @@ TEST(FunctionCallSample) { CheckChildrenNames(startNode, names); } - const v8::CpuProfileNode* unresolvedNode = FindChild( - env->GetIsolate(), root, i::ProfileGenerator::kUnresolvedFunctionName); + const v8::CpuProfileNode* unresolvedNode = + FindChild(root, i::ProfileGenerator::kUnresolvedFunctionName); if (unresolvedNode) { ScopedVector<v8::Handle<v8::String> > names(1); names[0] = v8_str("call"); @@ -1270,8 +1275,7 @@ TEST(FunctionApplySample) { CheckChildrenNames(root, names); } - const v8::CpuProfileNode* startNode = - FindChild(env->GetIsolate(), root, "start"); + const v8::CpuProfileNode* startNode = FindChild(root, "start"); if (startNode) { { ScopedVector<v8::Handle<v8::String> > names(2); @@ -1280,8 +1284,7 @@ TEST(FunctionApplySample) { CheckChildrenNames(startNode, names); } - const v8::CpuProfileNode* testNode = - FindChild(env->GetIsolate(), startNode, "test"); + const v8::CpuProfileNode* testNode = FindChild(startNode, "test"); if (testNode) { ScopedVector<v8::Handle<v8::String> > names(3); names[0] = v8_str("bar"); @@ -1293,12 +1296,11 @@ TEST(FunctionApplySample) { } if (const v8::CpuProfileNode* unresolvedNode = - FindChild(env->GetIsolate(), startNode, - ProfileGenerator::kUnresolvedFunctionName)) { + FindChild(startNode, ProfileGenerator::kUnresolvedFunctionName)) { ScopedVector<v8::Handle<v8::String> > names(1); names[0] = v8_str("apply"); CheckChildrenNames(unresolvedNode, names); - GetChild(env->GetIsolate(), unresolvedNode, "apply"); + GetChild(unresolvedNode, "apply"); } } @@ -1354,10 +1356,9 @@ TEST(CpuProfileDeepStack) { CheckChildrenNames(root, names); } - const v8::CpuProfileNode* node = - GetChild(env->GetIsolate(), root, "start"); + const v8::CpuProfileNode* node = GetChild(root, "start"); for (int i = 0; i < 250; ++i) { - node = GetChild(env->GetIsolate(), node, "foo"); + node = GetChild(node, "foo"); } // TODO(alph): // In theory there must be one more 'foo' and a 'startProfiling' nodes, @@ -1419,18 +1420,16 @@ TEST(JsNativeJsSample) { CheckChildrenNames(root, names); } - const v8::CpuProfileNode* startNode = - GetChild(env->GetIsolate(), root, "start"); + const v8::CpuProfileNode* startNode = GetChild(root, "start"); CHECK_EQ(1, startNode->GetChildrenCount()); const v8::CpuProfileNode* nativeFunctionNode = - GetChild(env->GetIsolate(), startNode, "CallJsFunction"); + GetChild(startNode, "CallJsFunction"); CHECK_EQ(1, nativeFunctionNode->GetChildrenCount()); - const v8::CpuProfileNode* barNode = - GetChild(env->GetIsolate(), nativeFunctionNode, "bar"); + const v8::CpuProfileNode* barNode = GetChild(nativeFunctionNode, "bar"); CHECK_EQ(1, barNode->GetChildrenCount()); - GetChild(env->GetIsolate(), barNode, "foo"); + GetChild(barNode, "foo"); profile->Delete(); } @@ -1481,22 +1480,20 @@ TEST(JsNativeJsRuntimeJsSample) { names[2] = v8_str("start"); CheckChildrenNames(root, names); - const v8::CpuProfileNode* startNode = - GetChild(env->GetIsolate(), root, "start"); + const v8::CpuProfileNode* startNode = GetChild(root, "start"); CHECK_EQ(1, startNode->GetChildrenCount()); const v8::CpuProfileNode* nativeFunctionNode = - GetChild(env->GetIsolate(), startNode, "CallJsFunction"); + GetChild(startNode, "CallJsFunction"); CHECK_EQ(1, nativeFunctionNode->GetChildrenCount()); - const v8::CpuProfileNode* barNode = - GetChild(env->GetIsolate(), nativeFunctionNode, "bar"); + const v8::CpuProfileNode* barNode = GetChild(nativeFunctionNode, "bar"); // The child is in fact a bound foo. // A bound function has a wrapper that may make calls to // other functions e.g. "get length". CHECK_LE(1, barNode->GetChildrenCount()); CHECK_GE(2, barNode->GetChildrenCount()); - GetChild(env->GetIsolate(), barNode, "foo"); + GetChild(barNode, "foo"); profile->Delete(); } @@ -1560,22 +1557,19 @@ TEST(JsNative1JsNative2JsSample) { names[2] = v8_str("start"); CheckChildrenNames(root, names); - const v8::CpuProfileNode* startNode = - GetChild(env->GetIsolate(), root, "start"); + const v8::CpuProfileNode* startNode = GetChild(root, "start"); CHECK_EQ(1, startNode->GetChildrenCount()); const v8::CpuProfileNode* nativeNode1 = - GetChild(env->GetIsolate(), startNode, "CallJsFunction1"); + GetChild(startNode, "CallJsFunction1"); CHECK_EQ(1, nativeNode1->GetChildrenCount()); - const v8::CpuProfileNode* barNode = - GetChild(env->GetIsolate(), nativeNode1, "bar"); + const v8::CpuProfileNode* barNode = GetChild(nativeNode1, "bar"); CHECK_EQ(1, barNode->GetChildrenCount()); - const v8::CpuProfileNode* nativeNode2 = - GetChild(env->GetIsolate(), barNode, "CallJsFunction2"); + const v8::CpuProfileNode* nativeNode2 = GetChild(barNode, "CallJsFunction2"); CHECK_EQ(1, nativeNode2->GetChildrenCount()); - GetChild(env->GetIsolate(), nativeNode2, "foo"); + GetChild(nativeNode2, "foo"); profile->Delete(); } @@ -1620,12 +1614,12 @@ TEST(IdleTime) { CheckChildrenNames(root, names); const v8::CpuProfileNode* programNode = - GetChild(env->GetIsolate(), root, ProfileGenerator::kProgramEntryName); + GetChild(root, ProfileGenerator::kProgramEntryName); CHECK_EQ(0, programNode->GetChildrenCount()); CHECK_GE(programNode->GetHitCount(), 3u); const v8::CpuProfileNode* idleNode = - GetChild(env->GetIsolate(), root, ProfileGenerator::kIdleEntryName); + GetChild(root, ProfileGenerator::kIdleEntryName); CHECK_EQ(0, idleNode->GetChildrenCount()); CHECK_GE(idleNode->GetHitCount(), 3u); @@ -1672,16 +1666,16 @@ TEST(FunctionDetails) { // 0 foo 18 #4 TryCatchStatement script_a:2 // 1 bar 18 #5 no reason script_a:3 const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - const v8::CpuProfileNode* script = GetChild(env->GetIsolate(), root, ""); + const v8::CpuProfileNode* script = GetChild(root, ""); CheckFunctionDetails(env->GetIsolate(), script, "", "script_b", script_b->GetUnboundScript()->GetId(), 1, 1); - const v8::CpuProfileNode* baz = GetChild(env->GetIsolate(), script, "baz"); + const v8::CpuProfileNode* baz = GetChild(script, "baz"); CheckFunctionDetails(env->GetIsolate(), baz, "baz", "script_b", script_b->GetUnboundScript()->GetId(), 3, 16); - const v8::CpuProfileNode* foo = GetChild(env->GetIsolate(), baz, "foo"); + const v8::CpuProfileNode* foo = GetChild(baz, "foo"); CheckFunctionDetails(env->GetIsolate(), foo, "foo", "script_a", script_a->GetUnboundScript()->GetId(), 2, 1); - const v8::CpuProfileNode* bar = GetChild(env->GetIsolate(), foo, "bar"); + const v8::CpuProfileNode* bar = GetChild(foo, "bar"); CheckFunctionDetails(env->GetIsolate(), bar, "bar", "script_a", script_a->GetUnboundScript()->GetId(), 3, 14); } @@ -1720,39 +1714,17 @@ TEST(DontStopOnFinishedProfileDelete) { } -static const char* collect_deopt_events_test_source = - "function opt_function(left, right, depth) {\n" - " if (depth) return opt_function(left, right, depth - 1);\n" - "\n" - " var k = left / 10;\n" - " var r = 10 / right;\n" - " return k + r;" - "}\n" - "\n" - "function test(left, right) {\n" - " return opt_function(left, right, 1);\n" - "}\n" - "\n" - "startProfiling();\n" - "\n" - "test(10, 10);\n" - "\n" - "%OptimizeFunctionOnNextCall(opt_function)\n" - "\n" - "test(10, 10);\n" - "\n" - "test(undefined, 10);\n" - "\n" - "%OptimizeFunctionOnNextCall(opt_function)\n" - "\n" - "test(10, 10);\n" - "\n" - "test(10, 0);\n" - "\n" - "stopProfiling();\n" - "\n"; +const char* GetBranchDeoptReason(i::CpuProfile* iprofile, const char* branch[], + int length) { + v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile); + const ProfileNode* iopt_function = NULL; + iopt_function = GetSimpleBranch(profile, branch, length); + CHECK_EQ(1, iopt_function->deopt_infos().size()); + return iopt_function->deopt_infos()[0].deopt_reason; +} +// deopt at top function TEST(CollectDeoptEvents) { if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; i::FLAG_allow_natives_syntax = true; @@ -1763,21 +1735,90 @@ TEST(CollectDeoptEvents) { v8::CpuProfiler* profiler = isolate->GetCpuProfiler(); i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler); - v8::Script::Compile(v8_str(collect_deopt_events_test_source))->Run(); + const char opt_source[] = + "function opt_function%d(value, depth) {\n" + " if (depth) return opt_function%d(value, depth - 1);\n" + "\n" + " return 10 / value;\n" + "}\n" + "\n"; + + for (int i = 0; i < 3; ++i) { + i::EmbeddedVector<char, sizeof(opt_source) + 100> buffer; + i::SNPrintF(buffer, opt_source, i, i); + v8::Script::Compile(v8_str(buffer.start()))->Run(); + } + + const char* source = + "startProfiling();\n" + "\n" + "opt_function0(1, 1);\n" + "\n" + "%OptimizeFunctionOnNextCall(opt_function0)\n" + "\n" + "opt_function0(1, 1);\n" + "\n" + "opt_function0(undefined, 1);\n" + "\n" + "opt_function1(1, 1);\n" + "\n" + "%OptimizeFunctionOnNextCall(opt_function1)\n" + "\n" + "opt_function1(1, 1);\n" + "\n" + "opt_function1(NaN, 1);\n" + "\n" + "opt_function2(1, 1);\n" + "\n" + "%OptimizeFunctionOnNextCall(opt_function2)\n" + "\n" + "opt_function2(1, 1);\n" + "\n" + "opt_function2(0, 1);\n" + "\n" + "stopProfiling();\n" + "\n"; + + v8::Script::Compile(v8_str(source))->Run(); i::CpuProfile* iprofile = iprofiler->GetProfile(0); iprofile->Print(); - v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile); - const char* branch[] = {"", "test", "opt_function", "opt_function"}; - const v8::CpuProfileNode* opt_function = GetSimpleBranch( - env->GetIsolate(), profile->GetTopDownRoot(), branch, arraysize(branch)); - CHECK(opt_function); - const i::ProfileNode* iopt_function = - reinterpret_cast<const i::ProfileNode*>(opt_function); - CHECK_EQ(2, iopt_function->deopt_infos().length()); - CHECK_EQ(i::Deoptimizer::GetDeoptReason(i::Deoptimizer::kNotAHeapNumber), - iopt_function->deopt_infos()[0].deopt_reason); - CHECK_EQ(i::Deoptimizer::GetDeoptReason(i::Deoptimizer::kDivisionByZero), - iopt_function->deopt_infos()[1].deopt_reason); + /* The expected profile + [Top down]: + 0 (root) 0 #1 + 23 32 #2 + 1 opt_function2 31 #7 + 1 opt_function2 31 #8 + ;;; deopted at script_id: 31 position: 106 with reason + 'division by zero'. + 2 opt_function0 29 #3 + 4 opt_function0 29 #4 + ;;; deopted at script_id: 29 position: 108 with reason 'not a + heap number'. + 0 opt_function1 30 #5 + 1 opt_function1 30 #6 + ;;; deopted at script_id: 30 position: 108 with reason 'lost + precision or NaN'. + */ + + { + const char* branch[] = {"", "opt_function0", "opt_function0"}; + CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber), + GetBranchDeoptReason(iprofile, branch, arraysize(branch))); + } + { + const char* branch[] = {"", "opt_function1", "opt_function1"}; + const char* deopt_reason = + GetBranchDeoptReason(iprofile, branch, arraysize(branch)); + if (deopt_reason != reason(i::Deoptimizer::kNaN) && + deopt_reason != reason(i::Deoptimizer::kLostPrecisionOrNaN)) { + FATAL(deopt_reason); + } + } + { + const char* branch[] = {"", "opt_function2", "opt_function2"}; + CHECK_EQ(reason(i::Deoptimizer::kDivisionByZero), + GetBranchDeoptReason(iprofile, branch, arraysize(branch))); + } iprofiler->DeleteProfile(iprofile); } @@ -1796,3 +1837,197 @@ TEST(SourceLocation) { v8::Script::Compile(v8_str(source))->Run(); } + + +static const char* inlined_source = + "function opt_function(left, right) { var k = left / 10; var r = 10 / " + "right; return k + r; }\n"; +// 0.........1.........2.........3.........4....*....5.........6......*..7 + + +// deopt at the first level inlined function +TEST(DeoptAtFirstLevelInlinedSource) { + if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; + i::FLAG_allow_natives_syntax = true; + v8::HandleScope scope(CcTest::isolate()); + v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION); + v8::Context::Scope context_scope(env); + v8::Isolate* isolate = env->GetIsolate(); + v8::CpuProfiler* profiler = isolate->GetCpuProfiler(); + i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler); + + // 0.........1.........2.........3.........4.........5.........6.........7 + const char* source = + "function test(left, right) { return opt_function(left, right); }\n" + "\n" + "startProfiling();\n" + "\n" + "test(10, 10);\n" + "\n" + "%OptimizeFunctionOnNextCall(test)\n" + "\n" + "test(10, 10);\n" + "\n" + "test(undefined, 10);\n" + "\n" + "stopProfiling();\n" + "\n"; + + v8::Handle<v8::Script> inlined_script = v8_compile(inlined_source); + inlined_script->Run(); + int inlined_script_id = inlined_script->GetUnboundScript()->GetId(); + + v8::Handle<v8::Script> script = v8_compile(source); + script->Run(); + int script_id = script->GetUnboundScript()->GetId(); + + i::CpuProfile* iprofile = iprofiler->GetProfile(0); + iprofile->Print(); + /* The expected profile output + [Top down]: + 0 (root) 0 #1 + 10 30 #2 + 1 test 30 #3 + ;;; deopted at script_id: 29 position: 45 with reason 'not a + heap number'. + ;;; Inline point: script_id 30 position: 36. + 4 opt_function 29 #4 + */ + v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile); + + const char* branch[] = {"", "test"}; + const ProfileNode* itest_node = + GetSimpleBranch(profile, branch, arraysize(branch)); + const std::vector<i::DeoptInfo>& deopt_infos = itest_node->deopt_infos(); + CHECK_EQ(1, deopt_infos.size()); + + const i::DeoptInfo& info = deopt_infos[0]; + CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber), info.deopt_reason); + CHECK_EQ(2, info.stack.size()); + CHECK_EQ(inlined_script_id, info.stack[0].script_id); + CHECK_EQ(offset(inlined_source, "left /"), info.stack[0].position); + CHECK_EQ(script_id, info.stack[1].script_id); + CHECK_EQ(offset(source, "opt_function(left,"), info.stack[1].position); + + iprofiler->DeleteProfile(iprofile); +} + + +// deopt at the second level inlined function +TEST(DeoptAtSecondLevelInlinedSource) { + if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; + i::FLAG_allow_natives_syntax = true; + v8::HandleScope scope(CcTest::isolate()); + v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION); + v8::Context::Scope context_scope(env); + v8::Isolate* isolate = env->GetIsolate(); + v8::CpuProfiler* profiler = isolate->GetCpuProfiler(); + i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler); + + // 0.........1.........2.........3.........4.........5.........6.........7 + const char* source = + "function test2(left, right) { return opt_function(left, right); }\n" + "function test1(left, right) { return test2(left, right); }\n" + "\n" + "startProfiling();\n" + "\n" + "test1(10, 10);\n" + "\n" + "%OptimizeFunctionOnNextCall(test1)\n" + "\n" + "test1(10, 10);\n" + "\n" + "test1(undefined, 10);\n" + "\n" + "stopProfiling();\n" + "\n"; + + v8::Handle<v8::Script> inlined_script = v8_compile(inlined_source); + inlined_script->Run(); + int inlined_script_id = inlined_script->GetUnboundScript()->GetId(); + + v8::Handle<v8::Script> script = v8_compile(source); + script->Run(); + int script_id = script->GetUnboundScript()->GetId(); + + i::CpuProfile* iprofile = iprofiler->GetProfile(0); + iprofile->Print(); + /* The expected profile output + [Top down]: + 0 (root) 0 #1 + 11 30 #2 + 1 test1 30 #3 + ;;; deopted at script_id: 29 position: 45 with reason 'not a + heap number'. + ;;; Inline point: script_id 30 position: 37. + ;;; Inline point: script_id 30 position: 103. + 1 test2 30 #4 + 3 opt_function 29 #5 + */ + + v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile); + + const char* branch[] = {"", "test1"}; + const ProfileNode* itest_node = + GetSimpleBranch(profile, branch, arraysize(branch)); + const std::vector<i::DeoptInfo>& deopt_infos = itest_node->deopt_infos(); + CHECK_EQ(1, deopt_infos.size()); + + const i::DeoptInfo info = deopt_infos[0]; + CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber), info.deopt_reason); + CHECK_EQ(3, info.stack.size()); + CHECK_EQ(inlined_script_id, info.stack[0].script_id); + CHECK_EQ(offset(inlined_source, "left /"), info.stack[0].position); + CHECK_EQ(script_id, info.stack[1].script_id); + CHECK_EQ(offset(source, "opt_function(left,"), info.stack[1].position); + CHECK_EQ(offset(source, "test2(left, right);"), info.stack[2].position); + + iprofiler->DeleteProfile(iprofile); +} + + +// deopt in untracked function +TEST(DeoptUntrackedFunction) { + if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; + i::FLAG_allow_natives_syntax = true; + v8::HandleScope scope(CcTest::isolate()); + v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION); + v8::Context::Scope context_scope(env); + v8::Isolate* isolate = env->GetIsolate(); + v8::CpuProfiler* profiler = isolate->GetCpuProfiler(); + i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler); + + // 0.........1.........2.........3.........4.........5.........6.........7 + const char* source = + "function test(left, right) { return opt_function(left, right); }\n" + "\n" + "test(10, 10);\n" + "\n" + "%OptimizeFunctionOnNextCall(test)\n" + "\n" + "test(10, 10);\n" + "\n" + "startProfiling();\n" // profiler started after compilation. + "\n" + "test(undefined, 10);\n" + "\n" + "stopProfiling();\n" + "\n"; + + v8::Handle<v8::Script> inlined_script = v8_compile(inlined_source); + inlined_script->Run(); + + v8::Handle<v8::Script> script = v8_compile(source); + script->Run(); + + i::CpuProfile* iprofile = iprofiler->GetProfile(0); + iprofile->Print(); + v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile); + + const char* branch[] = {"", "test"}; + const ProfileNode* itest_node = + GetSimpleBranch(profile, branch, arraysize(branch)); + CHECK_EQ(0, itest_node->deopt_infos().size()); + + iprofiler->DeleteProfile(iprofile); +} diff --git a/deps/v8/test/cctest/test-date.cc b/deps/v8/test/cctest/test-date.cc index 2f722c2baf..2bcc625a95 100644 --- a/deps/v8/test/cctest/test-date.cc +++ b/deps/v8/test/cctest/test-date.cc @@ -28,7 +28,6 @@ #include "src/v8.h" #include "src/global-handles.h" -#include "src/snapshot.h" #include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index a4a993ad30..5929379663 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -416,7 +416,7 @@ void CheckDebuggerUnloaded(bool check_functions) { if (RelocInfo::IsCodeTarget(rmode)) { CHECK(!Debug::IsDebugBreak(it.rinfo()->target_address())); } else if (RelocInfo::IsJSReturn(rmode)) { - CHECK(!Debug::IsDebugBreakAtReturn(it.rinfo())); + CHECK(!it.rinfo()->IsPatchedReturnSequence()); } } } @@ -437,47 +437,36 @@ static void CheckDebuggerUnloaded(bool check_functions = false) { } -// Inherit from BreakLocationIterator to get access to protected parts for -// testing. -class TestBreakLocationIterator: public v8::internal::BreakLocationIterator { - public: - explicit TestBreakLocationIterator(Handle<v8::internal::DebugInfo> debug_info) - : BreakLocationIterator(debug_info, v8::internal::SOURCE_BREAK_LOCATIONS) {} - v8::internal::RelocIterator* it() { return reloc_iterator_; } - v8::internal::RelocIterator* it_original() { - return reloc_iterator_original_; - } -}; - - // Compile a function, set a break point and check that the call at the break // location in the code is the expected debug_break function. void CheckDebugBreakFunction(DebugLocalContext* env, const char* source, const char* name, int position, v8::internal::RelocInfo::Mode mode, Code* debug_break) { - v8::internal::Debug* debug = CcTest::i_isolate()->debug(); + i::Debug* debug = CcTest::i_isolate()->debug(); // Create function and set the break point. - Handle<v8::internal::JSFunction> fun = v8::Utils::OpenHandle( - *CompileFunction(env, source, name)); + Handle<i::JSFunction> fun = + v8::Utils::OpenHandle(*CompileFunction(env, source, name)); int bp = SetBreakPoint(fun, position); // Check that the debug break function is as expected. - Handle<v8::internal::SharedFunctionInfo> shared(fun->shared()); + Handle<i::SharedFunctionInfo> shared(fun->shared()); CHECK(Debug::HasDebugInfo(shared)); - TestBreakLocationIterator it1(Debug::GetDebugInfo(shared)); - it1.FindBreakLocationFromPosition(position, v8::internal::STATEMENT_ALIGNED); - v8::internal::RelocInfo::Mode actual_mode = it1.it()->rinfo()->rmode(); - if (actual_mode == v8::internal::RelocInfo::CODE_TARGET_WITH_ID) { - actual_mode = v8::internal::RelocInfo::CODE_TARGET; + i::BreakLocation location = i::BreakLocation::FromPosition( + Debug::GetDebugInfo(shared), i::SOURCE_BREAK_LOCATIONS, position, + i::STATEMENT_ALIGNED); + i::RelocInfo::Mode actual_mode = location.rmode(); + if (actual_mode == i::RelocInfo::CODE_TARGET_WITH_ID) { + actual_mode = i::RelocInfo::CODE_TARGET; } CHECK_EQ(mode, actual_mode); - if (mode != v8::internal::RelocInfo::JS_RETURN) { - CHECK_EQ(debug_break, - Code::GetCodeFromTargetAddress(it1.it()->rinfo()->target_address())); + if (mode != i::RelocInfo::JS_RETURN) { + CHECK_EQ(debug_break, *location.CodeTarget()); } else { - CHECK(Debug::IsDebugBreakAtReturn(it1.it()->rinfo())); + i::RelocInfo rinfo = location.rinfo(); + CHECK(i::RelocInfo::IsJSReturn(rinfo.rmode())); + CHECK(rinfo.IsPatchedReturnSequence()); } // Clear the break point and check that the debug break function is no longer @@ -485,15 +474,17 @@ void CheckDebugBreakFunction(DebugLocalContext* env, ClearBreakPoint(bp); CHECK(!debug->HasDebugInfo(shared)); CHECK(debug->EnsureDebugInfo(shared, fun)); - TestBreakLocationIterator it2(Debug::GetDebugInfo(shared)); - it2.FindBreakLocationFromPosition(position, v8::internal::STATEMENT_ALIGNED); - actual_mode = it2.it()->rinfo()->rmode(); - if (actual_mode == v8::internal::RelocInfo::CODE_TARGET_WITH_ID) { - actual_mode = v8::internal::RelocInfo::CODE_TARGET; + location = i::BreakLocation::FromPosition(Debug::GetDebugInfo(shared), + i::SOURCE_BREAK_LOCATIONS, position, + i::STATEMENT_ALIGNED); + actual_mode = location.rmode(); + if (actual_mode == i::RelocInfo::CODE_TARGET_WITH_ID) { + actual_mode = i::RelocInfo::CODE_TARGET; } CHECK_EQ(mode, actual_mode); - if (mode == v8::internal::RelocInfo::JS_RETURN) { - CHECK(!Debug::IsDebugBreakAtReturn(it2.it()->rinfo())); + if (mode == i::RelocInfo::JS_RETURN) { + i::RelocInfo rinfo = location.rinfo(); + CHECK(!rinfo.IsPatchedReturnSequence()); } } @@ -6706,6 +6697,7 @@ TEST(ProcessDebugMessagesThreaded) { v8::FunctionTemplate::New(isolate, StartSendingCommands); env->Global()->Set(v8_str("start"), start->GetFunction()); + i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops. CompileRun("start(); while (true) { }"); CHECK_EQ(20, counting_message_handler_counter); @@ -7655,7 +7647,6 @@ static void DebugHarmonyScopingListener( TEST(DebugBreakInLexicalScopes) { - i::FLAG_harmony_scoping = true; i::FLAG_allow_natives_syntax = true; DebugLocalContext env; diff --git a/deps/v8/test/cctest/test-decls.cc b/deps/v8/test/cctest/test-decls.cc index 5d487bb7da..f3dc777102 100644 --- a/deps/v8/test/cctest/test-decls.cc +++ b/deps/v8/test/cctest/test-decls.cc @@ -637,7 +637,6 @@ TEST(CrossScriptReferences) { TEST(CrossScriptReferences_Simple) { - i::FLAG_harmony_scoping = true; i::FLAG_use_strict = true; v8::Isolate* isolate = CcTest::isolate(); @@ -652,7 +651,6 @@ TEST(CrossScriptReferences_Simple) { TEST(CrossScriptReferences_Simple2) { - i::FLAG_harmony_scoping = true; i::FLAG_use_strict = true; v8::Isolate* isolate = CcTest::isolate(); @@ -675,8 +673,6 @@ TEST(CrossScriptReferences_Simple2) { TEST(CrossScriptReferencesHarmony) { - i::FLAG_harmony_scoping = true; - v8::Isolate* isolate = CcTest::isolate(); HandleScope scope(isolate); @@ -818,9 +814,27 @@ TEST(CrossScriptReferencesHarmony) { } +TEST(CrossScriptReferencesHarmonyRegress) { + v8::Isolate* isolate = CcTest::isolate(); + HandleScope scope(isolate); + SimpleContext context; + context.Check( + "'use strict';" + "function i1() { " + " let y = 10; return (typeof x2 === 'undefined' ? 0 : 2) + y" + "}" + "i1();" + "i1();", + EXPECT_RESULT, Number::New(isolate, 10)); + context.Check( + "'use strict';" + "let x2 = 2; i1();", + EXPECT_RESULT, Number::New(isolate, 12)); +} + + TEST(GlobalLexicalOSR) { i::FLAG_use_strict = true; - i::FLAG_harmony_scoping = true; v8::Isolate* isolate = CcTest::isolate(); HandleScope scope(isolate); @@ -844,7 +858,6 @@ TEST(GlobalLexicalOSR) { TEST(CrossScriptConflicts) { i::FLAG_use_strict = true; - i::FLAG_harmony_scoping = true; HandleScope scope(CcTest::isolate()); @@ -880,8 +893,6 @@ TEST(CrossScriptConflicts) { TEST(CrossScriptDynamicLookup) { - i::FLAG_harmony_scoping = true; - HandleScope handle_scope(CcTest::isolate()); { @@ -913,8 +924,6 @@ TEST(CrossScriptDynamicLookup) { TEST(CrossScriptGlobal) { - i::FLAG_harmony_scoping = true; - HandleScope handle_scope(CcTest::isolate()); { SimpleContext context; @@ -957,8 +966,6 @@ TEST(CrossScriptGlobal) { TEST(CrossScriptStaticLookupUndeclared) { - i::FLAG_harmony_scoping = true; - HandleScope handle_scope(CcTest::isolate()); { @@ -991,7 +998,6 @@ TEST(CrossScriptStaticLookupUndeclared) { TEST(CrossScriptLoadICs) { - i::FLAG_harmony_scoping = true; i::FLAG_allow_natives_syntax = true; HandleScope handle_scope(CcTest::isolate()); @@ -1047,7 +1053,6 @@ TEST(CrossScriptLoadICs) { TEST(CrossScriptStoreICs) { - i::FLAG_harmony_scoping = true; i::FLAG_allow_natives_syntax = true; HandleScope handle_scope(CcTest::isolate()); @@ -1125,7 +1130,6 @@ TEST(CrossScriptStoreICs) { TEST(CrossScriptAssignmentToConst) { - i::FLAG_harmony_scoping = true; i::FLAG_allow_natives_syntax = true; HandleScope handle_scope(CcTest::isolate()); @@ -1148,7 +1152,6 @@ TEST(CrossScriptAssignmentToConst) { TEST(Regress425510) { - i::FLAG_harmony_scoping = true; i::FLAG_allow_natives_syntax = true; HandleScope handle_scope(CcTest::isolate()); @@ -1163,3 +1166,85 @@ TEST(Regress425510) { } } } + + +TEST(Regress3941) { + i::FLAG_allow_natives_syntax = true; + + HandleScope handle_scope(CcTest::isolate()); + + { + SimpleContext context; + context.Check("function f() { x = 1; }", EXPECT_RESULT, + Undefined(CcTest::isolate())); + context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); + } + + + { + // Train ICs. + SimpleContext context; + context.Check("function f() { x = 1; }", EXPECT_RESULT, + Undefined(CcTest::isolate())); + for (int i = 0; i < 4; i++) { + context.Check("f(); x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); + } + context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); + } + + + { + // Optimize. + SimpleContext context; + context.Check("function f() { x = 1; }", EXPECT_RESULT, + Undefined(CcTest::isolate())); + for (int i = 0; i < 4; i++) { + context.Check("f(); x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1)); + } + context.Check("%OptimizeFunctionOnNextCall(f); f(); x", EXPECT_RESULT, + Number::New(CcTest::isolate(), 1)); + + context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); + } +} + + +TEST(Regress3941_Reads) { + i::FLAG_allow_natives_syntax = true; + + HandleScope handle_scope(CcTest::isolate()); + + { + SimpleContext context; + context.Check("function f() { return x; }", EXPECT_RESULT, + Undefined(CcTest::isolate())); + context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); + } + + + { + // Train ICs. + SimpleContext context; + context.Check("function f() { return x; }", EXPECT_RESULT, + Undefined(CcTest::isolate())); + for (int i = 0; i < 4; i++) { + context.Check("f()", EXPECT_EXCEPTION); + } + context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); + } + + + { + // Optimize. + SimpleContext context; + context.Check("function f() { return x; }", EXPECT_RESULT, + Undefined(CcTest::isolate())); + for (int i = 0; i < 4; i++) { + context.Check("f()", EXPECT_EXCEPTION); + } + context.Check("%OptimizeFunctionOnNextCall(f);", EXPECT_RESULT, + Undefined(CcTest::isolate())); + + context.Check("'use strict'; f(); let x = 2; x", EXPECT_EXCEPTION); + } +} diff --git a/deps/v8/test/cctest/test-disasm-arm.cc b/deps/v8/test/cctest/test-disasm-arm.cc index 095c63679c..502b641df6 100644 --- a/deps/v8/test/cctest/test-disasm-arm.cc +++ b/deps/v8/test/cctest/test-disasm-arm.cc @@ -34,7 +34,6 @@ #include "src/disasm.h" #include "src/disassembler.h" #include "src/macro-assembler.h" -#include "src/serialize.h" #include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-disasm-ia32.cc b/deps/v8/test/cctest/test-disasm-ia32.cc index a2eaa15ed3..ca4a4f2868 100644 --- a/deps/v8/test/cctest/test-disasm-ia32.cc +++ b/deps/v8/test/cctest/test-disasm-ia32.cc @@ -34,7 +34,6 @@ #include "src/disassembler.h" #include "src/ic/ic.h" #include "src/macro-assembler.h" -#include "src/serialize.h" #include "test/cctest/cctest.h" using namespace v8::internal; @@ -442,6 +441,10 @@ TEST(DisasmIa320) { __ subsd(xmm1, Operand(ebx, ecx, times_4, 10000)); __ divsd(xmm1, xmm0); __ divsd(xmm1, Operand(ebx, ecx, times_4, 10000)); + __ minsd(xmm1, xmm0); + __ minsd(xmm1, Operand(ebx, ecx, times_4, 10000)); + __ maxsd(xmm1, xmm0); + __ maxsd(xmm1, Operand(ebx, ecx, times_4, 10000)); __ ucomisd(xmm0, xmm1); __ cmpltsd(xmm0, xmm1); @@ -451,6 +454,11 @@ TEST(DisasmIa320) { __ psrlq(xmm0, 17); __ psrlq(xmm0, xmm1); __ por(xmm0, xmm1); + + __ pcmpeqd(xmm1, xmm0); + + __ punpckldq(xmm1, xmm6); + __ punpckhdq(xmm7, xmm5); } // cmov. @@ -494,6 +502,10 @@ TEST(DisasmIa320) { __ vsubsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000)); __ vdivsd(xmm0, xmm1, xmm2); __ vdivsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000)); + __ vminsd(xmm0, xmm1, xmm2); + __ vminsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000)); + __ vmaxsd(xmm0, xmm1, xmm2); + __ vmaxsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000)); } } diff --git a/deps/v8/test/cctest/test-disasm-mips.cc b/deps/v8/test/cctest/test-disasm-mips.cc index 131f41384c..ca928a61eb 100644 --- a/deps/v8/test/cctest/test-disasm-mips.cc +++ b/deps/v8/test/cctest/test-disasm-mips.cc @@ -34,7 +34,6 @@ #include "src/disasm.h" #include "src/disassembler.h" #include "src/macro-assembler.h" -#include "src/serialize.h" #include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-disasm-mips64.cc b/deps/v8/test/cctest/test-disasm-mips64.cc index d682d33480..a2a93c611a 100644 --- a/deps/v8/test/cctest/test-disasm-mips64.cc +++ b/deps/v8/test/cctest/test-disasm-mips64.cc @@ -34,7 +34,6 @@ #include "src/disasm.h" #include "src/disassembler.h" #include "src/macro-assembler.h" -#include "src/serialize.h" #include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-disasm-ppc.cc b/deps/v8/test/cctest/test-disasm-ppc.cc index 87b9ade055..ed409f2f9d 100644 --- a/deps/v8/test/cctest/test-disasm-ppc.cc +++ b/deps/v8/test/cctest/test-disasm-ppc.cc @@ -34,7 +34,6 @@ #include "src/disasm.h" #include "src/disassembler.h" #include "src/macro-assembler.h" -#include "src/serialize.h" #include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-disasm-x64.cc b/deps/v8/test/cctest/test-disasm-x64.cc index 6cd58ec209..cdedc8be55 100644 --- a/deps/v8/test/cctest/test-disasm-x64.cc +++ b/deps/v8/test/cctest/test-disasm-x64.cc @@ -34,7 +34,6 @@ #include "src/disassembler.h" #include "src/ic/ic.h" #include "src/macro-assembler.h" -#include "src/serialize.h" #include "test/cctest/cctest.h" using namespace v8::internal; @@ -89,6 +88,9 @@ TEST(DisasmX64) { __ addq(rdi, Operand(rbp, rcx, times_4, -3999)); __ addq(Operand(rbp, rcx, times_4, 12), Immediate(12)); + __ bsrl(rax, r15); + __ bsrl(r9, Operand(rcx, times_8, 91919)); + __ nop(); __ addq(rbx, Immediate(12)); __ nop(); @@ -436,6 +438,10 @@ TEST(DisasmX64) { __ subsd(xmm1, Operand(rbx, rcx, times_4, 10000)); __ divsd(xmm1, xmm0); __ divsd(xmm1, Operand(rbx, rcx, times_4, 10000)); + __ minsd(xmm1, xmm0); + __ minsd(xmm1, Operand(rbx, rcx, times_4, 10000)); + __ maxsd(xmm1, xmm0); + __ maxsd(xmm1, Operand(rbx, rcx, times_4, 10000)); __ ucomisd(xmm0, xmm1); __ andpd(xmm0, xmm1); @@ -446,6 +452,9 @@ TEST(DisasmX64) { __ psrlq(xmm0, 6); __ pcmpeqd(xmm1, xmm0); + + __ punpckldq(xmm1, xmm11); + __ punpckhdq(xmm8, xmm15); } // cmov. @@ -472,6 +481,10 @@ TEST(DisasmX64) { if (CpuFeatures::IsSupported(SSE4_1)) { CpuFeatureScope scope(&assm, SSE4_1); __ extractps(rax, xmm1, 0); + __ pextrd(rbx, xmm15, 0); + __ pextrd(r12, xmm0, 1); + __ pinsrd(xmm9, r9, 0); + __ pinsrd(xmm5, rax, 1); } } @@ -486,7 +499,11 @@ TEST(DisasmX64) { __ vsubsd(xmm0, xmm1, xmm2); __ vsubsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000)); __ vdivsd(xmm0, xmm1, xmm2); - __ vdivsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000)); + __ vdivsd(xmm0, xmm1, Operand(rbx, rcx, times_2, 10000)); + __ vminsd(xmm8, xmm1, xmm2); + __ vminsd(xmm9, xmm1, Operand(rbx, rcx, times_8, 10000)); + __ vmaxsd(xmm8, xmm1, xmm2); + __ vmaxsd(xmm9, xmm1, Operand(rbx, rcx, times_1, 10000)); } } diff --git a/deps/v8/test/cctest/test-disasm-x87.cc b/deps/v8/test/cctest/test-disasm-x87.cc index e9b0dc5474..a3433b290b 100644 --- a/deps/v8/test/cctest/test-disasm-x87.cc +++ b/deps/v8/test/cctest/test-disasm-x87.cc @@ -34,7 +34,6 @@ #include "src/disassembler.h" #include "src/ic/ic.h" #include "src/macro-assembler.h" -#include "src/serialize.h" #include "test/cctest/cctest.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-feedback-vector.cc b/deps/v8/test/cctest/test-feedback-vector.cc index 89c475eab5..f53dfde10e 100644 --- a/deps/v8/test/cctest/test-feedback-vector.cc +++ b/deps/v8/test/cctest/test-feedback-vector.cc @@ -22,10 +22,11 @@ TEST(VectorStructure) { v8::HandleScope scope(context->GetIsolate()); Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); + Zone* zone = isolate->runtime_zone(); // Empty vectors are the empty fixed array. FeedbackVectorSpec empty; - Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(empty); + Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(&empty); CHECK(Handle<FixedArray>::cast(vector) .is_identical_to(factory->empty_fixed_array())); // Which can nonetheless be queried. @@ -34,24 +35,21 @@ TEST(VectorStructure) { CHECK_EQ(0, vector->Slots()); CHECK_EQ(0, vector->ICSlots()); - FeedbackVectorSpec one_slot(1, 0); - vector = factory->NewTypeFeedbackVector(one_slot); + FeedbackVectorSpec one_slot(1); + vector = factory->NewTypeFeedbackVector(&one_slot); CHECK_EQ(1, vector->Slots()); CHECK_EQ(0, vector->ICSlots()); - FeedbackVectorSpec one_icslot(0, 1); - if (FLAG_vector_ics) { - one_icslot.SetKind(0, Code::CALL_IC); - } - vector = factory->NewTypeFeedbackVector(one_icslot); + FeedbackVectorSpec one_icslot(0, Code::CALL_IC); + vector = factory->NewTypeFeedbackVector(&one_icslot); CHECK_EQ(0, vector->Slots()); CHECK_EQ(1, vector->ICSlots()); - FeedbackVectorSpec spec(3, 5); + ZoneFeedbackVectorSpec spec(zone, 3, 5); if (FLAG_vector_ics) { for (int i = 0; i < 5; i++) spec.SetKind(i, Code::CALL_IC); } - vector = factory->NewTypeFeedbackVector(spec); + vector = factory->NewTypeFeedbackVector(&spec); CHECK_EQ(3, vector->Slots()); CHECK_EQ(5, vector->ICSlots()); @@ -71,8 +69,8 @@ TEST(VectorStructure) { CHECK_EQ(index, TypeFeedbackVector::kReservedIndexCount + metadata_length + 3); CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index)); - - CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + 5, + CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + + 5 * TypeFeedbackVector::elements_per_ic_slot(), vector->length()); } @@ -88,8 +86,9 @@ TEST(VectorICMetadata) { } Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); + Zone* zone = isolate->runtime_zone(); - FeedbackVectorSpec spec(10, 3 * 10); + ZoneFeedbackVectorSpec spec(zone, 10, 3 * 10); // Set metadata. for (int i = 0; i < 30; i++) { Code::Kind kind; @@ -103,7 +102,7 @@ TEST(VectorICMetadata) { spec.SetKind(i, kind); } - Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec); + Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(&spec); CHECK_EQ(10, vector->Slots()); CHECK_EQ(3 * 10, vector->ICSlots()); @@ -136,8 +135,8 @@ TEST(VectorSlotClearing) { // We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots. // The reason is that FeedbackVectorICSlots need a full code environment // to fully test (See VectorICProfilerStatistics test below). - FeedbackVectorSpec spec(5, 0); - Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec); + FeedbackVectorSpec spec(5); + Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(&spec); // Fill with information vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1)); @@ -307,6 +306,34 @@ TEST(VectorLoadICStates) { } +TEST(VectorLoadICSlotSharing) { + if (i::FLAG_always_opt || !i::FLAG_vector_ics) return; + CcTest::InitializeVM(); + LocalContext context; + v8::HandleScope scope(context->GetIsolate()); + Isolate* isolate = CcTest::i_isolate(); + + // Function f has 3 LoadICs, one for each o, but the ICs share the same + // feedback vector IC slot. + CompileRun( + "var o = 10;" + "function f() {" + " var x = o + 10;" + " return o + x + o;" + "}" + "f();"); + Handle<JSFunction> f = v8::Utils::OpenHandle( + *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f")))); + // There should be one IC slot. + Handle<TypeFeedbackVector> feedback_vector = + Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate); + CHECK_EQ(1, feedback_vector->ICSlots()); + FeedbackVectorICSlot slot(0); + LoadICNexus nexus(feedback_vector, slot); + CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); +} + + TEST(VectorLoadICOnSmi) { if (i::FLAG_always_opt || !i::FLAG_vector_ics) return; CcTest::InitializeVM(); diff --git a/deps/v8/test/cctest/test-func-name-inference.cc b/deps/v8/test/cctest/test-func-name-inference.cc index 24f9c73532..ae8e77d745 100644 --- a/deps/v8/test/cctest/test-func-name-inference.cc +++ b/deps/v8/test/cctest/test-func-name-inference.cc @@ -81,11 +81,9 @@ static void CheckFunctionName(v8::Handle<v8::Script> script, // Obtain SharedFunctionInfo for the function. isolate->debug()->PrepareForBreakPoints(); - Object* shared_func_info_ptr = - isolate->debug()->FindSharedFunctionInfoInScript(i_script, func_pos); - CHECK(shared_func_info_ptr != CcTest::heap()->undefined_value()); - Handle<SharedFunctionInfo> shared_func_info( - SharedFunctionInfo::cast(shared_func_info_ptr)); + Handle<SharedFunctionInfo> shared_func_info = + Handle<SharedFunctionInfo>::cast( + isolate->debug()->FindSharedFunctionInfoInScript(i_script, func_pos)); // Verify inferred function name. SmartArrayPointer<char> inferred_name = diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index 5c9d2e69f0..d00532f48d 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -36,7 +36,6 @@ #include "src/debug.h" #include "src/hashmap.h" #include "src/heap-profiler.h" -#include "src/snapshot.h" #include "src/utils-inl.h" #include "test/cctest/cctest.h" @@ -183,8 +182,7 @@ TEST(HeapSnapshot) { "var a2 = new A2();\n" "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n" "var c2 = new C2(a2);"); - const v8::HeapSnapshot* snapshot_env2 = - heap_profiler->TakeHeapSnapshot(v8_str("env2")); + const v8::HeapSnapshot* snapshot_env2 = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot_env2)); const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2); @@ -217,8 +215,7 @@ TEST(HeapSnapshotObjectSizes) { "x = new X(new X(), new X());\n" "dummy = new X();\n" "(function() { x.a.a = x.b; })();"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("sizes")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* x = @@ -246,8 +243,7 @@ TEST(BoundFunctionInSnapshot) { "function myFunction(a, b) { this.a = a; this.b = b; }\n" "function AAAAA() {}\n" "boundFunction = myFunction.bind(new AAAAA(), 20, new Number(12)); \n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("sizes")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* f = @@ -286,8 +282,7 @@ TEST(HeapSnapshotEntryChildren) { CompileRun( "function A() { }\n" "a = new A;"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("children")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) { @@ -314,8 +309,7 @@ TEST(HeapSnapshotCodeObjects) { "function compiled(x) { return x + 1; }\n" "var anonymous = (function() { return function() { return 0; } })();\n" "compiled(1)"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("code")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); @@ -387,8 +381,7 @@ TEST(HeapSnapshotHeapNumbers) { CompileRun( "a = 1; // a is Smi\n" "b = 2.5; // b is HeapNumber"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("numbers")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK(!GetProperty(global, v8::HeapGraphEdge::kProperty, "a")); @@ -413,8 +406,7 @@ TEST(HeapSnapshotSlicedString) { "123456789.123456789.123456789.123456789.123456789." "123456789.123456789.123456789.123456789.123456789.\";" "child_string = parent_string.slice(100);"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("strings")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* parent_string = @@ -451,8 +443,7 @@ TEST(HeapSnapshotConsString) { global->SetInternalField(0, v8::ToApiHandle<v8::String>(cons_string)); v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler(); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("cons_strings")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot); @@ -479,8 +470,7 @@ TEST(HeapSnapshotSymbol) { v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("a = Symbol('mySymbol');\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("Symbol")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* a = @@ -504,8 +494,7 @@ TEST(HeapSnapshotWeakCollection) { "k = {}; v = {}; s = 'str';\n" "ws = new WeakSet(); ws.add(k); ws.add(v); ws[s] = s;\n" "wm = new WeakMap(); wm.set(k, v); wm[s] = s;\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("WeakCollections")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* k = @@ -578,8 +567,7 @@ TEST(HeapSnapshotCollection) { "k = {}; v = {}; s = 'str';\n" "set = new Set(); set.add(k); set.add(v); set[s] = s;\n" "map = new Map(); map.set(k, v); map[s] = s;\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("Collections")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* k = @@ -656,8 +644,7 @@ TEST(HeapSnapshotInternalReferences) { global->SetInternalField(0, v8_num(17)); global->SetInternalField(1, obj); v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler(); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("internals")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot); // The first reference will not present, because it's a Smi. @@ -677,8 +664,7 @@ TEST(HeapSnapshotAddressReuse) { "var a = [];\n" "for (var i = 0; i < 10000; ++i)\n" " a[i] = new A();\n"); - const v8::HeapSnapshot* snapshot1 = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot1")); + const v8::HeapSnapshot* snapshot1 = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot1)); v8::SnapshotObjectId maxId1 = snapshot1->GetMaxSnapshotJSObjectId(); @@ -687,8 +673,7 @@ TEST(HeapSnapshotAddressReuse) { " a[i] = new A();\n"); CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); - const v8::HeapSnapshot* snapshot2 = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot2")); + const v8::HeapSnapshot* snapshot2 = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot2)); const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2); @@ -721,8 +706,7 @@ TEST(HeapEntryIdsAndArrayShift) { "var a = new Array();\n" "for (var i = 0; i < 10; ++i)\n" " a.push(new AnObject());\n"); - const v8::HeapSnapshot* snapshot1 = - heap_profiler->TakeHeapSnapshot(v8_str("s1")); + const v8::HeapSnapshot* snapshot1 = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot1)); CompileRun( @@ -731,8 +715,7 @@ TEST(HeapEntryIdsAndArrayShift) { CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); - const v8::HeapSnapshot* snapshot2 = - heap_profiler->TakeHeapSnapshot(v8_str("s2")); + const v8::HeapSnapshot* snapshot2 = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot2)); const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1); @@ -768,16 +751,12 @@ TEST(HeapEntryIdsAndGC) { "function B(x) { this.x = x; }\n" "var a = new A();\n" "var b = new B(a);"); - v8::Local<v8::String> s1_str = v8_str("s1"); - v8::Local<v8::String> s2_str = v8_str("s2"); - const v8::HeapSnapshot* snapshot1 = - heap_profiler->TakeHeapSnapshot(s1_str); + const v8::HeapSnapshot* snapshot1 = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot1)); CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); - const v8::HeapSnapshot* snapshot2 = - heap_profiler->TakeHeapSnapshot(s2_str); + const v8::HeapSnapshot* snapshot2 = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot2)); CHECK_GT(snapshot1->GetMaxSnapshotJSObjectId(), 7000u); @@ -827,8 +806,7 @@ TEST(HeapSnapshotRootPreservedAfterSorting) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("s")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* root1 = snapshot->GetRoot(); const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>( @@ -896,8 +874,7 @@ TEST(HeapSnapshotJSONSerialization) { "function B(x) { this.x = x; }\n" "var a = new A(" STRING_LITERAL_FOR_TEST ");\n" "var b = new B(a);"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("json")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); TestJSONStream stream; @@ -996,8 +973,7 @@ TEST(HeapSnapshotJSONSerializationAborting) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("abort")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); TestJSONStream stream(5); snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON); @@ -1067,9 +1043,12 @@ static TestStatsStream GetHeapStatsUpdate( v8::HeapProfiler* heap_profiler, v8::SnapshotObjectId* object_id = NULL) { TestStatsStream stream; - v8::SnapshotObjectId last_seen_id = heap_profiler->GetHeapStats(&stream); + int64_t timestamp = -1; + v8::SnapshotObjectId last_seen_id = + heap_profiler->GetHeapStats(&stream, ×tamp); if (object_id) *object_id = last_seen_id; + CHECK_NE(-1, timestamp); CHECK_EQ(1, stream.eos_signaled()); return stream; } @@ -1279,8 +1258,7 @@ TEST(HeapSnapshotGetNodeById) { v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("id")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* root = snapshot->GetRoot(); CheckChildrenIds(snapshot, root, 0, 3); @@ -1294,8 +1272,7 @@ TEST(HeapSnapshotGetSnapshotObjectId) { v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("globalObject = {};\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("get_snapshot_object_id")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* global_object = @@ -1318,8 +1295,7 @@ TEST(HeapSnapshotUnknownSnapshotObjectId) { v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("globalObject = {};\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("unknown_object_id")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* node = snapshot->GetNodeById(v8::HeapProfiler::kUnknownObjectId); @@ -1357,16 +1333,13 @@ TEST(TakeHeapSnapshotAborting) { const int snapshots_count = heap_profiler->GetSnapshotCount(); TestActivityControl aborting_control(1); const v8::HeapSnapshot* no_snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("abort"), - &aborting_control); + heap_profiler->TakeHeapSnapshot(&aborting_control); CHECK(!no_snapshot); CHECK_EQ(snapshots_count, heap_profiler->GetSnapshotCount()); CHECK_GT(aborting_control.total(), aborting_control.done()); TestActivityControl control(-1); // Don't abort. - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("full"), - &control); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(&control); CHECK(ValidateSnapshot(snapshot)); CHECK(snapshot); @@ -1477,8 +1450,7 @@ TEST(HeapSnapshotRetainedObjectInfo) { v8::Persistent<v8::String> p_CCC(isolate, v8_str("CCC")); p_CCC.SetWrapperClassId(2); CHECK_EQ(0, TestRetainedObjectInfo::instances.length()); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("retained")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); CHECK_EQ(3, TestRetainedObjectInfo::instances.length()); @@ -1570,8 +1542,7 @@ TEST(HeapSnapshotImplicitReferences) { GraphWithImplicitRefs graph(&env); v8::V8::AddGCPrologueCallback(&GraphWithImplicitRefs::gcPrologue); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("implicit_refs")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot); @@ -1604,28 +1575,25 @@ TEST(DeleteAllHeapSnapshots) { CHECK_EQ(0, heap_profiler->GetSnapshotCount()); heap_profiler->DeleteAllHeapSnapshots(); CHECK_EQ(0, heap_profiler->GetSnapshotCount()); - CHECK(heap_profiler->TakeHeapSnapshot(v8_str("1"))); + CHECK(heap_profiler->TakeHeapSnapshot()); CHECK_EQ(1, heap_profiler->GetSnapshotCount()); heap_profiler->DeleteAllHeapSnapshots(); CHECK_EQ(0, heap_profiler->GetSnapshotCount()); - CHECK(heap_profiler->TakeHeapSnapshot(v8_str("1"))); - CHECK(heap_profiler->TakeHeapSnapshot(v8_str("2"))); + CHECK(heap_profiler->TakeHeapSnapshot()); + CHECK(heap_profiler->TakeHeapSnapshot()); CHECK_EQ(2, heap_profiler->GetSnapshotCount()); heap_profiler->DeleteAllHeapSnapshots(); CHECK_EQ(0, heap_profiler->GetSnapshotCount()); } -static const v8::HeapSnapshot* FindHeapSnapshot(v8::HeapProfiler* profiler, - unsigned uid) { +static bool FindHeapSnapshot(v8::HeapProfiler* profiler, + const v8::HeapSnapshot* snapshot) { int length = profiler->GetSnapshotCount(); for (int i = 0; i < length; i++) { - const v8::HeapSnapshot* snapshot = profiler->GetHeapSnapshot(i); - if (snapshot->GetUid() == uid) { - return snapshot; - } + if (snapshot == profiler->GetHeapSnapshot(i)) return true; } - return NULL; + return false; } @@ -1635,38 +1603,31 @@ TEST(DeleteHeapSnapshot) { v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CHECK_EQ(0, heap_profiler->GetSnapshotCount()); - const v8::HeapSnapshot* s1 = - heap_profiler->TakeHeapSnapshot(v8_str("1")); + const v8::HeapSnapshot* s1 = heap_profiler->TakeHeapSnapshot(); CHECK(s1); CHECK_EQ(1, heap_profiler->GetSnapshotCount()); - unsigned uid1 = s1->GetUid(); - CHECK_EQ(s1, FindHeapSnapshot(heap_profiler, uid1)); + CHECK(FindHeapSnapshot(heap_profiler, s1)); const_cast<v8::HeapSnapshot*>(s1)->Delete(); CHECK_EQ(0, heap_profiler->GetSnapshotCount()); - CHECK(!FindHeapSnapshot(heap_profiler, uid1)); + CHECK(!FindHeapSnapshot(heap_profiler, s1)); - const v8::HeapSnapshot* s2 = - heap_profiler->TakeHeapSnapshot(v8_str("2")); + const v8::HeapSnapshot* s2 = heap_profiler->TakeHeapSnapshot(); CHECK(s2); CHECK_EQ(1, heap_profiler->GetSnapshotCount()); - unsigned uid2 = s2->GetUid(); - CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2)); - CHECK_EQ(s2, FindHeapSnapshot(heap_profiler, uid2)); - const v8::HeapSnapshot* s3 = - heap_profiler->TakeHeapSnapshot(v8_str("3")); + CHECK(FindHeapSnapshot(heap_profiler, s2)); + const v8::HeapSnapshot* s3 = heap_profiler->TakeHeapSnapshot(); CHECK(s3); CHECK_EQ(2, heap_profiler->GetSnapshotCount()); - unsigned uid3 = s3->GetUid(); - CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3)); - CHECK_EQ(s3, FindHeapSnapshot(heap_profiler, uid3)); + CHECK_NE(s2, s3); + CHECK(FindHeapSnapshot(heap_profiler, s3)); const_cast<v8::HeapSnapshot*>(s2)->Delete(); CHECK_EQ(1, heap_profiler->GetSnapshotCount()); - CHECK(!FindHeapSnapshot(heap_profiler, uid2)); - CHECK_EQ(s3, FindHeapSnapshot(heap_profiler, uid3)); + CHECK(!FindHeapSnapshot(heap_profiler, s2)); + CHECK(FindHeapSnapshot(heap_profiler, s3)); const_cast<v8::HeapSnapshot*>(s3)->Delete(); CHECK_EQ(0, heap_profiler->GetSnapshotCount()); - CHECK(!FindHeapSnapshot(heap_profiler, uid3)); + CHECK(!FindHeapSnapshot(heap_profiler, s3)); } @@ -1687,9 +1648,7 @@ TEST(GlobalObjectName) { NameResolver name_resolver; const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("document"), - NULL, - &name_resolver); + heap_profiler->TakeHeapSnapshot(NULL, &name_resolver); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK(global); @@ -1705,8 +1664,7 @@ TEST(GlobalObjectFields) { v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("obj = {};"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* builtins = @@ -1728,10 +1686,9 @@ TEST(NoHandleLeaks) { CompileRun("document = { URL:\"abcdefgh\" };"); - v8::Handle<v8::String> name(v8_str("leakz")); i::Isolate* isolate = CcTest::i_isolate(); int count_before = i::HandleScope::NumberOfHandles(isolate); - heap_profiler->TakeHeapSnapshot(name); + heap_profiler->TakeHeapSnapshot(); int count_after = i::HandleScope::NumberOfHandles(isolate); CHECK_EQ(count_before, count_after); } @@ -1741,8 +1698,7 @@ TEST(NodesIteration) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("iteration")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK(global); @@ -1763,8 +1719,7 @@ TEST(GetHeapValueForNode) { v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("a = { s_prop: \'value\', n_prop: \'value2\' };"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("value")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK(heap_profiler->FindObjectById(global->GetId())->IsObject()); @@ -1798,8 +1753,7 @@ TEST(GetHeapValueForDeletedObject) { // property of the "a" object. Also, the "p" object can't be an empty one // because the empty object is static and isn't actually deleted. CompileRun("a = { p: { r: {} } };"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* obj = GetProperty( @@ -1889,8 +1843,7 @@ TEST(FastCaseAccessors) { "obj1.__defineSetter__('propWithSetter', function Z(value) {\n" " return this.value_ = value;\n" "});\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("fastCaseAccessors")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); @@ -1935,8 +1888,7 @@ TEST(FastCaseRedefinedAccessors) { v8::Utils::OpenHandle(*js_global->Get(v8_str("obj1")).As<v8::Object>()); USE(js_obj1); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("fastCaseAccessors")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK(global); @@ -1964,8 +1916,7 @@ TEST(SlowCaseAccessors) { "obj1.__defineSetter__('propWithSetter', function Z(value) {\n" " return this.value_ = value;\n" "});\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("slowCaseAccessors")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); @@ -1994,8 +1945,7 @@ TEST(HiddenPropertiesFastCase) { CompileRun( "function C(x) { this.a = this; this.b = x; }\n" "c = new C(2012);\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("HiddenPropertiesFastCase1")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* c = @@ -2010,8 +1960,7 @@ TEST(HiddenPropertiesFastCase) { CHECK(!cHandle.IsEmpty() && cHandle->IsObject()); cHandle->ToObject(isolate)->SetHiddenValue(v8_str("key"), v8_str("val")); - snapshot = heap_profiler->TakeHeapSnapshot( - v8_str("HiddenPropertiesFastCase2")); + snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); global = GetGlobalObject(snapshot); c = GetProperty(global, v8::HeapGraphEdge::kProperty, "c"); @@ -2028,8 +1977,7 @@ TEST(AccessorInfo) { v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("function foo(x) { }\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("AccessorInfoTest")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* foo = @@ -2074,8 +2022,7 @@ bool HasWeakEdge(const v8::HeapGraphNode* node) { bool HasWeakGlobalHandle() { v8::Isolate* isolate = CcTest::isolate(); v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler(); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("weaks")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* gc_roots = GetNode( snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)"); @@ -2115,8 +2062,7 @@ TEST(SfiAndJsFunctionWeakRefs) { CompileRun( "fun = (function (x) { return function () { return x + 1; } })(1);"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("fun")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); CHECK(global); @@ -2136,8 +2082,7 @@ TEST(NoDebugObjectInSnapshot) { CHECK(CcTest::i_isolate()->debug()->Load()); CompileRun("foo = {};"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* root = snapshot->GetRoot(); int globals_count = 0; @@ -2161,8 +2106,7 @@ TEST(AllStrongGcRootsHaveNames) { v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("foo = {};"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* gc_roots = GetNode( snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)"); @@ -2184,8 +2128,7 @@ TEST(NoRefsToNonEssentialEntries) { v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("global_object = {};\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* global_object = @@ -2205,8 +2148,7 @@ TEST(MapHasDescriptorsAndTransitions) { v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("obj = { a: 10 };\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* global_object = @@ -2244,8 +2186,7 @@ TEST(ManyLocalsInSharedContext) { "result.push('return f_' + (n - 1) + ';');" "result.push('})()');" "var ok = eval(result.join('\\n'));"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); @@ -2279,8 +2220,7 @@ TEST(AllocationSitesAreVisible) { CompileRun( "fun = function () { var a = [3, 2, 1]; return a; }\n" "fun();"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); @@ -2292,11 +2232,11 @@ TEST(AllocationSitesAreVisible) { GetProperty(fun_code, v8::HeapGraphEdge::kInternal, "literals"); CHECK(literals); CHECK_EQ(v8::HeapGraphNode::kArray, literals->GetType()); - CHECK_EQ(2, literals->GetChildrenCount()); + CHECK_EQ(1, literals->GetChildrenCount()); - // The second value in the literals array should be the boilerplate, + // The first value in the literals array should be the boilerplate, // after an AllocationSite. - const v8::HeapGraphEdge* prop = literals->GetChild(1); + const v8::HeapGraphEdge* prop = literals->GetChild(0); const v8::HeapGraphNode* allocation_site = prop->GetToNode(); v8::String::Utf8Value name(allocation_site->GetName()); CHECK_EQ(0, strcmp("system / AllocationSite", *name)); @@ -2333,8 +2273,7 @@ TEST(JSFunctionHasCodeLink) { v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("function foo(x, y) { return x + y; }\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* foo_func = @@ -2375,8 +2314,7 @@ TEST(CheckCodeNames) { v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("var a = 1.1;"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("CheckCodeNames")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const char* stub_path[] = { @@ -2634,8 +2572,7 @@ TEST(ArrayBufferAndArrayBufferView) { v8::HandleScope scope(env->GetIsolate()); v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); CompileRun("arr1 = new Uint32Array(100);\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* arr1_obj = @@ -2693,8 +2630,7 @@ TEST(ArrayBufferSharedBackingStore) { v8::Handle<v8::Value> result = CompileRun("ab2.byteLength"); CHECK_EQ(1024, result->Int32Value()); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* ab1_node = @@ -2728,8 +2664,7 @@ TEST(BoxObject) { global->Set(0, v8::ToApiHandle<v8::Object>(box)); v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler(); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot); const v8::HeapGraphNode* box_node = @@ -2756,8 +2691,7 @@ TEST(WeakContainers) { "foo(obj);\n" "%OptimizeFunctionOnNextCall(foo);\n" "foo(obj);\n"); - const v8::HeapSnapshot* snapshot = - heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); const v8::HeapGraphNode* global = GetGlobalObject(snapshot); const v8::HeapGraphNode* obj = diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc index ae3c1d365c..9867f933b1 100644 --- a/deps/v8/test/cctest/test-heap.cc +++ b/deps/v8/test/cctest/test-heap.cc @@ -36,10 +36,10 @@ #include "src/global-handles.h" #include "src/ic/ic.h" #include "src/macro-assembler.h" -#include "src/snapshot.h" #include "test/cctest/cctest.h" using namespace v8::internal; +using v8::Just; static void CheckMap(Map* map, int type, int instance_size) { CHECK(map->IsHeapObject()); @@ -191,9 +191,7 @@ TEST(HeapObjects) { Handle<String> object_string = Handle<String>::cast(factory->Object_string()); Handle<GlobalObject> global(CcTest::i_isolate()->context()->global_object()); - v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, object_string); - CHECK(maybe.has_value); - CHECK(maybe.value); + CHECK(Just(true) == JSReceiver::HasOwnProperty(global, object_string)); // Check ToString for oddballs CheckOddball(isolate, heap->true_value(), "true"); @@ -260,9 +258,7 @@ TEST(GarbageCollection) { heap->CollectGarbage(NEW_SPACE); // Function should be alive. - v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, name); - CHECK(maybe.has_value); - CHECK(maybe.value); + CHECK(Just(true) == JSReceiver::HasOwnProperty(global, name)); // Check function is retained. Handle<Object> func_value = Object::GetProperty(global, name).ToHandleChecked(); @@ -280,9 +276,7 @@ TEST(GarbageCollection) { // After gc, it should survive. heap->CollectGarbage(NEW_SPACE); - maybe = JSReceiver::HasOwnProperty(global, obj_name); - CHECK(maybe.has_value); - CHECK(maybe.value); + CHECK(Just(true) == JSReceiver::HasOwnProperty(global, obj_name)); Handle<Object> obj = Object::GetProperty(global, obj_name).ToHandleChecked(); CHECK(obj->IsJSObject()); @@ -639,85 +633,55 @@ TEST(ObjectProperties) { Handle<Smi> two(Smi::FromInt(2), isolate); // check for empty - v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(obj, first); - CHECK(maybe.has_value); - CHECK(!maybe.value); + CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, first)); // add first JSReceiver::SetProperty(obj, first, one, SLOPPY).Check(); - maybe = JSReceiver::HasOwnProperty(obj, first); - CHECK(maybe.has_value); - CHECK(maybe.value); + CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, first)); // delete first JSReceiver::DeleteProperty(obj, first, SLOPPY).Check(); - maybe = JSReceiver::HasOwnProperty(obj, first); - CHECK(maybe.has_value); - CHECK(!maybe.value); + CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, first)); // add first and then second JSReceiver::SetProperty(obj, first, one, SLOPPY).Check(); JSReceiver::SetProperty(obj, second, two, SLOPPY).Check(); - maybe = JSReceiver::HasOwnProperty(obj, first); - CHECK(maybe.has_value); - CHECK(maybe.value); - maybe = JSReceiver::HasOwnProperty(obj, second); - CHECK(maybe.has_value); - CHECK(maybe.value); + CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, first)); + CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, second)); // delete first and then second JSReceiver::DeleteProperty(obj, first, SLOPPY).Check(); - maybe = JSReceiver::HasOwnProperty(obj, second); - CHECK(maybe.has_value); - CHECK(maybe.value); + CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, second)); JSReceiver::DeleteProperty(obj, second, SLOPPY).Check(); - maybe = JSReceiver::HasOwnProperty(obj, first); - CHECK(maybe.has_value); - CHECK(!maybe.value); - maybe = JSReceiver::HasOwnProperty(obj, second); - CHECK(maybe.has_value); - CHECK(!maybe.value); + CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, first)); + CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, second)); // add first and then second JSReceiver::SetProperty(obj, first, one, SLOPPY).Check(); JSReceiver::SetProperty(obj, second, two, SLOPPY).Check(); - maybe = JSReceiver::HasOwnProperty(obj, first); - CHECK(maybe.has_value); - CHECK(maybe.value); - maybe = JSReceiver::HasOwnProperty(obj, second); - CHECK(maybe.has_value); - CHECK(maybe.value); + CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, first)); + CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, second)); // delete second and then first JSReceiver::DeleteProperty(obj, second, SLOPPY).Check(); - maybe = JSReceiver::HasOwnProperty(obj, first); - CHECK(maybe.has_value); - CHECK(maybe.value); + CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, first)); JSReceiver::DeleteProperty(obj, first, SLOPPY).Check(); - maybe = JSReceiver::HasOwnProperty(obj, first); - CHECK(maybe.has_value); - CHECK(!maybe.value); - maybe = JSReceiver::HasOwnProperty(obj, second); - CHECK(maybe.has_value); - CHECK(!maybe.value); + CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, first)); + CHECK(Just(false) == JSReceiver::HasOwnProperty(obj, second)); // check string and internalized string match const char* string1 = "fisk"; Handle<String> s1 = factory->NewStringFromAsciiChecked(string1); JSReceiver::SetProperty(obj, s1, one, SLOPPY).Check(); Handle<String> s1_string = factory->InternalizeUtf8String(string1); - maybe = JSReceiver::HasOwnProperty(obj, s1_string); - CHECK(maybe.has_value); - CHECK(maybe.value); + CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, s1_string)); // check internalized string and string match const char* string2 = "fugl"; Handle<String> s2_string = factory->InternalizeUtf8String(string2); JSReceiver::SetProperty(obj, s2_string, one, SLOPPY).Check(); Handle<String> s2 = factory->NewStringFromAsciiChecked(string2); - maybe = JSReceiver::HasOwnProperty(obj, s2); - CHECK(maybe.has_value); - CHECK(maybe.value); + CHECK(Just(true) == JSReceiver::HasOwnProperty(obj, s2)); } @@ -1502,6 +1466,7 @@ TEST(TestInternalWeakLists) { // Some flags turn Scavenge collections into Mark-sweep collections // and hence are incompatible with this test case. if (FLAG_gc_global || FLAG_stress_compaction) return; + FLAG_retain_maps_for_n_gc = 0; static const int kNumTestContexts = 10; @@ -2176,6 +2141,12 @@ TEST(InstanceOfStubWriteBarrier) { } +static int NumberOfProtoTransitions(Map* map) { + return TransitionArray::NumberOfPrototypeTransitions( + TransitionArray::GetPrototypeTransitions(map)); +} + + TEST(PrototypeTransitionClearing) { if (FLAG_never_compact) return; CcTest::InitializeVM(); @@ -2188,7 +2159,7 @@ TEST(PrototypeTransitionClearing) { v8::Utils::OpenHandle( *v8::Handle<v8::Object>::Cast( CcTest::global()->Get(v8_str("base")))); - int initialTransitions = baseObject->map()->NumberOfProtoTransitions(); + int initialTransitions = NumberOfProtoTransitions(baseObject->map()); CompileRun( "var live = [];" @@ -2201,16 +2172,17 @@ TEST(PrototypeTransitionClearing) { // Verify that only dead prototype transitions are cleared. CHECK_EQ(initialTransitions + 10, - baseObject->map()->NumberOfProtoTransitions()); + NumberOfProtoTransitions(baseObject->map())); CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); const int transitions = 10 - 3; CHECK_EQ(initialTransitions + transitions, - baseObject->map()->NumberOfProtoTransitions()); + NumberOfProtoTransitions(baseObject->map())); // Verify that prototype transitions array was compacted. - FixedArray* trans = baseObject->map()->GetPrototypeTransitions(); + FixedArray* trans = + TransitionArray::GetPrototypeTransitions(baseObject->map()); for (int i = initialTransitions; i < initialTransitions + transitions; i++) { - int j = Map::kProtoTransitionHeaderSize + i; + int j = TransitionArray::kProtoTransitionHeaderSize + i; CHECK(trans->get(j)->IsMap()); } @@ -2228,7 +2200,7 @@ TEST(PrototypeTransitionClearing) { i::FLAG_always_compact = true; Handle<Map> map(baseObject->map()); CHECK(!space->LastPage()->Contains( - map->GetPrototypeTransitions()->address())); + TransitionArray::GetPrototypeTransitions(*map)->address())); CHECK(space->LastPage()->Contains(prototype->address())); } @@ -2267,9 +2239,12 @@ TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) { marking->Start(); // The following two calls will increment CcTest::heap()->global_ic_age(). - const int kLongIdlePauseInMs = 1000; + const double kLongIdlePauseInSeconds = 1.0; CcTest::isolate()->ContextDisposedNotification(); - CcTest::isolate()->IdleNotification(kLongIdlePauseInMs); + CcTest::isolate()->IdleNotificationDeadline( + (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() / + static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) + + kLongIdlePauseInSeconds); while (!marking->IsStopped() && !marking->IsComplete()) { marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); @@ -2323,9 +2298,12 @@ TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) { // The following two calls will increment CcTest::heap()->global_ic_age(). // Since incremental marking is off, IdleNotification will do full GC. - const int kLongIdlePauseInMs = 1000; + const double kLongIdlePauseInSeconds = 1.0; CcTest::isolate()->ContextDisposedNotification(); - CcTest::isolate()->IdleNotification(kLongIdlePauseInMs); + CcTest::isolate()->IdleNotificationDeadline( + (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() / + static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) + + kLongIdlePauseInSeconds); CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age()); CHECK_EQ(0, f->shared()->opt_count()); @@ -2368,9 +2346,14 @@ TEST(IdleNotificationFinishMarking) { CHECK(!marking->IsIdleMarkingDelayCounterLimitReached()); } + marking->SetWeakClosureWasOverApproximatedForTesting(true); + // The next idle notification has to finish incremental marking. - const int kLongIdleTime = 1000000; - CcTest::isolate()->IdleNotification(kLongIdleTime); + const double kLongIdleTime = 1000.0; + CcTest::isolate()->IdleNotificationDeadline( + (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() / + static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) + + kLongIdleTime); CHECK_EQ(CcTest::heap()->gc_count(), 1); } @@ -2550,8 +2533,8 @@ TEST(OptimizedPretenuringMixedInObjectProperties) { } else { CHECK_EQ(2.2, inner_object->RawFastDoublePropertyAt(idx1)); } - CHECK(CcTest::heap()->InOldPointerSpace( - inner_object->RawFastPropertyAt(idx2))); + CHECK( + CcTest::heap()->InOldPointerSpace(inner_object->RawFastPropertyAt(idx2))); } @@ -2911,7 +2894,7 @@ TEST(OptimizedAllocationArrayLiterals) { static int CountMapTransitions(Map* map) { - return map->transitions()->number_of_transitions(); + return TransitionArray::NumberOfTransitions(map->raw_transitions()); } @@ -2921,6 +2904,7 @@ TEST(Regress1465) { i::FLAG_stress_compaction = false; i::FLAG_allow_natives_syntax = true; i::FLAG_trace_incremental_marking = true; + i::FLAG_retain_maps_for_n_gc = 0; CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); static const int transitions_count = 256; @@ -2983,6 +2967,7 @@ static void AddPropertyTo( Handle<Smi> twenty_three(Smi::FromInt(23), isolate); i::FLAG_gc_interval = gc_count; i::FLAG_gc_global = true; + i::FLAG_retain_maps_for_n_gc = 0; CcTest::heap()->set_allocation_timeout(gc_count); JSReceiver::SetProperty(object, prop_name, twenty_three, SLOPPY).Check(); } @@ -3090,7 +3075,7 @@ TEST(TransitionArraySimpleToFull) { CompileRun("o = new F;" "root = new F"); root = GetByName("root"); - DCHECK(root->map()->transitions()->IsSimpleTransition()); + DCHECK(TransitionArray::IsSimpleTransition(root->map()->raw_transitions())); AddPropertyTo(2, root, "happy"); // Count number of live transitions after marking. Note that one transition @@ -4090,7 +4075,8 @@ TEST(IncrementalMarkingStepMakesBigProgressWithLargeObjects) { if (marking->IsStopped()) marking->Start(); // This big step should be sufficient to mark the whole array. marking->Step(100 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); - DCHECK(marking->IsComplete()); + DCHECK(marking->IsComplete() || + marking->IsReadyToOverApproximateWeakClosure()); } @@ -4181,7 +4167,7 @@ TEST(EnsureAllocationSiteDependentCodesProcessed) { // Now make sure that a gc should get rid of the function, even though we // still have the allocation site alive. for (int i = 0; i < 4; i++) { - heap->CollectAllGarbage(Heap::kNoGCFlags); + heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); } // The site still exists because of our global handle, but the code is no @@ -4283,6 +4269,7 @@ TEST(NoWeakHashTableLeakWithIncrementalMarking) { i::FLAG_weak_embedded_objects_in_optimized_code = true; i::FLAG_allow_natives_syntax = true; i::FLAG_compilation_cache = false; + i::FLAG_retain_maps_for_n_gc = 0; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); v8::internal::Heap* heap = CcTest::heap(); @@ -4608,17 +4595,33 @@ Handle<JSFunction> GetFunctionByName(Isolate* isolate, const char* name) { } -void CheckIC(Code* code, Code::Kind kind, InlineCacheState state) { - Code* ic = FindFirstIC(code, kind); - CHECK(ic->is_inline_cache_stub()); - CHECK(ic->ic_state() == state); +void CheckIC(Code* code, Code::Kind kind, SharedFunctionInfo* shared, + int ic_slot, InlineCacheState state) { + if (FLAG_vector_ics && + (kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC || + kind == Code::CALL_IC)) { + TypeFeedbackVector* vector = shared->feedback_vector(); + FeedbackVectorICSlot slot(ic_slot); + if (kind == Code::LOAD_IC) { + LoadICNexus nexus(vector, slot); + CHECK_EQ(nexus.StateFromFeedback(), state); + } else if (kind == Code::KEYED_LOAD_IC) { + KeyedLoadICNexus nexus(vector, slot); + CHECK_EQ(nexus.StateFromFeedback(), state); + } else if (kind == Code::CALL_IC) { + CallICNexus nexus(vector, slot); + CHECK_EQ(nexus.StateFromFeedback(), state); + } + } else { + Code* ic = FindFirstIC(code, kind); + CHECK(ic->is_inline_cache_stub()); + CHECK(ic->ic_state() == state); + } } TEST(MonomorphicStaysMonomorphicAfterGC) { if (FLAG_always_opt) return; - // TODO(mvstanton): vector ics need weak support! - if (FLAG_vector_ics) return; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); Heap* heap = isolate->heap(); @@ -4641,19 +4644,17 @@ TEST(MonomorphicStaysMonomorphicAfterGC) { CompileRun("(testIC())"); } heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - CheckIC(loadIC->code(), Code::LOAD_IC, MONOMORPHIC); + CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 0, MONOMORPHIC); { v8::HandleScope scope(CcTest::isolate()); CompileRun("(testIC())"); } - CheckIC(loadIC->code(), Code::LOAD_IC, MONOMORPHIC); + CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 0, MONOMORPHIC); } TEST(PolymorphicStaysPolymorphicAfterGC) { if (FLAG_always_opt) return; - // TODO(mvstanton): vector ics need weak support! - if (FLAG_vector_ics) return; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); Heap* heap = isolate->heap(); @@ -4679,12 +4680,12 @@ TEST(PolymorphicStaysPolymorphicAfterGC) { CompileRun("(testIC())"); } heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - CheckIC(loadIC->code(), Code::LOAD_IC, POLYMORPHIC); + CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 0, POLYMORPHIC); { v8::HandleScope scope(CcTest::isolate()); CompileRun("(testIC())"); } - CheckIC(loadIC->code(), Code::LOAD_IC, POLYMORPHIC); + CheckIC(loadIC->code(), Code::LOAD_IC, loadIC->shared(), 0, POLYMORPHIC); } @@ -4878,7 +4879,7 @@ TEST(ArrayShiftSweeping) { UNINITIALIZED_TEST(PromotionQueue) { i::FLAG_expose_gc = true; - i::FLAG_max_semi_space_size = 2; + i::FLAG_max_semi_space_size = 2 * (Page::kPageSize / MB); v8::Isolate* isolate = v8::Isolate::New(); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); { @@ -5073,16 +5074,109 @@ TEST(Regress442710) { TEST(NumberStringCacheSize) { - if (!Snapshot::HaveASnapshotToStartFrom()) return; // Test that the number-string cache has not been resized in the snapshot. CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); + if (!isolate->snapshot_available()) return; Heap* heap = isolate->heap(); CHECK_EQ(TestHeap::kInitialNumberStringCacheSize * 2, heap->number_string_cache()->length()); } +TEST(Regress3877) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + Factory* factory = isolate->factory(); + HandleScope scope(isolate); + CompileRun("function cls() { this.x = 10; }"); + Handle<WeakCell> weak_prototype; + { + HandleScope inner_scope(isolate); + v8::Local<v8::Value> result = CompileRun("cls.prototype"); + Handle<JSObject> proto = + v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(result)); + weak_prototype = inner_scope.CloseAndEscape(factory->NewWeakCell(proto)); + } + CHECK(!weak_prototype->cleared()); + CompileRun( + "var a = { };" + "a.x = new cls();" + "cls.prototype = null;"); + for (int i = 0; i < 4; i++) { + heap->CollectAllGarbage(Heap::kNoGCFlags); + } + // The map of a.x keeps prototype alive + CHECK(!weak_prototype->cleared()); + // Change the map of a.x and make the previous map garbage collectable. + CompileRun("a.x.__proto__ = {};"); + for (int i = 0; i < 4; i++) { + heap->CollectAllGarbage(Heap::kNoGCFlags); + } + CHECK(weak_prototype->cleared()); +} + + +Handle<WeakCell> AddRetainedMap(Isolate* isolate, Heap* heap) { + HandleScope inner_scope(isolate); + Handle<Map> map = Map::Create(isolate, 1); + v8::Local<v8::Value> result = + CompileRun("(function () { return {x : 10}; })();"); + Handle<JSObject> proto = + v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(result)); + map->set_prototype(*proto); + heap->AddRetainedMap(map); + return inner_scope.CloseAndEscape(Map::WeakCellForMap(map)); +} + + +void CheckMapRetainingFor(int n) { + FLAG_retain_maps_for_n_gc = n; + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + Handle<WeakCell> weak_cell = AddRetainedMap(isolate, heap); + CHECK(!weak_cell->cleared()); + for (int i = 0; i < n; i++) { + heap->CollectGarbage(OLD_POINTER_SPACE); + } + CHECK(!weak_cell->cleared()); + heap->CollectGarbage(OLD_POINTER_SPACE); + CHECK(weak_cell->cleared()); +} + + +TEST(MapRetaining) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + CheckMapRetainingFor(FLAG_retain_maps_for_n_gc); + CheckMapRetainingFor(0); + CheckMapRetainingFor(1); + CheckMapRetainingFor(7); +} + + +TEST(RegressArrayListGC) { + FLAG_retain_maps_for_n_gc = 1; + FLAG_incremental_marking = 0; + FLAG_gc_global = true; + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + AddRetainedMap(isolate, heap); + Handle<Map> map = Map::Create(isolate, 1); + heap->CollectGarbage(OLD_POINTER_SPACE); + // Force GC in old space on next addition of retained map. + Map::WeakCellForMap(map); + SimulateFullSpace(CcTest::heap()->new_space()); + for (int i = 0; i < 10; i++) { + heap->AddRetainedMap(map); + } + heap->CollectGarbage(OLD_POINTER_SPACE); +} + + #ifdef DEBUG TEST(PathTracer) { CcTest::InitializeVM(); @@ -5095,23 +5189,63 @@ TEST(PathTracer) { #endif // DEBUG -TEST(FirstPageFitsStartup) { - // Test that the first page sizes provided by the default snapshot are large - // enough to fit everything right after startup and creating one context. - // If this test fails, we are allocating too much aside from deserialization. - if (!Snapshot::HaveASnapshotToStartFrom()) return; - if (Snapshot::EmbedsScript()) return; - CcTest::InitializeVM(); - LocalContext env; - PagedSpaces spaces(CcTest::heap()); - for (PagedSpace* s = spaces.next(); s != NULL; s = spaces.next()) { - uint32_t default_size = s->AreaSize(); - uint32_t reduced_size = Snapshot::SizeOfFirstPage(s->identity()); - if (reduced_size == default_size) continue; - int counter = 0; - Page* page = NULL; - for (PageIterator it(s); it.has_next(); page = it.next()) counter++; - CHECK_LE(counter, 1); - CHECK(static_cast<uint32_t>(page->area_size()) == reduced_size); +TEST(WritableVsImmortalRoots) { + for (int i = 0; i < Heap::kStrongRootListLength; ++i) { + Heap::RootListIndex root_index = static_cast<Heap::RootListIndex>(i); + bool writable = Heap::RootCanBeWrittenAfterInitialization(root_index); + bool immortal = Heap::RootIsImmortalImmovable(root_index); + // A root value can be writable, immortal, or neither, but not both. + CHECK(!immortal || !writable); } } + + +static void TestRightTrimFixedTypedArray(v8::ExternalArrayType type, + int initial_length, + int elements_to_trim) { + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + Heap* heap = isolate->heap(); + + Handle<FixedTypedArrayBase> array = + factory->NewFixedTypedArray(initial_length, type); + int old_size = array->size(); + heap->RightTrimFixedArray<Heap::FROM_MUTATOR>(*array, elements_to_trim); + + // Check that free space filler is at the right place and did not smash the + // array header. + CHECK(array->IsFixedArrayBase()); + CHECK_EQ(initial_length - elements_to_trim, array->length()); + int new_size = array->size(); + if (new_size != old_size) { + // Free space filler should be created in this case. + Address next_obj_address = array->address() + array->size(); + CHECK(HeapObject::FromAddress(next_obj_address)->IsFiller()); + } + heap->CollectAllAvailableGarbage(); +} + + +TEST(Regress472513) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + + // The combination of type/initial_length/elements_to_trim triggered + // typed array header smashing with free space filler (crbug/472513). + + // 64-bit cases. + TestRightTrimFixedTypedArray(v8::kExternalUint8Array, 32, 6); + TestRightTrimFixedTypedArray(v8::kExternalUint8Array, 32 - 7, 6); + TestRightTrimFixedTypedArray(v8::kExternalUint16Array, 16, 6); + TestRightTrimFixedTypedArray(v8::kExternalUint16Array, 16 - 3, 6); + TestRightTrimFixedTypedArray(v8::kExternalUint32Array, 8, 6); + TestRightTrimFixedTypedArray(v8::kExternalUint32Array, 8 - 1, 6); + + // 32-bit cases. + TestRightTrimFixedTypedArray(v8::kExternalUint8Array, 16, 3); + TestRightTrimFixedTypedArray(v8::kExternalUint8Array, 16 - 3, 3); + TestRightTrimFixedTypedArray(v8::kExternalUint16Array, 8, 3); + TestRightTrimFixedTypedArray(v8::kExternalUint16Array, 8 - 1, 3); + TestRightTrimFixedTypedArray(v8::kExternalUint32Array, 4, 3); +} diff --git a/deps/v8/test/cctest/test-javascript-arm64.cc b/deps/v8/test/cctest/test-javascript-arm64.cc index 5e4503478d..cbbbf3c22a 100644 --- a/deps/v8/test/cctest/test-javascript-arm64.cc +++ b/deps/v8/test/cctest/test-javascript-arm64.cc @@ -35,7 +35,6 @@ #include "src/execution.h" #include "src/isolate.h" #include "src/parser.h" -#include "src/snapshot.h" #include "src/unicode-inl.h" #include "src/utils.h" #include "test/cctest/cctest.h" diff --git a/deps/v8/test/cctest/test-js-arm64-variables.cc b/deps/v8/test/cctest/test-js-arm64-variables.cc index 7f2771094c..98d3365b87 100644 --- a/deps/v8/test/cctest/test-js-arm64-variables.cc +++ b/deps/v8/test/cctest/test-js-arm64-variables.cc @@ -37,7 +37,6 @@ #include "src/execution.h" #include "src/isolate.h" #include "src/parser.h" -#include "src/snapshot.h" #include "src/unicode-inl.h" #include "src/utils.h" #include "test/cctest/cctest.h" diff --git a/deps/v8/test/cctest/test-lockers.cc b/deps/v8/test/cctest/test-lockers.cc index c909a02125..b571564601 100644 --- a/deps/v8/test/cctest/test-lockers.cc +++ b/deps/v8/test/cctest/test-lockers.cc @@ -36,7 +36,6 @@ #include "src/isolate.h" #include "src/parser.h" #include "src/smart-pointers.h" -#include "src/snapshot.h" #include "src/unicode-inl.h" #include "src/utils.h" #include "test/cctest/cctest.h" diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc index 4b676d2e05..2386cec55b 100644 --- a/deps/v8/test/cctest/test-log.cc +++ b/deps/v8/test/cctest/test-log.cc @@ -39,7 +39,7 @@ #include "src/cpu-profiler.h" #include "src/log.h" #include "src/log-utils.h" -#include "src/natives.h" +#include "src/snapshot/natives.h" #include "src/utils.h" #include "src/v8threads.h" #include "src/version.h" diff --git a/deps/v8/test/cctest/test-macro-assembler-ia32.cc b/deps/v8/test/cctest/test-macro-assembler-ia32.cc index b2b8c946c3..3834b18798 100644 --- a/deps/v8/test/cctest/test-macro-assembler-ia32.cc +++ b/deps/v8/test/cctest/test-macro-assembler-ia32.cc @@ -33,7 +33,6 @@ #include "src/base/platform/platform.h" #include "src/factory.h" #include "src/macro-assembler.h" -#include "src/serialize.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-macro-assembler-x64.cc b/deps/v8/test/cctest/test-macro-assembler-x64.cc index 7f20a8dd4b..4ff8cba68b 100644 --- a/deps/v8/test/cctest/test-macro-assembler-x64.cc +++ b/deps/v8/test/cctest/test-macro-assembler-x64.cc @@ -32,7 +32,6 @@ #include "src/base/platform/platform.h" #include "src/factory.h" #include "src/macro-assembler.h" -#include "src/serialize.h" #include "test/cctest/cctest.h" namespace i = v8::internal; @@ -98,21 +97,13 @@ typedef int (*F0)(); static void EntryCode(MacroAssembler* masm) { // Smi constant register is callee save. - __ pushq(i::kSmiConstantRegister); __ pushq(i::kRootRegister); - __ InitializeSmiConstantRegister(); __ InitializeRootRegister(); } static void ExitCode(MacroAssembler* masm) { - // Return -1 if kSmiConstantRegister was clobbered during the test. - __ Move(rdx, Smi::FromInt(1)); - __ cmpq(rdx, i::kSmiConstantRegister); - __ movq(rdx, Immediate(-1)); - __ cmovq(not_equal, rax, rdx); __ popq(i::kRootRegister); - __ popq(i::kSmiConstantRegister); } @@ -556,32 +547,6 @@ TEST(SmiCheck) { cond = masm->CheckNonNegativeSmi(rcx); // "Positive" non-smi. __ j(cond, &exit); - // CheckIsMinSmi - - __ incq(rax); - __ movq(rcx, Immediate(Smi::kMaxValue)); - __ Integer32ToSmi(rcx, rcx); - cond = masm->CheckIsMinSmi(rcx); - __ j(cond, &exit); - - __ incq(rax); - __ movq(rcx, Immediate(0)); - __ Integer32ToSmi(rcx, rcx); - cond = masm->CheckIsMinSmi(rcx); - __ j(cond, &exit); - - __ incq(rax); - __ movq(rcx, Immediate(Smi::kMinValue)); - __ Integer32ToSmi(rcx, rcx); - cond = masm->CheckIsMinSmi(rcx); - __ j(NegateCondition(cond), &exit); - - __ incq(rax); - __ movq(rcx, Immediate(Smi::kMinValue + 1)); - __ Integer32ToSmi(rcx, rcx); - cond = masm->CheckIsMinSmi(rcx); - __ j(cond, &exit); - // CheckBothSmi __ incq(rax); diff --git a/deps/v8/test/cctest/test-macro-assembler-x87.cc b/deps/v8/test/cctest/test-macro-assembler-x87.cc index 0b057d818f..3cee27add0 100644 --- a/deps/v8/test/cctest/test-macro-assembler-x87.cc +++ b/deps/v8/test/cctest/test-macro-assembler-x87.cc @@ -33,7 +33,6 @@ #include "src/base/platform/platform.h" #include "src/factory.h" #include "src/macro-assembler.h" -#include "src/serialize.h" using namespace v8::internal; diff --git a/deps/v8/test/cctest/test-mark-compact.cc b/deps/v8/test/cctest/test-mark-compact.cc index 64d995d95a..cfc971770d 100644 --- a/deps/v8/test/cctest/test-mark-compact.cc +++ b/deps/v8/test/cctest/test-mark-compact.cc @@ -41,10 +41,10 @@ #include "src/full-codegen.h" #include "src/global-handles.h" -#include "src/snapshot.h" #include "test/cctest/cctest.h" using namespace v8::internal; +using v8::Just; TEST(MarkingDeque) { @@ -127,6 +127,7 @@ TEST(NoPromotion) { TEST(MarkCompactCollector) { FLAG_incremental_marking = false; + FLAG_retain_maps_for_n_gc = 0; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); TestHeap* heap = CcTest::test_heap(); @@ -167,9 +168,7 @@ TEST(MarkCompactCollector) { { HandleScope scope(isolate); Handle<String> func_name = factory->InternalizeUtf8String("theFunction"); - v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, func_name); - CHECK(maybe.has_value); - CHECK(maybe.value); + CHECK(Just(true) == JSReceiver::HasOwnProperty(global, func_name)); Handle<Object> func_value = Object::GetProperty(global, func_name).ToHandleChecked(); CHECK(func_value->IsJSFunction()); @@ -187,9 +186,7 @@ TEST(MarkCompactCollector) { { HandleScope scope(isolate); Handle<String> obj_name = factory->InternalizeUtf8String("theObject"); - v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, obj_name); - CHECK(maybe.has_value); - CHECK(maybe.value); + CHECK(Just(true) == JSReceiver::HasOwnProperty(global, obj_name)); Handle<Object> object = Object::GetProperty(global, obj_name).ToHandleChecked(); CHECK(object->IsJSObject()); diff --git a/deps/v8/test/cctest/test-mementos.cc b/deps/v8/test/cctest/test-mementos.cc index 4c85151b88..391c934475 100644 --- a/deps/v8/test/cctest/test-mementos.cc +++ b/deps/v8/test/cctest/test-mementos.cc @@ -58,9 +58,26 @@ TEST(Regress340063) { if (!i::FLAG_allocation_site_pretenuring) return; v8::HandleScope scope(CcTest::isolate()); + SetUpNewSpaceWithPoisonedMementoAtTop(); + + // Call GC to see if we can handle a poisonous memento right after the + // current new space top pointer. + CcTest::i_isolate()->heap()->CollectAllGarbage( + Heap::kAbortIncrementalMarkingMask); +} + + +TEST(Regress470390) { + CcTest::InitializeVM(); + if (!i::FLAG_allocation_site_pretenuring) return; + v8::HandleScope scope(CcTest::isolate()); SetUpNewSpaceWithPoisonedMementoAtTop(); + // Set the new space limit to be equal to the top. + Address top = CcTest::i_isolate()->heap()->new_space()->top(); + *(CcTest::i_isolate()->heap()->new_space()->allocation_limit_address()) = top; + // Call GC to see if we can handle a poisonous memento right after the // current new space top pointer. CcTest::i_isolate()->heap()->CollectAllGarbage( diff --git a/deps/v8/test/cctest/test-migrations.cc b/deps/v8/test/cctest/test-migrations.cc index 2f7ff8703c..3be173453a 100644 --- a/deps/v8/test/cctest/test-migrations.cc +++ b/deps/v8/test/cctest/test-migrations.cc @@ -145,6 +145,7 @@ class Expectations { os << ": " << representations_[i].Mnemonic(); os << ", attrs: " << attributes_[i] << ")\n"; } + os << "\n"; } Handle<HeapType> GetFieldType(int index) { @@ -232,12 +233,14 @@ class Expectations { representations_[descriptor])) { return false; } - Object* expected_value = *values_[descriptor]; Object* value = descriptors->GetValue(descriptor); + Object* expected_value = *values_[descriptor]; switch (type) { case DATA: - case ACCESSOR: - return HeapType::cast(expected_value)->Equals(HeapType::cast(value)); + case ACCESSOR: { + HeapType* type = descriptors->GetFieldType(descriptor); + return HeapType::cast(expected_value)->Equals(type); + } case DATA_CONSTANT: return value == expected_value; @@ -263,6 +266,9 @@ class Expectations { for (int i = 0; i < expected_nof; i++) { if (!Check(descriptors, i)) { Print(); +#ifdef OBJECT_PRINT + descriptors->Print(); +#endif Check(descriptors, i); return false; } @@ -336,9 +342,10 @@ class Expectations { SetDataField(property_index, attributes, representation, heap_type); Handle<String> name = MakeName("prop", property_index); - int t = map->SearchTransition(kData, *name, attributes); - CHECK_NE(TransitionArray::kNotFound, t); - return handle(map->GetTransition(t)); + Map* target = + TransitionArray::SearchTransition(*map, kData, *name, attributes); + CHECK(target != NULL); + return handle(target); } Handle<Map> AddAccessorConstant(Handle<Map> map, @@ -517,21 +524,51 @@ TEST(ReconfigureAccessorToNonExistingDataFieldHeavy) { // A set of tests for representation generalization case. // -static void TestGeneralizeRepresentation(Representation from_representation, - Handle<HeapType> from_type, - Representation to_representation, - Handle<HeapType> to_type, - Representation expected_representation, - Handle<HeapType> expected_type) { +// This test ensures that representation/field type generalization at +// |property_index| is done correctly independently of the fact that the |map| +// is detached from transition tree or not. +// +// {} - p0 - p1 - p2: |detach_point_map| +// | +// X - detached at |detach_property_at_index| +// | +// + - p3 - p4: |map| +// +// Detaching does not happen if |detach_property_at_index| is -1. +// +static void TestGeneralizeRepresentation( + int detach_property_at_index, int property_index, + Representation from_representation, Handle<HeapType> from_type, + Representation to_representation, Handle<HeapType> to_type, + Representation expected_representation, Handle<HeapType> expected_type, + bool expected_deprecation, bool expected_field_type_dependency) { Isolate* isolate = CcTest::i_isolate(); + Handle<HeapType> any_type = HeapType::Any(isolate); + + CHECK(detach_property_at_index >= -1 && + detach_property_at_index < kPropCount); + CHECK(property_index < kPropCount); + CHECK_NE(detach_property_at_index, property_index); + + const bool is_detached_map = detach_property_at_index >= 0; Expectations expectations(isolate); // Create a map, add required properties to it and initialize expectations. Handle<Map> initial_map = Map::Create(isolate, 0); Handle<Map> map = initial_map; + Handle<Map> detach_point_map; for (int i = 0; i < kPropCount; i++) { - map = expectations.AddDataField(map, NONE, from_representation, from_type); + if (i == property_index) { + map = + expectations.AddDataField(map, NONE, from_representation, from_type); + } else { + map = + expectations.AddDataField(map, NONE, Representation::Smi(), any_type); + if (i == detach_property_at_index) { + detach_point_map = map; + } + } } CHECK(!map->is_deprecated()); CHECK(map->is_stable()); @@ -540,97 +577,121 @@ static void TestGeneralizeRepresentation(Representation from_representation, Zone zone; FakeStubForTesting stub(isolate); + if (is_detached_map) { + detach_point_map = Map::ReconfigureProperty( + detach_point_map, detach_property_at_index, kData, NONE, + Representation::Tagged(), any_type, FORCE_FIELD); + expectations.SetDataField(detach_property_at_index, + Representation::Tagged(), any_type); + CHECK(map->is_deprecated()); + CHECK(expectations.Check(*detach_point_map, + detach_point_map->NumberOfOwnDescriptors())); + } + // Create new maps by generalizing representation of propX field. - Handle<Map> maps[kPropCount]; - for (int i = 0; i < kPropCount; i++) { - Handle<Map> field_owner(map->FindFieldOwner(i), isolate); - CompilationInfo info(&stub, isolate, &zone); - CHECK(!info.HasAbortedDueToDependencyChange()); + Handle<Map> field_owner(map->FindFieldOwner(property_index), isolate); + CompilationInfo info(&stub, isolate, &zone); + CHECK(!info.HasAbortedDueToDependencyChange()); + + Map::AddDependentCompilationInfo(field_owner, DependentCode::kFieldTypeGroup, + &info); - Map::AddDependentCompilationInfo(field_owner, - DependentCode::kFieldTypeGroup, &info); + Handle<Map> new_map = + Map::ReconfigureProperty(map, property_index, kData, NONE, + to_representation, to_type, FORCE_FIELD); - Handle<Map> new_map = Map::ReconfigureProperty( - map, i, kData, NONE, to_representation, to_type, FORCE_FIELD); - maps[i] = new_map; + expectations.SetDataField(property_index, expected_representation, + expected_type); - expectations.SetDataField(i, expected_representation, expected_type); + CHECK(!new_map->is_deprecated()); + CHECK(expectations.Check(*new_map)); + if (is_detached_map) { CHECK(map->is_deprecated()); - CHECK(!info.HasAbortedDueToDependencyChange()); - info.RollbackDependencies(); // Properly cleanup compilation info. + CHECK_NE(*map, *new_map); + CHECK_EQ(expected_field_type_dependency && !field_owner->is_deprecated(), + info.HasAbortedDueToDependencyChange()); + } else if (expected_deprecation) { + CHECK(map->is_deprecated()); + CHECK(field_owner->is_deprecated()); CHECK_NE(*map, *new_map); - CHECK(i == 0 || maps[i - 1]->is_deprecated()); + CHECK(!info.HasAbortedDueToDependencyChange()); - CHECK(!new_map->is_deprecated()); - CHECK(!new_map->is_dictionary_map()); - CHECK(expectations.Check(*new_map)); + } else { + CHECK(!field_owner->is_deprecated()); + CHECK_EQ(*map, *new_map); + + CHECK_EQ(expected_field_type_dependency, + info.HasAbortedDueToDependencyChange()); } - Handle<Map> active_map = maps[kPropCount - 1]; - CHECK(!active_map->is_deprecated()); + info.RollbackDependencies(); // Properly cleanup compilation info. // Update all deprecated maps and check that they are now the same. Handle<Map> updated_map = Map::Update(map); - CHECK_EQ(*active_map, *updated_map); - for (int i = 0; i < kPropCount; i++) { - updated_map = Map::Update(maps[i]); - CHECK_EQ(*active_map, *updated_map); - } + CHECK_EQ(*new_map, *updated_map); } -static void TestGeneralizeRepresentationTrivial( +static void TestGeneralizeRepresentation( Representation from_representation, Handle<HeapType> from_type, Representation to_representation, Handle<HeapType> to_type, Representation expected_representation, Handle<HeapType> expected_type, - bool expected_field_type_dependency = true) { - Isolate* isolate = CcTest::i_isolate(); - - Expectations expectations(isolate); - - // Create a map, add required properties to it and initialize expectations. - Handle<Map> initial_map = Map::Create(isolate, 0); - Handle<Map> map = initial_map; - for (int i = 0; i < kPropCount; i++) { - map = expectations.AddDataField(map, NONE, from_representation, from_type); + bool expected_deprecation, bool expected_field_type_dependency) { + // Check the cases when the map being reconfigured is a part of the + // transition tree. + STATIC_ASSERT(kPropCount > 4); + int indices[] = {0, 2, kPropCount - 1}; + for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) { + TestGeneralizeRepresentation( + -1, indices[i], from_representation, from_type, to_representation, + to_type, expected_representation, expected_type, expected_deprecation, + expected_field_type_dependency); + } + + if (!from_representation.IsNone()) { + // Check the cases when the map being reconfigured is NOT a part of the + // transition tree. "None -> anything" representation changes make sense + // only for "attached" maps. + int indices[] = {0, kPropCount - 1}; + for (int i = 0; i < static_cast<int>(arraysize(indices)); i++) { + TestGeneralizeRepresentation( + indices[i], 2, from_representation, from_type, to_representation, + to_type, expected_representation, expected_type, expected_deprecation, + expected_field_type_dependency); + } } - CHECK(!map->is_deprecated()); - CHECK(map->is_stable()); - CHECK(expectations.Check(*map)); - - Zone zone; - FakeStubForTesting stub(isolate); - - // Create new maps by generalizing representation of propX field. - for (int i = 0; i < kPropCount; i++) { - Handle<Map> field_owner(map->FindFieldOwner(i), isolate); - CompilationInfo info(&stub, isolate, &zone); - CHECK(!info.HasAbortedDueToDependencyChange()); - - Map::AddDependentCompilationInfo(field_owner, - DependentCode::kFieldTypeGroup, &info); +} - Handle<Map> new_map = Map::ReconfigureProperty( - map, i, kData, NONE, to_representation, to_type, FORCE_FIELD); - expectations.SetDataField(i, expected_representation, expected_type); +static void TestGeneralizeRepresentation(Representation from_representation, + Handle<HeapType> from_type, + Representation to_representation, + Handle<HeapType> to_type, + Representation expected_representation, + Handle<HeapType> expected_type) { + const bool expected_deprecation = true; + const bool expected_field_type_dependency = false; - CHECK_EQ(*map, *new_map); - CHECK_EQ(expected_field_type_dependency, - info.HasAbortedDueToDependencyChange()); + TestGeneralizeRepresentation( + from_representation, from_type, to_representation, to_type, + expected_representation, expected_type, expected_deprecation, + expected_field_type_dependency); +} - info.RollbackDependencies(); // Properly cleanup compilation info. - CHECK_EQ(*map, *new_map); - CHECK(!new_map->is_deprecated()); - CHECK(!new_map->is_dictionary_map()); - CHECK(expectations.Check(*new_map)); - } +static void TestGeneralizeRepresentationTrivial( + Representation from_representation, Handle<HeapType> from_type, + Representation to_representation, Handle<HeapType> to_type, + Representation expected_representation, Handle<HeapType> expected_type, + bool expected_field_type_dependency = true) { + const bool expected_deprecation = false; - Handle<Map> updated_map = Map::Update(map); - CHECK_EQ(*map, *updated_map); + TestGeneralizeRepresentation( + from_representation, from_type, to_representation, to_type, + expected_representation, expected_type, expected_deprecation, + expected_field_type_dependency); } @@ -828,7 +889,6 @@ TEST(GeneralizeRepresentationWithAccessorProperties) { CHECK(i == 0 || maps[i - 1]->is_deprecated()); CHECK(!new_map->is_deprecated()); - CHECK(!new_map->is_dictionary_map()); CHECK(expectations.Check(*new_map)); } @@ -925,7 +985,6 @@ static void TestReconfigureDataFieldAttribute_GeneralizeRepresentation( CHECK_NE(*map, *new_map); CHECK(!new_map->is_deprecated()); - CHECK(!new_map->is_dictionary_map()); CHECK(expectations.Check(*new_map)); // Update deprecated |map|, it should become |new_map|. @@ -1016,7 +1075,6 @@ static void TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial( info.RollbackDependencies(); // Properly cleanup compilation info. CHECK(!new_map->is_deprecated()); - CHECK(!new_map->is_dictionary_map()); CHECK(expectations.Check(*new_map)); Handle<Map> updated_map = Map::Update(map); @@ -1121,7 +1179,6 @@ struct CheckDeprecated { CHECK_NE(*map, *new_map); CHECK(!new_map->is_deprecated()); - CHECK(!new_map->is_dictionary_map()); CHECK(expectations.Check(*new_map)); // Update deprecated |map|, it should become |new_map|. @@ -1140,7 +1197,6 @@ struct CheckSameMap { CHECK_EQ(*map, *new_map); CHECK(!new_map->is_deprecated()); - CHECK(!new_map->is_dictionary_map()); CHECK(expectations.Check(*new_map)); // Update deprecated |map|, it should become |new_map|. @@ -1163,7 +1219,6 @@ struct CheckCopyGeneralizeAllRepresentations { } CHECK(!new_map->is_deprecated()); - CHECK(!new_map->is_dictionary_map()); CHECK(expectations.Check(*new_map)); } }; @@ -1423,9 +1478,10 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) { } Handle<String> name = MakeName("prop", i); - int t = map2->SearchTransition(kData, *name, NONE); - CHECK_NE(TransitionArray::kNotFound, t); - map2 = handle(map2->GetTransition(t)); + Map* target = + TransitionArray::SearchTransition(*map2, kData, *name, NONE); + CHECK(target != NULL); + map2 = handle(target); } map2 = Map::ReconfigureProperty(map2, kSplitProp, kData, NONE, @@ -1445,12 +1501,12 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) { // Fill in transition tree of |map2| so that it can't have more transitions. for (int i = 0; i < TransitionArray::kMaxNumberOfTransitions; i++) { - CHECK(map2->CanHaveMoreTransitions()); + CHECK(TransitionArray::CanHaveMoreTransitions(map2)); Handle<String> name = MakeName("foo", i); Map::CopyWithField(map2, name, any_type, NONE, Representation::Smi(), INSERT_TRANSITION).ToHandleChecked(); } - CHECK(!map2->CanHaveMoreTransitions()); + CHECK(!TransitionArray::CanHaveMoreTransitions(map2)); // Try to update |map|, since there is no place for propX transition at |map2| // |map| should become "copy-generalized". diff --git a/deps/v8/test/cctest/test-parsing.cc b/deps/v8/test/cctest/test-parsing.cc index 1a17475ada..5b19746f93 100644 --- a/deps/v8/test/cctest/test-parsing.cc +++ b/deps/v8/test/cctest/test-parsing.cc @@ -72,7 +72,6 @@ TEST(ScanKeywords) { i::Utf8ToUtf16CharacterStream stream(keyword, length); i::Scanner scanner(&unicode_cache); // The scanner should parse Harmony keywords for this test. - scanner.SetHarmonyScoping(true); scanner.SetHarmonyModules(true); scanner.SetHarmonyClasses(true); scanner.Initialize(&stream); @@ -1045,15 +1044,14 @@ TEST(ScopeUsesArgumentsSuperThis) { factory->NewStringFromUtf8(i::CStrVector(program.start())) .ToHandleChecked(); i::Handle<i::Script> script = factory->NewScript(source); - i::CompilationInfoWithZone info(script); - i::Parser parser(&info, isolate->stack_guard()->real_climit(), - isolate->heap()->HashSeed(), isolate->unicode_cache()); + i::Zone zone; + i::ParseInfo info(&zone, script); + i::Parser parser(&info); parser.set_allow_harmony_arrow_functions(true); parser.set_allow_harmony_classes(true); parser.set_allow_harmony_object_literals(true); - parser.set_allow_harmony_scoping(true); parser.set_allow_harmony_sloppy(true); - info.MarkAsGlobal(); + info.set_global(); CHECK(parser.Parse(&info)); CHECK(i::Rewriter::Rewrite(&info)); CHECK(i::Scope::Analyze(&info)); @@ -1086,8 +1084,6 @@ TEST(ScopeUsesArgumentsSuperThis) { TEST(ScopePositions) { - v8::internal::FLAG_harmony_scoping = true; - // Test the parser for correctly setting the start and end positions // of a scope. We check the scope positions of exactly one scope // nested in the global scope of a program. 'inner source' is the @@ -1297,14 +1293,13 @@ TEST(ScopePositions) { i::CStrVector(program.start())).ToHandleChecked(); CHECK_EQ(source->length(), kProgramSize); i::Handle<i::Script> script = factory->NewScript(source); - i::CompilationInfoWithZone info(script); - i::Parser parser(&info, isolate->stack_guard()->real_climit(), - isolate->heap()->HashSeed(), isolate->unicode_cache()); + i::Zone zone; + i::ParseInfo info(&zone, script); + i::Parser parser(&info); parser.set_allow_lazy(true); - parser.set_allow_harmony_scoping(true); parser.set_allow_harmony_arrow_functions(true); - info.MarkAsGlobal(); - info.SetLanguageMode(source_data[i].language_mode); + info.set_global(); + info.set_language_mode(source_data[i].language_mode); parser.Parse(&info); CHECK(info.function() != NULL); @@ -1377,14 +1372,12 @@ i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) { enum ParserFlag { kAllowLazy, kAllowNatives, - kAllowHarmonyScoping, kAllowHarmonyModules, kAllowHarmonyNumericLiterals, kAllowHarmonyArrowFunctions, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, kAllowHarmonyRestParameters, - kAllowHarmonyTemplates, kAllowHarmonySloppy, kAllowHarmonyUnicode, kAllowHarmonyComputedPropertyNames, @@ -1403,7 +1396,6 @@ void SetParserFlags(i::ParserBase<Traits>* parser, i::EnumSet<ParserFlag> flags) { parser->set_allow_lazy(flags.Contains(kAllowLazy)); parser->set_allow_natives(flags.Contains(kAllowNatives)); - parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping)); parser->set_allow_harmony_modules(flags.Contains(kAllowHarmonyModules)); parser->set_allow_harmony_numeric_literals( flags.Contains(kAllowHarmonyNumericLiterals)); @@ -1412,7 +1404,6 @@ void SetParserFlags(i::ParserBase<Traits>* parser, parser->set_allow_harmony_arrow_functions( flags.Contains(kAllowHarmonyArrowFunctions)); parser->set_allow_harmony_classes(flags.Contains(kAllowHarmonyClasses)); - parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates)); parser->set_allow_harmony_rest_params( flags.Contains(kAllowHarmonyRestParameters)); parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy)); @@ -1456,11 +1447,11 @@ void TestParserSyncWithFlags(i::Handle<i::String> source, i::FunctionLiteral* function; { i::Handle<i::Script> script = factory->NewScript(source); - i::CompilationInfoWithZone info(script); - i::Parser parser(&info, isolate->stack_guard()->real_climit(), - isolate->heap()->HashSeed(), isolate->unicode_cache()); + i::Zone zone; + i::ParseInfo info(&zone, script); + i::Parser parser(&info); SetParserFlags(&parser, flags); - info.MarkAsGlobal(); + info.set_global(); parser.Parse(&info); function = info.function(); if (function) { @@ -1973,8 +1964,8 @@ TEST(NoErrorsFutureStrictReservedWords) { RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); - static const ParserFlag classes_flags[] = { - kAllowHarmonyArrowFunctions, kAllowHarmonyClasses, kAllowHarmonyScoping}; + static const ParserFlag classes_flags[] = {kAllowHarmonyArrowFunctions, + kAllowHarmonyClasses}; RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, classes_flags, arraysize(classes_flags)); } @@ -2544,10 +2535,13 @@ TEST(DontRegressPreParserDataSizes) { i::Handle<i::String> source = factory->NewStringFromUtf8(i::CStrVector(program)).ToHandleChecked(); i::Handle<i::Script> script = factory->NewScript(source); - i::CompilationInfoWithZone info(script); + i::Zone zone; + i::ParseInfo info(&zone, script); i::ScriptData* sd = NULL; - info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache); - i::Parser::ParseStatic(&info, true); + info.set_cached_data(&sd); + info.set_compile_options(v8::ScriptCompiler::kProduceParserCache); + info.set_allow_lazy_parsing(); + i::Parser::ParseStatic(&info); i::ParseData* pd = i::ParseData::FromCachedData(sd); if (pd->FunctionCount() != test_cases[i].functions) { @@ -2961,6 +2955,36 @@ TEST(StrictDelete) { } +TEST(NoErrorsDeclsInCase) { + const char* context_data[][2] = { + {"'use strict'; switch(x) { case 1:", "}"}, + {"function foo() {'use strict'; switch(x) { case 1:", "}}"}, + {"'use strict'; switch(x) { case 1: case 2:", "}"}, + {"function foo() {'use strict'; switch(x) { case 1: case 2:", "}}"}, + {"'use strict'; switch(x) { default:", "}"}, + {"function foo() {'use strict'; switch(x) { default:", "}}"}, + {"'use strict'; switch(x) { case 1: default:", "}"}, + {"function foo() {'use strict'; switch(x) { case 1: default:", "}}"}, + { nullptr, nullptr } + }; + + const char* statement_data[] = { + "function f() { }", + "class C { }", + "class C extends Q {}", + "function f() { } class C {}", + "function f() { }; class C {}", + "class C {}; function f() {}", + nullptr + }; + + static const ParserFlag always_flags[] = {kAllowHarmonyClasses}; + + RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, + always_flags, arraysize(always_flags)); +} + + TEST(InvalidLeftHandSide) { const char* assignment_context_data[][2] = { {"", " = 1;"}, @@ -3246,70 +3270,6 @@ TEST(IfArgumentsArrayAccessedThenParametersMaybeAssigned) { } -TEST(ExportsMaybeAssigned) { - i::FLAG_use_strict = true; - i::FLAG_harmony_scoping = true; - i::FLAG_harmony_modules = true; - - i::Isolate* isolate = CcTest::i_isolate(); - i::Factory* factory = isolate->factory(); - i::HandleScope scope(isolate); - LocalContext env; - - const char* src = - "module A {" - " export var x = 1;" - " export function f() { return x };" - " export const y = 2;" - " module B {}" - " export module C {}" - "};" - "A.f"; - - i::ScopedVector<char> program(Utf8LengthHelper(src) + 1); - i::SNPrintF(program, "%s", src); - i::Handle<i::String> source = factory->InternalizeUtf8String(program.start()); - source->PrintOn(stdout); - printf("\n"); - i::Zone zone; - v8::Local<v8::Value> v = CompileRun(src); - i::Handle<i::Object> o = v8::Utils::OpenHandle(*v); - i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o); - i::Context* context = f->context(); - i::AstValueFactory avf(&zone, isolate->heap()->HashSeed()); - avf.Internalize(isolate); - - i::Scope* script_scope = - new (&zone) i::Scope(&zone, NULL, i::SCRIPT_SCOPE, &avf); - script_scope->Initialize(); - i::Scope* s = - i::Scope::DeserializeScopeChain(isolate, &zone, context, script_scope); - DCHECK(s != script_scope); - const i::AstRawString* name_x = avf.GetOneByteString("x"); - const i::AstRawString* name_f = avf.GetOneByteString("f"); - const i::AstRawString* name_y = avf.GetOneByteString("y"); - const i::AstRawString* name_B = avf.GetOneByteString("B"); - const i::AstRawString* name_C = avf.GetOneByteString("C"); - - // Get result from h's function context (that is f's context) - i::Variable* var_x = s->Lookup(name_x); - CHECK(var_x != NULL); - CHECK(var_x->maybe_assigned() == i::kMaybeAssigned); - i::Variable* var_f = s->Lookup(name_f); - CHECK(var_f != NULL); - CHECK(var_f->maybe_assigned() == i::kMaybeAssigned); - i::Variable* var_y = s->Lookup(name_y); - CHECK(var_y != NULL); - CHECK(var_y->maybe_assigned() == i::kNotAssigned); - i::Variable* var_B = s->Lookup(name_B); - CHECK(var_B != NULL); - CHECK(var_B->maybe_assigned() == i::kNotAssigned); - i::Variable* var_C = s->Lookup(name_C); - CHECK(var_C != NULL); - CHECK(var_C->maybe_assigned() == i::kNotAssigned); -} - - TEST(InnerAssignment) { i::Isolate* isolate = CcTest::i_isolate(); i::Factory* factory = isolate->factory(); @@ -3431,11 +3391,9 @@ TEST(InnerAssignment) { printf("\n"); i::Handle<i::Script> script = factory->NewScript(source); - i::CompilationInfoWithZone info(script); - i::Parser parser(&info, isolate->stack_guard()->real_climit(), - isolate->heap()->HashSeed(), - isolate->unicode_cache()); - parser.set_allow_harmony_scoping(true); + i::Zone zone; + i::ParseInfo info(&zone, script); + i::Parser parser(&info); CHECK(parser.Parse(&info)); CHECK(i::Compiler::Analyze(&info)); CHECK(info.function() != NULL); @@ -3583,7 +3541,7 @@ TEST(ErrorsArrowFunctions) { }; // The test is quite slow, so run it with a reduced set of flags. - static const ParserFlag flags[] = {kAllowLazy, kAllowHarmonyScoping}; + static const ParserFlag flags[] = {kAllowLazy}; static const ParserFlag always_flags[] = { kAllowHarmonyArrowFunctions }; RunParserSyncTest(context_data, statement_data, kError, flags, arraysize(flags), always_flags, arraysize(always_flags)); @@ -4111,8 +4069,7 @@ TEST(ClassDeclarationNoErrors) { "class name extends class base {} {}", NULL}; - static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, kAllowHarmonyScoping}; + static const ParserFlag always_flags[] = {kAllowHarmonyClasses}; RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); } @@ -4631,9 +4588,7 @@ TEST(ConstParsingInForIn) { "for(const x in [1,2,3]) {}", "for(const x of [1,2,3]) {}", NULL}; - static const ParserFlag always_flags[] = {kAllowHarmonyScoping}; - RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags, - arraysize(always_flags)); + RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, nullptr, 0); } @@ -4653,9 +4608,7 @@ TEST(ConstParsingInForInError) { "for(const x = 1, y = 2 of []) {}", "for(const x,y of []) {}", NULL}; - static const ParserFlag always_flags[] = {kAllowHarmonyScoping}; - RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, - arraysize(always_flags)); + RunParserSyncTest(context_data, data, kError, nullptr, 0, nullptr, 0); } @@ -4749,9 +4702,7 @@ TEST(ScanTemplateLiterals) { "`foo${\r a}`", "`foo${'a' in a}`", NULL}; - static const ParserFlag always_flags[] = {kAllowHarmonyTemplates}; - RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags, - arraysize(always_flags)); + RunParserSyncTest(context_data, data, kSuccess, NULL, 0, NULL, 0); } @@ -4786,9 +4737,7 @@ TEST(ScanTaggedTemplateLiterals) { "tag`foo${\r a}`", "tag`foo${'a' in a}`", NULL}; - static const ParserFlag always_flags[] = {kAllowHarmonyTemplates}; - RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags, - arraysize(always_flags)); + RunParserSyncTest(context_data, data, kSuccess, NULL, 0, NULL, 0); } @@ -4815,9 +4764,7 @@ TEST(TemplateMaterializedLiterals) { NULL }; - static const ParserFlag always_flags[] = {kAllowHarmonyTemplates}; - RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags, - arraysize(always_flags)); + RunParserSyncTest(context_data, data, kSuccess, NULL, 0, NULL, 0); } @@ -4851,9 +4798,7 @@ TEST(ScanUnterminatedTemplateLiterals) { "`foo${fn(}`", "`foo${1 if}`", NULL}; - static const ParserFlag always_flags[] = {kAllowHarmonyTemplates}; - RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, - arraysize(always_flags)); + RunParserSyncTest(context_data, data, kError, NULL, 0, NULL, 0); } @@ -4873,9 +4818,7 @@ TEST(TemplateLiteralsIllegalTokens) { "`hello${1}\\x\n${2}`", NULL}; - static const ParserFlag always_flags[] = {kAllowHarmonyTemplates}; - RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, - arraysize(always_flags)); + RunParserSyncTest(context_data, data, kError, NULL, 0, NULL, 0); } @@ -5010,8 +4953,7 @@ TEST(LexicalScopingSloppyMode) { "(class C {})", "(class C extends D {})", NULL}; - static const ParserFlag always_true_flags[] = { - kAllowHarmonyScoping, kAllowHarmonyClasses}; + static const ParserFlag always_true_flags[] = {kAllowHarmonyClasses}; static const ParserFlag always_false_flags[] = {kAllowHarmonySloppy}; RunParserSyncTest(context_data, bad_data, kError, NULL, 0, always_true_flags, arraysize(always_true_flags), @@ -5108,6 +5050,7 @@ TEST(BasicImportExportParsing) { "export { yield } from 'm.js'", "export { static } from 'm.js'", "export { let } from 'm.js'", + "var a; export { a as b, a as c };", "import 'somemodule.js';", "import { } from 'm.js';", @@ -5135,23 +5078,18 @@ TEST(BasicImportExportParsing) { 128 * 1024); for (unsigned i = 0; i < arraysize(kSources); ++i) { - int kProgramByteSize = i::StrLength(kSources[i]); - i::ScopedVector<char> program(kProgramByteSize + 1); - i::SNPrintF(program, "%s", kSources[i]); i::Handle<i::String> source = - factory->NewStringFromUtf8(i::CStrVector(program.start())) - .ToHandleChecked(); + factory->NewStringFromAsciiChecked(kSources[i]); // Show that parsing as a module works { i::Handle<i::Script> script = factory->NewScript(source); - i::CompilationInfoWithZone info(script); - i::Parser parser(&info, isolate->stack_guard()->real_climit(), - isolate->heap()->HashSeed(), isolate->unicode_cache()); + i::Zone zone; + i::ParseInfo info(&zone, script); + i::Parser parser(&info); parser.set_allow_harmony_classes(true); parser.set_allow_harmony_modules(true); - parser.set_allow_harmony_scoping(true); - info.MarkAsModule(); + info.set_module(); if (!parser.Parse(&info)) { i::Handle<i::JSObject> exception_handle( i::JSObject::cast(isolate->pending_exception())); @@ -5173,13 +5111,12 @@ TEST(BasicImportExportParsing) { // And that parsing a script does not. { i::Handle<i::Script> script = factory->NewScript(source); - i::CompilationInfoWithZone info(script); - i::Parser parser(&info, isolate->stack_guard()->real_climit(), - isolate->heap()->HashSeed(), isolate->unicode_cache()); + i::Zone zone; + i::ParseInfo info(&zone, script); + i::Parser parser(&info); parser.set_allow_harmony_classes(true); parser.set_allow_harmony_modules(true); - parser.set_allow_harmony_scoping(true); - info.MarkAsGlobal(); + info.set_global(); CHECK(!parser.Parse(&info)); } } @@ -5211,6 +5148,10 @@ TEST(ImportExportParsingErrors) { "export { arguments }", "export { arguments as foo }", "var a; export { a, a };", + "var a, b; export { a as b, b };", + "var a, b; export { a as c, b as c };", + "export default function f(){}; export default class C {};", + "export default function f(){}; var a; export { a as default };", "import from;", "import from 'm.js';", @@ -5256,26 +5197,81 @@ TEST(ImportExportParsingErrors) { 128 * 1024); for (unsigned i = 0; i < arraysize(kErrorSources); ++i) { - int kProgramByteSize = i::StrLength(kErrorSources[i]); - i::ScopedVector<char> program(kProgramByteSize + 1); - i::SNPrintF(program, "%s", kErrorSources[i]); i::Handle<i::String> source = - factory->NewStringFromUtf8(i::CStrVector(program.start())) - .ToHandleChecked(); + factory->NewStringFromAsciiChecked(kErrorSources[i]); i::Handle<i::Script> script = factory->NewScript(source); - i::CompilationInfoWithZone info(script); - i::Parser parser(&info, isolate->stack_guard()->real_climit(), - isolate->heap()->HashSeed(), isolate->unicode_cache()); + i::Zone zone; + i::ParseInfo info(&zone, script); + i::Parser parser(&info); parser.set_allow_harmony_classes(true); parser.set_allow_harmony_modules(true); - parser.set_allow_harmony_scoping(true); - info.MarkAsModule(); + info.set_module(); CHECK(!parser.Parse(&info)); } } +TEST(ModuleParsingInternals) { + i::FLAG_harmony_modules = true; + + i::Isolate* isolate = CcTest::i_isolate(); + i::Factory* factory = isolate->factory(); + v8::HandleScope handles(CcTest::isolate()); + v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate()); + v8::Context::Scope context_scope(context); + isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() - + 128 * 1024); + + static const char kSource[] = + "let x = 5;" + "export { x as y };" + "import { q as z } from 'm.js';" + "import n from 'n.js'"; + i::Handle<i::String> source = factory->NewStringFromAsciiChecked(kSource); + i::Handle<i::Script> script = factory->NewScript(source); + i::Zone zone; + i::ParseInfo info(&zone, script); + i::AstValueFactory avf(&zone, isolate->heap()->HashSeed()); + i::Parser parser(&info); + parser.set_allow_harmony_modules(true); + info.set_module(); + CHECK(parser.Parse(&info)); + CHECK(i::Compiler::Analyze(&info)); + + i::FunctionLiteral* func = info.function(); + i::Scope* module_scope = func->scope(); + i::Scope* outer_scope = module_scope->outer_scope(); + CHECK(outer_scope->is_script_scope()); + CHECK_NULL(outer_scope->outer_scope()); + CHECK_EQ(1, outer_scope->num_modules()); + CHECK(module_scope->is_module_scope()); + CHECK_NOT_NULL(module_scope->module_var()); + CHECK_EQ(i::INTERNAL, module_scope->module_var()->mode()); + + i::ModuleDescriptor* descriptor = module_scope->module(); + CHECK_NOT_NULL(descriptor); + CHECK_EQ(1, descriptor->Length()); + const i::AstRawString* export_name = avf.GetOneByteString("y"); + const i::AstRawString* local_name = + descriptor->LookupLocalExport(export_name, &zone); + CHECK_NOT_NULL(local_name); + CHECK(local_name->IsOneByteEqualTo("x")); + i::ZoneList<i::Declaration*>* declarations = module_scope->declarations(); + CHECK_EQ(3, declarations->length()); + CHECK(declarations->at(0)->proxy()->raw_name()->IsOneByteEqualTo("x")); + i::ImportDeclaration* import_decl = + declarations->at(1)->AsImportDeclaration(); + CHECK(import_decl->import_name()->IsOneByteEqualTo("q")); + CHECK(import_decl->proxy()->raw_name()->IsOneByteEqualTo("z")); + CHECK(import_decl->module_specifier()->IsOneByteEqualTo("m.js")); + import_decl = declarations->at(2)->AsImportDeclaration(); + CHECK(import_decl->import_name()->IsOneByteEqualTo("default")); + CHECK(import_decl->proxy()->raw_name()->IsOneByteEqualTo("n")); + CHECK(import_decl->module_specifier()->IsOneByteEqualTo("n.js")); +} + + TEST(DuplicateProtoError) { const char* context_data[][2] = { {"({", "});"}, @@ -5339,8 +5335,8 @@ TEST(DeclarationsError) { "class C {}", NULL}; - static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, kAllowHarmonyScoping, kAllowStrongMode}; + static const ParserFlag always_flags[] = {kAllowHarmonyClasses, + kAllowStrongMode}; RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags, arraysize(always_flags)); } @@ -5358,11 +5354,11 @@ void TestLanguageMode(const char* source, i::Handle<i::Script> script = factory->NewScript(factory->NewStringFromAsciiChecked(source)); - i::CompilationInfoWithZone info(script); - i::Parser parser(&info, isolate->stack_guard()->real_climit(), - isolate->heap()->HashSeed(), isolate->unicode_cache()); + i::Zone zone; + i::ParseInfo info(&zone, script); + i::Parser parser(&info); parser.set_allow_strong_mode(true); - info.MarkAsGlobal(); + info.set_global(); parser.Parse(&info); CHECK(info.function() != NULL); CHECK_EQ(expected_language_mode, info.function()->language_mode()); @@ -5425,8 +5421,7 @@ TEST(PropertyNameEvalArguments) { NULL}; static const ParserFlag always_flags[] = { - kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, kAllowHarmonyScoping, - kAllowStrongMode}; + kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, kAllowStrongMode}; RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); } @@ -5498,8 +5493,7 @@ TEST(VarForbiddenInStrongMode) { "const x = 0;", NULL}; - static const ParserFlag always_flags[] = {kAllowStrongMode, - kAllowHarmonyScoping}; + static const ParserFlag always_flags[] = {kAllowStrongMode}; RunParserSyncTest(strong_context_data, var_declarations, kError, NULL, 0, always_flags, arraysize(always_flags)); RunParserSyncTest(strong_context_data, let_declarations, kSuccess, NULL, 0, @@ -5539,7 +5533,7 @@ TEST(StrongEmptySubStatements) { NULL}; static const ParserFlag always_flags[] = { - kAllowStrongMode, kAllowHarmonyScoping + kAllowStrongMode, }; RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); @@ -5561,7 +5555,7 @@ TEST(StrongForIn) { NULL}; static const ParserFlag always_flags[] = { - kAllowStrongMode, kAllowHarmonyScoping + kAllowStrongMode, }; RunParserSyncTest(sloppy_context_data, data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); @@ -5570,3 +5564,227 @@ TEST(StrongForIn) { RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags, arraysize(always_flags)); } + + +TEST(StrongSuperCalls) { + const char* sloppy_context_data[][2] = {{"", ""}, {NULL}}; + const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}}; + const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}}; + + const char* data[] = { + "class C extends Object { constructor() {} }", + "class C extends Object { constructor() { (super()); } }", + "class C extends Object { constructor() { (() => super())(); } }", + "class C extends Object { constructor() { { super(); } } }", + "class C extends Object { constructor() { if (1) super(); } }", + "class C extends Object { constructor() { super(), super(); } }", + "class C extends Object { constructor() { super(); super(); } }", + "class C extends Object { constructor() { super(); (super()); } }", + "class C extends Object { constructor() { super(); { super() } } }", + NULL}; + + static const ParserFlag always_flags[] = { + kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals, + kAllowHarmonyArrowFunctions + }; + RunParserSyncTest(sloppy_context_data, data, kError, NULL, 0, always_flags, + arraysize(always_flags)); + RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags, + arraysize(always_flags)); + RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(StrongConstructorReturns) { + const char* sloppy_context_data[][2] = {{"", ""}, {NULL}}; + const char* strict_context_data[][2] = {{"'use strict';", ""}, {NULL}}; + const char* strong_context_data[][2] = {{"'use strong';", ""}, {NULL}}; + + const char* data[] = { + "class C extends Object { constructor() { super(); return {}; } }", + "class C extends Object { constructor() { super(); { return {}; } } }", + "class C extends Object { constructor() { super(); if (1) return {}; } }", + "class C extends Object { constructor() { return; super(); } }", + "class C extends Object { constructor() { { return; } super(); } }", + "class C extends Object { constructor() { if (0) return; super(); } }", + NULL}; + + static const ParserFlag always_flags[] = { + kAllowStrongMode, kAllowHarmonyClasses, kAllowHarmonyObjectLiterals + }; + RunParserSyncTest(sloppy_context_data, data, kError, NULL, 0, always_flags, + arraysize(always_flags)); + RunParserSyncTest(strict_context_data, data, kSuccess, NULL, 0, always_flags, + arraysize(always_flags)); + RunParserSyncTest(strong_context_data, data, kError, NULL, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(ArrowFunctionASIErrors) { + const char* context_data[][2] = {{"'use strict';", ""}, {"", ""}, + {NULL, NULL}}; + + const char* data[] = { + "(a\n=> a)(1)", + "(a/*\n*/=> a)(1)", + "((a)\n=> a)(1)", + "((a)/*\n*/=> a)(1)", + "((a, b)\n=> a + b)(1, 2)", + "((a, b)/*\n*/=> a + b)(1, 2)", + NULL}; + static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions}; + RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(StrongModeFreeVariablesDeclaredByPreviousScript) { + i::FLAG_strong_mode = true; + v8::V8::Initialize(); + v8::HandleScope scope(CcTest::isolate()); + v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate())); + v8::TryCatch try_catch; + + // Introduce a bunch of variables, in all language modes. + const char* script1 = + "var my_var1 = 0; \n" + "function my_func1() { } \n" + "const my_const1 = 0; \n"; + CompileRun(v8_str(script1)); + CHECK(!try_catch.HasCaught()); + + const char* script2 = + "\"use strict\"; \n" + "let my_var2 = 0; \n" + "function my_func2() { } \n" + "const my_const2 = 0 \n"; + CompileRun(v8_str(script2)); + CHECK(!try_catch.HasCaught()); + + const char* script3 = + "\"use strong\"; \n" + "let my_var3 = 0; \n" + "function my_func3() { } \n" + "const my_const3 = 0; \n"; + CompileRun(v8_str(script3)); + CHECK(!try_catch.HasCaught()); + + // Sloppy eval introduces variables in the surrounding scope. + const char* script4 = + "eval('var my_var4 = 0;') \n" + "eval('function my_func4() { }') \n" + "eval('const my_const4 = 0;') \n"; + CompileRun(v8_str(script4)); + CHECK(!try_catch.HasCaught()); + + // Test that referencing these variables work. + const char* script5 = + "\"use strong\"; \n" + "my_var1; \n" + "my_func1; \n" + "my_const1; \n" + "my_var2; \n" + "my_func2; \n" + "my_const2; \n" + "my_var3; \n" + "my_func3; \n" + "my_const3; \n" + "my_var4; \n" + "my_func4; \n" + "my_const4; \n"; + CompileRun(v8_str(script5)); + CHECK(!try_catch.HasCaught()); +} + + +TEST(StrongModeFreeVariablesDeclaredByLanguage) { + i::FLAG_strong_mode = true; + v8::V8::Initialize(); + v8::HandleScope scope(CcTest::isolate()); + v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate())); + v8::TryCatch try_catch; + + const char* script1 = + "\"use strong\"; \n" + "Math; \n" + "RegExp; \n"; + CompileRun(v8_str(script1)); + CHECK(!try_catch.HasCaught()); +} + + +TEST(StrongModeFreeVariablesDeclaredInGlobalPrototype) { + i::FLAG_strong_mode = true; + v8::V8::Initialize(); + v8::HandleScope scope(CcTest::isolate()); + v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate())); + v8::TryCatch try_catch; + + const char* script1 = "this.__proto__.my_var = 0;\n"; + CompileRun(v8_str(script1)); + CHECK(!try_catch.HasCaught()); + + const char* script2 = + "\"use strong\"; \n" + "my_var; \n"; + CompileRun(v8_str(script2)); + CHECK(!try_catch.HasCaught()); +} + + +TEST(StrongModeFreeVariablesNotDeclared) { + i::FLAG_strong_mode = true; + v8::V8::Initialize(); + v8::HandleScope scope(CcTest::isolate()); + v8::Context::Scope context_scope(v8::Context::New(CcTest::isolate())); + v8::TryCatch try_catch; + + // Test that referencing unintroduced variables in sloppy mode is ok. + const char* script1 = + "if (false) { \n" + " not_there1; \n" + "} \n"; + CompileRun(v8_str(script1)); + CHECK(!try_catch.HasCaught()); + + // But not in strong mode. + { + const char* script2 = + "\"use strong\"; \n" + "if (false) { \n" + " not_there2; \n" + "} \n"; + v8::TryCatch try_catch2; + v8::Script::Compile(v8_str(script2)); + CHECK(try_catch2.HasCaught()); + v8::String::Utf8Value exception(try_catch2.Exception()); + CHECK_EQ(0, + strcmp( + "ReferenceError: In strong mode, using an undeclared global " + "variable 'not_there2' is not allowed", + *exception)); + } + + // Check that the variable reference is detected inside a strong function too, + // even if the script scope is not strong. + { + const char* script3 = + "(function not_lazy() { \n" + " \"use strong\"; \n" + " if (false) { \n" + " not_there3; \n" + " } \n" + "})(); \n"; + v8::TryCatch try_catch2; + v8::Script::Compile(v8_str(script3)); + CHECK(try_catch2.HasCaught()); + v8::String::Utf8Value exception(try_catch2.Exception()); + CHECK_EQ(0, + strcmp( + "ReferenceError: In strong mode, using an undeclared global " + "variable 'not_there3' is not allowed", + *exception)); + } +} diff --git a/deps/v8/test/cctest/test-serialize.cc b/deps/v8/test/cctest/test-serialize.cc index 55eac60f37..80aa77bacf 100644 --- a/deps/v8/test/cctest/test-serialize.cc +++ b/deps/v8/test/cctest/test-serialize.cc @@ -35,83 +35,41 @@ #include "src/compilation-cache.h" #include "src/debug.h" #include "src/heap/spaces.h" -#include "src/natives.h" #include "src/objects.h" +#include "src/parser.h" #include "src/runtime/runtime.h" #include "src/scopeinfo.h" -#include "src/serialize.h" -#include "src/snapshot.h" +#include "src/snapshot/natives.h" +#include "src/snapshot/serialize.h" +#include "src/snapshot/snapshot.h" #include "test/cctest/cctest.h" using namespace v8::internal; -template <class T> -static Address AddressOf(T id) { - return ExternalReference(id, CcTest::i_isolate()).address(); +bool DefaultSnapshotAvailable() { + return i::Snapshot::DefaultSnapshotBlob() != NULL; } -template <class T> -static uint32_t Encode(const ExternalReferenceEncoder& encoder, T id) { - return encoder.Encode(AddressOf(id)); +void DisableTurbofan() { + const char* flag = "--turbo-filter=\"\""; + FlagList::SetFlagsFromString(flag, StrLength(flag)); } -static uint32_t make_code(TypeCode type, int id) { - return static_cast<uint32_t>(type) << kReferenceTypeShift | id; -} - - -TEST(ExternalReferenceEncoder) { - Isolate* isolate = CcTest::i_isolate(); - v8::V8::Initialize(); - - ExternalReferenceEncoder encoder(isolate); - CHECK_EQ(make_code(BUILTIN, Builtins::kArrayCode), - Encode(encoder, Builtins::kArrayCode)); - CHECK_EQ(make_code(v8::internal::RUNTIME_FUNCTION, Runtime::kAbort), - Encode(encoder, Runtime::kAbort)); - ExternalReference stack_limit_address = - ExternalReference::address_of_stack_limit(isolate); - CHECK_EQ(make_code(UNCLASSIFIED, 2), - encoder.Encode(stack_limit_address.address())); - ExternalReference real_stack_limit_address = - ExternalReference::address_of_real_stack_limit(isolate); - CHECK_EQ(make_code(UNCLASSIFIED, 3), - encoder.Encode(real_stack_limit_address.address())); - CHECK_EQ(make_code(UNCLASSIFIED, 8), - encoder.Encode(ExternalReference::debug_break(isolate).address())); - CHECK_EQ( - make_code(UNCLASSIFIED, 4), - encoder.Encode(ExternalReference::new_space_start(isolate).address())); - CHECK_EQ( - make_code(UNCLASSIFIED, 1), - encoder.Encode(ExternalReference::roots_array_start(isolate).address())); - CHECK_EQ(make_code(UNCLASSIFIED, 33), - encoder.Encode(ExternalReference::cpu_features().address())); -} - - -TEST(ExternalReferenceDecoder) { - Isolate* isolate = CcTest::i_isolate(); - v8::V8::Initialize(); - - ExternalReferenceDecoder decoder(isolate); - CHECK_EQ(AddressOf(Builtins::kArrayCode), - decoder.Decode(make_code(BUILTIN, Builtins::kArrayCode))); - CHECK_EQ(AddressOf(Runtime::kAbort), - decoder.Decode(make_code(v8::internal::RUNTIME_FUNCTION, - Runtime::kAbort))); - CHECK_EQ(ExternalReference::address_of_stack_limit(isolate).address(), - decoder.Decode(make_code(UNCLASSIFIED, 2))); - CHECK_EQ(ExternalReference::address_of_real_stack_limit(isolate).address(), - decoder.Decode(make_code(UNCLASSIFIED, 3))); - CHECK_EQ(ExternalReference::debug_break(isolate).address(), - decoder.Decode(make_code(UNCLASSIFIED, 8))); - CHECK_EQ(ExternalReference::new_space_start(isolate).address(), - decoder.Decode(make_code(UNCLASSIFIED, 4))); -} +// TestIsolate is used for testing isolate serialization. +class TestIsolate : public Isolate { + public: + static v8::Isolate* NewInitialized(bool enable_serializer) { + i::Isolate* isolate = new TestIsolate(enable_serializer); + v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); + v8::Isolate::Scope isolate_scope(v8_isolate); + isolate->Init(NULL); + return v8_isolate; + } + explicit TestIsolate(bool enable_serializer) : Isolate(enable_serializer) {} +}; void WritePayload(const Vector<const byte>& payload, const char* file_name) { @@ -175,24 +133,20 @@ Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head, // Test that the whole heap can be serialized. UNINITIALIZED_TEST(Serialize) { - if (!Snapshot::HaveASnapshotToStartFrom()) { - v8::Isolate::CreateParams params; - params.enable_serializer = true; - v8::Isolate* isolate = v8::Isolate::New(params); - Serialize(isolate); - } + DisableTurbofan(); + if (DefaultSnapshotAvailable()) return; + v8::Isolate* isolate = TestIsolate::NewInitialized(true); + Serialize(isolate); } // Test that heap serialization is non-destructive. UNINITIALIZED_TEST(SerializeTwice) { - if (!Snapshot::HaveASnapshotToStartFrom()) { - v8::Isolate::CreateParams params; - params.enable_serializer = true; - v8::Isolate* isolate = v8::Isolate::New(params); - Serialize(isolate); - Serialize(isolate); - } + DisableTurbofan(); + if (DefaultSnapshotAvailable()) return; + v8::Isolate* isolate = TestIsolate::NewInitialized(true); + Serialize(isolate); + Serialize(isolate); } @@ -207,7 +161,7 @@ v8::Isolate* InitializeFromFile(const char* snapshot_file) { { SnapshotData snapshot_data(Vector<const byte>(str, len)); Deserializer deserializer(&snapshot_data); - Isolate* isolate = Isolate::NewForTesting(); + Isolate* isolate = new TestIsolate(false); v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); v8::Isolate::Scope isolate_scope(v8_isolate); isolate->Init(&deserializer); @@ -241,466 +195,538 @@ UNINITIALIZED_DEPENDENT_TEST(Deserialize, Serialize) { // The serialize-deserialize tests only work if the VM is built without // serialization. That doesn't matter. We don't need to be able to // serialize a snapshot in a VM that is booted from a snapshot. - if (!Snapshot::HaveASnapshotToStartFrom()) { - v8::Isolate* isolate = Deserialize(); - { - v8::HandleScope handle_scope(isolate); - v8::Isolate::Scope isolate_scope(isolate); + DisableTurbofan(); + if (DefaultSnapshotAvailable()) return; + v8::Isolate* isolate = Deserialize(); + { + v8::HandleScope handle_scope(isolate); + v8::Isolate::Scope isolate_scope(isolate); - v8::Local<v8::Context> env = v8::Context::New(isolate); - env->Enter(); + v8::Local<v8::Context> env = v8::Context::New(isolate); + env->Enter(); - SanityCheck(isolate); - } - isolate->Dispose(); + SanityCheck(isolate); } + isolate->Dispose(); } UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerialization, SerializeTwice) { - if (!Snapshot::HaveASnapshotToStartFrom()) { - v8::Isolate* isolate = Deserialize(); - { - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); + DisableTurbofan(); + if (DefaultSnapshotAvailable()) return; + v8::Isolate* isolate = Deserialize(); + { + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); - v8::Local<v8::Context> env = v8::Context::New(isolate); - env->Enter(); + v8::Local<v8::Context> env = v8::Context::New(isolate); + env->Enter(); - SanityCheck(isolate); - } - isolate->Dispose(); + SanityCheck(isolate); } + isolate->Dispose(); } UNINITIALIZED_DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) { - if (!Snapshot::HaveASnapshotToStartFrom()) { - v8::Isolate* isolate = Deserialize(); - { - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); + DisableTurbofan(); + if (DefaultSnapshotAvailable()) return; + v8::Isolate* isolate = Deserialize(); + { + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); - v8::Local<v8::Context> env = v8::Context::New(isolate); - env->Enter(); + v8::Local<v8::Context> env = v8::Context::New(isolate); + env->Enter(); - const char* c_source = "\"1234\".length"; - v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source); - v8::Local<v8::Script> script = v8::Script::Compile(source); - CHECK_EQ(4, script->Run()->Int32Value()); - } - isolate->Dispose(); + const char* c_source = "\"1234\".length"; + v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source); + v8::Local<v8::Script> script = v8::Script::Compile(source); + CHECK_EQ(4, script->Run()->Int32Value()); } + isolate->Dispose(); } UNINITIALIZED_DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2, SerializeTwice) { - if (!Snapshot::HaveASnapshotToStartFrom()) { - v8::Isolate* isolate = Deserialize(); - { - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); + DisableTurbofan(); + if (DefaultSnapshotAvailable()) return; + v8::Isolate* isolate = Deserialize(); + { + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); - v8::Local<v8::Context> env = v8::Context::New(isolate); - env->Enter(); + v8::Local<v8::Context> env = v8::Context::New(isolate); + env->Enter(); - const char* c_source = "\"1234\".length"; - v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source); - v8::Local<v8::Script> script = v8::Script::Compile(source); - CHECK_EQ(4, script->Run()->Int32Value()); - } - isolate->Dispose(); + const char* c_source = "\"1234\".length"; + v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, c_source); + v8::Local<v8::Script> script = v8::Script::Compile(source); + CHECK_EQ(4, script->Run()->Int32Value()); } + isolate->Dispose(); } UNINITIALIZED_TEST(PartialSerialization) { - if (!Snapshot::HaveASnapshotToStartFrom()) { - v8::Isolate::CreateParams params; - params.enable_serializer = true; - v8::Isolate* v8_isolate = v8::Isolate::New(params); - Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); - v8_isolate->Enter(); - { - Heap* heap = isolate->heap(); + DisableTurbofan(); + if (DefaultSnapshotAvailable()) return; + v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); + Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); + v8_isolate->Enter(); + { + Heap* heap = isolate->heap(); - v8::Persistent<v8::Context> env; - { - HandleScope scope(isolate); - env.Reset(v8_isolate, v8::Context::New(v8_isolate)); - } - DCHECK(!env.IsEmpty()); - { - v8::HandleScope handle_scope(v8_isolate); - v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); - } - // Make sure all builtin scripts are cached. - { - HandleScope scope(isolate); - for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { - isolate->bootstrapper()->NativesSourceLookup(i); - } - } - heap->CollectAllGarbage(Heap::kNoGCFlags); - heap->CollectAllGarbage(Heap::kNoGCFlags); - - Object* raw_foo; - { - v8::HandleScope handle_scope(v8_isolate); - v8::Local<v8::String> foo = v8::String::NewFromUtf8(v8_isolate, "foo"); - DCHECK(!foo.IsEmpty()); - raw_foo = *(v8::Utils::OpenHandle(*foo)); + v8::Persistent<v8::Context> env; + { + HandleScope scope(isolate); + env.Reset(v8_isolate, v8::Context::New(v8_isolate)); + } + DCHECK(!env.IsEmpty()); + { + v8::HandleScope handle_scope(v8_isolate); + v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); + } + // Make sure all builtin scripts are cached. + { + HandleScope scope(isolate); + for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { + isolate->bootstrapper()->NativesSourceLookup(i); } + } + heap->CollectAllGarbage(Heap::kNoGCFlags); + heap->CollectAllGarbage(Heap::kNoGCFlags); - int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; - Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + Object* raw_foo; + { + v8::HandleScope handle_scope(v8_isolate); + v8::Local<v8::String> foo = v8::String::NewFromUtf8(v8_isolate, "foo"); + DCHECK(!foo.IsEmpty()); + raw_foo = *(v8::Utils::OpenHandle(*foo)); + } - { - v8::HandleScope handle_scope(v8_isolate); - v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); - } - env.Reset(); + int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; + Vector<char> startup_name = Vector<char>::New(file_name_length + 1); + SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); - SnapshotByteSink startup_sink; - StartupSerializer startup_serializer(isolate, &startup_sink); - startup_serializer.SerializeStrongReferences(); + { + v8::HandleScope handle_scope(v8_isolate); + v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); + } + env.Reset(); - SnapshotByteSink partial_sink; - PartialSerializer partial_serializer(isolate, &startup_serializer, - &partial_sink); - partial_serializer.Serialize(&raw_foo); + SnapshotByteSink startup_sink; + StartupSerializer startup_serializer(isolate, &startup_sink); + startup_serializer.SerializeStrongReferences(); - startup_serializer.SerializeWeakReferences(); + SnapshotByteSink partial_sink; + PartialSerializer partial_serializer(isolate, &startup_serializer, + &partial_sink); + partial_serializer.Serialize(&raw_foo); - SnapshotData startup_snapshot(startup_serializer); - SnapshotData partial_snapshot(partial_serializer); + startup_serializer.SerializeWeakReferences(); - WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file); - WritePayload(startup_snapshot.RawData(), startup_name.start()); + SnapshotData startup_snapshot(startup_serializer); + SnapshotData partial_snapshot(partial_serializer); - startup_name.Dispose(); - } - v8_isolate->Exit(); - v8_isolate->Dispose(); + WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file); + WritePayload(startup_snapshot.RawData(), startup_name.start()); + + startup_name.Dispose(); } + v8_isolate->Exit(); + v8_isolate->Dispose(); } UNINITIALIZED_DEPENDENT_TEST(PartialDeserialization, PartialSerialization) { - if (!Snapshot::HaveASnapshotToStartFrom()) { - int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; - Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + DisableTurbofan(); + if (DefaultSnapshotAvailable()) return; + int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; + Vector<char> startup_name = Vector<char>::New(file_name_length + 1); + SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + + v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start()); + CHECK(v8_isolate); + startup_name.Dispose(); + { + v8::Isolate::Scope isolate_scope(v8_isolate); - v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start()); - CHECK(v8_isolate); - startup_name.Dispose(); + const char* file_name = FLAG_testing_serialization_file; + + int snapshot_size = 0; + byte* snapshot = ReadBytes(file_name, &snapshot_size); + + Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); + HandleScope handle_scope(isolate); + Handle<Object> root; + Handle<FixedArray> outdated_contexts; + // Intentionally empty handle. The deserializer should not come across + // any references to the global proxy in this test. + Handle<JSGlobalProxy> global_proxy = Handle<JSGlobalProxy>::null(); { - v8::Isolate::Scope isolate_scope(v8_isolate); - - const char* file_name = FLAG_testing_serialization_file; - - int snapshot_size = 0; - byte* snapshot = ReadBytes(file_name, &snapshot_size); - - Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); - HandleScope handle_scope(isolate); - Handle<Object> root; - Handle<FixedArray> outdated_contexts; - // Intentionally empty handle. The deserializer should not come across - // any references to the global proxy in this test. - Handle<JSGlobalProxy> global_proxy = Handle<JSGlobalProxy>::null(); - { - SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); - Deserializer deserializer(&snapshot_data); - root = deserializer.DeserializePartial(isolate, global_proxy, - &outdated_contexts) - .ToHandleChecked(); - CHECK_EQ(0, outdated_contexts->length()); - CHECK(root->IsString()); - } + SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); + Deserializer deserializer(&snapshot_data); + root = + deserializer.DeserializePartial(isolate, global_proxy, + &outdated_contexts).ToHandleChecked(); + CHECK_EQ(0, outdated_contexts->length()); + CHECK(root->IsString()); + } - Handle<Object> root2; - { - SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); - Deserializer deserializer(&snapshot_data); - root2 = deserializer.DeserializePartial(isolate, global_proxy, - &outdated_contexts) - .ToHandleChecked(); - CHECK(root2->IsString()); - CHECK(root.is_identical_to(root2)); - } + Handle<Object> root2; + { + SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); + Deserializer deserializer(&snapshot_data); + root2 = + deserializer.DeserializePartial(isolate, global_proxy, + &outdated_contexts).ToHandleChecked(); + CHECK(root2->IsString()); + CHECK(root.is_identical_to(root2)); } - v8_isolate->Dispose(); + + DeleteArray(snapshot); } + v8_isolate->Dispose(); } UNINITIALIZED_TEST(ContextSerialization) { - if (!Snapshot::HaveASnapshotToStartFrom()) { - v8::Isolate::CreateParams params; - params.enable_serializer = true; - v8::Isolate* v8_isolate = v8::Isolate::New(params); - Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); - Heap* heap = isolate->heap(); - { - v8::Isolate::Scope isolate_scope(v8_isolate); + DisableTurbofan(); + if (DefaultSnapshotAvailable()) return; + v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); + Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); + Heap* heap = isolate->heap(); + { + v8::Isolate::Scope isolate_scope(v8_isolate); - v8::Persistent<v8::Context> env; - { - HandleScope scope(isolate); - env.Reset(v8_isolate, v8::Context::New(v8_isolate)); - } - DCHECK(!env.IsEmpty()); - { - v8::HandleScope handle_scope(v8_isolate); - v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); - } - // Make sure all builtin scripts are cached. - { - HandleScope scope(isolate); - for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { - isolate->bootstrapper()->NativesSourceLookup(i); - } + v8::Persistent<v8::Context> env; + { + HandleScope scope(isolate); + env.Reset(v8_isolate, v8::Context::New(v8_isolate)); + } + DCHECK(!env.IsEmpty()); + { + v8::HandleScope handle_scope(v8_isolate); + v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); + } + // Make sure all builtin scripts are cached. + { + HandleScope scope(isolate); + for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { + isolate->bootstrapper()->NativesSourceLookup(i); } - // If we don't do this then we end up with a stray root pointing at the - // context even after we have disposed of env. - heap->CollectAllGarbage(Heap::kNoGCFlags); + } + // If we don't do this then we end up with a stray root pointing at the + // context even after we have disposed of env. + heap->CollectAllGarbage(Heap::kNoGCFlags); - int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; - Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; + Vector<char> startup_name = Vector<char>::New(file_name_length + 1); + SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); - { - v8::HandleScope handle_scope(v8_isolate); - v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); - } + { + v8::HandleScope handle_scope(v8_isolate); + v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); + } - i::Object* raw_context = *v8::Utils::OpenPersistent(env); + i::Object* raw_context = *v8::Utils::OpenPersistent(env); - env.Reset(); + env.Reset(); - SnapshotByteSink startup_sink; - StartupSerializer startup_serializer(isolate, &startup_sink); - startup_serializer.SerializeStrongReferences(); + SnapshotByteSink startup_sink; + StartupSerializer startup_serializer(isolate, &startup_sink); + startup_serializer.SerializeStrongReferences(); - SnapshotByteSink partial_sink; - PartialSerializer partial_serializer(isolate, &startup_serializer, - &partial_sink); - partial_serializer.Serialize(&raw_context); - startup_serializer.SerializeWeakReferences(); + SnapshotByteSink partial_sink; + PartialSerializer partial_serializer(isolate, &startup_serializer, + &partial_sink); + partial_serializer.Serialize(&raw_context); + startup_serializer.SerializeWeakReferences(); - SnapshotData startup_snapshot(startup_serializer); - SnapshotData partial_snapshot(partial_serializer); + SnapshotData startup_snapshot(startup_serializer); + SnapshotData partial_snapshot(partial_serializer); - WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file); - WritePayload(startup_snapshot.RawData(), startup_name.start()); + WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file); + WritePayload(startup_snapshot.RawData(), startup_name.start()); - startup_name.Dispose(); - } - v8_isolate->Dispose(); + startup_name.Dispose(); } + v8_isolate->Dispose(); } UNINITIALIZED_DEPENDENT_TEST(ContextDeserialization, ContextSerialization) { - if (!Snapshot::HaveASnapshotToStartFrom()) { - int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; - Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + DisableTurbofan(); + if (DefaultSnapshotAvailable()) return; + int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; + Vector<char> startup_name = Vector<char>::New(file_name_length + 1); + SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + + v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start()); + CHECK(v8_isolate); + startup_name.Dispose(); + { + v8::Isolate::Scope isolate_scope(v8_isolate); - v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start()); - CHECK(v8_isolate); - startup_name.Dispose(); + const char* file_name = FLAG_testing_serialization_file; + + int snapshot_size = 0; + byte* snapshot = ReadBytes(file_name, &snapshot_size); + + Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); + HandleScope handle_scope(isolate); + Handle<Object> root; + Handle<FixedArray> outdated_contexts; + Handle<JSGlobalProxy> global_proxy = + isolate->factory()->NewUninitializedJSGlobalProxy(); { - v8::Isolate::Scope isolate_scope(v8_isolate); - - const char* file_name = FLAG_testing_serialization_file; - - int snapshot_size = 0; - byte* snapshot = ReadBytes(file_name, &snapshot_size); - - Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); - HandleScope handle_scope(isolate); - Handle<Object> root; - Handle<FixedArray> outdated_contexts; - Handle<JSGlobalProxy> global_proxy = - isolate->factory()->NewUninitializedJSGlobalProxy(); - { - SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); - Deserializer deserializer(&snapshot_data); - root = deserializer.DeserializePartial(isolate, global_proxy, - &outdated_contexts) - .ToHandleChecked(); - CHECK(root->IsContext()); - CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy); - CHECK_EQ(1, outdated_contexts->length()); - } + SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); + Deserializer deserializer(&snapshot_data); + root = + deserializer.DeserializePartial(isolate, global_proxy, + &outdated_contexts).ToHandleChecked(); + CHECK(root->IsContext()); + CHECK(Handle<Context>::cast(root)->global_proxy() == *global_proxy); + CHECK_EQ(1, outdated_contexts->length()); + } - Handle<Object> root2; - { - SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); - Deserializer deserializer(&snapshot_data); - root2 = deserializer.DeserializePartial(isolate, global_proxy, - &outdated_contexts) - .ToHandleChecked(); - CHECK(root2->IsContext()); - CHECK(!root.is_identical_to(root2)); - } + Handle<Object> root2; + { + SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); + Deserializer deserializer(&snapshot_data); + root2 = + deserializer.DeserializePartial(isolate, global_proxy, + &outdated_contexts).ToHandleChecked(); + CHECK(root2->IsContext()); + CHECK(!root.is_identical_to(root2)); } - v8_isolate->Dispose(); + DeleteArray(snapshot); } + v8_isolate->Dispose(); } UNINITIALIZED_TEST(CustomContextSerialization) { - if (!Snapshot::HaveASnapshotToStartFrom()) { - v8::Isolate::CreateParams params; - params.enable_serializer = true; - v8::Isolate* v8_isolate = v8::Isolate::New(params); - Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); - { - v8::Isolate::Scope isolate_scope(v8_isolate); + DisableTurbofan(); + if (DefaultSnapshotAvailable()) return; + v8::Isolate* v8_isolate = TestIsolate::NewInitialized(true); + Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); + { + v8::Isolate::Scope isolate_scope(v8_isolate); - v8::Persistent<v8::Context> env; - { - HandleScope scope(isolate); - env.Reset(v8_isolate, v8::Context::New(v8_isolate)); - } - DCHECK(!env.IsEmpty()); - { - v8::HandleScope handle_scope(v8_isolate); - v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); - // After execution, e's function context refers to the global object. - CompileRun( - "var e;" - "(function() {" - " e = function(s) { return eval (s); }" - "})();" - "var o = this;" - "var r = Math.random() + Math.cos(0);" - "var f = (function(a, b) { return a + b; }).bind(1, 2, 3);" - "var s = parseInt('12345');"); - - Vector<const uint8_t> source = ConstructSource( - STATIC_CHAR_VECTOR("function g() { return [,"), - STATIC_CHAR_VECTOR("1,"), - STATIC_CHAR_VECTOR("];} a = g(); b = g(); b.push(1);"), 100000); - v8::Handle<v8::String> source_str = v8::String::NewFromOneByte( - v8_isolate, source.start(), v8::String::kNormalString, - source.length()); - CompileRun(source_str); - source.Dispose(); - } - // Make sure all builtin scripts are cached. - { - HandleScope scope(isolate); - for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { - isolate->bootstrapper()->NativesSourceLookup(i); - } + v8::Persistent<v8::Context> env; + { + HandleScope scope(isolate); + env.Reset(v8_isolate, v8::Context::New(v8_isolate)); + } + DCHECK(!env.IsEmpty()); + { + v8::HandleScope handle_scope(v8_isolate); + v8::Local<v8::Context>::New(v8_isolate, env)->Enter(); + // After execution, e's function context refers to the global object. + CompileRun( + "var e;" + "(function() {" + " e = function(s) { return eval (s); }" + "})();" + "var o = this;" + "var r = Math.random() + Math.cos(0);" + "var f = (function(a, b) { return a + b; }).bind(1, 2, 3);" + "var s = parseInt('12345');"); + + Vector<const uint8_t> source = ConstructSource( + STATIC_CHAR_VECTOR("function g() { return [,"), + STATIC_CHAR_VECTOR("1,"), + STATIC_CHAR_VECTOR("];} a = g(); b = g(); b.push(1);"), 100000); + v8::Handle<v8::String> source_str = v8::String::NewFromOneByte( + v8_isolate, source.start(), v8::String::kNormalString, + source.length()); + CompileRun(source_str); + source.Dispose(); + } + // Make sure all builtin scripts are cached. + { + HandleScope scope(isolate); + for (int i = 0; i < Natives::GetBuiltinsCount(); i++) { + isolate->bootstrapper()->NativesSourceLookup(i); } - // If we don't do this then we end up with a stray root pointing at the - // context even after we have disposed of env. - isolate->heap()->CollectAllAvailableGarbage("snapshotting"); + } + // If we don't do this then we end up with a stray root pointing at the + // context even after we have disposed of env. + isolate->heap()->CollectAllAvailableGarbage("snapshotting"); - int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; - Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; + Vector<char> startup_name = Vector<char>::New(file_name_length + 1); + SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); - { - v8::HandleScope handle_scope(v8_isolate); - v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); - } + { + v8::HandleScope handle_scope(v8_isolate); + v8::Local<v8::Context>::New(v8_isolate, env)->Exit(); + } - i::Object* raw_context = *v8::Utils::OpenPersistent(env); + i::Object* raw_context = *v8::Utils::OpenPersistent(env); - env.Reset(); + env.Reset(); - SnapshotByteSink startup_sink; - StartupSerializer startup_serializer(isolate, &startup_sink); - startup_serializer.SerializeStrongReferences(); + SnapshotByteSink startup_sink; + StartupSerializer startup_serializer(isolate, &startup_sink); + startup_serializer.SerializeStrongReferences(); - SnapshotByteSink partial_sink; - PartialSerializer partial_serializer(isolate, &startup_serializer, - &partial_sink); - partial_serializer.Serialize(&raw_context); - startup_serializer.SerializeWeakReferences(); + SnapshotByteSink partial_sink; + PartialSerializer partial_serializer(isolate, &startup_serializer, + &partial_sink); + partial_serializer.Serialize(&raw_context); + startup_serializer.SerializeWeakReferences(); - SnapshotData startup_snapshot(startup_serializer); - SnapshotData partial_snapshot(partial_serializer); + SnapshotData startup_snapshot(startup_serializer); + SnapshotData partial_snapshot(partial_serializer); - WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file); - WritePayload(startup_snapshot.RawData(), startup_name.start()); + WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file); + WritePayload(startup_snapshot.RawData(), startup_name.start()); - startup_name.Dispose(); - } - v8_isolate->Dispose(); + startup_name.Dispose(); } + v8_isolate->Dispose(); } UNINITIALIZED_DEPENDENT_TEST(CustomContextDeserialization, CustomContextSerialization) { + DisableTurbofan(); FLAG_crankshaft = false; - if (!Snapshot::HaveASnapshotToStartFrom()) { - int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; - Vector<char> startup_name = Vector<char>::New(file_name_length + 1); - SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + if (DefaultSnapshotAvailable()) return; + int file_name_length = StrLength(FLAG_testing_serialization_file) + 10; + Vector<char> startup_name = Vector<char>::New(file_name_length + 1); + SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); + + v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start()); + CHECK(v8_isolate); + startup_name.Dispose(); + { + v8::Isolate::Scope isolate_scope(v8_isolate); - v8::Isolate* v8_isolate = InitializeFromFile(startup_name.start()); - CHECK(v8_isolate); - startup_name.Dispose(); + const char* file_name = FLAG_testing_serialization_file; + + int snapshot_size = 0; + byte* snapshot = ReadBytes(file_name, &snapshot_size); + + Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); + HandleScope handle_scope(isolate); + Handle<Object> root; + Handle<FixedArray> outdated_contexts; + Handle<JSGlobalProxy> global_proxy = + isolate->factory()->NewUninitializedJSGlobalProxy(); { - v8::Isolate::Scope isolate_scope(v8_isolate); - - const char* file_name = FLAG_testing_serialization_file; - - int snapshot_size = 0; - byte* snapshot = ReadBytes(file_name, &snapshot_size); - - Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); - HandleScope handle_scope(isolate); - Handle<Object> root; - Handle<FixedArray> outdated_contexts; - Handle<JSGlobalProxy> global_proxy = - isolate->factory()->NewUninitializedJSGlobalProxy(); - { - SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); - Deserializer deserializer(&snapshot_data); - root = deserializer.DeserializePartial(isolate, global_proxy, - &outdated_contexts) - .ToHandleChecked(); - CHECK_EQ(2, outdated_contexts->length()); - CHECK(root->IsContext()); - Handle<Context> context = Handle<Context>::cast(root); - CHECK(context->global_proxy() == *global_proxy); - Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o"); - Handle<JSObject> global_object(context->global_object(), isolate); - Handle<Object> property = JSObject::GetDataProperty(global_object, o); - CHECK(property.is_identical_to(global_proxy)); - - v8::Handle<v8::Context> v8_context = v8::Utils::ToLocal(context); - v8::Context::Scope context_scope(v8_context); - double r = CompileRun("r")->ToNumber(v8_isolate)->Value(); - CHECK(r >= 1 && r <= 2); - int f = CompileRun("f()")->ToNumber(v8_isolate)->Int32Value(); - CHECK_EQ(5, f); - f = CompileRun("e('f()')")->ToNumber(v8_isolate)->Int32Value(); - CHECK_EQ(5, f); - v8::Handle<v8::String> s = CompileRun("s")->ToString(v8_isolate); - CHECK(s->Equals(v8_str("12345"))); - int a = CompileRun("a.length")->ToNumber(v8_isolate)->Int32Value(); - CHECK_EQ(100001, a); - int b = CompileRun("b.length")->ToNumber(v8_isolate)->Int32Value(); - CHECK_EQ(100002, b); - } + SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size)); + Deserializer deserializer(&snapshot_data); + root = + deserializer.DeserializePartial(isolate, global_proxy, + &outdated_contexts).ToHandleChecked(); + CHECK_EQ(2, outdated_contexts->length()); + CHECK(root->IsContext()); + Handle<Context> context = Handle<Context>::cast(root); + CHECK(context->global_proxy() == *global_proxy); + Handle<String> o = isolate->factory()->NewStringFromAsciiChecked("o"); + Handle<JSObject> global_object(context->global_object(), isolate); + Handle<Object> property = JSObject::GetDataProperty(global_object, o); + CHECK(property.is_identical_to(global_proxy)); + + v8::Handle<v8::Context> v8_context = v8::Utils::ToLocal(context); + v8::Context::Scope context_scope(v8_context); + double r = CompileRun("r")->ToNumber(v8_isolate)->Value(); + CHECK(r >= 1 && r <= 2); + int f = CompileRun("f()")->ToNumber(v8_isolate)->Int32Value(); + CHECK_EQ(5, f); + f = CompileRun("e('f()')")->ToNumber(v8_isolate)->Int32Value(); + CHECK_EQ(5, f); + v8::Handle<v8::String> s = CompileRun("s")->ToString(v8_isolate); + CHECK(s->Equals(v8_str("12345"))); + int a = CompileRun("a.length")->ToNumber(v8_isolate)->Int32Value(); + CHECK_EQ(100001, a); + int b = CompileRun("b.length")->ToNumber(v8_isolate)->Int32Value(); + CHECK_EQ(100002, b); } - v8_isolate->Dispose(); + DeleteArray(snapshot); + } + v8_isolate->Dispose(); +} + + +TEST(PerIsolateSnapshotBlobs) { + DisableTurbofan(); + const char* source1 = "function f() { return 42; }"; + const char* source2 = + "function f() { return g() * 2; }" + "function g() { return 43; }" + "/./.test('a')"; + + v8::StartupData data1 = v8::V8::CreateSnapshotDataBlob(source1); + v8::StartupData data2 = v8::V8::CreateSnapshotDataBlob(source2); + + v8::Isolate::CreateParams params1; + params1.snapshot_blob = &data1; + v8::Isolate* isolate1 = v8::Isolate::New(params1); + { + v8::Isolate::Scope i_scope(isolate1); + v8::HandleScope h_scope(isolate1); + v8::Local<v8::Context> context = v8::Context::New(isolate1); + delete[] data1.data; // We can dispose of the snapshot blob now. + v8::Context::Scope c_scope(context); + CHECK_EQ(42, CompileRun("f()")->ToInt32(isolate1)->Int32Value()); + CHECK(CompileRun("this.g")->IsUndefined()); + } + isolate1->Dispose(); + + v8::Isolate::CreateParams params2; + params2.snapshot_blob = &data2; + v8::Isolate* isolate2 = v8::Isolate::New(params2); + { + v8::Isolate::Scope i_scope(isolate2); + v8::HandleScope h_scope(isolate2); + v8::Local<v8::Context> context = v8::Context::New(isolate2); + delete[] data2.data; // We can dispose of the snapshot blob now. + v8::Context::Scope c_scope(context); + CHECK_EQ(86, CompileRun("f()")->ToInt32(isolate2)->Int32Value()); + CHECK_EQ(43, CompileRun("g()")->ToInt32(isolate2)->Int32Value()); + } + isolate2->Dispose(); +} + + +TEST(PerIsolateSnapshotBlobsWithLocker) { + DisableTurbofan(); + v8::Isolate* isolate0 = v8::Isolate::New(); + { + v8::Locker locker(isolate0); + v8::Isolate::Scope i_scope(isolate0); + v8::HandleScope h_scope(isolate0); + v8::Local<v8::Context> context = v8::Context::New(isolate0); + v8::Context::Scope c_scope(context); + CHECK_EQ(1, CompileRun("Math.cos(0)")->ToInt32(isolate0)->Int32Value()); } + isolate0->Dispose(); + + const char* source1 = "function f() { return 42; }"; + + v8::StartupData data1 = v8::V8::CreateSnapshotDataBlob(source1); + + v8::Isolate::CreateParams params1; + params1.snapshot_blob = &data1; + v8::Isolate* isolate1 = v8::Isolate::New(params1); + { + v8::Locker locker(isolate1); + v8::Isolate::Scope i_scope(isolate1); + v8::HandleScope h_scope(isolate1); + v8::Local<v8::Context> context = v8::Context::New(isolate1); + delete[] data1.data; // We can dispose of the snapshot blob now. + v8::Context::Scope c_scope(context); + CHECK_EQ(42, CompileRun("f()")->ToInt32(isolate1)->Int32Value()); + } + isolate1->Dispose(); } @@ -735,10 +761,10 @@ int CountBuiltins() { static Handle<SharedFunctionInfo> CompileScript( Isolate* isolate, Handle<String> source, Handle<String> name, ScriptData** cached_data, v8::ScriptCompiler::CompileOptions options) { - return Compiler::CompileScript(source, name, 0, 0, false, false, - Handle<Context>(isolate->native_context()), - NULL, cached_data, options, NOT_NATIVES_CODE, - false); + return Compiler::CompileScript( + source, name, 0, 0, false, false, Handle<Object>(), + Handle<Context>(isolate->native_context()), NULL, cached_data, options, + NOT_NATIVES_CODE, false); } @@ -1346,7 +1372,9 @@ TEST(SerializeToplevelFlagChange) { v8::ScriptCompiler::CachedData* cache = ProduceCache(source); v8::Isolate* isolate2 = v8::Isolate::New(); + FLAG_allow_natives_syntax = true; // Flag change should trigger cache reject. + FlagList::EnforceFlagImplications(); { v8::Isolate::Scope iscope(isolate2); v8::HandleScope scope(isolate2); @@ -1393,7 +1421,6 @@ TEST(SerializeToplevelBitFlip) { TEST(SerializeWithHarmonyScoping) { FLAG_serialize_toplevel = true; - FLAG_harmony_scoping = true; const char* source1 = "'use strict'; let x = 'X'"; const char* source2 = "'use strict'; let y = 'Y'"; @@ -1454,3 +1481,71 @@ TEST(SerializeWithHarmonyScoping) { } isolate2->Dispose(); } + + +TEST(SerializeInternalReference) { +#ifdef V8_TARGET_ARCH_ARM64 + return; +#endif // V8_TARGET_ARCH_ARM64 + // Disable experimental natives that are loaded after deserialization. + FLAG_turbo_deoptimization = false; + FLAG_context_specialization = false; + FLAG_always_opt = true; + const char* flag = "--turbo-filter=foo"; + FlagList::SetFlagsFromString(flag, StrLength(flag)); + + const char* source = + "var foo = (function(stdlib, foreign, heap) {" + " function foo(i) {" + " i = i|0;" + " var j = 0;" + " switch (i) {" + " case 0:" + " case 1: j = 1; break;" + " case 2:" + " case 3: j = 2; break;" + " case 4:" + " case 5: j = foo(3) + 1; break;" + " default: j = 0; break;" + " }" + " return j + 10;" + " }" + " return { foo: foo };" + "})(this, {}, undefined).foo;" + "foo(1);"; + + v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source); + CHECK(data.data); + + v8::Isolate::CreateParams params; + params.snapshot_blob = &data; + v8::Isolate* isolate = v8::Isolate::New(params); + { + v8::Isolate::Scope i_scope(isolate); + v8::HandleScope h_scope(isolate); + v8::Local<v8::Context> context = v8::Context::New(isolate); + delete[] data.data; // We can dispose of the snapshot blob now. + v8::Context::Scope c_scope(context); + v8::Handle<v8::Function> foo = + v8::Handle<v8::Function>::Cast(CompileRun("foo")); + + // There are at least 6 internal references. + int mask = RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | + RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED); + RelocIterator it(v8::Utils::OpenHandle(*foo)->code(), mask); + for (int i = 0; i < 6; ++i) { + CHECK(!it.done()); + it.next(); + } + + CHECK(v8::Utils::OpenHandle(*foo)->code()->is_turbofanned()); + CHECK_EQ(11, CompileRun("foo(0)")->ToInt32(isolate)->Int32Value()); + CHECK_EQ(11, CompileRun("foo(1)")->ToInt32(isolate)->Int32Value()); + CHECK_EQ(12, CompileRun("foo(2)")->ToInt32(isolate)->Int32Value()); + CHECK_EQ(12, CompileRun("foo(3)")->ToInt32(isolate)->Int32Value()); + CHECK_EQ(23, CompileRun("foo(4)")->ToInt32(isolate)->Int32Value()); + CHECK_EQ(23, CompileRun("foo(5)")->ToInt32(isolate)->Int32Value()); + CHECK_EQ(10, CompileRun("foo(6)")->ToInt32(isolate)->Int32Value()); + } + isolate->Dispose(); +} diff --git a/deps/v8/test/cctest/test-spaces.cc b/deps/v8/test/cctest/test-spaces.cc index 331ea02510..92305f9f1e 100644 --- a/deps/v8/test/cctest/test-spaces.cc +++ b/deps/v8/test/cctest/test-spaces.cc @@ -28,7 +28,7 @@ #include <stdlib.h> #include "src/base/platform/platform.h" -#include "src/snapshot.h" +#include "src/snapshot/snapshot.h" #include "src/v8.h" #include "test/cctest/cctest.h" @@ -207,12 +207,13 @@ static void VerifyMemoryChunk(Isolate* isolate, TEST(Regress3540) { Isolate* isolate = CcTest::i_isolate(); Heap* heap = isolate->heap(); + const int pageSize = Page::kPageSize; MemoryAllocator* memory_allocator = new MemoryAllocator(isolate); CHECK( memory_allocator->SetUp(heap->MaxReserved(), heap->MaxExecutableSize())); TestMemoryAllocatorScope test_allocator_scope(isolate, memory_allocator); CodeRange* code_range = new CodeRange(isolate); - const size_t code_range_size = 4 * MB; + const size_t code_range_size = 4 * pageSize; if (!code_range->SetUp( code_range_size + RoundUp(v8::base::OS::CommitPageSize() * kReservedCodeRangePages, @@ -222,13 +223,13 @@ TEST(Regress3540) { } Address address; size_t size; - address = code_range->AllocateRawMemory(code_range_size - 2 * MB, - code_range_size - 2 * MB, &size); + address = code_range->AllocateRawMemory( + code_range_size - 2 * pageSize, code_range_size - 2 * pageSize, &size); CHECK(address != NULL); Address null_address; size_t null_size; null_address = code_range->AllocateRawMemory( - code_range_size - MB, code_range_size - MB, &null_size); + code_range_size - pageSize, code_range_size - pageSize, &null_size); CHECK(null_address == NULL); code_range->FreeRawMemory(address, size); delete code_range; @@ -307,9 +308,7 @@ TEST(MemoryAllocator) { heap->MaxExecutableSize())); int total_pages = 0; - OldSpace faked_space(heap, - heap->MaxReserved(), - OLD_POINTER_SPACE, + OldSpace faked_space(heap, heap->MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE); Page* first_page = memory_allocator->AllocatePage( faked_space.AreaSize(), &faked_space, NOT_EXECUTABLE); @@ -379,10 +378,8 @@ TEST(OldSpace) { heap->MaxExecutableSize())); TestMemoryAllocatorScope test_scope(isolate, memory_allocator); - OldSpace* s = new OldSpace(heap, - heap->MaxOldGenerationSize(), - OLD_POINTER_SPACE, - NOT_EXECUTABLE); + OldSpace* s = new OldSpace(heap, heap->MaxOldGenerationSize(), + OLD_POINTER_SPACE, NOT_EXECUTABLE); CHECK(s != NULL); CHECK(s->SetUp()); @@ -422,7 +419,9 @@ TEST(LargeObjectSpace) { { AllocationResult allocation = lo->AllocateRaw(lo_size, NOT_EXECUTABLE); if (allocation.IsRetry()) break; } - CHECK(lo->Available() < available); + // The available value is conservative such that it may report + // zero prior to heap exhaustion. + CHECK(lo->Available() < available || available == 0); } CHECK(!lo->IsEmpty()); @@ -434,9 +433,10 @@ TEST(LargeObjectSpace) { TEST(SizeOfFirstPageIsLargeEnough) { if (i::FLAG_always_opt) return; // Bootstrapping without a snapshot causes more allocations. - if (!i::Snapshot::HaveASnapshotToStartFrom()) return; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); + if (!isolate->snapshot_available()) return; + if (Snapshot::EmbedsScript(isolate)) return; // Freshly initialized VM gets by with one page per space. for (int i = FIRST_PAGED_SPACE; i <= LAST_PAGED_SPACE; i++) { @@ -460,7 +460,7 @@ TEST(SizeOfFirstPageIsLargeEnough) { UNINITIALIZED_TEST(NewSpaceGrowsToTargetCapacity) { - FLAG_target_semi_space_size = 2; + FLAG_target_semi_space_size = 2 * (Page::kPageSize / MB); if (FLAG_optimize_for_size) return; v8::Isolate* isolate = v8::Isolate::New(); diff --git a/deps/v8/test/cctest/test-strings.cc b/deps/v8/test/cctest/test-strings.cc index 9a4e96ffd5..8d5129cd05 100644 --- a/deps/v8/test/cctest/test-strings.cc +++ b/deps/v8/test/cctest/test-strings.cc @@ -1209,7 +1209,7 @@ UNINITIALIZED_TEST(OneByteArrayJoin) { v8::Isolate::CreateParams create_params; // Set heap limits. create_params.constraints.set_max_semi_space_size(1); - create_params.constraints.set_max_old_space_size(5); + create_params.constraints.set_max_old_space_size(6); v8::Isolate* isolate = v8::Isolate::New(create_params); isolate->Enter(); diff --git a/deps/v8/test/cctest/test-thread-termination.cc b/deps/v8/test/cctest/test-thread-termination.cc index d31b4131df..0d20e0f043 100644 --- a/deps/v8/test/cctest/test-thread-termination.cc +++ b/deps/v8/test/cctest/test-thread-termination.cc @@ -192,6 +192,7 @@ TEST(TerminateOnlyV8ThreadFromOtherThread) { // Run a loop that will be infinite if thread termination does not work. v8::Handle<v8::String> source = v8::String::NewFromUtf8( CcTest::isolate(), "try { loop(); fail(); } catch(e) { fail(); }"); + i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops. v8::Script::Compile(source)->Run(); thread.Join(); @@ -228,6 +229,7 @@ void LoopGetProperty(const v8::FunctionCallbackInfo<v8::Value>& args) { " }" " fail();" " } catch(e) {" + " (function() {})();" // trigger stack check. " fail();" " }" "}" @@ -375,6 +377,7 @@ void MicrotaskLoopForever(const v8::FunctionCallbackInfo<v8::Value>& info) { // Enqueue another should-not-run task to ensure we clean out the queue // when we terminate. isolate->EnqueueMicrotask(v8::Function::New(isolate, MicrotaskShouldNotRun)); + i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops. CompileRun("terminate(); while (true) { }"); CHECK(v8::V8::IsExecutionTerminating()); } @@ -474,3 +477,65 @@ TEST(ErrorObjectAfterTermination) { // TODO(yangguo): crbug/403509. Check for empty handle instead. CHECK(error->IsUndefined()); } + + +void InnerTryCallTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) { + CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate())); + v8::Handle<v8::Object> global = CcTest::global(); + v8::Handle<v8::Function> loop = + v8::Handle<v8::Function>::Cast(global->Get(v8_str("loop"))); + i::MaybeHandle<i::Object> result = + i::Execution::TryCall(v8::Utils::OpenHandle((*loop)), + v8::Utils::OpenHandle((*global)), 0, NULL, NULL); + CHECK(result.is_null()); + // TryCall ignores terminate execution, but rerequests the interrupt. + CHECK(!v8::V8::IsExecutionTerminating(args.GetIsolate())); + CHECK(CompileRun("1 + 1;").IsEmpty()); +} + + +TEST(TerminationInInnerTryCall) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + v8::Handle<v8::ObjectTemplate> global_template = CreateGlobalTemplate( + CcTest::isolate(), TerminateCurrentThread, DoLoopNoCall); + global_template->Set( + v8_str("inner_try_call_terminate"), + v8::FunctionTemplate::New(isolate, InnerTryCallTerminate)); + v8::Handle<v8::Context> context = + v8::Context::New(CcTest::isolate(), NULL, global_template); + v8::Context::Scope context_scope(context); + { + v8::TryCatch try_catch; + CompileRun("inner_try_call_terminate()"); + CHECK(try_catch.HasTerminated()); + } + CHECK_EQ(4, CompileRun("2 + 2")->ToInt32()->Int32Value()); + CHECK(!v8::V8::IsExecutionTerminating()); +} + + +TEST(TerminateAndTryCall) { + i::FLAG_allow_natives_syntax = true; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate( + isolate, TerminateCurrentThread, DoLoopCancelTerminate); + v8::Handle<v8::Context> context = v8::Context::New(isolate, NULL, global); + v8::Context::Scope context_scope(context); + CHECK(!v8::V8::IsExecutionTerminating(isolate)); + v8::TryCatch try_catch; + CHECK(!v8::V8::IsExecutionTerminating(isolate)); + // Terminate execution has been triggered inside TryCall, but re-requested + // to trigger later. + CHECK(CompileRun("terminate(); reference_error();").IsEmpty()); + CHECK(try_catch.HasCaught()); + CHECK(!v8::V8::IsExecutionTerminating(isolate)); + CHECK(CcTest::global()->Get(v8_str("terminate"))->IsFunction()); + // The first stack check after terminate has been re-requested fails. + CHECK(CompileRun("1 + 1").IsEmpty()); + CHECK(!v8::V8::IsExecutionTerminating(isolate)); + // V8 then recovers. + CHECK_EQ(4, CompileRun("2 + 2")->ToInt32()->Int32Value()); + CHECK(!v8::V8::IsExecutionTerminating(isolate)); +} diff --git a/deps/v8/test/cctest/test-transitions.cc b/deps/v8/test/cctest/test-transitions.cc index 59c9f74c96..800c2a0e44 100644 --- a/deps/v8/test/cctest/test-transitions.cc +++ b/deps/v8/test/cctest/test-transitions.cc @@ -20,16 +20,6 @@ using namespace v8::internal; // Helper functions. // -static void ConnectTransition(Handle<Map> parent, - Handle<TransitionArray> transitions, - Handle<Map> child) { - if (!parent->HasTransitionArray() || *transitions != parent->transitions()) { - parent->set_transitions(*transitions); - } - child->SetBackPointer(*parent); -} - - static void CheckPropertyDetailsFieldsConsistency(PropertyType type, PropertyKind kind, PropertyLocation location) { @@ -69,34 +59,32 @@ TEST(TransitionArray_SimpleFieldTransitions) { attributes, Representation::Tagged(), OMIT_TRANSITION).ToHandleChecked(); - CHECK(!map0->HasTransitionArray()); - Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0); - CHECK(transitions->IsFullTransitionArray()); - - int transition; - transitions = - transitions->Insert(map0, name1, map1, SIMPLE_PROPERTY_TRANSITION); - ConnectTransition(map0, transitions, map1); - CHECK(transitions->IsSimpleTransition()); - transition = transitions->Search(kData, *name1, attributes); - CHECK_EQ(TransitionArray::kSimpleTransitionIndex, transition); - CHECK_EQ(*name1, transitions->GetKey(transition)); - CHECK_EQ(*map1, transitions->GetTarget(transition)); - - transitions = - transitions->Insert(map0, name2, map2, SIMPLE_PROPERTY_TRANSITION); - ConnectTransition(map0, transitions, map2); - CHECK(transitions->IsFullTransitionArray()); - - transition = transitions->Search(kData, *name1, attributes); - CHECK_EQ(*name1, transitions->GetKey(transition)); - CHECK_EQ(*map1, transitions->GetTarget(transition)); - - transition = transitions->Search(kData, *name2, attributes); - CHECK_EQ(*name2, transitions->GetKey(transition)); - CHECK_EQ(*map2, transitions->GetTarget(transition)); - - DCHECK(transitions->IsSortedNoDuplicates()); + CHECK(map0->raw_transitions()->IsSmi()); + + TransitionArray::Insert(map0, name1, map1, SIMPLE_PROPERTY_TRANSITION); + CHECK(TransitionArray::IsSimpleTransition(map0->raw_transitions())); + CHECK_EQ(*map1, + TransitionArray::SearchTransition(*map0, kData, *name1, attributes)); + CHECK_EQ(1, TransitionArray::NumberOfTransitions(map0->raw_transitions())); + CHECK_EQ(*name1, TransitionArray::GetKey(map0->raw_transitions(), 0)); + CHECK_EQ(*map1, TransitionArray::GetTarget(map0->raw_transitions(), 0)); + + TransitionArray::Insert(map0, name2, map2, SIMPLE_PROPERTY_TRANSITION); + CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions())); + + CHECK_EQ(*map1, + TransitionArray::SearchTransition(*map0, kData, *name1, attributes)); + CHECK_EQ(*map2, + TransitionArray::SearchTransition(*map0, kData, *name2, attributes)); + CHECK_EQ(2, TransitionArray::NumberOfTransitions(map0->raw_transitions())); + for (int i = 0; i < 2; i++) { + Name* key = TransitionArray::GetKey(map0->raw_transitions(), i); + Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i); + CHECK((key == *name1 && target == *map1) || + (key == *name2 && target == *map2)); + } + + DCHECK(TransitionArray::IsSortedNoDuplicates(*map0)); } @@ -120,31 +108,32 @@ TEST(TransitionArray_FullFieldTransitions) { attributes, Representation::Tagged(), OMIT_TRANSITION).ToHandleChecked(); - CHECK(!map0->HasTransitionArray()); - Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0); - CHECK(transitions->IsFullTransitionArray()); - - int transition; - transitions = transitions->Insert(map0, name1, map1, PROPERTY_TRANSITION); - ConnectTransition(map0, transitions, map1); - CHECK(transitions->IsFullTransitionArray()); - transition = transitions->Search(kData, *name1, attributes); - CHECK_EQ(*name1, transitions->GetKey(transition)); - CHECK_EQ(*map1, transitions->GetTarget(transition)); - - transitions = transitions->Insert(map0, name2, map2, PROPERTY_TRANSITION); - ConnectTransition(map0, transitions, map2); - CHECK(transitions->IsFullTransitionArray()); - - transition = transitions->Search(kData, *name1, attributes); - CHECK_EQ(*name1, transitions->GetKey(transition)); - CHECK_EQ(*map1, transitions->GetTarget(transition)); - - transition = transitions->Search(kData, *name2, attributes); - CHECK_EQ(*name2, transitions->GetKey(transition)); - CHECK_EQ(*map2, transitions->GetTarget(transition)); + CHECK(map0->raw_transitions()->IsSmi()); + + TransitionArray::Insert(map0, name1, map1, PROPERTY_TRANSITION); + CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions())); + CHECK_EQ(*map1, + TransitionArray::SearchTransition(*map0, kData, *name1, attributes)); + CHECK_EQ(1, TransitionArray::NumberOfTransitions(map0->raw_transitions())); + CHECK_EQ(*name1, TransitionArray::GetKey(map0->raw_transitions(), 0)); + CHECK_EQ(*map1, TransitionArray::GetTarget(map0->raw_transitions(), 0)); + + TransitionArray::Insert(map0, name2, map2, PROPERTY_TRANSITION); + CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions())); + + CHECK_EQ(*map1, + TransitionArray::SearchTransition(*map0, kData, *name1, attributes)); + CHECK_EQ(*map2, + TransitionArray::SearchTransition(*map0, kData, *name2, attributes)); + CHECK_EQ(2, TransitionArray::NumberOfTransitions(map0->raw_transitions())); + for (int i = 0; i < 2; i++) { + Name* key = TransitionArray::GetKey(map0->raw_transitions(), i); + Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i); + CHECK((key == *name1 && target == *map1) || + (key == *name2 && target == *map2)); + } - DCHECK(transitions->IsSortedNoDuplicates()); + DCHECK(TransitionArray::IsSortedNoDuplicates(*map0)); } @@ -160,9 +149,7 @@ TEST(TransitionArray_DifferentFieldNames) { PropertyAttributes attributes = NONE; Handle<Map> map0 = Map::Create(isolate, 0); - CHECK(!map0->HasTransitionArray()); - Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0); - CHECK(transitions->IsFullTransitionArray()); + CHECK(map0->raw_transitions()->IsSmi()); for (int i = 0; i < PROPS_COUNT; i++) { EmbeddedVector<char, 64> buffer; @@ -175,17 +162,25 @@ TEST(TransitionArray_DifferentFieldNames) { names[i] = name; maps[i] = map; - transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION); - ConnectTransition(map0, transitions, map); + TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION); } for (int i = 0; i < PROPS_COUNT; i++) { - int transition = transitions->Search(kData, *names[i], attributes); - CHECK_EQ(*names[i], transitions->GetKey(transition)); - CHECK_EQ(*maps[i], transitions->GetTarget(transition)); + CHECK_EQ(*maps[i], TransitionArray::SearchTransition( + *map0, kData, *names[i], attributes)); + } + for (int i = 0; i < PROPS_COUNT; i++) { + Name* key = TransitionArray::GetKey(map0->raw_transitions(), i); + Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i); + for (int j = 0; j < PROPS_COUNT; j++) { + if (*names[i] == key) { + CHECK_EQ(*maps[i], target); + break; + } + } } - DCHECK(transitions->IsSortedNoDuplicates()); + DCHECK(TransitionArray::IsSortedNoDuplicates(*map0)); } @@ -196,9 +191,7 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) { Factory* factory = isolate->factory(); Handle<Map> map0 = Map::Create(isolate, 0); - CHECK(!map0->HasTransitionArray()); - Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0); - CHECK(transitions->IsFullTransitionArray()); + CHECK(map0->raw_transitions()->IsSmi()); const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1; STATIC_ASSERT(ATTRS_COUNT == 8); @@ -215,20 +208,20 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) { OMIT_TRANSITION).ToHandleChecked(); attr_maps[i] = map; - transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION); - ConnectTransition(map0, transitions, map); + TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION); } // Ensure that transitions for |name| field are valid. for (int i = 0; i < ATTRS_COUNT; i++) { PropertyAttributes attributes = static_cast<PropertyAttributes>(i); - - int transition = transitions->Search(kData, *name, attributes); - CHECK_EQ(*name, transitions->GetKey(transition)); - CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition)); + CHECK_EQ(*attr_maps[i], TransitionArray::SearchTransition( + *map0, kData, *name, attributes)); + // All transitions use the same key, so this check doesn't need to + // care about ordering. + CHECK_EQ(*name, TransitionArray::GetKey(map0->raw_transitions(), i)); } - DCHECK(transitions->IsSortedNoDuplicates()); + DCHECK(TransitionArray::IsSortedNoDuplicates(*map0)); } @@ -243,9 +236,7 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) { Handle<Map> maps[PROPS_COUNT]; Handle<Map> map0 = Map::Create(isolate, 0); - CHECK(!map0->HasTransitionArray()); - Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0); - CHECK(transitions->IsFullTransitionArray()); + CHECK(map0->raw_transitions()->IsSmi()); // Some number of fields. for (int i = 0; i < PROPS_COUNT; i++) { @@ -259,8 +250,7 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) { names[i] = name; maps[i] = map; - transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION); - ConnectTransition(map0, transitions, map); + TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION); } const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1; @@ -278,25 +268,36 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) { OMIT_TRANSITION).ToHandleChecked(); attr_maps[i] = map; - transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION); - ConnectTransition(map0, transitions, map); + TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION); } // Ensure that transitions for |name| field are valid. for (int i = 0; i < ATTRS_COUNT; i++) { - PropertyAttributes attributes = static_cast<PropertyAttributes>(i); - - int transition = transitions->Search(kData, *name, attributes); - CHECK_EQ(*name, transitions->GetKey(transition)); - CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition)); + PropertyAttributes attr = static_cast<PropertyAttributes>(i); + CHECK_EQ(*attr_maps[i], + TransitionArray::SearchTransition(*map0, kData, *name, attr)); } // Ensure that info about the other fields still valid. - for (int i = 0; i < PROPS_COUNT; i++) { - int transition = transitions->Search(kData, *names[i], NONE); - CHECK_EQ(*names[i], transitions->GetKey(transition)); - CHECK_EQ(*maps[i], transitions->GetTarget(transition)); + CHECK_EQ(PROPS_COUNT + ATTRS_COUNT, + TransitionArray::NumberOfTransitions(map0->raw_transitions())); + for (int i = 0; i < PROPS_COUNT + ATTRS_COUNT; i++) { + Name* key = TransitionArray::GetKey(map0->raw_transitions(), i); + Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i); + if (key == *name) { + // Attributes transition. + PropertyAttributes attributes = + target->GetLastDescriptorDetails().attributes(); + CHECK_EQ(*attr_maps[static_cast<int>(attributes)], target); + } else { + for (int j = 0; j < PROPS_COUNT; j++) { + if (*names[j] == key) { + CHECK_EQ(*maps[j], target); + break; + } + } + } } - DCHECK(transitions->IsSortedNoDuplicates()); + DCHECK(TransitionArray::IsSortedNoDuplicates(*map0)); } diff --git a/deps/v8/test/cctest/test-typedarrays.cc b/deps/v8/test/cctest/test-typedarrays.cc new file mode 100644 index 0000000000..d031048cae --- /dev/null +++ b/deps/v8/test/cctest/test-typedarrays.cc @@ -0,0 +1,81 @@ +// Copyright 2015 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 <stdlib.h> + +#include "src/v8.h" +#include "test/cctest/cctest.h" + +#include "src/api.h" +#include "src/heap/heap.h" +#include "src/objects.h" +#include "src/v8.h" + +using namespace v8::internal; + +void TestArrayBufferViewContents(LocalContext& env, bool should_use_buffer) { + v8::Local<v8::Object> obj_a = + v8::Local<v8::Object>::Cast(env->Global()->Get(v8_str("a"))); + CHECK(obj_a->IsArrayBufferView()); + v8::Local<v8::ArrayBufferView> array_buffer_view = + v8::Local<v8::ArrayBufferView>::Cast(obj_a); + CHECK_EQ(array_buffer_view->HasBuffer(), should_use_buffer); + unsigned char contents[4] = {23, 23, 23, 23}; + CHECK_EQ(sizeof(contents), + array_buffer_view->CopyContents(contents, sizeof(contents))); + CHECK_EQ(array_buffer_view->HasBuffer(), should_use_buffer); + for (size_t i = 0; i < sizeof(contents); ++i) { + CHECK_EQ(i, contents[i]); + } +} + + +TEST(CopyContentsTypedArray) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + CompileRun( + "var a = new Uint8Array(4);" + "a[0] = 0;" + "a[1] = 1;" + "a[2] = 2;" + "a[3] = 3;"); + TestArrayBufferViewContents(env, false); +} + + +TEST(CopyContentsArray) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + CompileRun("var a = new Uint8Array([0, 1, 2, 3]);"); + TestArrayBufferViewContents(env, true); +} + + +TEST(CopyContentsView) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + CompileRun( + "var b = new ArrayBuffer(6);" + "var c = new Uint8Array(b);" + "c[0] = -1;" + "c[1] = -1;" + "c[2] = 0;" + "c[3] = 1;" + "c[4] = 2;" + "c[5] = 3;" + "var a = new DataView(b, 2);"); + TestArrayBufferViewContents(env, true); +} + + +TEST(AllocateNotExternal) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + void* memory = V8::ArrayBufferAllocator()->Allocate(1024); + v8::Local<v8::ArrayBuffer> buffer = + v8::ArrayBuffer::New(env->GetIsolate(), memory, 1024, + v8::ArrayBufferCreationMode::kInternalized); + CHECK(!buffer->IsExternal()); + CHECK_EQ(memory, buffer->GetContents().Data()); +} diff --git a/deps/v8/test/cctest/test-unboxed-doubles.cc b/deps/v8/test/cctest/test-unboxed-doubles.cc index fdcac3af35..05c13e5776 100644 --- a/deps/v8/test/cctest/test-unboxed-doubles.cc +++ b/deps/v8/test/cctest/test-unboxed-doubles.cc @@ -18,7 +18,7 @@ using namespace v8::base; using namespace v8::internal; -#if (V8_DOUBLE_FIELDS_UNBOXING) +#if V8_DOUBLE_FIELDS_UNBOXING // @@ -30,7 +30,7 @@ static void InitializeVerifiedMapDescriptors( Map* map, DescriptorArray* descriptors, LayoutDescriptor* layout_descriptor) { map->InitializeDescriptors(descriptors, layout_descriptor); - CHECK(layout_descriptor->IsConsistentWithMap(map)); + CHECK(layout_descriptor->IsConsistentWithMap(map, true)); } @@ -48,6 +48,12 @@ static Handle<String> MakeName(const char* str, int suffix) { } +Handle<JSObject> GetObject(const char* name) { + return v8::Utils::OpenHandle( + *v8::Handle<v8::Object>::Cast(CcTest::global()->Get(v8_str(name)))); +} + + static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) { if (obj->IsUnboxedDoubleField(field_index)) { return obj->RawFastDoublePropertyAt(field_index); @@ -224,7 +230,7 @@ TEST(LayoutDescriptorBasicSlow) { } CHECK(layout_desc->IsSlowLayout()); CHECK(!layout_desc->IsFastPointerLayout()); - CHECK(layout_descriptor->IsConsistentWithMap(*map)); + CHECK(layout_descriptor->IsConsistentWithMap(*map, true)); } } @@ -638,7 +644,7 @@ static Handle<LayoutDescriptor> TestLayoutDescriptorAppend( map->InitializeDescriptors(*descriptors, *layout_descriptor); } Handle<LayoutDescriptor> layout_descriptor(map->layout_descriptor(), isolate); - CHECK(layout_descriptor->IsConsistentWithMap(*map)); + CHECK(layout_descriptor->IsConsistentWithMap(*map, true)); return layout_descriptor; } @@ -907,42 +913,126 @@ TEST(Regress436816) { } +TEST(DescriptorArrayTrimming) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + + const int kFieldCount = 128; + const int kSplitFieldIndex = 32; + const int kTrimmedLayoutDescriptorLength = 64; + + Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<Map> map = Map::Create(isolate, kFieldCount); + for (int i = 0; i < kSplitFieldIndex; i++) { + map = Map::CopyWithField(map, MakeName("prop", i), any_type, NONE, + Representation::Smi(), + INSERT_TRANSITION).ToHandleChecked(); + } + map = Map::CopyWithField(map, MakeName("dbl", kSplitFieldIndex), any_type, + NONE, Representation::Double(), + INSERT_TRANSITION).ToHandleChecked(); + CHECK(map->layout_descriptor()->IsConsistentWithMap(*map, true)); + CHECK(map->layout_descriptor()->IsSlowLayout()); + CHECK(map->owns_descriptors()); + CHECK_EQ(2, map->layout_descriptor()->length()); + + { + // Add transitions to double fields. + v8::HandleScope scope(CcTest::isolate()); + + Handle<Map> tmp_map = map; + for (int i = kSplitFieldIndex + 1; i < kFieldCount; i++) { + tmp_map = Map::CopyWithField(tmp_map, MakeName("dbl", i), any_type, NONE, + Representation::Double(), + INSERT_TRANSITION).ToHandleChecked(); + CHECK(tmp_map->layout_descriptor()->IsConsistentWithMap(*tmp_map, true)); + } + // Check that descriptors are shared. + CHECK(tmp_map->owns_descriptors()); + CHECK_EQ(map->instance_descriptors(), tmp_map->instance_descriptors()); + CHECK_EQ(map->layout_descriptor(), tmp_map->layout_descriptor()); + } + CHECK(map->layout_descriptor()->IsSlowLayout()); + CHECK_EQ(4, map->layout_descriptor()->length()); + + // The unused tail of the layout descriptor is now "durty" because of sharing. + CHECK(map->layout_descriptor()->IsConsistentWithMap(*map)); + for (int i = kSplitFieldIndex + 1; i < kTrimmedLayoutDescriptorLength; i++) { + CHECK(!map->layout_descriptor()->IsTagged(i)); + } + CHECK_LT(map->NumberOfOwnDescriptors(), + map->instance_descriptors()->number_of_descriptors()); + + // Call GC that should trim both |map|'s descriptor array and layout + // descriptor. + CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); + + // The unused tail of the layout descriptor is now "clean" again. + CHECK(map->layout_descriptor()->IsConsistentWithMap(*map, true)); + CHECK(map->owns_descriptors()); + CHECK_EQ(map->NumberOfOwnDescriptors(), + map->instance_descriptors()->number_of_descriptors()); + CHECK(map->layout_descriptor()->IsSlowLayout()); + CHECK_EQ(2, map->layout_descriptor()->length()); + + { + // Add transitions to tagged fields. + v8::HandleScope scope(CcTest::isolate()); + + Handle<Map> tmp_map = map; + for (int i = kSplitFieldIndex + 1; i < kFieldCount - 1; i++) { + tmp_map = Map::CopyWithField(tmp_map, MakeName("tagged", i), any_type, + NONE, Representation::Tagged(), + INSERT_TRANSITION).ToHandleChecked(); + CHECK(tmp_map->layout_descriptor()->IsConsistentWithMap(*tmp_map, true)); + } + tmp_map = Map::CopyWithField(tmp_map, MakeString("dbl"), any_type, NONE, + Representation::Double(), + INSERT_TRANSITION).ToHandleChecked(); + CHECK(tmp_map->layout_descriptor()->IsConsistentWithMap(*tmp_map, true)); + // Check that descriptors are shared. + CHECK(tmp_map->owns_descriptors()); + CHECK_EQ(map->instance_descriptors(), tmp_map->instance_descriptors()); + } + CHECK(map->layout_descriptor()->IsSlowLayout()); +} + + TEST(DoScavenge) { CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); - v8::HandleScope scope(CcTest::isolate()); - CompileRun( - "function A() {" - " this.x = 42.5;" - " this.o = {};" - "};" - "var o = new A();"); + // The plan: create |obj| with double field in new space, do scanvenge so + // that |obj| is moved to old space, construct a double value that looks like + // a pointer to "from space" pointer. Do scavenge one more time and ensure + // that it didn't crash or corrupt the double value stored in the object. - Handle<String> obj_name = factory->InternalizeUtf8String("o"); + Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<Map> map = Map::Create(isolate, 10); + map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE, + Representation::Double(), + INSERT_TRANSITION).ToHandleChecked(); - Handle<Object> obj_value = - Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked(); - CHECK(obj_value->IsJSObject()); - Handle<JSObject> obj = Handle<JSObject>::cast(obj_value); + // Create object in new space. + Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED, false); + + Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5); + obj->WriteToField(0, *heap_number); { // Ensure the object is properly set up. - Map* map = obj->map(); - DescriptorArray* descriptors = map->instance_descriptors(); - CHECK(map->NumberOfOwnDescriptors() == 2); - CHECK(descriptors->GetDetails(0).representation().IsDouble()); - CHECK(descriptors->GetDetails(1).representation().IsHeapObject()); - FieldIndex field_index = FieldIndex::ForDescriptor(map, 0); + FieldIndex field_index = FieldIndex::ForDescriptor(*map, 0); CHECK(field_index.is_inobject() && field_index.is_double()); CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index)); CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index)); } CHECK(isolate->heap()->new_space()->Contains(*obj)); - // Trigger GCs so that the newly allocated object moves to old gen. - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now + // Do scavenge so that |obj| is moved to survivor space. + CcTest::heap()->CollectGarbage(i::NEW_SPACE); // Create temp object in the new space. Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED); @@ -957,9 +1047,9 @@ TEST(DoScavenge) { Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE); obj->FastPropertyAtPut(field_index, *boom_number); - // Now the object moves to old gen and it has a double field that looks like + // Now |obj| moves to old gen and it has a double field that looks like // a pointer to a from semi-space. - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now + CcTest::heap()->CollectGarbage(i::NEW_SPACE, "boom"); CHECK(isolate->heap()->old_pointer_space()->Contains(*obj)); @@ -967,6 +1057,96 @@ TEST(DoScavenge) { } +TEST(DoScavengeWithIncrementalWriteBarrier) { + if (FLAG_never_compact || !FLAG_incremental_marking) return; + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + Heap* heap = CcTest::heap(); + PagedSpace* old_pointer_space = heap->old_pointer_space(); + + // The plan: create |obj_value| in old space and ensure that it is allocated + // on evacuation candidate page, create |obj| with double and tagged fields + // in new space and write |obj_value| to tagged field of |obj|, do two + // scavenges to promote |obj| to old space, a GC in old space and ensure that + // the tagged value was properly updated after candidates evacuation. + + Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<Map> map = Map::Create(isolate, 10); + map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE, + Representation::Double(), + INSERT_TRANSITION).ToHandleChecked(); + map = Map::CopyWithField(map, MakeName("prop", 1), any_type, NONE, + Representation::Tagged(), + INSERT_TRANSITION).ToHandleChecked(); + + // Create |obj_value| in old space. + Handle<HeapObject> obj_value; + Page* ec_page; + { + AlwaysAllocateScope always_allocate(isolate); + // Make sure |obj_value| is placed on an old-space evacuation candidate. + SimulateFullSpace(old_pointer_space); + obj_value = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED); + ec_page = Page::FromAddress(obj_value->address()); + } + + // Create object in new space. + Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED, false); + + Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5); + obj->WriteToField(0, *heap_number); + obj->WriteToField(1, *obj_value); + + { + // Ensure the object is properly set up. + FieldIndex field_index = FieldIndex::ForDescriptor(*map, 0); + CHECK(field_index.is_inobject() && field_index.is_double()); + CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index)); + CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index)); + + field_index = FieldIndex::ForDescriptor(*map, 1); + CHECK(field_index.is_inobject() && !field_index.is_double()); + CHECK(!map->IsUnboxedDoubleField(field_index)); + } + CHECK(isolate->heap()->new_space()->Contains(*obj)); + + // Heap is ready, force |ec_page| to become an evacuation candidate and + // simulate incremental marking. + FLAG_stress_compaction = true; + FLAG_manual_evacuation_candidates_selection = true; + ec_page->SetFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING); + SimulateIncrementalMarking(heap); + // Disable stress compaction mode in order to let GC do scavenge. + FLAG_stress_compaction = false; + + // Check that everything is ready for triggering incremental write barrier + // during scavenge (i.e. that |obj| is black and incremental marking is + // in compacting mode and |obj_value|'s page is an evacuation candidate). + IncrementalMarking* marking = heap->incremental_marking(); + CHECK(marking->IsCompacting()); + CHECK(Marking::IsBlack(Marking::MarkBitFrom(*obj))); + CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value)); + + // Trigger GCs so that |obj| moves to old gen. + heap->CollectGarbage(i::NEW_SPACE); // in survivor space now + heap->CollectGarbage(i::NEW_SPACE); // in old gen now + + CHECK(isolate->heap()->old_pointer_space()->Contains(*obj)); + CHECK(isolate->heap()->old_pointer_space()->Contains(*obj_value)); + CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value)); + + heap->CollectGarbage(i::OLD_POINTER_SPACE, "boom"); + + // |obj_value| must be evacuated. + CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(*obj_value)); + + FieldIndex field_index = FieldIndex::ForDescriptor(*map, 1); + CHECK_EQ(*obj_value, obj->RawFastPropertyAt(field_index)); +} + + static void TestLayoutDescriptorHelper(Isolate* isolate, int inobject_properties, Handle<DescriptorArray> descriptors, @@ -1131,7 +1311,7 @@ TEST(LayoutDescriptorSharing) { } Handle<LayoutDescriptor> split_layout_descriptor( split_map->layout_descriptor(), isolate); - CHECK(split_layout_descriptor->IsConsistentWithMap(*split_map)); + CHECK(split_layout_descriptor->IsConsistentWithMap(*split_map, true)); CHECK(split_layout_descriptor->IsSlowLayout()); CHECK(split_map->owns_descriptors()); @@ -1144,7 +1324,7 @@ TEST(LayoutDescriptorSharing) { // Layout descriptors should be shared with |split_map|. CHECK(map1->owns_descriptors()); CHECK_EQ(*split_layout_descriptor, map1->layout_descriptor()); - CHECK(map1->layout_descriptor()->IsConsistentWithMap(*map1)); + CHECK(map1->layout_descriptor()->IsConsistentWithMap(*map1, true)); Handle<Map> map2 = Map::CopyWithField(split_map, MakeString("bar"), any_type, NONE, Representation::Tagged(), @@ -1153,7 +1333,7 @@ TEST(LayoutDescriptorSharing) { // Layout descriptors should not be shared with |split_map|. CHECK(map2->owns_descriptors()); CHECK_NE(*split_layout_descriptor, map2->layout_descriptor()); - CHECK(map2->layout_descriptor()->IsConsistentWithMap(*map2)); + CHECK(map2->layout_descriptor()->IsConsistentWithMap(*map2, true)); } @@ -1163,28 +1343,23 @@ TEST(StoreBufferScanOnScavenge) { Factory* factory = isolate->factory(); v8::HandleScope scope(CcTest::isolate()); - CompileRun( - "function A() {" - " this.x = 42.5;" - " this.o = {};" - "};" - "var o = new A();"); + Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<Map> map = Map::Create(isolate, 10); + map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE, + Representation::Double(), + INSERT_TRANSITION).ToHandleChecked(); - Handle<String> obj_name = factory->InternalizeUtf8String("o"); + // Create object in new space. + Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED, false); - Handle<Object> obj_value = - Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked(); - CHECK(obj_value->IsJSObject()); - Handle<JSObject> obj = Handle<JSObject>::cast(obj_value); + Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5); + obj->WriteToField(0, *heap_number); { // Ensure the object is properly set up. - Map* map = obj->map(); DescriptorArray* descriptors = map->instance_descriptors(); - CHECK(map->NumberOfOwnDescriptors() == 2); CHECK(descriptors->GetDetails(0).representation().IsDouble()); - CHECK(descriptors->GetDetails(1).representation().IsHeapObject()); - FieldIndex field_index = FieldIndex::ForDescriptor(map, 0); + FieldIndex field_index = FieldIndex::ForDescriptor(*map, 0); CHECK(field_index.is_inobject() && field_index.is_double()); CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index)); CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index)); @@ -1305,4 +1480,211 @@ TEST(WriteBarriersInCopyJSObject) { CHECK_EQ(boom_value, clone->RawFastDoublePropertyAt(index)); } + +static void TestWriteBarrier(Handle<Map> map, Handle<Map> new_map, + int tagged_descriptor, int double_descriptor, + bool check_tagged_value = true) { + FLAG_stress_compaction = true; + FLAG_manual_evacuation_candidates_selection = true; + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + Heap* heap = CcTest::heap(); + PagedSpace* old_pointer_space = heap->old_pointer_space(); + + // The plan: create |obj| by |map| in old space, create |obj_value| in + // new space and ensure that write barrier is triggered when |obj_value| is + // written to property |tagged_descriptor| of |obj|. + // Then migrate object to |new_map| and set proper value for property + // |double_descriptor|. Call GC and ensure that it did not crash during + // store buffer entries updating. + + Handle<JSObject> obj; + Handle<HeapObject> obj_value; + { + AlwaysAllocateScope always_allocate(isolate); + obj = factory->NewJSObjectFromMap(map, TENURED, false); + CHECK(old_pointer_space->Contains(*obj)); + + obj_value = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS); + } + + CHECK(heap->InNewSpace(*obj_value)); + + { + FieldIndex index = FieldIndex::ForDescriptor(*map, tagged_descriptor); + const int n = 153; + for (int i = 0; i < n; i++) { + obj->FastPropertyAtPut(index, *obj_value); + } + } + + // Migrate |obj| to |new_map| which should shift fields and put the + // |boom_value| to the slot that was earlier recorded by write barrier. + JSObject::MigrateToMap(obj, new_map); + + Address fake_object = reinterpret_cast<Address>(*obj_value) + kPointerSize; + double boom_value = bit_cast<double>(fake_object); + + FieldIndex double_field_index = + FieldIndex::ForDescriptor(*new_map, double_descriptor); + CHECK(obj->IsUnboxedDoubleField(double_field_index)); + obj->RawFastDoublePropertyAtPut(double_field_index, boom_value); + + // Trigger GC to evacuate all candidates. + CcTest::heap()->CollectGarbage(NEW_SPACE, "boom"); + + if (check_tagged_value) { + FieldIndex tagged_field_index = + FieldIndex::ForDescriptor(*new_map, tagged_descriptor); + CHECK_EQ(*obj_value, obj->RawFastPropertyAt(tagged_field_index)); + } + CHECK_EQ(boom_value, obj->RawFastDoublePropertyAt(double_field_index)); +} + + +static void TestIncrementalWriteBarrier(Handle<Map> map, Handle<Map> new_map, + int tagged_descriptor, + int double_descriptor, + bool check_tagged_value = true) { + if (FLAG_never_compact || !FLAG_incremental_marking) return; + FLAG_stress_compaction = true; + FLAG_manual_evacuation_candidates_selection = true; + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + Heap* heap = CcTest::heap(); + PagedSpace* old_pointer_space = heap->old_pointer_space(); + + // The plan: create |obj| by |map| in old space, create |obj_value| in + // old space and ensure it end up in evacuation candidate page. Start + // incremental marking and ensure that incremental write barrier is triggered + // when |obj_value| is written to property |tagged_descriptor| of |obj|. + // Then migrate object to |new_map| and set proper value for property + // |double_descriptor|. Call GC and ensure that it did not crash during + // slots buffer entries updating. + + Handle<JSObject> obj; + Handle<HeapObject> obj_value; + Page* ec_page; + { + AlwaysAllocateScope always_allocate(isolate); + obj = factory->NewJSObjectFromMap(map, TENURED, false); + CHECK(old_pointer_space->Contains(*obj)); + + // Make sure |obj_value| is placed on an old-space evacuation candidate. + SimulateFullSpace(old_pointer_space); + obj_value = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED); + ec_page = Page::FromAddress(obj_value->address()); + CHECK_NE(ec_page, Page::FromAddress(obj->address())); + } + + // Heap is ready, force |ec_page| to become an evacuation candidate and + // simulate incremental marking. + ec_page->SetFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING); + SimulateIncrementalMarking(heap); + + // Check that everything is ready for triggering incremental write barrier + // (i.e. that both |obj| and |obj_value| are black and the marking phase is + // still active and |obj_value|'s page is indeed an evacuation candidate). + IncrementalMarking* marking = heap->incremental_marking(); + CHECK(marking->IsMarking()); + CHECK(Marking::IsBlack(Marking::MarkBitFrom(*obj))); + CHECK(Marking::IsBlack(Marking::MarkBitFrom(*obj_value))); + CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value)); + + // Trigger incremental write barrier, which should add a slot to |ec_page|'s + // slots buffer. + { + int slots_buffer_len = SlotsBuffer::SizeOfChain(ec_page->slots_buffer()); + FieldIndex index = FieldIndex::ForDescriptor(*map, tagged_descriptor); + const int n = SlotsBuffer::kNumberOfElements + 10; + for (int i = 0; i < n; i++) { + obj->FastPropertyAtPut(index, *obj_value); + } + // Ensure that the slot was actually added to the |ec_page|'s slots buffer. + CHECK_EQ(slots_buffer_len + n, + SlotsBuffer::SizeOfChain(ec_page->slots_buffer())); + } + + // Migrate |obj| to |new_map| which should shift fields and put the + // |boom_value| to the slot that was earlier recorded by incremental write + // barrier. + JSObject::MigrateToMap(obj, new_map); + + double boom_value = bit_cast<double>(UINT64_C(0xbaad0176a37c28e1)); + + FieldIndex double_field_index = + FieldIndex::ForDescriptor(*new_map, double_descriptor); + CHECK(obj->IsUnboxedDoubleField(double_field_index)); + obj->RawFastDoublePropertyAtPut(double_field_index, boom_value); + + // Trigger GC to evacuate all candidates. + CcTest::heap()->CollectGarbage(OLD_POINTER_SPACE, "boom"); + + // Ensure that the values are still there and correct. + CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(*obj_value)); + + if (check_tagged_value) { + FieldIndex tagged_field_index = + FieldIndex::ForDescriptor(*new_map, tagged_descriptor); + CHECK_EQ(*obj_value, obj->RawFastPropertyAt(tagged_field_index)); + } + CHECK_EQ(boom_value, obj->RawFastDoublePropertyAt(double_field_index)); +} + + +enum WriteBarrierKind { OLD_TO_OLD_WRITE_BARRIER, OLD_TO_NEW_WRITE_BARRIER }; +static void TestWriteBarrierObjectShiftFieldsRight( + WriteBarrierKind write_barrier_kind) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + v8::HandleScope scope(CcTest::isolate()); + + Handle<HeapType> any_type = HeapType::Any(isolate); + + CompileRun("function func() { return 1; }"); + + Handle<JSObject> func = GetObject("func"); + + Handle<Map> map = Map::Create(isolate, 10); + map = Map::CopyWithConstant(map, MakeName("prop", 0), func, NONE, + INSERT_TRANSITION).ToHandleChecked(); + map = Map::CopyWithField(map, MakeName("prop", 1), any_type, NONE, + Representation::Double(), + INSERT_TRANSITION).ToHandleChecked(); + map = Map::CopyWithField(map, MakeName("prop", 2), any_type, NONE, + Representation::Tagged(), + INSERT_TRANSITION).ToHandleChecked(); + + // Shift fields right by turning constant property to a field. + Handle<Map> new_map = Map::ReconfigureProperty( + map, 0, kData, NONE, Representation::Tagged(), any_type, FORCE_FIELD); + + if (write_barrier_kind == OLD_TO_NEW_WRITE_BARRIER) { + TestWriteBarrier(map, new_map, 2, 1); + } else { + CHECK_EQ(OLD_TO_OLD_WRITE_BARRIER, write_barrier_kind); + TestIncrementalWriteBarrier(map, new_map, 2, 1); + } +} + + +// TODO(ishell): enable when this issue is fixed. +DISABLED_TEST(WriteBarrierObjectShiftFieldsRight) { + TestWriteBarrierObjectShiftFieldsRight(OLD_TO_NEW_WRITE_BARRIER); +} + + +TEST(IncrementalWriteBarrierObjectShiftFieldsRight) { + TestWriteBarrierObjectShiftFieldsRight(OLD_TO_OLD_WRITE_BARRIER); +} + + +// TODO(ishell): add respective tests for property kind reconfiguring from +// accessor field to double, once accessor fields are supported by +// Map::ReconfigureProperty(). + + +// TODO(ishell): add respective tests for fast property removal case once +// Map::ReconfigureProperty() supports that. + #endif diff --git a/deps/v8/test/cctest/test-weakmaps.cc b/deps/v8/test/cctest/test-weakmaps.cc index 04f41b9aee..dfe3f453c5 100644 --- a/deps/v8/test/cctest/test-weakmaps.cc +++ b/deps/v8/test/cctest/test-weakmaps.cc @@ -30,7 +30,6 @@ #include "src/v8.h" #include "src/global-handles.h" -#include "src/snapshot.h" #include "test/cctest/cctest.h" using namespace v8::internal; @@ -184,7 +183,8 @@ TEST(Regress2060a) { // Start second old-space page so that values land on evacuation candidate. Page* first_page = heap->old_pointer_space()->anchor()->next_page(); - factory->NewFixedArray(900 * KB / kPointerSize, TENURED); + int dummy_array_size = Page::kMaxRegularHeapObjectSize - 92 * KB; + factory->NewFixedArray(dummy_array_size / kPointerSize, TENURED); // Fill up weak map with values on an evacuation candidate. { @@ -222,7 +222,8 @@ TEST(Regress2060b) { // Start second old-space page so that keys land on evacuation candidate. Page* first_page = heap->old_pointer_space()->anchor()->next_page(); - factory->NewFixedArray(900 * KB / kPointerSize, TENURED); + int dummy_array_size = Page::kMaxRegularHeapObjectSize - 92 * KB; + factory->NewFixedArray(dummy_array_size / kPointerSize, TENURED); // Fill up weak map with keys on an evacuation candidate. Handle<JSObject> keys[32]; diff --git a/deps/v8/test/cctest/test-weaksets.cc b/deps/v8/test/cctest/test-weaksets.cc index f08a99bcbf..1ab9f10989 100644 --- a/deps/v8/test/cctest/test-weaksets.cc +++ b/deps/v8/test/cctest/test-weaksets.cc @@ -30,7 +30,6 @@ #include "src/v8.h" #include "src/global-handles.h" -#include "src/snapshot.h" #include "test/cctest/cctest.h" using namespace v8::internal; @@ -184,7 +183,8 @@ TEST(WeakSet_Regress2060a) { // Start second old-space page so that values land on evacuation candidate. Page* first_page = heap->old_pointer_space()->anchor()->next_page(); - factory->NewFixedArray(900 * KB / kPointerSize, TENURED); + int dummy_array_size = Page::kMaxRegularHeapObjectSize - 92 * KB; + factory->NewFixedArray(dummy_array_size / kPointerSize, TENURED); // Fill up weak set with values on an evacuation candidate. { @@ -222,7 +222,8 @@ TEST(WeakSet_Regress2060b) { // Start second old-space page so that keys land on evacuation candidate. Page* first_page = heap->old_pointer_space()->anchor()->next_page(); - factory->NewFixedArray(900 * KB / kPointerSize, TENURED); + int dummy_array_size = Page::kMaxRegularHeapObjectSize - 92 * KB; + factory->NewFixedArray(dummy_array_size / kPointerSize, TENURED); // Fill up weak set with keys on an evacuation candidate. Handle<JSObject> keys[32]; diff --git a/deps/v8/test/cctest/test-weaktypedarrays.cc b/deps/v8/test/cctest/test-weaktypedarrays.cc index d40b7e95a9..c1f59de45a 100644 --- a/deps/v8/test/cctest/test-weaktypedarrays.cc +++ b/deps/v8/test/cctest/test-weaktypedarrays.cc @@ -62,7 +62,20 @@ static bool HasArrayBufferInWeakList(Heap* heap, JSArrayBuffer* ab) { } -static int CountViews(JSArrayBuffer* array_buffer) { +static int CountViewsInNewSpaceList(Heap* heap, JSArrayBuffer* array_buffer) { + int count = 0; + for (Object* o = heap->new_array_buffer_views_list(); !o->IsUndefined();) { + JSArrayBufferView* view = JSArrayBufferView::cast(o); + if (array_buffer == view->buffer()) { + count++; + } + o = view->weak_next(); + } + return count; +} + + +static int CountViews(Heap* heap, JSArrayBuffer* array_buffer) { int count = 0; for (Object* o = array_buffer->weak_first_view(); !o->IsUndefined(); @@ -70,17 +83,27 @@ static int CountViews(JSArrayBuffer* array_buffer) { count++; } - return count; + return count + CountViewsInNewSpaceList(heap, array_buffer); } -static bool HasViewInWeakList(JSArrayBuffer* array_buffer, + +static bool HasViewInNewSpaceList(Heap* heap, JSArrayBufferView* ta) { + for (Object* o = heap->new_array_buffer_views_list(); !o->IsUndefined(); + o = JSArrayBufferView::cast(o)->weak_next()) { + if (ta == o) return true; + } + return false; +} + + +static bool HasViewInWeakList(Heap* heap, JSArrayBuffer* array_buffer, JSArrayBufferView* ta) { for (Object* o = array_buffer->weak_first_view(); !o->IsUndefined(); o = JSArrayBufferView::cast(o)->weak_next()) { if (ta == o) return true; } - return false; + return HasViewInNewSpaceList(heap, ta); } @@ -200,18 +223,18 @@ void TestViewFromApi() { Handle<JSArrayBufferView> ita1 = v8::Utils::OpenHandle(*ta1); Handle<JSArrayBufferView> ita2 = v8::Utils::OpenHandle(*ta2); - CHECK_EQ(2, CountViews(*iab)); - CHECK(HasViewInWeakList(*iab, *ita1)); - CHECK(HasViewInWeakList(*iab, *ita2)); + CHECK_EQ(2, CountViews(isolate->heap(), *iab)); + CHECK(HasViewInWeakList(isolate->heap(), *iab, *ita1)); + CHECK(HasViewInWeakList(isolate->heap(), *iab, *ita2)); } isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - CHECK_EQ(1, CountViews(*iab)); + CHECK_EQ(1, CountViews(isolate->heap(), *iab)); Handle<JSArrayBufferView> ita1 = v8::Utils::OpenHandle(*ta1); - CHECK(HasViewInWeakList(*iab, *ita1)); + CHECK(HasViewInWeakList(isolate->heap(), *iab, *ita1)); } isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); - CHECK_EQ(0, CountViews(*iab)); + CHECK_EQ(0, CountViews(isolate->heap(), *iab)); } @@ -299,10 +322,13 @@ static void TestTypedArrayFromScript(const char* constructor) { v8::Handle<TypedArray>::Cast(CompileRun("ta3")); CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start); Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab); - CHECK_EQ(3, CountViews(*iab)); - CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta1))); - CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta2))); - CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta3))); + CHECK_EQ(3, CountViews(isolate->heap(), *iab)); + CHECK(HasViewInWeakList(isolate->heap(), *iab, + *v8::Utils::OpenHandle(*ta1))); + CHECK(HasViewInWeakList(isolate->heap(), *iab, + *v8::Utils::OpenHandle(*ta2))); + CHECK(HasViewInWeakList(isolate->heap(), *iab, + *v8::Utils::OpenHandle(*ta3))); } i::SNPrintF(source, "ta%d = null;", i); @@ -316,13 +342,14 @@ static void TestTypedArrayFromScript(const char* constructor) { v8::Handle<v8::ArrayBuffer> ab = v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab")); Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab); - CHECK_EQ(2, CountViews(*iab)); + CHECK_EQ(2, CountViews(isolate->heap(), *iab)); for (int j = 1; j <= 3; j++) { if (j == i) continue; i::SNPrintF(source, "ta%d", j); v8::Handle<TypedArray> ta = v8::Handle<TypedArray>::Cast(CompileRun(source.start())); - CHECK(HasViewInWeakList(*iab, *v8::Utils::OpenHandle(*ta))); + CHECK(HasViewInWeakList(isolate->heap(), *iab, + *v8::Utils::OpenHandle(*ta))); } } @@ -336,7 +363,7 @@ static void TestTypedArrayFromScript(const char* constructor) { v8::Handle<v8::ArrayBuffer> ab = v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab")); Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab); - CHECK_EQ(0, CountViews(*iab)); + CHECK_EQ(0, CountViews(isolate->heap(), *iab)); } } } diff --git a/deps/v8/test/js-perf-test/JSTests.json b/deps/v8/test/js-perf-test/JSTests.json index 0a99ad4d6a..a703642390 100644 --- a/deps/v8/test/js-perf-test/JSTests.json +++ b/deps/v8/test/js-perf-test/JSTests.json @@ -60,7 +60,6 @@ "path": ["Strings"], "main": "run.js", "resources": ["harmony-string.js"], - "flags": ["--harmony-strings"], "results_regexp": "^%s\\-Strings\\(Score\\): (.+)$", "tests": [ {"name": "StringFunctions"} @@ -71,7 +70,6 @@ "path": ["Templates"], "main": "run.js", "resources": ["templates.js"], - "flags": ["--harmony-templates"], "run_count": 5, "units": "score", "results_regexp": "^%s\\-Templates\\(Score\\): (.+)$", diff --git a/deps/v8/test/mjsunit/harmony/disable-harmony-string.js b/deps/v8/test/message/class-constructor-accessor.js index 0b88ae0be9..edc3c13169 100644 --- a/deps/v8/test/mjsunit/harmony/disable-harmony-string.js +++ b/deps/v8/test/message/class-constructor-accessor.js @@ -1,7 +1,10 @@ // 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: --harmony-classes +'use strict'; -// Flags: --noharmony-strings - -assertEquals(undefined, String.prototype.includes); +class C { + get constructor() {} +} diff --git a/deps/v8/test/message/class-constructor-accessor.out b/deps/v8/test/message/class-constructor-accessor.out new file mode 100644 index 0000000000..8776f54db1 --- /dev/null +++ b/deps/v8/test/message/class-constructor-accessor.out @@ -0,0 +1,7 @@ +# Copyright 2014 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +*%(basename)s:9: SyntaxError: Class constructor may not be an accessor + get constructor() {} + ^^^^^^^^^^^ +SyntaxError: Class constructor may not be an accessor diff --git a/deps/v8/test/message/class-constructor-generator.js b/deps/v8/test/message/class-constructor-generator.js new file mode 100644 index 0000000000..5d370f865e --- /dev/null +++ b/deps/v8/test/message/class-constructor-generator.js @@ -0,0 +1,10 @@ +// 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: --harmony-classes +'use strict'; + +class C { + *constructor() {} +} diff --git a/deps/v8/test/message/class-constructor-generator.out b/deps/v8/test/message/class-constructor-generator.out new file mode 100644 index 0000000000..5075e511cc --- /dev/null +++ b/deps/v8/test/message/class-constructor-generator.out @@ -0,0 +1,7 @@ +# Copyright 2014 the V8 project authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +*%(basename)s:9: SyntaxError: Class constructor may not be a generator + *constructor() {} + ^^^^^^^^^^^ +SyntaxError: Class constructor may not be a generator diff --git a/deps/v8/test/message/export-duplicate-as.js b/deps/v8/test/message/export-duplicate-as.js new file mode 100644 index 0000000000..49b52d4b17 --- /dev/null +++ b/deps/v8/test/message/export-duplicate-as.js @@ -0,0 +1,9 @@ +// Copyright 2015 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. +// +// MODULE + +var a, b; +export { a as c }; +export { a, b as c }; diff --git a/deps/v8/test/message/export-duplicate-as.out b/deps/v8/test/message/export-duplicate-as.out new file mode 100644 index 0000000000..1726d9491a --- /dev/null +++ b/deps/v8/test/message/export-duplicate-as.out @@ -0,0 +1,7 @@ +# Copyright 2015 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. +*%(basename)s:9: SyntaxError: Duplicate export of 'c' +export { a, b as c }; + ^ +SyntaxError: Duplicate export of 'c' diff --git a/deps/v8/test/message/export-duplicate-default.js b/deps/v8/test/message/export-duplicate-default.js new file mode 100644 index 0000000000..72a54a45f4 --- /dev/null +++ b/deps/v8/test/message/export-duplicate-default.js @@ -0,0 +1,8 @@ +// Copyright 2015 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. +// +// MODULE + +export default function f() {}; +export default class C {}; diff --git a/deps/v8/test/message/export-duplicate-default.out b/deps/v8/test/message/export-duplicate-default.out new file mode 100644 index 0000000000..4c6b97a7a1 --- /dev/null +++ b/deps/v8/test/message/export-duplicate-default.out @@ -0,0 +1,7 @@ +# Copyright 2015 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. +*%(basename)s:8: SyntaxError: Duplicate export of 'default' +export default class C {}; + ^^^^^^^ +SyntaxError: Duplicate export of 'default' diff --git a/deps/v8/test/message/export-duplicate.js b/deps/v8/test/message/export-duplicate.js new file mode 100644 index 0000000000..f45aefe13f --- /dev/null +++ b/deps/v8/test/message/export-duplicate.js @@ -0,0 +1,9 @@ +// Copyright 2015 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. +// +// MODULE + +var a, b; +export { a }; +export { a, b }; diff --git a/deps/v8/test/message/export-duplicate.out b/deps/v8/test/message/export-duplicate.out new file mode 100644 index 0000000000..e88779f580 --- /dev/null +++ b/deps/v8/test/message/export-duplicate.out @@ -0,0 +1,7 @@ +# Copyright 2015 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. +*%(basename)s:9: SyntaxError: Duplicate export of 'a' +export { a, b }; + ^ +SyntaxError: Duplicate export of 'a' diff --git a/deps/v8/test/message/import-as-eval.js b/deps/v8/test/message/import-as-eval.js new file mode 100644 index 0000000000..66adc32cbe --- /dev/null +++ b/deps/v8/test/message/import-as-eval.js @@ -0,0 +1,7 @@ +// Copyright 2015 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. +// +// MODULE + +import { foo as eval } from "mod"; diff --git a/deps/v8/test/message/import-as-eval.out b/deps/v8/test/message/import-as-eval.out new file mode 100644 index 0000000000..622f7fe9e1 --- /dev/null +++ b/deps/v8/test/message/import-as-eval.out @@ -0,0 +1,7 @@ +# Copyright 2015 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. +*%(basename)s:7: SyntaxError: Unexpected eval or arguments in strict mode +import { foo as eval } from "mod"; + ^^^^ +SyntaxError: Unexpected eval or arguments in strict mode diff --git a/deps/v8/test/message/import-as-redeclaration.js b/deps/v8/test/message/import-as-redeclaration.js new file mode 100644 index 0000000000..43bf278d1b --- /dev/null +++ b/deps/v8/test/message/import-as-redeclaration.js @@ -0,0 +1,8 @@ +// Copyright 2015 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. +// +// MODULE + +let foo = 42; +import { bar as foo } from "mod"; diff --git a/deps/v8/test/message/import-as-redeclaration.out b/deps/v8/test/message/import-as-redeclaration.out new file mode 100644 index 0000000000..51c4c032dc --- /dev/null +++ b/deps/v8/test/message/import-as-redeclaration.out @@ -0,0 +1,7 @@ +# Copyright 2015 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. +*%(basename)s:8: SyntaxError: Identifier 'foo' has already been declared +import { bar as foo } from "mod"; + ^^^ +SyntaxError: Identifier 'foo' has already been declared diff --git a/deps/v8/test/message/import-as-reserved-word.js b/deps/v8/test/message/import-as-reserved-word.js new file mode 100644 index 0000000000..562699d45f --- /dev/null +++ b/deps/v8/test/message/import-as-reserved-word.js @@ -0,0 +1,7 @@ +// Copyright 2015 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. +// +// MODULE + +import { foo as import } from "mod"; diff --git a/deps/v8/test/message/import-as-reserved-word.out b/deps/v8/test/message/import-as-reserved-word.out new file mode 100644 index 0000000000..1ee8d41c1a --- /dev/null +++ b/deps/v8/test/message/import-as-reserved-word.out @@ -0,0 +1,7 @@ +# Copyright 2015 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. +*%(basename)s:7: SyntaxError: Unexpected reserved word +import { foo as import } from "mod"; + ^^^^^^ +SyntaxError: Unexpected reserved word diff --git a/deps/v8/test/message/import-eval.js b/deps/v8/test/message/import-eval.js new file mode 100644 index 0000000000..8ab35baef6 --- /dev/null +++ b/deps/v8/test/message/import-eval.js @@ -0,0 +1,7 @@ +// Copyright 2015 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. +// +// MODULE + +import { eval } from "mod"; diff --git a/deps/v8/test/message/import-eval.out b/deps/v8/test/message/import-eval.out new file mode 100644 index 0000000000..148662a28c --- /dev/null +++ b/deps/v8/test/message/import-eval.out @@ -0,0 +1,7 @@ +# Copyright 2015 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. +*%(basename)s:7: SyntaxError: Unexpected eval or arguments in strict mode +import { eval } from "mod"; + ^^^^ +SyntaxError: Unexpected eval or arguments in strict mode diff --git a/deps/v8/test/message/import-redeclaration.js b/deps/v8/test/message/import-redeclaration.js new file mode 100644 index 0000000000..27b0cdccef --- /dev/null +++ b/deps/v8/test/message/import-redeclaration.js @@ -0,0 +1,8 @@ +// Copyright 2015 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. +// +// MODULE + +let foo = 42; +import { foo } from "mod"; diff --git a/deps/v8/test/message/import-redeclaration.out b/deps/v8/test/message/import-redeclaration.out new file mode 100644 index 0000000000..641948810f --- /dev/null +++ b/deps/v8/test/message/import-redeclaration.out @@ -0,0 +1,7 @@ +# Copyright 2015 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. +*%(basename)s:8: SyntaxError: Identifier 'foo' has already been declared +import { foo } from "mod"; + ^^^ +SyntaxError: Identifier 'foo' has already been declared diff --git a/deps/v8/test/message/import-reserved-word.js b/deps/v8/test/message/import-reserved-word.js new file mode 100644 index 0000000000..1fd7ba291e --- /dev/null +++ b/deps/v8/test/message/import-reserved-word.js @@ -0,0 +1,7 @@ +// Copyright 2015 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. +// +// MODULE + +import { import } from "mod"; diff --git a/deps/v8/test/message/import-reserved-word.out b/deps/v8/test/message/import-reserved-word.out new file mode 100644 index 0000000000..5b990e9e59 --- /dev/null +++ b/deps/v8/test/message/import-reserved-word.out @@ -0,0 +1,7 @@ +# Copyright 2015 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. +*%(basename)s:7: SyntaxError: Unexpected reserved word +import { import } from "mod"; + ^^^^^^ +SyntaxError: Unexpected reserved word diff --git a/deps/v8/test/message/testcfg.py b/deps/v8/test/message/testcfg.py index 5d6ab84663..cfe22f15d7 100644 --- a/deps/v8/test/message/testcfg.py +++ b/deps/v8/test/message/testcfg.py @@ -36,6 +36,7 @@ from testrunner.objects import testcase FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)") INVALID_FLAGS = ["--enable-slow-asserts"] +MODULE_PATTERN = re.compile(r"^// MODULE$", flags=re.MULTILINE) class MessageTestSuite(testsuite.TestSuite): @@ -63,6 +64,8 @@ class MessageTestSuite(testsuite.TestSuite): for match in flags_match: result += match.strip().split() result += context.mode_flags + if MODULE_PATTERN.search(source): + result.append("--module") result = [x for x in result if x not in INVALID_FLAGS] result.append(os.path.join(self.root, testcase.path + ".js")) return testcase.flags + result diff --git a/deps/v8/test/message/unterminated-arg-list.js b/deps/v8/test/message/unterminated-arg-list.js new file mode 100644 index 0000000000..b0fd1dd893 --- /dev/null +++ b/deps/v8/test/message/unterminated-arg-list.js @@ -0,0 +1,7 @@ +// Copyright 2015 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. + +$(document).ready(function() { +$("html").load( "https://localhost" ); +} diff --git a/deps/v8/test/message/unterminated-arg-list.out b/deps/v8/test/message/unterminated-arg-list.out new file mode 100644 index 0000000000..5be2b3d90c --- /dev/null +++ b/deps/v8/test/message/unterminated-arg-list.out @@ -0,0 +1,8 @@ +# Copyright 2015 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. + +*%(basename)s:7: SyntaxError: missing ) after argument list +} +^ +SyntaxError: missing ) after argument list diff --git a/deps/v8/test/mjsunit/asm/construct-double.js b/deps/v8/test/mjsunit/asm/construct-double.js new file mode 100644 index 0000000000..8bb5000082 --- /dev/null +++ b/deps/v8/test/mjsunit/asm/construct-double.js @@ -0,0 +1,33 @@ +// Copyright 2015 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 + +var stdlib = this; +var foreign = {}; +var heap = new ArrayBuffer(64 * 1024); + + +var m = (function(stdlib, foreign, heap) { + "use asm"; + function cd1(i, j) { + i = i|0; + j = j|0; + return +%_ConstructDouble(i, j); + } + function cd2(i) { + i = i|0; + return +%_ConstructDouble(0, i); + } + return { cd1: cd1, cd2: cd2 }; +})(stdlib, foreign, heap); + +assertEquals(0.0, m.cd1(0, 0)); +assertEquals(%ConstructDouble(0, 1), m.cd2(1)); +for (var i = -2147483648; i < 2147483648; i += 3999773) { + assertEquals(%ConstructDouble(0, i), m.cd2(i)); + for (var j = -2147483648; j < 2147483648; j += 3999773) { + assertEquals(%ConstructDouble(i, j), m.cd1(i, j)); + } +} diff --git a/deps/v8/test/mjsunit/asm/double-hi.js b/deps/v8/test/mjsunit/asm/double-hi.js new file mode 100644 index 0000000000..5a5f942f7b --- /dev/null +++ b/deps/v8/test/mjsunit/asm/double-hi.js @@ -0,0 +1,40 @@ +// Copyright 2015 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 + +var stdlib = this; +var foreign = {}; +var heap = new ArrayBuffer(64 * 1024); + + +var m = (function(stdlib, foreign, heap) { + "use asm"; + function hi1(i) { + i = +i; + return %_DoubleHi(i)|0; + } + function hi2(i, j) { + i = +i; + j = +j; + return %_DoubleHi(i)+%_DoubleHi(j)|0; + } + return { hi1: hi1, hi2: hi2 }; +})(stdlib, foreign, heap); + +assertEquals(0, m.hi1(0.0)); +assertEquals(-2147483648, m.hi1(-0.0)); +assertEquals(2146435072, m.hi1(Infinity)); +assertEquals(-1048576, m.hi1(-Infinity)); +assertEquals(0, m.hi2(0.0, 0.0)); +assertEquals(-2147483648, m.hi2(0.0, -0.0)); +assertEquals(-2147483648, m.hi2(-0.0, 0.0)); +assertEquals(0, m.hi2(-0.0, -0.0)); +for (var i = -2147483648; i < 2147483648; i += 3999773) { + assertEquals(%_DoubleHi(i), m.hi1(i)); + assertEquals(i, m.hi1(%ConstructDouble(i, 0))); + assertEquals(i, m.hi1(%ConstructDouble(i, i))); + assertEquals(i+i|0, m.hi2(%ConstructDouble(i, 0), %ConstructDouble(i, 0))); + assertEquals(i+i|0, m.hi2(%ConstructDouble(i, i), %ConstructDouble(i, i))); +} diff --git a/deps/v8/test/mjsunit/asm/double-lo.js b/deps/v8/test/mjsunit/asm/double-lo.js new file mode 100644 index 0000000000..39d5b5268f --- /dev/null +++ b/deps/v8/test/mjsunit/asm/double-lo.js @@ -0,0 +1,40 @@ +// Copyright 2015 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 + +var stdlib = this; +var foreign = {}; +var heap = new ArrayBuffer(64 * 1024); + + +var m = (function(stdlib, foreign, heap) { + "use asm"; + function lo1(i) { + i = +i; + return %_DoubleLo(i)|0; + } + function lo2(i, j) { + i = +i; + j = +j; + return %_DoubleLo(i)+%_DoubleLo(j)|0; + } + return { lo1: lo1, lo2: lo2 }; +})(stdlib, foreign, heap); + +assertEquals(0, m.lo1(0.0)); +assertEquals(0, m.lo1(-0.0)); +assertEquals(0, m.lo1(Infinity)); +assertEquals(0, m.lo1(-Infinity)); +assertEquals(0, m.lo2(0.0, 0.0)); +assertEquals(0, m.lo2(0.0, -0.0)); +assertEquals(0, m.lo2(-0.0, 0.0)); +assertEquals(0, m.lo2(-0.0, -0.0)); +for (var i = -2147483648; i < 2147483648; i += 3999773) { + assertEquals(%_DoubleLo(i), m.lo1(i)); + assertEquals(i, m.lo1(%ConstructDouble(0, i))); + assertEquals(i, m.lo1(%ConstructDouble(i, i))); + assertEquals(i+i|0, m.lo2(%ConstructDouble(0, i), %ConstructDouble(0, i))); + assertEquals(i+i|0, m.lo2(%ConstructDouble(i, i), %ConstructDouble(i, i))); +} diff --git a/deps/v8/test/mjsunit/asm/if-cloning.js b/deps/v8/test/mjsunit/asm/if-cloning.js new file mode 100644 index 0000000000..99d4edc67a --- /dev/null +++ b/deps/v8/test/mjsunit/asm/if-cloning.js @@ -0,0 +1,34 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var if0 = (function Module() { + "use asm"; + function if0(i, j) { + i = i|0; + j = j|0; + if (i == 0 ? j == 0 : 0) return 1; + return 0; + } + return {if0: if0}; +})().if0; +assertEquals(1, if0(0, 0)); +assertEquals(0, if0(11, 0)); +assertEquals(0, if0(0, -1)); +assertEquals(0, if0(-1024, 1)); + + +var if1 = (function Module() { + "use asm"; + function if1(i, j) { + i = i|0; + j = j|0; + if (i == 0 ? j == 0 : 1) return 0; + return 1; + } + return {if1: if1}; +})().if1; +assertEquals(0, if1(0, 0)); +assertEquals(0, if1(11, 0)); +assertEquals(1, if1(0, -1)); +assertEquals(0, if1(-1024, 9)); diff --git a/deps/v8/test/mjsunit/asm/math-clz32.js b/deps/v8/test/mjsunit/asm/math-clz32.js new file mode 100644 index 0000000000..004aa65b46 --- /dev/null +++ b/deps/v8/test/mjsunit/asm/math-clz32.js @@ -0,0 +1,31 @@ +// Copyright 2015 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 + +var stdlib = { Math: Math }; + +var f = (function Module(stdlib) { + "use asm"; + + var clz32 = stdlib.Math.clz32; + + function f(a) { + a = a >>> 0; + return clz32(a)|0; + } + + return f; +})(stdlib); + +assertEquals(32, f(0)); +assertEquals(32, f(NaN)); +assertEquals(32, f(undefined)); +for (var i = 0; i < 32; ++i) { + assertEquals(i, f((-1) >>> i)); +} +for (var i = -2147483648; i < 2147483648; i += 3999773) { + assertEquals(%MathClz32(i), f(i)); + assertEquals(%_MathClz32(i), f(i)); +} diff --git a/deps/v8/test/mjsunit/bugs/harmony/debug-blockscopes.js b/deps/v8/test/mjsunit/bugs/harmony/debug-blockscopes.js index 9ef8efbc0c..52c94e7548 100644 --- a/deps/v8/test/mjsunit/bugs/harmony/debug-blockscopes.js +++ b/deps/v8/test/mjsunit/bugs/harmony/debug-blockscopes.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --expose-debug-as debug --harmony-scoping +// Flags: --expose-debug-as debug // The functions used for testing backtraces. They are at the top to make the // testing of source line/column easier. diff --git a/deps/v8/test/mjsunit/compiler/deopt-tonumber-binop.js b/deps/v8/test/mjsunit/compiler/deopt-tonumber-binop.js new file mode 100644 index 0000000000..c93ef9dfd5 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/deopt-tonumber-binop.js @@ -0,0 +1,40 @@ +// Copyright 2015 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 +// +var f = (function() { + "use asm"; + function f(x, y) { + return x - y; + } + return f; +})(); + +var counter = 0; + +var deopt = { toString : function() { + %DeoptimizeFunction(f); + counter++; + return "2"; +} }; + +var o = { toString : function() { + counter++; + return "1"; +} }; + +counter = 0; +assertEquals(1, f(deopt, o)); +assertEquals(2, counter); + +%OptimizeFunctionOnNextCall(f); +counter = 0; +assertEquals(-1, f(o, deopt)); +assertEquals(2, counter); + +%OptimizeFunctionOnNextCall(f); +counter = 0; +assertEquals(0, f(deopt, deopt)); +assertEquals(2, counter); diff --git a/deps/v8/test/mjsunit/compiler/eager-deopt-simple.js b/deps/v8/test/mjsunit/compiler/eager-deopt-simple.js new file mode 100644 index 0000000000..067400cfc6 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/eager-deopt-simple.js @@ -0,0 +1,18 @@ +// Copyright 2015 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 + +function g(a, b, c) { + return a + b + c; +} + +function f() { + return g(1, (%_DeoptimizeNow(), 2), 3); +} + +f(); +f(); +%OptimizeFunctionOnNextCall(f); +assertEquals(6, f()); diff --git a/deps/v8/test/mjsunit/compiler/osr-forin-nested.js b/deps/v8/test/mjsunit/compiler/osr-forin-nested.js new file mode 100644 index 0000000000..ad55b30bd8 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/osr-forin-nested.js @@ -0,0 +1,35 @@ +// Copyright 2015 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: --turbo-osr --allow-natives-syntax + +function test(e, f, v) { + assertEquals(e, f(v)); + assertEquals(e, f(v)); + assertEquals(e, f(v)); +} + +function foo(t) { + for (var x in t) { + for (var i = 0; i < 2; i++) { + %OptimizeOsr(); + } + } + return 5; +} + +test(5, foo, {x:20}); + +function bar(t) { + var sum = 0; + for (var x in t) { + for (var i = 0; i < 2; i++) { + %OptimizeOsr(); + sum += t[x]; + } + } + return sum; +} + +test(62, bar, {x:20,y:11}); diff --git a/deps/v8/test/mjsunit/compiler/osr-infinite.js b/deps/v8/test/mjsunit/compiler/osr-infinite.js new file mode 100644 index 0000000000..aa74c877d5 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/osr-infinite.js @@ -0,0 +1,78 @@ +// Copyright 2015 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: --use-osr --allow-natives-syntax --turbo-osr + +var global_counter = 0; + +function thrower() { + var x = global_counter++; + if (x == 5) %OptimizeOsr(thrower.caller); + if (x == 10) throw "terminate"; +} + +%NeverOptimizeFunction(thrower); // Don't want to inline the thrower. +%NeverOptimizeFunction(test); // Don't want to inline the func into test. + +function test(func) { + for (var i = 0; i < 3; i++) { + global_counter = 0; + assertThrows(func); + } +} + +function n1() { + while (true) thrower(); +} + +function n2() { + while (true) while (true) thrower(); +} + +function n3() { + while (true) while (true) while (true) thrower(); +} + +function n4() { + while (true) while (true) while (true) while (true) thrower(); +} + +function b1(a) { + while (true) { + thrower(); + if (a) break + } +} + + +function b2(a) { + while (true) { + while (true) { + thrower(); + if (a) break + } + } +} + + +function b3(a) { + while (true) { + while (true) { + while (true) { + thrower(); + if (a) break + } + if (a) break + } + } +} + + +test(n1); +test(n2); +test(n3); +test(n4); +test(b1); +test(b2); +test(b3); diff --git a/deps/v8/test/mjsunit/compiler/osr-labeled.js b/deps/v8/test/mjsunit/compiler/osr-labeled.js new file mode 100644 index 0000000000..1a9709285e --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/osr-labeled.js @@ -0,0 +1,47 @@ +// Copyright 2015 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 --use-osr --turbo-osr + +function foo() { + var sum = 0; + A: for (var i = 0; i < 5; i++) { + B: for (var j = 0; j < 5; j++) { + C: for (var k = 0; k < 10; k++) { + if (k === 5) %OptimizeOsr(); + if (k === 6) break B; + sum++; + } + } + } + return sum; +} + +assertEquals(30, foo()); +assertEquals(30, foo()); + +function bar(a) { + var sum = 0; + A: for (var i = 0; i < 5; i++) { + B: for (var j = 0; j < 5; j++) { + C: for (var k = 0; k < 10; k++) { + sum++; + %OptimizeOsr(); + if (a === 1) break A; + if (a === 2) break B; + if (a === 3) break C; + } + } + } + return sum; +} + +assertEquals(1, bar(1)); +assertEquals(1, bar(1)); + +assertEquals(5, bar(2)); +assertEquals(5, bar(2)); + +assertEquals(25, bar(3)); +assertEquals(25, bar(3)); diff --git a/deps/v8/test/mjsunit/compiler/osr-literals-adapted.js b/deps/v8/test/mjsunit/compiler/osr-literals-adapted.js new file mode 100644 index 0000000000..950d8b0762 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/osr-literals-adapted.js @@ -0,0 +1,56 @@ +// Copyright 2015 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 --use-osr --turbo-osr + +function mod() { + function f0() { + for (var i = 0; i < 3; i = i + 1 | 0) { + %OptimizeOsr(); + } + return {blah: i}; + } + + function f1(a) { + for (var i = 0; i < 3; i = i + 1 | 0) { + %OptimizeOsr(); + } + return {blah: i}; + } + + function f2(a,b) { + for (var i = 0; i < 3; i = i + 1 | 0) { + %OptimizeOsr(); + } + return {blah: i}; + } + + function f3(a,b,c) { + for (var i = 0; i < 3; i = i + 1 | 0) { + %OptimizeOsr(); + } + return {blah: i}; + } + + function f4(a,b,c,d) { + for (var i = 0; i < 3; i = i + 1 | 0) { + %OptimizeOsr(); + } + return {blah: i}; + } + + function bar() { + assertEquals(3, f0().blah); + assertEquals(3, f1().blah); + assertEquals(3, f2().blah); + assertEquals(3, f3().blah); + assertEquals(3, f4().blah); + } + bar(); +} + + +mod(); +mod(); +mod(); diff --git a/deps/v8/test/mjsunit/compiler/osr-literals.js b/deps/v8/test/mjsunit/compiler/osr-literals.js new file mode 100644 index 0000000000..d9f68a0b37 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/osr-literals.js @@ -0,0 +1,56 @@ +// Copyright 2015 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 --use-osr --turbo-osr + +function mod() { + function f0() { + for (var i = 0; i < 3; i = i + 1 | 0) { + %OptimizeOsr(); + } + return {blah: i}; + } + + function f1(a) { + for (var i = 0; i < 3; i = i + 1 | 0) { + %OptimizeOsr(); + } + return {blah: i}; + } + + function f2(a,b) { + for (var i = 0; i < 3; i = i + 1 | 0) { + %OptimizeOsr(); + } + return {blah: i}; + } + + function f3(a,b,c) { + for (var i = 0; i < 3; i = i + 1 | 0) { + %OptimizeOsr(); + } + return {blah: i}; + } + + function f4(a,b,c,d) { + for (var i = 0; i < 3; i = i + 1 | 0) { + %OptimizeOsr(); + } + return {blah: i}; + } + + function bar() { + assertEquals(3, f0().blah); + assertEquals(3, f1(1).blah); + assertEquals(3, f2(1,2).blah); + assertEquals(3, f3(1,2,3).blah); + assertEquals(3, f4(1,2,3,4).blah); + } + bar(); +} + + +mod(); +mod(); +mod(); diff --git a/deps/v8/test/mjsunit/compiler/regress-463056.js b/deps/v8/test/mjsunit/compiler/regress-463056.js new file mode 100644 index 0000000000..fb871618e4 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-463056.js @@ -0,0 +1,9 @@ +// Copyright 2015 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 f() { + return ((0%0)&1) + (1>>>(0%0)); +} + +f(); diff --git a/deps/v8/test/mjsunit/compiler/regress-468727.js b/deps/v8/test/mjsunit/compiler/regress-468727.js new file mode 100644 index 0000000000..a69efe5a56 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-468727.js @@ -0,0 +1,16 @@ +// Copyright 2015 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: --noanalyze-environment-liveness + +function f() { + var __v_7 = -126 - __v_3; + var __v_17 = ((__v_15 & __v_14) != 4) | 16; + if (__v_17) { + var __v_11 = 1 << __v_7; + } + __v_12 >>= __v_3; +} + +assertThrows(f); diff --git a/deps/v8/test/mjsunit/compiler/regress-469089.js b/deps/v8/test/mjsunit/compiler/regress-469089.js new file mode 100644 index 0000000000..6aff2b7203 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-469089.js @@ -0,0 +1,16 @@ +// Copyright 2015 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-gc + +(function() { + var __v_6 = false; + function f(val, idx) { + if (idx === 1) { + gc(); + __v_6 = (val === 0); + } + } + f(.1, 1); +})(); diff --git a/deps/v8/test/mjsunit/compiler/truncating-store-deopt.js b/deps/v8/test/mjsunit/compiler/truncating-store-deopt.js new file mode 100644 index 0000000000..a640caf583 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/truncating-store-deopt.js @@ -0,0 +1,28 @@ +// Copyright 2015 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 + +function g(a, b, c) { + return a + b + c; +} + +var asm = (function Module(global, env, buffer) { + "use asm"; + + var i32 = new global.Int32Array(buffer); + + // This is not valid asm.js, but we should still generate correct code. + function store(x) { + return g(1, i32[0] = x, 2); + } + + return { store: store }; +})({ + "Int32Array": Int32Array +}, {}, new ArrayBuffer(64 * 1024)); + +var o = { toString : function() { %DeoptimizeFunction(asm.store); return "1"; } } + +asm.store(o); diff --git a/deps/v8/test/mjsunit/compiler/try-deopt.js b/deps/v8/test/mjsunit/compiler/try-deopt.js new file mode 100644 index 0000000000..dc44e7326f --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/try-deopt.js @@ -0,0 +1,56 @@ +// Copyright 2015 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. + +// TODO(mstarzinger): Add FLAG_turbo_exceptions once we want ClusterFuzz. +// Flags: --allow-natives-syntax --turbo-deoptimization + +function DeoptFromTry(x) { + try { + %DeoptimizeFunction(DeoptFromTry); + throw x; + } catch (e) { + return e + 1; + } + return x + 2; +} +%OptimizeFunctionOnNextCall(DeoptFromTry); +assertEquals(24, DeoptFromTry(23)); + + +function DeoptFromCatch(x) { + try { + throw x; + } catch (e) { + %DeoptimizeFunction(DeoptFromCatch); + return e + 1; + } + return x + 2; +} +%OptimizeFunctionOnNextCall(DeoptFromCatch); +assertEquals(24, DeoptFromCatch(23)); + + +function DeoptFromFinally_Return(x) { + try { + throw x; + } finally { + %DeoptimizeFunction(DeoptFromFinally_Return); + return x + 1; + } + return x + 2; +} +%OptimizeFunctionOnNextCall(DeoptFromFinally_Return); +assertEquals(24, DeoptFromFinally_Return(23)); + + +function DeoptFromFinally_ReThrow(x) { + try { + throw x; + } finally { + %DeoptimizeFunction(DeoptFromFinally_ReThrow); + } + return x + 2; +} +%OptimizeFunctionOnNextCall(DeoptFromFinally_ReThrow); +assertThrows("DeoptFromFinally_ReThrow(new Error)", Error); diff --git a/deps/v8/test/mjsunit/constant-folding-2.js b/deps/v8/test/mjsunit/constant-folding-2.js index 73cf040f5a..3f82c2fa43 100644 --- a/deps/v8/test/mjsunit/constant-folding-2.js +++ b/deps/v8/test/mjsunit/constant-folding-2.js @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --nodead-code-elimination --fold-constants --allow-natives-syntax +// Flags: --nodead-code-elimination --fold-constants --allow-natives-syntax --nostress-opt function test(f) { f(); diff --git a/deps/v8/test/mjsunit/debug-allscopes-on-debugger.js b/deps/v8/test/mjsunit/debug-allscopes-on-debugger.js new file mode 100644 index 0000000000..f0613b2926 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-allscopes-on-debugger.js @@ -0,0 +1,58 @@ +// Copyright 2015 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 debug + +Debug = debug.Debug +var exception = null; +var break_count = 0; + +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + assertTrue(exec_state.frameCount() != 0, "FAIL: Empty stack trace"); + // Count number of expected breakpoints in this source file. + if (!break_count) { + var source_text = exec_state.frame(0).func().script().source(); + expected_breaks = source_text.match(/\/\/\s*Break\s+\d+\./g).length; + print("Expected breaks: " + expected_breaks); + } + var frameMirror = exec_state.frame(0); + + frameMirror.allScopes(); + var source = frameMirror.sourceLineText(); + print("paused at: " + source); + assertTrue(source.indexOf("// Break " + break_count + ".") > 0, + "Unexpected pause at: " + source + "\n" + + "Expected: // Break " + break_count + "."); + ++break_count; + + if (break_count !== expected_breaks) { + exec_state.prepareStep(Debug.StepAction.StepIn, 1); + print("Next step prepared"); + } + } + } catch(e) { + exception = e; + print(e, e.stack); + } +}; + +Debug.setListener(listener); + +var sum = 0; +(function (){ + 'use strict'; + + debugger; // Break 0. + var i = 0; // Break 1. + i++; // Break 2. + i++; // Break 3. + return i; // Break 4. +}()); // Break 5. + +assertNull(exception); // Break 6. +assertEquals(expected_breaks, break_count); + +Debug.setListener(null); diff --git a/deps/v8/test/mjsunit/debug-liveedit-check-stack.js b/deps/v8/test/mjsunit/debug-liveedit-check-stack.js index 6948a70d6b..d843ca6a60 100644 --- a/deps/v8/test/mjsunit/debug-liveedit-check-stack.js +++ b/deps/v8/test/mjsunit/debug-liveedit-check-stack.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --expose-debug-as debug +// Flags: --expose-debug-as debug --allow-natives-syntax // Get the Debug object exposed from the debug context global object. Debug = debug.Debug @@ -87,13 +87,13 @@ function WrapInCatcher(f, holder) { function WrapInNativeCall(f) { return function() { - return Debug.ExecuteInDebugContext(f, true); + return %Call(undefined, f); }; } function WrapInDebuggerCall(f) { return function() { - return Debug.ExecuteInDebugContext(f, false); + return %ExecuteInDebugContext(f); }; } diff --git a/deps/v8/test/mjsunit/debug-references.js b/deps/v8/test/mjsunit/debug-references.js index bb339768b8..cb9f3701e2 100644 --- a/deps/v8/test/mjsunit/debug-references.js +++ b/deps/v8/test/mjsunit/debug-references.js @@ -26,6 +26,8 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Flags: --expose-debug-as debug --turbo-deoptimization +// Flags: --stack-trace-on-illegal + // Get the Debug object exposed from the debug context global object. Debug = debug.Debug @@ -98,7 +100,8 @@ function listener(event, exec_state, event_data, data) { listenerComplete = true; } } catch (e) { - exception = e + exception = e; + print(e + "\n" + e.stack); }; }; diff --git a/deps/v8/test/mjsunit/debug-scopes.js b/deps/v8/test/mjsunit/debug-scopes.js index 7c08120e2a..78a70af26a 100644 --- a/deps/v8/test/mjsunit/debug-scopes.js +++ b/deps/v8/test/mjsunit/debug-scopes.js @@ -1049,6 +1049,30 @@ catch_block_7(); EndTest(); +BeginTest("Classes and methods 1"); + +listener_delegate = function(exec_state) { + "use strict" + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Block, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({C1: class { m() { debugger; }} }, 1, exec_state); +}; + +(function() { + "use strict"; + class C1 { + m() { + debugger; + } + } + new C1().m(); +})(); + +EndTest(); + + assertEquals(begin_test_count, break_count, 'one or more tests did not enter the debugger'); assertEquals(begin_test_count, end_test_count, diff --git a/deps/v8/test/mjsunit/debug-set-variable-value.js b/deps/v8/test/mjsunit/debug-set-variable-value.js index 4667a71d6b..65434289d0 100644 --- a/deps/v8/test/mjsunit/debug-set-variable-value.js +++ b/deps/v8/test/mjsunit/debug-set-variable-value.js @@ -29,6 +29,7 @@ // Get the Debug object exposed from the debug context global object. var Debug = debug.Debug; +var DebugCommandProcessor = debug.DebugCommandProcessor; // Accepts a function/closure 'fun' that must have a debugger statement inside. // A variable 'variable_name' must be initialized before debugger statement @@ -291,18 +292,18 @@ RunPauseTest(0, 5, 'p', 2012, 2012, (function Factory() { // Test value description protocol JSON -assertEquals(true, Debug.TestApi.CommandProcessorResolveValue({value: true})); +assertEquals(true, DebugCommandProcessor.resolveValue_({value: true})); -assertSame(null, Debug.TestApi.CommandProcessorResolveValue({type: "null"})); +assertSame(null, DebugCommandProcessor.resolveValue_({type: "null"})); assertSame(undefined, - Debug.TestApi.CommandProcessorResolveValue({type: "undefined"})); + DebugCommandProcessor.resolveValue_({type: "undefined"})); -assertSame("123", Debug.TestApi.CommandProcessorResolveValue( +assertSame("123", DebugCommandProcessor.resolveValue_( {type: "string", stringDescription: "123"})); -assertSame(123, Debug.TestApi.CommandProcessorResolveValue( +assertSame(123, DebugCommandProcessor.resolveValue_( {type: "number", stringDescription: "123"})); -assertSame(Number, Debug.TestApi.CommandProcessorResolveValue( +assertSame(Number, DebugCommandProcessor.resolveValue_( {handle: Debug.MakeMirror(Number).handle()})); -assertSame(RunClosureTest, Debug.TestApi.CommandProcessorResolveValue( +assertSame(RunClosureTest, DebugCommandProcessor.resolveValue_( {handle: Debug.MakeMirror(RunClosureTest).handle()})); diff --git a/deps/v8/test/mjsunit/debug-sourceinfo.js b/deps/v8/test/mjsunit/debug-sourceinfo.js index ddf80dc51c..1dbe1b7a0a 100644 --- a/deps/v8/test/mjsunit/debug-sourceinfo.js +++ b/deps/v8/test/mjsunit/debug-sourceinfo.js @@ -1,352 +1,266 @@ -// Copyright 2008 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.
-
-// Flags: --expose-debug-as debug
-// For this test to work this file MUST have CR LF line endings.
-function a() { b(); };
-function b() {
- c(true);
-};
- function c(x) {
- if (x) {
- return 1;
- } else {
- return 1;
- }
- };
-function d(x) {
- x = 1 ;
- x = 2 ;
- x = 3 ;
- x = 4 ;
- x = 5 ;
- x = 6 ;
- x = 7 ;
- x = 8 ;
- x = 9 ;
- x = 10;
- x = 11;
- x = 12;
- x = 13;
- x = 14;
- x = 15;
-}
-
-// Get the Debug object exposed from the debug context global object.
-Debug = debug.Debug
-
-// This is the number of comment lines above the first test function.
-var comment_lines = 29;
-
-// This is the last position in the entire file (note: this equals
-// file size of <debug-sourceinfo.js> - 1, since starting at 0).
-var last_position = 14312;
-// This is the last line of entire file (note: starting at 0).
-var last_line = 351;
-// This is the last column of last line (note: starting at 0 and +2, due
-// to trailing <CR><LF>).
-var last_column = 2;
-
-// This magic number is the length or the first line comment (actually number
-// of characters before 'function a(...'.
-var comment_line_length = 1726;
-var start_a = 10 + comment_line_length;
-var start_b = 37 + comment_line_length;
-var start_c = 71 + comment_line_length;
-var start_d = 163 + comment_line_length;
-
-// The position of the first line of d(), i.e. "x = 1 ;".
-var start_code_d = start_d + 7;
-// The line # of the first line of d() (note: starting at 0).
-var start_line_d = 41;
-var line_length_d = 11;
-var num_lines_d = 15;
-
-assertEquals(start_a, Debug.sourcePosition(a));
-assertEquals(start_b, Debug.sourcePosition(b));
-assertEquals(start_c, Debug.sourcePosition(c));
-assertEquals(start_d, Debug.sourcePosition(d));
-
-var script = Debug.findScript(a);
-assertTrue(script.data === Debug.findScript(b).data);
-assertTrue(script.data === Debug.findScript(c).data);
-assertTrue(script.data === Debug.findScript(d).data);
-assertTrue(script.source === Debug.findScript(b).source);
-assertTrue(script.source === Debug.findScript(c).source);
-assertTrue(script.source === Debug.findScript(d).source);
-
-// Test that when running through source positions the position, line and
-// column progresses as expected.
-var position;
-var line;
-var column;
-for (var p = 0; p < 100; p++) {
- var location = script.locationFromPosition(p);
- if (p > 0) {
- assertEquals(position + 1, location.position);
- if (line == location.line) {
- assertEquals(column + 1, location.column);
- } else {
- assertEquals(line + 1, location.line);
- assertEquals(0, location.column);
- }
- } else {
- assertEquals(0, location.position);
- assertEquals(0, location.line);
- assertEquals(0, location.column);
- }
-
- // Remember the location.
- position = location.position;
- line = location.line;
- column = location.column;
-}
-
-// Every line of d() is the same length. Verify we can loop through all
-// positions and find the right line # for each.
-var p = start_code_d;
-for (line = 0; line < num_lines_d; line++) {
- for (column = 0; column < line_length_d; column++) {
- var location = script.locationFromPosition(p);
- assertEquals(p, location.position);
- assertEquals(start_line_d + line, location.line);
- assertEquals(column, location.column);
- p++;
- }
-}
-
-// Test first position.
-assertEquals(0, script.locationFromPosition(0).position);
-assertEquals(0, script.locationFromPosition(0).line);
-assertEquals(0, script.locationFromPosition(0).column);
-
-// Test second position.
-assertEquals(1, script.locationFromPosition(1).position);
-assertEquals(0, script.locationFromPosition(1).line);
-assertEquals(1, script.locationFromPosition(1).column);
-
-// Test first position in function a().
-assertEquals(start_a, script.locationFromPosition(start_a).position);
-assertEquals(0, script.locationFromPosition(start_a).line - comment_lines);
-assertEquals(10, script.locationFromPosition(start_a).column);
-
-// Test first position in function b().
-assertEquals(start_b, script.locationFromPosition(start_b).position);
-assertEquals(1, script.locationFromPosition(start_b).line - comment_lines);
-assertEquals(13, script.locationFromPosition(start_b).column);
-
-// Test first position in function c().
-assertEquals(start_c, script.locationFromPosition(start_c).position);
-assertEquals(4, script.locationFromPosition(start_c).line - comment_lines);
-assertEquals(12, script.locationFromPosition(start_c).column);
-
-// Test first position in function d().
-assertEquals(start_d, script.locationFromPosition(start_d).position);
-assertEquals(11, script.locationFromPosition(start_d).line - comment_lines);
-assertEquals(10, script.locationFromPosition(start_d).column);
-
-// Test first line.
-assertEquals(0, script.locationFromLine().position);
-assertEquals(0, script.locationFromLine().line);
-assertEquals(0, script.locationFromLine().column);
-assertEquals(0, script.locationFromLine(0).position);
-assertEquals(0, script.locationFromLine(0).line);
-assertEquals(0, script.locationFromLine(0).column);
-
-// Test first line column 1.
-assertEquals(1, script.locationFromLine(0, 1).position);
-assertEquals(0, script.locationFromLine(0, 1).line);
-assertEquals(1, script.locationFromLine(0, 1).column);
-
-// Test first line offset 1.
-assertEquals(1, script.locationFromLine(0, 0, 1).position);
-assertEquals(0, script.locationFromLine(0, 0, 1).line);
-assertEquals(1, script.locationFromLine(0, 0, 1).column);
-
-// Test offset function a().
-assertEquals(start_a, script.locationFromLine(void 0, void 0, start_a).position);
-assertEquals(0, script.locationFromLine(void 0, void 0, start_a).line - comment_lines);
-assertEquals(10, script.locationFromLine(void 0, void 0, start_a).column);
-assertEquals(start_a, script.locationFromLine(0, void 0, start_a).position);
-assertEquals(0, script.locationFromLine(0, void 0, start_a).line - comment_lines);
-assertEquals(10, script.locationFromLine(0, void 0, start_a).column);
-assertEquals(start_a, script.locationFromLine(0, 0, start_a).position);
-assertEquals(0, script.locationFromLine(0, 0, start_a).line - comment_lines);
-assertEquals(10, script.locationFromLine(0, 0, start_a).column);
-
-// Test second line offset function a().
-assertEquals(start_a + 14, script.locationFromLine(1, 0, start_a).position);
-assertEquals(1, script.locationFromLine(1, 0, start_a).line - comment_lines);
-assertEquals(0, script.locationFromLine(1, 0, start_a).column);
-
-// Test second line column 2 offset function a().
-assertEquals(start_a + 14 + 2, script.locationFromLine(1, 2, start_a).position);
-assertEquals(1, script.locationFromLine(1, 2, start_a).line - comment_lines);
-assertEquals(2, script.locationFromLine(1, 2, start_a).column);
-
-// Test offset function b().
-assertEquals(start_b, script.locationFromLine(0, 0, start_b).position);
-assertEquals(1, script.locationFromLine(0, 0, start_b).line - comment_lines);
-assertEquals(13, script.locationFromLine(0, 0, start_b).column);
-
-// Test second line offset function b().
-assertEquals(start_b + 6, script.locationFromLine(1, 0, start_b).position);
-assertEquals(2, script.locationFromLine(1, 0, start_b).line - comment_lines);
-assertEquals(0, script.locationFromLine(1, 0, start_b).column);
-
-// Test second line column 11 offset function b().
-assertEquals(start_b + 6 + 11, script.locationFromLine(1, 11, start_b).position);
-assertEquals(2, script.locationFromLine(1, 11, start_b).line - comment_lines);
-assertEquals(11, script.locationFromLine(1, 11, start_b).column);
-
-// Test second line column 12 offset function b. Second line in b is 11 long
-// using column 12 wraps to next line.
-assertEquals(start_b + 6 + 12, script.locationFromLine(1, 12, start_b).position);
-assertEquals(3, script.locationFromLine(1, 12, start_b).line - comment_lines);
-assertEquals(0, script.locationFromLine(1, 12, start_b).column);
-
-// Test the Debug.findSourcePosition which wraps SourceManager.
-assertEquals(0 + start_a, Debug.findFunctionSourceLocation(a, 0, 0).position);
-assertEquals(0 + start_b, Debug.findFunctionSourceLocation(b, 0, 0).position);
-assertEquals(6 + start_b, Debug.findFunctionSourceLocation(b, 1, 0).position);
-assertEquals(8 + start_b, Debug.findFunctionSourceLocation(b, 1, 2).position);
-assertEquals(18 + start_b, Debug.findFunctionSourceLocation(b, 2, 0).position);
-assertEquals(0 + start_c, Debug.findFunctionSourceLocation(c, 0, 0).position);
-assertEquals(7 + start_c, Debug.findFunctionSourceLocation(c, 1, 0).position);
-assertEquals(21 + start_c, Debug.findFunctionSourceLocation(c, 2, 0).position);
-assertEquals(38 + start_c, Debug.findFunctionSourceLocation(c, 3, 0).position);
-assertEquals(52 + start_c, Debug.findFunctionSourceLocation(c, 4, 0).position);
-assertEquals(69 + start_c, Debug.findFunctionSourceLocation(c, 5, 0).position);
-assertEquals(76 + start_c, Debug.findFunctionSourceLocation(c, 6, 0).position);
-assertEquals(0 + start_d, Debug.findFunctionSourceLocation(d, 0, 0).position);
-assertEquals(7 + start_d, Debug.findFunctionSourceLocation(d, 1, 0).position);
-for (i = 1; i <= num_lines_d; i++) {
- assertEquals(7 + (i * line_length_d) + start_d, Debug.findFunctionSourceLocation(d, (i + 1), 0).position);
-}
-assertEquals(175 + start_d, Debug.findFunctionSourceLocation(d, 17, 0).position);
-
-// Make sure invalid inputs work properly.
-assertEquals(0, script.locationFromPosition(-1).line);
-assertEquals(null, script.locationFromPosition(last_position + 1));
-
-// Test last position.
-assertEquals(last_position, script.locationFromPosition(last_position).position);
-assertEquals(last_line, script.locationFromPosition(last_position).line);
-assertEquals(last_column, script.locationFromPosition(last_position).column);
-
-// Test source line and restriction. All the following tests start from line 1
-// column 2 in function b, which is the call to c.
-// c(true);
-// ^
-
-var location;
-
-location = script.locationFromLine(1, 0, start_b);
-assertEquals(' c(true);', location.sourceText());
-
-result = ['c', ' c', ' c(', ' c(', ' c(t']
-for (var i = 1; i <= 5; i++) {
- location = script.locationFromLine(1, 2, start_b);
- location.restrict(i);
- assertEquals(result[i - 1], location.sourceText());
-}
-
-location = script.locationFromLine(1, 2, start_b);
-location.restrict(1, 0);
-assertEquals('c', location.sourceText());
-
-location = script.locationFromLine(1, 2, start_b);
-location.restrict(2, 0);
-assertEquals('c(', location.sourceText());
-
-location = script.locationFromLine(1, 2, start_b);
-location.restrict(2, 1);
-assertEquals(' c', location.sourceText());
-
-location = script.locationFromLine(1, 2, start_b);
-location.restrict(2, 2);
-assertEquals(' c', location.sourceText());
-
-location = script.locationFromLine(1, 2, start_b);
-location.restrict(2, 3);
-assertEquals(' c', location.sourceText());
-
-location = script.locationFromLine(1, 2, start_b);
-location.restrict(3, 1);
-assertEquals(' c(', location.sourceText());
-
-location = script.locationFromLine(1, 2, start_b);
-location.restrict(5, 0);
-assertEquals('c(tru', location.sourceText());
-
-location = script.locationFromLine(1, 2, start_b);
-location.restrict(5, 2);
-assertEquals(' c(t', location.sourceText());
-
-location = script.locationFromLine(1, 2, start_b);
-location.restrict(5, 4);
-assertEquals(' c(t', location.sourceText());
-
-// All the following tests start from line 1 column 10 in function b, which is
-// the final character.
-// c(true);
-// ^
-
-location = script.locationFromLine(1, 10, start_b);
-location.restrict(5, 0);
-assertEquals('rue);', location.sourceText());
-
-location = script.locationFromLine(1, 10, start_b);
-location.restrict(7, 0);
-assertEquals('(true);', location.sourceText());
-
-// All the following tests start from line 1 column 0 in function b, which is
-// the first character.
-// c(true);
-//^
-
-location = script.locationFromLine(1, 0, start_b);
-location.restrict(5, 0);
-assertEquals(' c(t', location.sourceText());
-
-location = script.locationFromLine(1, 0, start_b);
-location.restrict(5, 4);
-assertEquals(' c(t', location.sourceText());
-
-location = script.locationFromLine(1, 0, start_b);
-location.restrict(7, 0);
-assertEquals(' c(tru', location.sourceText());
-
-location = script.locationFromLine(1, 0, start_b);
-location.restrict(7, 6);
-assertEquals(' c(tru', location.sourceText());
-
-// Test that script.sourceLine(line) works.
-for (line = 0; line < num_lines_d; line++) {
- var line_content_regexp = new RegExp(" x = " + (line + 1));
- assertTrue(line_content_regexp.test(script.sourceLine(start_line_d + line)));
-}
+// Copyright 2008 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. + +// Flags: --expose-debug-as debug +function a() { b(); }; +function b() { + c(true); +}; + function c(x) { + if (x) { + return 1; + } else { + return 1; + } + }; +function d(x) { + x = 1 ; + x = 2 ; + x = 3 ; + x = 4 ; + x = 5 ; + x = 6 ; + x = 7 ; + x = 8 ; + x = 9 ; + x = 10; + x = 11; + x = 12; + x = 13; + x = 14; + x = 15; +} + +// Get the Debug object exposed from the debug context global object. +Debug = debug.Debug + +// This is the number of comment lines above the first test function. +var comment_lines = 28; + +// This is the last position in the entire file (note: this equals +// file size of <debug-sourceinfo.js> - 1, since starting at 0). +var last_position = 11337; +// This is the last line of entire file (note: starting at 0). +var last_line = 265; +// This is the last column of last line (note: starting at 0 and +1, due +// to trailing <LF>). +var last_column = 1; + +// This magic number is the length or the first line comment (actually number +// of characters before 'function a(...'. +var comment_line_length = 1633; +var start_a = 9 + comment_line_length; +var start_b = 35 + comment_line_length; +var start_c = 66 + comment_line_length; +var start_d = 151 + comment_line_length; + +// The position of the first line of d(), i.e. "x = 1 ;". +var start_code_d = start_d + 6; +// The line # of the first line of d() (note: starting at 0). +var start_line_d = 40; +var line_length_d = 10; +var num_lines_d = 15; + +assertEquals(start_a, Debug.sourcePosition(a)); +assertEquals(start_b, Debug.sourcePosition(b)); +assertEquals(start_c, Debug.sourcePosition(c)); +assertEquals(start_d, Debug.sourcePosition(d)); + +var script = Debug.findScript(a); +assertTrue(script.data === Debug.findScript(b).data); +assertTrue(script.data === Debug.findScript(c).data); +assertTrue(script.data === Debug.findScript(d).data); +assertTrue(script.source === Debug.findScript(b).source); +assertTrue(script.source === Debug.findScript(c).source); +assertTrue(script.source === Debug.findScript(d).source); + +// Test that when running through source positions the position, line and +// column progresses as expected. +var position; +var line; +var column; +for (var p = 0; p < 100; p++) { + var location = script.locationFromPosition(p); + if (p > 0) { + assertEquals(position + 1, location.position); + if (line == location.line) { + assertEquals(column + 1, location.column); + } else { + assertEquals(line + 1, location.line); + assertEquals(0, location.column); + } + } else { + assertEquals(0, location.position); + assertEquals(0, location.line); + assertEquals(0, location.column); + } + + // Remember the location. + position = location.position; + line = location.line; + column = location.column; +} + +// Every line of d() is the same length. Verify we can loop through all +// positions and find the right line # for each. +var p = start_code_d; +for (line = 0; line < num_lines_d; line++) { + for (column = 0; column < line_length_d; column++) { + var location = script.locationFromPosition(p); + assertEquals(p, location.position); + assertEquals(start_line_d + line, location.line); + assertEquals(column, location.column); + p++; + } +} + +// Test first position. +assertEquals(0, script.locationFromPosition(0).position); +assertEquals(0, script.locationFromPosition(0).line); +assertEquals(0, script.locationFromPosition(0).column); + +// Test second position. +assertEquals(1, script.locationFromPosition(1).position); +assertEquals(0, script.locationFromPosition(1).line); +assertEquals(1, script.locationFromPosition(1).column); + +// Test first position in function a(). +assertEquals(start_a, script.locationFromPosition(start_a).position); +assertEquals(0, script.locationFromPosition(start_a).line - comment_lines); +assertEquals(10, script.locationFromPosition(start_a).column); + +// Test first position in function b(). +assertEquals(start_b, script.locationFromPosition(start_b).position); +assertEquals(1, script.locationFromPosition(start_b).line - comment_lines); +assertEquals(13, script.locationFromPosition(start_b).column); + +// Test first position in function c(). +assertEquals(start_c, script.locationFromPosition(start_c).position); +assertEquals(4, script.locationFromPosition(start_c).line - comment_lines); +assertEquals(12, script.locationFromPosition(start_c).column); + +// Test first position in function d(). +assertEquals(start_d, script.locationFromPosition(start_d).position); +assertEquals(11, script.locationFromPosition(start_d).line - comment_lines); +assertEquals(10, script.locationFromPosition(start_d).column); + +// Test first line. +assertEquals(0, script.locationFromLine().position); +assertEquals(0, script.locationFromLine().line); +assertEquals(0, script.locationFromLine().column); +assertEquals(0, script.locationFromLine(0).position); +assertEquals(0, script.locationFromLine(0).line); +assertEquals(0, script.locationFromLine(0).column); + +// Test first line column 1. +assertEquals(1, script.locationFromLine(0, 1).position); +assertEquals(0, script.locationFromLine(0, 1).line); +assertEquals(1, script.locationFromLine(0, 1).column); + +// Test first line offset 1. +assertEquals(1, script.locationFromLine(0, 0, 1).position); +assertEquals(0, script.locationFromLine(0, 0, 1).line); +assertEquals(1, script.locationFromLine(0, 0, 1).column); + +// Test offset function a(). +assertEquals(start_a, script.locationFromLine(void 0, void 0, start_a).position); +assertEquals(0, script.locationFromLine(void 0, void 0, start_a).line - comment_lines); +assertEquals(10, script.locationFromLine(void 0, void 0, start_a).column); +assertEquals(start_a, script.locationFromLine(0, void 0, start_a).position); +assertEquals(0, script.locationFromLine(0, void 0, start_a).line - comment_lines); +assertEquals(10, script.locationFromLine(0, void 0, start_a).column); +assertEquals(start_a, script.locationFromLine(0, 0, start_a).position); +assertEquals(0, script.locationFromLine(0, 0, start_a).line - comment_lines); +assertEquals(10, script.locationFromLine(0, 0, start_a).column); + +// Test second line offset function a(). +assertEquals(start_a + 13, script.locationFromLine(1, 0, start_a).position); +assertEquals(1, script.locationFromLine(1, 0, start_a).line - comment_lines); +assertEquals(0, script.locationFromLine(1, 0, start_a).column); + +// Test second line column 2 offset function a(). +assertEquals(start_a + 13 + 1, script.locationFromLine(1, 1, start_a).position); +assertEquals(1, script.locationFromLine(1, 2, start_a).line - comment_lines); +assertEquals(2, script.locationFromLine(1, 2, start_a).column); + +// Test offset function b(). +assertEquals(start_b, script.locationFromLine(0, 0, start_b).position); +assertEquals(1, script.locationFromLine(0, 0, start_b).line - comment_lines); +assertEquals(13, script.locationFromLine(0, 0, start_b).column); + +// Test second line offset function b(). +assertEquals(start_b + 5, script.locationFromLine(1, 0, start_b).position); +assertEquals(2, script.locationFromLine(1, 0, start_b).line - comment_lines); +assertEquals(0, script.locationFromLine(1, 0, start_b).column); + +// Test second line column 10 offset function b(). +assertEquals(start_b + 5 + 10, script.locationFromLine(1, 10, start_b).position); +assertEquals(2, script.locationFromLine(1, 10, start_b).line - comment_lines); +assertEquals(10, script.locationFromLine(1, 10, start_b).column); + +// Test second line column 11 offset function b. Second line in b is 10 long +// using column 11 wraps to next line. +assertEquals(start_b + 5 + 11, script.locationFromLine(1, 11, start_b).position); +assertEquals(3, script.locationFromLine(1, 11, start_b).line - comment_lines); +assertEquals(0, script.locationFromLine(1, 11, start_b).column); + +// Test the Debug.findSourcePosition which wraps SourceManager. +assertEquals(0 + start_a, Debug.findFunctionSourceLocation(a, 0, 0).position); +assertEquals(0 + start_b, Debug.findFunctionSourceLocation(b, 0, 0).position); +assertEquals(5 + start_b, Debug.findFunctionSourceLocation(b, 1, 0).position); +assertEquals(7 + start_b, Debug.findFunctionSourceLocation(b, 1, 2).position); +assertEquals(16 + start_b, Debug.findFunctionSourceLocation(b, 2, 0).position); +assertEquals(0 + start_c, Debug.findFunctionSourceLocation(c, 0, 0).position); +assertEquals(6 + start_c, Debug.findFunctionSourceLocation(c, 1, 0).position); +assertEquals(19 + start_c, Debug.findFunctionSourceLocation(c, 2, 0).position); +assertEquals(35 + start_c, Debug.findFunctionSourceLocation(c, 3, 0).position); +assertEquals(48 + start_c, Debug.findFunctionSourceLocation(c, 4, 0).position); +assertEquals(64 + start_c, Debug.findFunctionSourceLocation(c, 5, 0).position); +assertEquals(70 + start_c, Debug.findFunctionSourceLocation(c, 6, 0).position); +assertEquals(0 + start_d, Debug.findFunctionSourceLocation(d, 0, 0).position); +assertEquals(6 + start_d, Debug.findFunctionSourceLocation(d, 1, 0).position); +for (i = 1; i <= num_lines_d; i++) { + assertEquals(6 + (i * line_length_d) + start_d, Debug.findFunctionSourceLocation(d, (i + 1), 0).position); +} +assertEquals(158 + start_d, Debug.findFunctionSourceLocation(d, 17, 0).position); + +// Make sure invalid inputs work properly. +assertEquals(0, script.locationFromPosition(-1).line); +assertEquals(null, script.locationFromPosition(last_position + 1)); + +// Test last position. +assertEquals(last_position, script.locationFromPosition(last_position).position); +assertEquals(last_line, script.locationFromPosition(last_position).line); +assertEquals(last_column, script.locationFromPosition(last_position).column); + +// Test that script.sourceLine(line) works. +var location; + +for (line = 0; line < num_lines_d; line++) { + var line_content_regexp = new RegExp(" x = " + (line + 1)); + assertTrue(line_content_regexp.test(script.sourceLine(start_line_d + line))); +} diff --git a/deps/v8/test/mjsunit/debug-step-turbofan.js b/deps/v8/test/mjsunit/debug-step-turbofan.js index c8c346b2c7..1710942e9a 100644 --- a/deps/v8/test/mjsunit/debug-step-turbofan.js +++ b/deps/v8/test/mjsunit/debug-step-turbofan.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --turbo-filter=g --allow-natives-syntax +// Flags: --expose-debug-as debug --turbo-filter=g --allow-natives-syntax // Test that Debug::PrepareForBreakPoints can deal with turbofan code (g) // on the stack. Without deoptimization support, we will not be able to diff --git a/deps/v8/test/mjsunit/debug-stepframe-clearing.js b/deps/v8/test/mjsunit/debug-stepframe-clearing.js new file mode 100644 index 0000000000..c440e78dd2 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-stepframe-clearing.js @@ -0,0 +1,97 @@ +// Copyright 2015 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 debug + +// This test ensures that IC learning doesn't interfere with stepping into +// property accessor. f1()'s ICs are allowed to learn to a monomorphic state, +// and the breakpoints flooding get() are allowed to expire, then we ensure +// that we can step into get() again later (when k == 1). +function f1() { + for (var k = 0; k < 2; k++) { // Break 1 + var v10 = 0; // Line 2 + for (var i = 0; i < 10; i++) { // Line 3 + var v12 = o.slappy; // Line 4 + var v13 = 3 // Line 5 + } // Line 6 + print("break here"); // Break 3 + } // Line 8 + print("exiting f1"); // Line 9 (dummy break) +} + +function get() { + var g0 = 0; // Break 2 + var g1 = 1; + return 3; +} + + +var o = {}; +Object.defineProperty(o, "slappy", { get : get }); + +Debug = debug.Debug; +var break_count = 0 +var exception = null; +var bp_f1_line7; +var bp_f1_line9; + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + var line = exec_state.frame(0).sourceLineText(); + print(line); + var match = line.match(/\/\/ Break (\d+)$/); + assertEquals(2, match.length); + var match_value = parseInt(match[1]); + + if (break_count >= 0 && break_count < 2) { + // 0, 1: Keep stepping through frames. + assertEquals(break_count, match_value); + exec_state.prepareStep(Debug.StepAction.StepFrame, 1); + } else if (break_count === 2) { + // 2: let the code run to a breakpoint we set. The load should + // go monomorphic. + assertEquals(break_count, match_value); + } else if (break_count === 3) { + // 3: back to frame stepping. Does the monomorphic slappy accessor + // call still have the ability to break like before? + assertEquals(break_count, match_value); + Debug.clearBreakPoint(bp_f1_line7); + exec_state.prepareStep(Debug.StepAction.StepFrame, 1); + } else { + assertEquals(4, break_count); + assertEquals(2, match_value); + // Apparently we can still stop in the accessor even though we cleared + // breakpoints earlier and there was a monomorphic step. + // Allow running to completion now. + Debug.clearBreakPoint(bp_f1_line9); + } + + break_count++; + } catch (e) { + print(e + e.stack); + exception = e; + } +} + +for (var j = 1; j < 3; j++) { + break_count = 0; + Debug.setListener(listener); + + // Breakpoints are added here rather than in the listener because their + // addition causes a full (clearing) gc that clears type feedback when we + // want to let it build up. Also, bp_f1_line9 is set simply because if we + // handled then deleted bp_f1_line7, then the debugger clears DebugInfo from + // f1 while we are still using it, again, resetting type feedback which is + // undesirable. + bp_f1_line7 = Debug.setBreakPoint(f1, 7); + bp_f1_line9 = Debug.setBreakPoint(f1, 9); + + debugger; // Break 0 + f1(); + Debug.setListener(null); + assertTrue(break_count === 5); +} + +assertNull(exception); diff --git a/deps/v8/test/mjsunit/debug-stepin-foreach.js b/deps/v8/test/mjsunit/debug-stepin-foreach.js index fa728e019c..c2702f794a 100644 --- a/deps/v8/test/mjsunit/debug-stepin-foreach.js +++ b/deps/v8/test/mjsunit/debug-stepin-foreach.js @@ -37,15 +37,17 @@ function listener(event, exec_state, event_data, data) { }; Debug.setListener(listener); +var bound_callback = callback.bind(null); debugger; // Break 0. [1,2].forEach(callback); // Break 1. +[3,4].forEach(bound_callback); // Break 6. function callback(x) { - return x; // Break 2. // Break 4. -} // Break 3. // Break 5. + return x; // Break 2. // Break 4. // Break 7. // Break 9. +} // Break 3. // Break 5. // Break 8. // Break 10. -assertNull(exception); // Break 6. +assertNull(exception); // Break 11. assertEquals(expected_breaks, break_count); Debug.setListener(null); diff --git a/deps/v8/test/mjsunit/harmony/block-conflicts.js b/deps/v8/test/mjsunit/es6/block-conflicts.js index d19a34a2c3..fdd581dd70 100644 --- a/deps/v8/test/mjsunit/harmony/block-conflicts.js +++ b/deps/v8/test/mjsunit/es6/block-conflicts.js @@ -1,8 +1,6 @@ // Copyright 2011 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: --harmony-scoping // Test for conflicting variable bindings. diff --git a/deps/v8/test/mjsunit/es6/block-const-assign.js b/deps/v8/test/mjsunit/es6/block-const-assign.js new file mode 100644 index 0000000000..f78faa689d --- /dev/null +++ b/deps/v8/test/mjsunit/es6/block-const-assign.js @@ -0,0 +1,160 @@ +// 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. + +// Flags: --harmony-computed-property-names + +// Test that we throw early syntax errors in harmony mode +// when using an immutable binding in an assigment or with +// prefix/postfix decrement/increment operators. + +"use strict"; + +const decls = [ + // Const declaration. + function(use) { return "const c = 1; " + use + ";" }, TypeError, + function(use) { return "const x = 0, c = 1; " + use + ";" }, TypeError, + function(use) { return "const c = 1, x = (" + use + ");" }, TypeError, + function(use) { return use + "; const c = 1;" }, ReferenceError, + function(use) { return use + "; const x = 0, c = 1;" }, ReferenceError, + function(use) { return "const x = (" + use + "), c = 1;" }, ReferenceError, + function(use) { return "const c = (" + use + ");" }, ReferenceError, + + // Function expression. + function(use) { return "(function c() { " + use + "; })();"; }, TypeError, + // TODO(rossberg): Once we have default parameters, test using 'c' there. + + // Class expression. + function(use) { + return "new class c { constructor() { " + use + " } };"; + }, TypeError, + function(use) { + return "(new class c { m() { " + use + " } }).m();"; + }, TypeError, + function(use) { + return "(new class c { get a() { " + use + " } }).a;"; + }, TypeError, + function(use) { + return "(new class c { set a(x) { " + use + " } }).a = 0;"; + }, TypeError, + function(use) { + return "(class c { static m() { " + use + " } }).s();"; + }, TypeError, + function(use) { + return "(class c extends (" + use + ") {});"; + }, ReferenceError, + function(use) { + return "(class c { [" + use + "]() {} });"; + }, ReferenceError, + function(use) { + return "(class c { get [" + use + "]() {} });"; + }, ReferenceError, + function(use) { + return "(class c { set [" + use + "](x) {} });"; + }, ReferenceError, + function(use) { + return "(class c { static [" + use + "]() {} });"; + }, ReferenceError, + + // For loop. + function(use) { + return "for (const c = 0; " + use + ";) {}" + }, TypeError, + function(use) { + return "for (const x = 0, c = 0; " + use + ";) {}" + }, TypeError, + function(use) { + return "for (const c = 0; ; " + use + ") {}" + }, TypeError, + function(use) { + return "for (const x = 0, c = 0; ; " + use + ") {}" + }, TypeError, + function(use) { + return "for (const c = 0; ;) { " + use + "; }" + }, TypeError, + function(use) { + return "for (const x = 0, c = 0; ;) { " + use + "; }" + }, TypeError, + function(use) { + return "for (const c in {a: 1}) { " + use + "; }" + }, TypeError, + function(use) { + return "for (const c of [1]) { " + use + "; }" + }, TypeError, + function(use) { + return "for (const x = (" + use + "), c = 0; ;) {}" + }, ReferenceError, + function(use) { + return "for (const c = (" + use + "); ;) {}" + }, ReferenceError, +] + +let uses = [ + 'c = 1', + 'c += 1', + '++c', + 'c--', +]; + +let declcontexts = [ + function(decl) { return decl; }, + function(decl) { return "eval(\'" + decl + "\')"; }, + function(decl) { return "{ " + decl + " }"; }, + function(decl) { return "(function() { " + decl + " })()"; }, +]; + +let usecontexts = [ + function(use) { return use; }, + function(use) { return "eval(\"" + use + "\")"; }, + function(use) { return "(function() { " + use + " })()"; }, + function(use) { return "(function() { eval(\"" + use + "\"); })()"; }, + function(use) { return "eval(\"(function() { " + use + "; })\")()"; }, +]; + +function Test(program, error) { + program = "'use strict'; " + program; + try { + print(program, " // throw " + error.name); + eval(program); + } catch (e) { + assertInstanceof(e, error); + if (e === TypeError) { + assertTrue(e.toString().indexOf("Assignment to constant variable") >= 0); + } + return; + } + assertUnreachable(); +} + +for (var d = 0; d < decls.length; d += 2) { + for (var u = 0; u < uses.length; ++u) { + for (var o = 0; o < declcontexts.length; ++o) { + for (var i = 0; i < usecontexts.length; ++i) { + Test(declcontexts[o](decls[d](usecontexts[i](uses[u]))), decls[d + 1]); + } + } + } +} diff --git a/deps/v8/test/mjsunit/harmony/block-early-errors.js b/deps/v8/test/mjsunit/es6/block-early-errors.js index 8ed5ea84ec..bf24942bb1 100644 --- a/deps/v8/test/mjsunit/harmony/block-early-errors.js +++ b/deps/v8/test/mjsunit/es6/block-early-errors.js @@ -25,8 +25,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-scoping - function CheckException(e) { var string = e.toString(); assertInstanceof(e, SyntaxError); diff --git a/deps/v8/test/mjsunit/harmony/block-for.js b/deps/v8/test/mjsunit/es6/block-for.js index 110f1ccf45..b91af0116c 100644 --- a/deps/v8/test/mjsunit/harmony/block-for.js +++ b/deps/v8/test/mjsunit/es6/block-for.js @@ -24,9 +24,6 @@ // 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. - -// Flags: --harmony-scoping - "use strict"; function props(x) { @@ -147,7 +144,7 @@ function closure_in_for_cond() { assertEquals(k, a[k]()); } } -closure_in_for_next(); +closure_in_for_cond(); function closure_in_for_next() { diff --git a/deps/v8/test/mjsunit/harmony/block-leave.js b/deps/v8/test/mjsunit/es6/block-leave.js index 87d35b396d..338631b76e 100644 --- a/deps/v8/test/mjsunit/harmony/block-leave.js +++ b/deps/v8/test/mjsunit/es6/block-leave.js @@ -25,8 +25,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-scoping - "use strict"; // We want to test the context chain shape. In each of the tests cases diff --git a/deps/v8/test/mjsunit/harmony/block-let-crankshaft.js b/deps/v8/test/mjsunit/es6/block-let-crankshaft.js index e8e00b200e..9cfdf847fc 100644 --- a/deps/v8/test/mjsunit/harmony/block-let-crankshaft.js +++ b/deps/v8/test/mjsunit/es6/block-let-crankshaft.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-scoping --allow-natives-syntax +// Flags: --allow-natives-syntax "use strict"; diff --git a/deps/v8/test/mjsunit/harmony/block-let-declaration.js b/deps/v8/test/mjsunit/es6/block-let-declaration.js index 44a0049a44..5fbb12824b 100644 --- a/deps/v8/test/mjsunit/harmony/block-let-declaration.js +++ b/deps/v8/test/mjsunit/es6/block-let-declaration.js @@ -25,8 +25,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-scoping - // Test let declarations in various settings. "use strict"; @@ -70,8 +68,8 @@ TestLocalThrows("do let x; while (false)", SyntaxError); TestLocalThrows("while (false) let x;", SyntaxError); TestLocalThrows("label: let x;", SyntaxError); TestLocalThrows("for (;false;) let x;", SyntaxError); -TestLocalThrows("switch (true) { case true: let x; }", SyntaxError); -TestLocalThrows("switch (true) { default: let x; }", SyntaxError); +TestLocalDoesNotThrow("switch (true) { case true: let x; }"); +TestLocalDoesNotThrow("switch (true) { default: let x; }"); // Test const declarations with initialisers in statement positions. TestLocalThrows("if (true) const x = 1;", SyntaxError); @@ -80,8 +78,8 @@ TestLocalThrows("do const x = 1; while (false)", SyntaxError); TestLocalThrows("while (false) const x = 1;", SyntaxError); TestLocalThrows("label: const x = 1;", SyntaxError); TestLocalThrows("for (;false;) const x = 1;", SyntaxError); -TestLocalThrows("switch (true) { case true: const x = 1; }", SyntaxError); -TestLocalThrows("switch (true) { default: const x = 1; }", SyntaxError); +TestLocalDoesNotThrow("switch (true) { case true: const x = 1; }"); +TestLocalDoesNotThrow("switch (true) { default: const x = 1; }"); // Test const declarations without initialisers. TestLocalThrows("const x;", SyntaxError); @@ -149,11 +147,11 @@ function f() { f(); // Test function declarations in statement position in strict mode. -TestLocalThrows("function f() { if (true) function g() {}", SyntaxError); -TestLocalThrows("function f() { if (true) {} else function g() {}", SyntaxError); -TestLocalThrows("function f() { do function g() {} while (false)", SyntaxError); -TestLocalThrows("function f() { while (false) function g() {}", SyntaxError); -TestLocalThrows("function f() { label: function g() {}", SyntaxError); -TestLocalThrows("function f() { for (;false;) function g() {}", SyntaxError); -TestLocalThrows("function f() { switch (true) { case true: function g() {} }", SyntaxError); -TestLocalThrows("function f() { switch (true) { default: function g() {} }", SyntaxError); +TestLocalThrows("function f() { if (true) function g() {} }", SyntaxError); +TestLocalThrows("function f() { if (true) {} else function g() {} }", SyntaxError); +TestLocalThrows("function f() { do function g() {} while (false) }", SyntaxError); +TestLocalThrows("function f() { while (false) function g() {} }", SyntaxError); +TestLocalThrows("function f() { label: function g() {} }", SyntaxError); +TestLocalThrows("function f() { for (;false;) function g() {} }", SyntaxError); +TestLocalDoesNotThrow("function f() { switch (true) { case true: function g() {} } }"); +TestLocalDoesNotThrow("function f() { switch (true) { default: function g() {} } }"); diff --git a/deps/v8/test/mjsunit/harmony/block-let-semantics.js b/deps/v8/test/mjsunit/es6/block-let-semantics.js index a37b795b0a..b0a826a007 100644 --- a/deps/v8/test/mjsunit/harmony/block-let-semantics.js +++ b/deps/v8/test/mjsunit/es6/block-let-semantics.js @@ -25,8 +25,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-scoping - "use strict"; // Test temporal dead zone semantics of let bound variables in diff --git a/deps/v8/test/mjsunit/harmony/block-non-strict-errors.js b/deps/v8/test/mjsunit/es6/block-non-strict-errors.js index 11fa5c6a52..48cac21141 100644 --- a/deps/v8/test/mjsunit/harmony/block-non-strict-errors.js +++ b/deps/v8/test/mjsunit/es6/block-non-strict-errors.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-scoping --harmony-classes +// Flags: --harmony-classes function CheckError(source) { var exception = null; diff --git a/deps/v8/test/mjsunit/harmony/block-scoping.js b/deps/v8/test/mjsunit/es6/block-scoping.js index 001d9fbfd5..5f481b8bf2 100644 --- a/deps/v8/test/mjsunit/harmony/block-scoping.js +++ b/deps/v8/test/mjsunit/es6/block-scoping.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --allow-natives-syntax --harmony-scoping +// Flags: --allow-natives-syntax // Test functionality of block scopes. "use strict"; @@ -101,7 +101,8 @@ function f4(one) { assertEquals(4, eval('z')); assertEquals(5, eval('u')); assertEquals(6, eval('v')); - }; + } + f(); } } f4(1); @@ -122,7 +123,8 @@ function f5(one) { assertEquals(4, z); assertEquals(5, u); assertEquals(6, v); - }; + } + f(); } } f5(1); diff --git a/deps/v8/test/mjsunit/es6/collections.js b/deps/v8/test/mjsunit/es6/collections.js index 92cd087839..888b6863c1 100644 --- a/deps/v8/test/mjsunit/es6/collections.js +++ b/deps/v8/test/mjsunit/es6/collections.js @@ -51,6 +51,21 @@ function TestValidMapCalls(m) { assertDoesNotThrow(function () { m.set(new Object) }); assertDoesNotThrow(function () { m.has(new Object) }); assertDoesNotThrow(function () { m.delete(new Object) }); + assertDoesNotThrow(function () { m.get(undefined) }); + assertDoesNotThrow(function () { m.get(null) }); + assertDoesNotThrow(function () { m.get(0) }); + assertDoesNotThrow(function () { m.get('a-key') }); + assertDoesNotThrow(function () { m.get(Symbol()) }); + assertDoesNotThrow(function () { m.has(undefined) }); + assertDoesNotThrow(function () { m.has(null) }); + assertDoesNotThrow(function () { m.has(0) }); + assertDoesNotThrow(function () { m.has('a-key') }); + assertDoesNotThrow(function () { m.has(Symbol()) }); + assertDoesNotThrow(function () { m.delete(undefined) }); + assertDoesNotThrow(function () { m.delete(null) }); + assertDoesNotThrow(function () { m.delete(0) }); + assertDoesNotThrow(function () { m.delete('a-key') }); + assertDoesNotThrow(function () { m.delete(Symbol()) }); } TestValidMapCalls(new Map); TestValidMapCalls(new WeakMap); @@ -58,14 +73,11 @@ TestValidMapCalls(new WeakMap); // Test invalid getter and setter calls for WeakMap only function TestInvalidCalls(m) { - assertThrows(function () { m.get(undefined) }, TypeError); assertThrows(function () { m.set(undefined, 0) }, TypeError); - assertThrows(function () { m.get(null) }, TypeError); assertThrows(function () { m.set(null, 0) }, TypeError); - assertThrows(function () { m.get(0) }, TypeError); assertThrows(function () { m.set(0, 0) }, TypeError); - assertThrows(function () { m.get('a-key') }, TypeError); assertThrows(function () { m.set('a-key', 0) }, TypeError); + assertThrows(function () { m.set(Symbol(), 0) }, TypeError); } TestInvalidCalls(new WeakMap); @@ -73,57 +85,79 @@ TestInvalidCalls(new WeakMap); // Test expected behavior for Sets and WeakSets function TestSet(set, key) { assertFalse(set.has(key)); - assertSame(set, set.add(key)); - assertTrue(set.has(key)); - assertTrue(set.delete(key)); + assertFalse(set.delete(key)); + if (typeof key === 'object' && !(set instanceof WeakSet)) { + assertSame(set, set.add(key)); + assertTrue(set.has(key)); + assertTrue(set.delete(key)); + } assertFalse(set.has(key)); assertFalse(set.delete(key)); assertFalse(set.has(key)); } function TestSetBehavior(set) { + // Fill for (var i = 0; i < 20; i++) { TestSet(set, new Object); TestSet(set, i); TestSet(set, i / 100); TestSet(set, 'key-' + i); + TestSet(set, Symbol(i)); } - var keys = [ +0, -0, +Infinity, -Infinity, true, false, null, undefined ]; + + var keys = [ + -0, +0, 1, 1/3, 10, +Infinity, -Infinity, NaN, true, false, null, undefined, + 'x', Symbol(), {}, function(){} + ]; for (var i = 0; i < keys.length; i++) { TestSet(set, keys[i]); } } TestSetBehavior(new Set); -TestSet(new WeakSet, new Object); +TestSetBehavior(new WeakSet); // Test expected mapping behavior for Maps and WeakMaps function TestMapping(map, key, value) { - assertSame(map, map.set(key, value)); - assertSame(value, map.get(key)); + assertFalse(map.has(key)); + assertSame(undefined, map.get(key)); + assertFalse(map.delete(key)); + if (typeof key === 'object' && !(map instanceof WeakMap)) { + assertSame(map, map.set(key, value)); + assertSame(value, map.get(key)); + assertTrue(map.has(key)); + assertTrue(map.delete(key)); + } + assertFalse(map.has(key)); + assertSame(undefined, map.get(key)); + assertFalse(map.delete(key)); + assertFalse(map.has(key)); + assertSame(undefined, map.get(key)); } -function TestMapBehavior1(m) { +function TestMapBehavior(m) { + // Fill TestMapping(m, new Object, 23); TestMapping(m, new Object, 'the-value'); TestMapping(m, new Object, new Object); -} -TestMapBehavior1(new Map); -TestMapBehavior1(new WeakMap); - - -// Test expected mapping behavior for Maps only -function TestMapBehavior2(m) { for (var i = 0; i < 20; i++) { TestMapping(m, i, new Object); TestMapping(m, i / 10, new Object); TestMapping(m, 'key-' + i, new Object); + TestMapping(m, Symbol(i), new Object); } - // -0 is handled in TestMinusZeroMap - var keys = [ 0, +Infinity, -Infinity, true, false, null, undefined ]; + + var keys = [ + -0, +0, 1, 1/3, 10, +Infinity, -Infinity, NaN, true, false, null, undefined, + 'x', Symbol(), {}, function(){} + ]; for (var i = 0; i < keys.length; i++) { + TestMapping(m, keys[i], 23); + TestMapping(m, keys[i], 'the-value'); TestMapping(m, keys[i], new Object); } } -TestMapBehavior2(new Map); +TestMapBehavior(new Map); +TestMapBehavior(new WeakMap); // Test expected querying behavior of Maps and WeakMaps @@ -132,8 +166,6 @@ function TestQuery(m) { var values = [ 'x', 0, +Infinity, -Infinity, true, false, null, undefined ]; for (var i = 0; i < values.length; i++) { TestMapping(m, key, values[i]); - assertTrue(m.has(key)); - assertFalse(m.has(new Object)); } } TestQuery(new Map); @@ -144,7 +176,6 @@ TestQuery(new WeakMap); function TestDelete(m) { var key = new Object; TestMapping(m, key, 'to-be-deleted'); - assertTrue(m.delete(key)); assertFalse(m.delete(key)); assertFalse(m.delete(new Object)); assertSame(m.get(key), undefined); @@ -1190,8 +1221,9 @@ function TestSetConstructorIterableValue(ctor) { // Strict mode is required to prevent implicit wrapping in the getter. Object.defineProperty(Number.prototype, Symbol.iterator, { get: function() { - assertEquals('object', typeof this); + assertEquals('number', typeof this); return function() { + assertEquals('number', typeof this); return oneAndTwo.keys(); }; }, @@ -1380,8 +1412,9 @@ function TestMapConstructorIterableValue(ctor) { // Strict mode is required to prevent implicit wrapping in the getter. Object.defineProperty(Number.prototype, Symbol.iterator, { get: function() { - assertEquals('object', typeof this); + assertEquals('number', typeof this); return function() { + assertEquals('number', typeof this); return oneAndTwo.entries(); }; }, @@ -1406,3 +1439,38 @@ TestCollectionToString(Map); TestCollectionToString(Set); TestCollectionToString(WeakMap); TestCollectionToString(WeakSet); + + +function TestConstructorOrderOfAdderIterator(ctor, adderName) { + var iterable = new Map(); + iterable.set({}, {}); + iterable.set({}, {}); + var iterableFunction = iterable[Symbol.iterator]; + Object.defineProperty(iterable, Symbol.iterator, { + get: function() { + log += 'iterator'; + return iterableFunction; + } + }); + + var log = ''; + var adderFunction = ctor.prototype[adderName]; + + Object.defineProperty(ctor.prototype, adderName, { + get: function() { + log += adderName; + return adderFunction; + } + }); + + new ctor(iterable); + assertEquals(adderName + 'iterator', log); + + Object.defineProperty(ctor.prototype, adderName, { + value: adderFunction + }); +} +TestConstructorOrderOfAdderIterator(Map, 'set'); +TestConstructorOrderOfAdderIterator(Set, 'add'); +TestConstructorOrderOfAdderIterator(WeakMap, 'set'); +TestConstructorOrderOfAdderIterator(WeakSet, 'add'); diff --git a/deps/v8/test/mjsunit/harmony/debug-blockscopes.js b/deps/v8/test/mjsunit/es6/debug-blockscopes.js index 8180377e6d..9f5d13e900 100644 --- a/deps/v8/test/mjsunit/harmony/debug-blockscopes.js +++ b/deps/v8/test/mjsunit/es6/debug-blockscopes.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --expose-debug-as debug --harmony-scoping +// Flags: --expose-debug-as debug // The functions used for testing backtraces. They are at the top to make the // testing of source line/column easier. diff --git a/deps/v8/test/mjsunit/harmony/debug-evaluate-blockscopes.js b/deps/v8/test/mjsunit/es6/debug-evaluate-blockscopes.js index d133cc07ce..e24ca78315 100644 --- a/deps/v8/test/mjsunit/harmony/debug-evaluate-blockscopes.js +++ b/deps/v8/test/mjsunit/es6/debug-evaluate-blockscopes.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --expose-debug-as debug --harmony-scoping +// Flags: --expose-debug-as debug // Test debug evaluation for functions without local context, but with // nested catch contexts. diff --git a/deps/v8/test/mjsunit/harmony/debug-function-scopes.js b/deps/v8/test/mjsunit/es6/debug-function-scopes.js index 1b380c2b84..699bd5343d 100644 --- a/deps/v8/test/mjsunit/harmony/debug-function-scopes.js +++ b/deps/v8/test/mjsunit/es6/debug-function-scopes.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --expose-debug-as debug --harmony-scoping +// Flags: --expose-debug-as debug "use strict"; let top_level_let = 255; diff --git a/deps/v8/test/mjsunit/es6/debug-promises/resolve-after-aborted-try-finally.js b/deps/v8/test/mjsunit/es6/debug-promises/resolve-after-aborted-try-finally.js new file mode 100644 index 0000000000..918ae2a2e8 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/debug-promises/resolve-after-aborted-try-finally.js @@ -0,0 +1,32 @@ +// 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 debug --allow-natives-syntax + +// Test debug events when we listen to all exceptions and +// there is a catch handler for the exception thrown in a Promise. +// We expect a normal Exception debug event to be triggered. + +Debug = debug.Debug; + +var events = []; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.PromiseEvent) events.push(event_data.status()); +} + +Debug.setListener(listener); + +var p = new Promise(function(resolve, reject) { + do { + try { + throw new Error("reject"); + } finally { + break; // No rethrow. + } + } while (false); + resolve(); +}); + +assertEquals([0 /* create */, 1 /* resolve */], events); diff --git a/deps/v8/test/mjsunit/es6/debug-promises/resolve-after-try-catch.js b/deps/v8/test/mjsunit/es6/debug-promises/resolve-after-try-catch.js new file mode 100644 index 0000000000..298201f103 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/debug-promises/resolve-after-try-catch.js @@ -0,0 +1,29 @@ +// 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 debug --allow-natives-syntax + +// Test debug events when we listen to all exceptions and +// there is a catch handler for the exception thrown in a Promise. +// We expect a normal Exception debug event to be triggered. + +Debug = debug.Debug; + +var events = []; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.PromiseEvent) events.push(event_data.status()); +} + +Debug.setListener(listener); + +var p = new Promise(function (resolve, reject) { + try { + throw new Error("reject"); + } catch (e) { + } + resolve(); +}); + +assertEquals([0 /* create */, 1 /* resolve */], events); diff --git a/deps/v8/test/mjsunit/es6/debug-promises/rethrow-in-try-finally.js b/deps/v8/test/mjsunit/es6/debug-promises/rethrow-in-try-finally.js new file mode 100644 index 0000000000..b1e2ff98e1 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/debug-promises/rethrow-in-try-finally.js @@ -0,0 +1,30 @@ +// 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 debug --allow-natives-syntax + +// Test debug events when we listen to all exceptions and +// there is a catch handler for the exception thrown in a Promise. +// We expect a normal Exception debug event to be triggered. + +Debug = debug.Debug; + +var events = []; + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.PromiseEvent) events.push(event_data.status()); +} + +Debug.setListener(listener); + +var p = new Promise(function(resolve, reject) { + try { + throw new Error("reject"); + } finally { + // Implicit rethrow. + } + resolve(); +}); + +assertEquals([0 /* create */, -1 /* rethrown */], events); diff --git a/deps/v8/test/mjsunit/es6/debug-stepin-promises.js b/deps/v8/test/mjsunit/es6/debug-stepin-promises.js new file mode 100644 index 0000000000..8548a2badd --- /dev/null +++ b/deps/v8/test/mjsunit/es6/debug-stepin-promises.js @@ -0,0 +1,65 @@ +// Copyright 2015 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 debug --allow-natives-syntax --noalways-opt +// Tests stepping into through Promises. + +Debug = debug.Debug +var exception = null; +var break_count = 0; +var expected_breaks = -1; + +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + assertTrue(exec_state.frameCount() != 0, "FAIL: Empty stack trace"); + if (!break_count) { + // Count number of expected breakpoints in this source file. + var source_text = exec_state.frame(0).func().script().source(); + expected_breaks = source_text.match(/\/\/\s*Break\s+\d+\./g).length; + print("Expected breaks: " + expected_breaks); + } + var source = exec_state.frame(0).sourceLineText(); + print("paused at: " + source); + assertTrue(source.indexOf("// Break " + break_count + ".") > 0, + "Unexpected pause at: " + source + "\n" + + "Expected: // Break " + break_count + "."); + ++break_count; + if (break_count !== expected_breaks) { + exec_state.prepareStep(Debug.StepAction.StepIn, 1); + } + } + } catch(e) { + exception = e; + print(e, e.stack); + } +}; + +Debug.setListener(listener); + +Promise.resolve(42) + .then( + function f0() { + debugger; // Break 0. + } // Break 1. + ) + .then(callback) + .then(callback.bind(null)) + .then(Object) + .then(callback.bind(null).bind(null)) + .then(finalize) + .catch(function(err) { + %AbortJS("FAIL: " + err); + }); + +function callback(x) { + return x; // Break 2. // Break 4. // Break 6. +} // Break 3. // Break 5. // Break 7. + +function finalize() { + assertNull(exception); // Break 8. + assertEquals(expected_breaks, break_count); + + Debug.setListener(null); +} diff --git a/deps/v8/test/mjsunit/harmony/empty-for.js b/deps/v8/test/mjsunit/es6/empty-for.js index 02211260ff..dad892d328 100644 --- a/deps/v8/test/mjsunit/harmony/empty-for.js +++ b/deps/v8/test/mjsunit/es6/empty-for.js @@ -25,8 +25,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-scoping - "use strict"; function for_const() { diff --git a/deps/v8/test/mjsunit/es6/function-length-configurable.js b/deps/v8/test/mjsunit/es6/function-length-configurable.js new file mode 100644 index 0000000000..e5b51aba20 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/function-length-configurable.js @@ -0,0 +1,119 @@ +// Copyright 2015 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 getStrictF() { + 'use strict'; + return function f(x) {}; +} + + +function getSloppyF() { + return function f(x) {}; +} + + +function getStrictGenerator() { + 'use strict'; + return function* f(x) {}; +} + + +function getSloppyGenerator() { + return function* f(x) {}; +} + + +function test(testFunction) { + testFunction(getStrictF()); + testFunction(getSloppyF()); + testFunction(getStrictGenerator()); + testFunction(getSloppyGenerator()); +} + + +function testDescriptor(f) { + var descr = Object.getOwnPropertyDescriptor(f, 'length'); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertEquals(1, descr.value); + assertFalse(descr.writable); +} +test(testDescriptor); + + +function testSet(f) { + f.length = 2; + assertEquals(1, f.length); +} +test(testSet); + + +function testSetStrict(f) { + 'use strict'; + assertThrows(function() { + f.length = 2; + }, TypeError); +} +test(testSetStrict); + + +function testReconfigureAsDataProperty(f) { + Object.defineProperty(f, 'length', { + value: 2, + }); + assertEquals(2, f.length); + Object.defineProperty(f, 'length', { + writable: true + }); + f.length = 3; + assertEquals(3, f.length); + + f.length = 42; + assertEquals(42, f.length); +} +test(testReconfigureAsDataProperty); + + +function testReconfigureAsAccessorProperty(f) { + var length = 2; + Object.defineProperty(f, 'length', { + get: function() { return length; }, + set: function(v) { length = v; } + }); + assertEquals(2, f.length); + f.length = 3; + assertEquals(3, f.length); +} +test(testReconfigureAsAccessorProperty); + + +(function testSetOnInstance() { + // This needs to come before testDelete below + assertTrue(Function.prototype.hasOwnProperty('length')); + + function f() {} + delete f.length; + assertEquals(0, f.length); + + f.length = 42; + assertEquals(0, f.length); // non writable prototype property. + assertFalse(f.hasOwnProperty('length')); + + Object.defineProperty(Function.prototype, 'length', {writable: true}); + + f.length = 123; + assertTrue(f.hasOwnProperty('length')); + assertEquals(123, f.length); +})(); + + +(function testDelete() { + function f(x) {} + assertTrue(delete f.length); + assertFalse(f.hasOwnProperty('length')); + assertEquals(0, f.length); + + assertTrue(delete Function.prototype.length); + assertEquals(undefined, f.length); +})(); diff --git a/deps/v8/test/mjsunit/es6/function-name-configurable.js b/deps/v8/test/mjsunit/es6/function-name-configurable.js new file mode 100644 index 0000000000..f0ff406da8 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/function-name-configurable.js @@ -0,0 +1,115 @@ +// Copyright 2015 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 getStrictF() { + 'use strict'; + return function f() {}; +} + + +function getSloppyF() { + return function f() {}; +} + + +function test(testFunction) { + testFunction(getStrictF()); + testFunction(getSloppyF()); +} + + +function testDescriptor(f) { + var descr = Object.getOwnPropertyDescriptor(f, 'name'); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertEquals('f', descr.value); + assertFalse(descr.writable); +} +test(testDescriptor); + + +function testSet(f) { + f.name = 'g'; + assertEquals('f', f.name); +} +test(testSet); + + +function testSetStrict(f) { + 'use strict'; + assertThrows(function() { + f.name = 'g'; + }, TypeError); +} +test(testSetStrict); + + +function testReconfigureAsDataProperty(f) { + Object.defineProperty(f, 'name', { + value: 'g', + }); + assertEquals('g', f.name); + Object.defineProperty(f, 'name', { + writable: true + }); + f.name = 'h'; + assertEquals('h', f.name); + + f.name = 42; + assertEquals(42, f.name); +} +test(testReconfigureAsDataProperty); + + +function testReconfigureAsAccessorProperty(f) { + var name = 'g'; + Object.defineProperty(f, 'name', { + get: function() { return name; }, + set: function(v) { name = v; } + }); + assertEquals('g', f.name); + f.name = 'h'; + assertEquals('h', f.name); +} +test(testReconfigureAsAccessorProperty); + + +function testFunctionToString(f) { + Object.defineProperty(f, 'name', { + value: {toString: function() { assertUnreachable(); }}, + }); + assertEquals('function f() {}', f.toString()); +} +test(testFunctionToString); + + +(function testSetOnInstance() { + // This needs to come before testDelete below + assertTrue(Function.prototype.hasOwnProperty('name')); + + function f() {} + delete f.name; + assertEquals('Empty', f.name); + + f.name = 42; + assertEquals('Empty', f.name); // non writable prototype property. + assertFalse(f.hasOwnProperty('name')); + + Object.defineProperty(Function.prototype, 'name', {writable: true}); + + f.name = 123; + assertTrue(f.hasOwnProperty('name')); + assertEquals(123, f.name); +})(); + + +(function testDelete() { + function f() {} + assertTrue(delete f.name); + assertFalse(f.hasOwnProperty('name')); + assertEquals('Empty', f.name); + + assertTrue(delete Function.prototype.name); + assertEquals(undefined, f.name); +})(); diff --git a/deps/v8/test/mjsunit/es6/generators-debug-liveedit.js b/deps/v8/test/mjsunit/es6/generators-debug-liveedit.js index 6f0c443afc..987a42c41c 100644 --- a/deps/v8/test/mjsunit/es6/generators-debug-liveedit.js +++ b/deps/v8/test/mjsunit/es6/generators-debug-liveedit.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --expose-debug-as debug +// Flags: --expose-debug-as debug --allow-natives-syntax var Debug = debug.Debug; var LiveEdit = Debug.LiveEdit; @@ -54,7 +54,7 @@ function patch(fun, from, to) { print("Change log: " + JSON.stringify(log) + "\n"); } } - Debug.ExecuteInDebugContext(debug, false); + %ExecuteInDebugContext(debug); } // Try to edit a MakeGenerator while it's running, then again while it's diff --git a/deps/v8/test/mjsunit/es6/generators-objects.js b/deps/v8/test/mjsunit/es6/generators-objects.js index 8039ca8bb1..5112443ea0 100644 --- a/deps/v8/test/mjsunit/es6/generators-objects.js +++ b/deps/v8/test/mjsunit/es6/generators-objects.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-scoping --allow-natives-syntax --harmony-tostring +// Flags: --allow-natives-syntax --harmony-tostring // Test instantations of generators. diff --git a/deps/v8/test/mjsunit/es6/indexed-integer-exotics.js b/deps/v8/test/mjsunit/es6/indexed-integer-exotics.js new file mode 100644 index 0000000000..7aefd78c4f --- /dev/null +++ b/deps/v8/test/mjsunit/es6/indexed-integer-exotics.js @@ -0,0 +1,63 @@ +// 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 + +Object.prototype["10"] = "unreachable"; +Object.prototype["7"] = "unreachable"; +Object.prototype["-1"] = "unreachable"; +Object.prototype["-0"] = "unreachable"; +Object.prototype["4294967296"] = "unreachable"; + +var array = new Int32Array(10); + +function check() { + for (var i = 0; i < 4; i++) { + assertEquals(undefined, array["-1"]); + assertEquals(undefined, array["-0"]); + assertEquals(undefined, array["10"]); + assertEquals(undefined, array["4294967296"]); + } + assertEquals("unreachable", array.__proto__["-1"]); + assertEquals("unreachable", array.__proto__["-0"]); + assertEquals("unreachable", array.__proto__["10"]); + assertEquals("unreachable", array.__proto__["4294967296"]); +} + +check(); + +array["-1"] = "unreachable"; +array["-0"] = "unreachable"; +array["10"] = "unreachable"; +array["4294967296"] = "unreachable"; + +check(); + +delete array["-0"]; +delete array["-1"]; +delete array["10"]; +delete array["4294967296"]; + +assertEquals(undefined, Object.getOwnPropertyDescriptor(array, "-1")); +assertEquals(undefined, Object.getOwnPropertyDescriptor(array, "-0")); +assertEquals(undefined, Object.getOwnPropertyDescriptor(array, "10")); +assertEquals(undefined, Object.getOwnPropertyDescriptor(array, "4294967296")); +assertEquals(10, Object.keys(array).length); + +check(); + +function f() { return array["-1"]; } + +for (var i = 0; i < 3; i++) { + assertEquals(undefined, f()); +} +%OptimizeFunctionOnNextCall(f); +assertEquals(undefined, f()); + +Object.defineProperty(new Int32Array(), "-1", {'value': 1}); +Object.defineProperty(new Int32Array(), "-0", {'value': 1}); +Object.defineProperty(new Int32Array(), "-10", {'value': 1}); +Object.defineProperty(new Int32Array(), "4294967296", {'value': 1}); + +check(); diff --git a/deps/v8/test/mjsunit/es6/iteration-semantics.js b/deps/v8/test/mjsunit/es6/iteration-semantics.js index 544c94d915..f29e6e011b 100644 --- a/deps/v8/test/mjsunit/es6/iteration-semantics.js +++ b/deps/v8/test/mjsunit/es6/iteration-semantics.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-scoping --harmony-proxies +// Flags: --harmony-proxies // Test for-of semantics. @@ -200,9 +200,11 @@ assertEquals([undefined, 1, 2, 3], // Done. { value: 4, done: 42 }]))); // Results that are not objects. -assertEquals([undefined, undefined, undefined], - fold(append, [], - results([10, "foo", /qux/, { value: 37, done: true }]))); +assertThrows(function() { + assertEquals([undefined, undefined, undefined], + fold(append, [], + results([10, "foo", /qux/, { value: 37, done: true }]))); +}, TypeError); // Getters (shudder). assertEquals([1, 2], fold(append, [], @@ -334,3 +336,25 @@ function poison_proxy_after(iterable, n) { })); } assertEquals(45, fold(sum, 0, poison_proxy_after(integers_until(10), 10))); + + +function test_iterator_result_object_non_object(value, descr) { + var arr = []; + var ex; + var message = 'Iterator result ' + (descr || value) + ' is not an object'; + try { + fold(append, arr, + results([{value: 1}, {}, value, {value: 2}, {done: true}])); + } catch (e) { + ex = e; + } + assertInstanceof(ex, TypeError); + assertEquals(message, ex.message); + assertArrayEquals([1, undefined], arr); +} +test_iterator_result_object_non_object(null); +test_iterator_result_object_non_object(undefined); +test_iterator_result_object_non_object(42); +test_iterator_result_object_non_object('abc'); +test_iterator_result_object_non_object(false); +test_iterator_result_object_non_object(Symbol('x'), 'Symbol(x)'); diff --git a/deps/v8/test/mjsunit/es6/iteration-syntax.js b/deps/v8/test/mjsunit/es6/iteration-syntax.js index 4be94c5db4..c6a7d477bc 100644 --- a/deps/v8/test/mjsunit/es6/iteration-syntax.js +++ b/deps/v8/test/mjsunit/es6/iteration-syntax.js @@ -25,8 +25,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-scoping - // Test for-of syntax. "use strict"; diff --git a/deps/v8/test/mjsunit/es6/map-minus-zero.js b/deps/v8/test/mjsunit/es6/map-minus-zero.js new file mode 100644 index 0000000000..f9f397ec5c --- /dev/null +++ b/deps/v8/test/mjsunit/es6/map-minus-zero.js @@ -0,0 +1,51 @@ +// 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. + +'use strict'; + +var map = new Map(); + +var objectKey = {}; +var stringKey = 'keykeykey'; +var numberKey = 42.24; +var booleanKey = true; +var undefinedKey = undefined; +var nullKey = null; +var nanKey = NaN; +var zeroKey = 0; +var minusZeroKey = -0; + +assertEquals(map.size, 0); + +map.set(objectKey, 'aaa'); +map.set(stringKey, 'bbb'); +map.set(numberKey, 'ccc'); +map.set(booleanKey, 'ddd'); +map.set(undefinedKey, 'eee'); +map.set(nullKey, 'fff'); +map.set(nanKey, 'ggg'); +map.set(zeroKey, 'hhh'); + +assertEquals(8, map.size); + +assertEquals('aaa', map.get(objectKey)); +assertEquals('bbb', map.get(stringKey)); +assertEquals('ccc', map.get(numberKey)); +assertEquals('ddd', map.get(booleanKey)); +assertEquals('eee', map.get(undefinedKey)); +assertEquals('fff', map.get(nullKey)); +assertEquals('ggg', map.get(nanKey)); +assertEquals('hhh', map.get(zeroKey)); + +assertEquals(undefined, map.get({})); +assertEquals('bbb', map.get('keykeykey')); +assertEquals('ccc', map.get(42.24)); +assertEquals('ddd', map.get(true)); +assertEquals('eee', map.get(undefined)); +assertEquals('fff', map.get(null)); +assertEquals('ggg', map.get(NaN)); +assertEquals('hhh', map.get(0)); +assertEquals('hhh', map.get(-0)); +assertEquals('hhh', map.get(1 / Infinity)); +assertEquals('hhh', map.get(-1 / Infinity)); diff --git a/deps/v8/test/mjsunit/es6/promises.js b/deps/v8/test/mjsunit/es6/promises.js index 04059aa720..63b6d2f94a 100644 --- a/deps/v8/test/mjsunit/es6/promises.js +++ b/deps/v8/test/mjsunit/es6/promises.js @@ -32,6 +32,8 @@ var call = Function.prototype.call.call.bind(Function.prototype.call) var observe = Object.observe; var getOwnPropertyNames = Object.getOwnPropertyNames; var defineProperty = Object.defineProperty; +var numberPrototype = Number.prototype; +var symbolIterator = Symbol.iterator; (function() { @@ -637,14 +639,6 @@ function assertAsyncDone(iteration) { })(); (function() { - Promise.all({}).chain( - assertUnreachable, - function(r) { assertAsync(r instanceof TypeError, "all/no-array") } - ) - assertAsyncRan() -})(); - -(function() { Promise.all([]).chain( function(x) { assertAsync(x.length === 0, "all/resolve/empty") }, assertUnreachable @@ -653,6 +647,45 @@ function assertAsyncDone(iteration) { })(); (function() { + function testPromiseAllNonIterable(value) { + Promise.all(value).chain( + assertUnreachable, + function(r) { + assertAsync(r instanceof TypeError, 'all/non iterable'); + }); + assertAsyncRan(); + } + testPromiseAllNonIterable(null); + testPromiseAllNonIterable(undefined); + testPromiseAllNonIterable({}); + testPromiseAllNonIterable(42); +})(); + +(function() { + var deferred = Promise.defer(); + var p = deferred.promise; + function* f() { + yield 1; + yield p; + yield 3; + } + Promise.all(f()).chain( + function(x) { + assertAsync(x.length === 3, "all/resolve/iterable"); + assertAsync(x[0] === 1, "all/resolve/iterable/0"); + assertAsync(x[1] === 2, "all/resolve/iterable/1"); + assertAsync(x[2] === 3, "all/resolve/iterable/2"); + }, + assertUnreachable); + deferred.resolve(2); + assertAsyncRan(); + assertAsyncRan(); + assertAsyncRan(); + assertAsyncRan(); +})(); + + +(function() { var deferred1 = Promise.defer() var p1 = deferred1.promise var deferred2 = Promise.defer() @@ -706,6 +739,52 @@ function assertAsyncDone(iteration) { assertAsyncRan() })(); + +(function() { + 'use strict'; + var getCalls = 0; + var funcCalls = 0; + var nextCalls = 0; + defineProperty(numberPrototype, symbolIterator, { + get: function() { + assertEquals('number', typeof this); + getCalls++; + return function() { + assertEquals('number', typeof this); + funcCalls++; + var n = this; + var i = 0 + return { + next() { + nextCalls++; + return {value: i++, done: i > n}; + } + }; + }; + }, + configurable: true + }); + + Promise.all(3).chain( + function(x) { + assertAsync(x.length === 3, "all/iterable/number/length"); + assertAsync(x[0] === 0, "all/iterable/number/0"); + assertAsync(x[1] === 1, "all/iterable/number/1"); + assertAsync(x[2] === 2, "all/iterable/number/2"); + }, + assertUnreachable); + delete numberPrototype[symbolIterator]; + + assertEquals(getCalls, 1); + assertEquals(funcCalls, 1); + assertEquals(nextCalls, 3 + 1); // + 1 for {done: true} + assertAsyncRan(); + assertAsyncRan(); + assertAsyncRan(); + assertAsyncRan(); +})(); + + (function() { Promise.race([]).chain( assertUnreachable, @@ -736,14 +815,6 @@ function assertAsyncDone(iteration) { })(); (function() { - Promise.race({}).chain( - assertUnreachable, - function(r) { assertAsync(r instanceof TypeError, "one/no-array") } - ) - assertAsyncRan() -})(); - -(function() { var deferred1 = Promise.defer() var p1 = deferred1.promise var deferred2 = Promise.defer() @@ -804,6 +875,103 @@ function assertAsyncDone(iteration) { assertAsyncRan() })(); + +(function() { + function testPromiseRaceNonIterable(value) { + Promise.race(value).chain( + assertUnreachable, + function(r) { + assertAsync(r instanceof TypeError, 'race/non iterable'); + }); + assertAsyncRan(); + } + testPromiseRaceNonIterable(null); + testPromiseRaceNonIterable(undefined); + testPromiseRaceNonIterable({}); + testPromiseRaceNonIterable(42); +})(); + + +(function() { + var deferred1 = Promise.defer() + var p1 = deferred1.promise + var deferred2 = Promise.defer() + var p2 = deferred2.promise + var deferred3 = Promise.defer() + var p3 = deferred3.promise + function* f() { + yield p1; + yield p2; + yield p3; + } + Promise.race(f()).chain( + function(x) { assertAsync(x === 3, "race/iterable/resolve/reject") }, + assertUnreachable + ) + deferred3.resolve(3) + deferred1.reject(1) + assertAsyncRan() +})(); + +(function() { + var deferred1 = Promise.defer() + var p1 = deferred1.promise + var deferred2 = Promise.defer() + var p2 = deferred2.promise + var deferred3 = Promise.defer() + var p3 = deferred3.promise + function* f() { + yield p1; + yield p2; + yield p3; + } + Promise.race(f()).chain( + assertUnreachable, + function(x) { assertAsync(x === 3, "race/iterable/reject/resolve") } + ) + deferred3.reject(3) + deferred1.resolve(1) + assertAsyncRan() +})(); + +(function() { + 'use strict'; + var getCalls = 0; + var funcCalls = 0; + var nextCalls = 0; + defineProperty(numberPrototype, symbolIterator, { + get: function() { + assertEquals('number', typeof this); + getCalls++; + return function() { + assertEquals('number', typeof this); + funcCalls++; + var n = this; + var i = 0 + return { + next() { + nextCalls++; + return {value: i++, done: i > n}; + } + }; + }; + }, + configurable: true + }); + + Promise.race(3).chain( + function(x) { + assertAsync(x === 0, "race/iterable/number"); + }, + assertUnreachable); + delete numberPrototype[symbolIterator]; + + assertEquals(getCalls, 1); + assertEquals(funcCalls, 1); + assertEquals(nextCalls, 3 + 1); // + 1 for {done: true} + assertAsyncRan(); +})(); + (function() { var log function MyPromise(resolver) { diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-2243.js b/deps/v8/test/mjsunit/es6/regress/regress-2243.js index e2411d241b..d5377cfd54 100644 --- a/deps/v8/test/mjsunit/harmony/regress/regress-2243.js +++ b/deps/v8/test/mjsunit/es6/regress/regress-2243.js @@ -25,7 +25,5 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-scoping - assertThrows("'use strict'; (function f() { f = 123; })()", TypeError); assertThrows("(function f() { 'use strict'; f = 123; })()", TypeError); diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-2322.js b/deps/v8/test/mjsunit/es6/regress/regress-2322.js index 1195bab67c..6eca046397 100644 --- a/deps/v8/test/mjsunit/harmony/regress/regress-2322.js +++ b/deps/v8/test/mjsunit/es6/regress/regress-2322.js @@ -25,8 +25,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-scoping - "use strict"; assertThrows("'use strict'; for (let x in x);", ReferenceError); diff --git a/deps/v8/test/mjsunit/regress/regress-2506.js b/deps/v8/test/mjsunit/es6/regress/regress-2506.js index 0eb2770e59..b5cc91dbd7 100644 --- a/deps/v8/test/mjsunit/regress/regress-2506.js +++ b/deps/v8/test/mjsunit/es6/regress/regress-2506.js @@ -1,8 +1,6 @@ // 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: --harmony-scoping 'use strict'; diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-2858.js b/deps/v8/test/mjsunit/es6/regress/regress-2858.js index 4ce9478497..3b54b17da0 100644 --- a/deps/v8/test/mjsunit/harmony/regress/regress-2858.js +++ b/deps/v8/test/mjsunit/es6/regress/regress-2858.js @@ -1,8 +1,6 @@ // 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: --harmony-scoping "use strict"; function f() { diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-3426.js b/deps/v8/test/mjsunit/es6/regress/regress-3426.js index c3b11a1792..fd4903b1f8 100644 --- a/deps/v8/test/mjsunit/harmony/regress/regress-3426.js +++ b/deps/v8/test/mjsunit/es6/regress/regress-3426.js @@ -2,6 +2,4 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-scoping - assertThrows("(function() { 'use strict'; { let f; var f; } })", SyntaxError); diff --git a/deps/v8/test/mjsunit/regress/regress-347906.js b/deps/v8/test/mjsunit/es6/regress/regress-347906.js index c751618928..daa62f5df7 100644 --- a/deps/v8/test/mjsunit/regress/regress-347906.js +++ b/deps/v8/test/mjsunit/es6/regress/regress-347906.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --harmony +// Flags: --allow-natives-syntax function foo() { return Math.clz32(12.34); diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-3683.js b/deps/v8/test/mjsunit/es6/regress/regress-3683.js index a00d82bd1f..2c18632719 100644 --- a/deps/v8/test/mjsunit/harmony/regress/regress-3683.js +++ b/deps/v8/test/mjsunit/es6/regress/regress-3683.js @@ -1,8 +1,6 @@ // 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: --harmony-scoping "use strict"; diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-3741.js b/deps/v8/test/mjsunit/es6/regress/regress-3741.js index 8a9dd9e09c..0c5074a0f8 100644 --- a/deps/v8/test/mjsunit/harmony/regress/regress-3741.js +++ b/deps/v8/test/mjsunit/es6/regress/regress-3741.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Flags: --harmony-scoping --allow-natives-syntax +// Flags: --allow-natives-syntax 'use strict'; function f24(deopt) { let x = 1; diff --git a/deps/v8/test/mjsunit/es6/regress/regress-3938.js b/deps/v8/test/mjsunit/es6/regress/regress-3938.js new file mode 100644 index 0000000000..bd7d1befa1 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress/regress-3938.js @@ -0,0 +1,8 @@ +// Copyright 2015 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. + +'use strict'; + +assertThrows(function() { for (const i = 0; ; i++) {} }, TypeError); +assertThrows("'use strict'; for (const i = 0; ; i++) {}", TypeError); diff --git a/deps/v8/test/mjsunit/regress/regress-411237.js b/deps/v8/test/mjsunit/es6/regress/regress-411237.js index 8b75ba3015..ece6481737 100644 --- a/deps/v8/test/mjsunit/regress/regress-411237.js +++ b/deps/v8/test/mjsunit/es6/regress/regress-411237.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --allow-natives-syntax --harmony +// Flags: --allow-natives-syntax try { %OptimizeFunctionOnNextCall(print); diff --git a/deps/v8/test/mjsunit/es6/regress/regress-468661.js b/deps/v8/test/mjsunit/es6/regress/regress-468661.js new file mode 100644 index 0000000000..656190da0b --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress/regress-468661.js @@ -0,0 +1,75 @@ +// Copyright 2015 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 debug + +Debug = debug.Debug +var exception = null; +var break_count = 0; + +var expected_values = + [ReferenceError, ReferenceError, 0, 0, 0, 0, 0, 1, ReferenceError, ReferenceError]; + +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + assertTrue(exec_state.frameCount() != 0, "FAIL: Empty stack trace"); + // Count number of expected breakpoints in this source file. + if (!break_count) { + var source_text = exec_state.frame(0).func().script().source(); + expected_breaks = source_text.match(/\/\/\s*Break\s+\d+\./g).length; + print("Expected breaks: " + expected_breaks); + } + var frameMirror = exec_state.frame(0); + + var v = null;; + try { + v = frameMirror.evaluate('i').value(); + } catch(e) { + v = e; + } + frameMirror.allScopes(); + var source = frameMirror.sourceLineText(); + print("paused at: " + source); + assertTrue(source.indexOf("// Break " + break_count + ".") > 0, + "Unexpected pause at: " + source + "\n" + + "Expected: // Break " + break_count + "."); + if (expected_values[break_count] === ReferenceError) { + assertTrue(v instanceof ReferenceError); + } else { + assertSame(expected_values[break_count], v); + } + ++break_count; + + if (break_count !== expected_breaks) { + exec_state.prepareStep(Debug.StepAction.StepIn, 1); + print("Next step prepared"); + } + } + } catch(e) { + exception = e; + print(e, e.stack); + } +}; + +Debug.setListener(listener); + +var sum = 0; +(function (){ + 'use strict'; + + debugger; // Break 0. + + for (let i=0; // Break 1. + i < 1; // Break 2. // Break 3. // Break 6. // Break 7. + i++) { + let key = i; // Break 4. + sum += key; // Break 5. + } +}()); // Break 8. + +assertNull(exception); // Break 9. +assertEquals(expected_breaks, break_count); + +Debug.setListener(null); diff --git a/deps/v8/test/mjsunit/es6/regress/regress-474783.js b/deps/v8/test/mjsunit/es6/regress/regress-474783.js new file mode 100644 index 0000000000..e258dcb49f --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regress/regress-474783.js @@ -0,0 +1,24 @@ +// Copyright 2015 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. + + +"use strict"; +class Base { +} +class Subclass extends Base { + constructor(a,b,c) { + arguments[1]; + } +} +assertThrows(function() { Subclass(); }, TypeError); +assertThrows(function() { Subclass(1); }, TypeError); +assertThrows(function() { Subclass(1, 2); }, TypeError); +assertThrows(function() { Subclass(1, 2, 3); }, TypeError); +assertThrows(function() { Subclass(1, 2, 3, 4); }, TypeError); + +assertThrows(function() { Subclass.call(); }, TypeError); +assertThrows(function() { Subclass.call({}); }, TypeError); +assertThrows(function() { Subclass.call({}, 1); }, TypeError); +assertThrows(function() { Subclass.call({}, 1, 2); }, TypeError); +assertThrows(function() { Subclass.call({}, 1, 2, 3, 4); }, TypeError); diff --git a/deps/v8/test/mjsunit/es6/set-minus-zero.js b/deps/v8/test/mjsunit/es6/set-minus-zero.js new file mode 100644 index 0000000000..792332c648 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/set-minus-zero.js @@ -0,0 +1,51 @@ +// Copyright 2015 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. + +'use strict'; + +var set = new Set(); + +var objectKey = {}; +var stringKey = 'keykeykey'; +var numberKey = 42.24; +var booleanKey = true; +var undefinedKey = undefined; +var nullKey = null; +var nanKey = NaN; +var zeroKey = 0; +var minusZeroKey = -0; + +assertEquals(set.size, 0); + +set.add(objectKey); +set.add(stringKey); +set.add(numberKey); +set.add(booleanKey); +set.add(undefinedKey); +set.add(nullKey); +set.add(nanKey); +set.add(zeroKey); + +assertEquals(8, set.size); + +assertTrue(set.has(objectKey)); +assertTrue(set.has(stringKey)); +assertTrue(set.has(numberKey)); +assertTrue(set.has(booleanKey)); +assertTrue(set.has(undefinedKey)); +assertTrue(set.has(nullKey)); +assertTrue(set.has(nanKey)); +assertTrue(set.has(zeroKey)); + +assertFalse(set.has({})); +assertTrue(set.has('keykeykey')); +assertTrue(set.has(42.24)); +assertTrue(set.has(true)); +assertTrue(set.has(undefined)); +assertTrue(set.has(null)); +assertTrue(set.has(NaN)); +assertTrue(set.has(0)); +assertTrue(set.has(-0)); +assertTrue(set.has(1 / Infinity)); +assertTrue(set.has(-1 / Infinity)); diff --git a/deps/v8/test/mjsunit/harmony/string-codepointat.js b/deps/v8/test/mjsunit/es6/string-codepointat.js index 411b0f23c7..976d5be6af 100644 --- a/deps/v8/test/mjsunit/harmony/string-codepointat.js +++ b/deps/v8/test/mjsunit/es6/string-codepointat.js @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-strings - // Tests taken from: // https://github.com/mathiasbynens/String.prototype.codePointAt diff --git a/deps/v8/test/mjsunit/harmony/string-endswith.js b/deps/v8/test/mjsunit/es6/string-endswith.js index cc76b5fe4e..cbf2ed8766 100644 --- a/deps/v8/test/mjsunit/harmony/string-endswith.js +++ b/deps/v8/test/mjsunit/es6/string-endswith.js @@ -25,8 +25,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-strings - assertEquals(1, String.prototype.endsWith.length); var testString = "Hello World"; diff --git a/deps/v8/test/mjsunit/harmony/string-fromcodepoint.js b/deps/v8/test/mjsunit/es6/string-fromcodepoint.js index 97ecf0eec5..c4634ace44 100644 --- a/deps/v8/test/mjsunit/harmony/string-fromcodepoint.js +++ b/deps/v8/test/mjsunit/es6/string-fromcodepoint.js @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-strings - // Tests taken from: // https://github.com/mathiasbynens/String.fromCodePoint diff --git a/deps/v8/test/mjsunit/harmony/string-includes.js b/deps/v8/test/mjsunit/es6/string-includes.js index 33ed8ea44c..61bf779483 100644 --- a/deps/v8/test/mjsunit/harmony/string-includes.js +++ b/deps/v8/test/mjsunit/es6/string-includes.js @@ -25,8 +25,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-strings - assertEquals(1, String.prototype.includes.length); var reString = "asdf[a-z]+(asdf)?"; diff --git a/deps/v8/test/mjsunit/harmony/string-raw.js b/deps/v8/test/mjsunit/es6/string-raw.js index 28e2af9164..2c6bb2ff30 100644 --- a/deps/v8/test/mjsunit/harmony/string-raw.js +++ b/deps/v8/test/mjsunit/es6/string-raw.js @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-templates - (function testStringRawArity() { assertEquals(1, String.raw.length); })(); @@ -256,3 +254,39 @@ assertEquals("12345", String.raw(callSiteObj, arg(2), arg(4), arg(6))); assertEquals(["length", "raw1", "arg2", "raw3", "arg4", "raw5"], order); })(); + + +(function testStringRawToStringSubstitutionsOrder() { + var subs = []; + var log = []; + function stringify(toString) { + var valueOf = "_" + toString + "_"; + return { + toString: function() { return toString; }, + valueOf: function() { return valueOf; } + }; + } + function getter(name, value) { + return { + get: function() { + log.push("get" + name); + return value; + }, + set: function(v) { + log.push("set" + name); + } + }; + } + Object.defineProperties(subs, { + 0: getter(0, stringify("a")), + 1: getter(1, stringify("b")), + 2: getter(2, stringify("c")) + }); + + assertEquals("-a-b-c-", String.raw`-${subs[0]}-${subs[1]}-${subs[2]}-`); + assertArrayEquals(["get0", "get1", "get2"], log); + + log.length = 0; + assertEquals("-a-", String.raw`-${subs[0]}-`); + assertArrayEquals(["get0"], log); +})(); diff --git a/deps/v8/test/mjsunit/harmony/string-repeat.js b/deps/v8/test/mjsunit/es6/string-repeat.js index 0af74483a0..15caea14f3 100644 --- a/deps/v8/test/mjsunit/harmony/string-repeat.js +++ b/deps/v8/test/mjsunit/es6/string-repeat.js @@ -25,8 +25,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-strings - assertEquals("000", String.prototype.repeat.call(0, 3)); assertEquals("-1-1-1", String.prototype.repeat.call(-1, 3)); assertEquals("2.12.12.1", String.prototype.repeat.call(2.1, 3)); diff --git a/deps/v8/test/mjsunit/harmony/string-startswith.js b/deps/v8/test/mjsunit/es6/string-startswith.js index d72f2946f5..887db994a0 100644 --- a/deps/v8/test/mjsunit/harmony/string-startswith.js +++ b/deps/v8/test/mjsunit/es6/string-startswith.js @@ -25,8 +25,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-strings - assertEquals(1, String.prototype.startsWith.length); var testString = "Hello World"; diff --git a/deps/v8/test/mjsunit/es6/symbols.js b/deps/v8/test/mjsunit/es6/symbols.js index b9811f509e..46c3daba8a 100644 --- a/deps/v8/test/mjsunit/es6/symbols.js +++ b/deps/v8/test/mjsunit/es6/symbols.js @@ -245,25 +245,20 @@ TestCall() function TestCollections() { var set = new Set var map = new Map - var weakmap = new WeakMap for (var i in symbols) { set.add(symbols[i]) map.set(symbols[i], i) - weakmap.set(symbols[i], i) } assertEquals(symbols.length, set.size) assertEquals(symbols.length, map.size) for (var i in symbols) { assertTrue(set.has(symbols[i])) assertTrue(map.has(symbols[i])) - assertTrue(weakmap.has(symbols[i])) assertEquals(i, map.get(symbols[i])) - assertEquals(i, weakmap.get(symbols[i])) } for (var i in symbols) { assertTrue(set.delete(symbols[i])) assertTrue(map.delete(symbols[i])) - assertTrue(weakmap.delete(symbols[i])) } assertEquals(0, set.size) assertEquals(0, map.size) diff --git a/deps/v8/test/mjsunit/harmony/templates.js b/deps/v8/test/mjsunit/es6/templates.js index a884f58fb6..15296e8722 100644 --- a/deps/v8/test/mjsunit/harmony/templates.js +++ b/deps/v8/test/mjsunit/es6/templates.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-templates --harmony-unicode +// Flags: --harmony-unicode var num = 5; var str = "str"; @@ -423,10 +423,12 @@ var obj = { Object.defineProperty(Array.prototype, 0, { set: function() { assertUnreachable(); - } + }, + configurable: true }); function tag(){} tag`a${1}b`; + delete Array.prototype[0]; })(); @@ -518,3 +520,162 @@ var obj = { assertThrows("`${(function() { \"use strict\"; return \"\\07\"; })()}`", SyntaxError); })(); + + +var global = this; +(function testCallNew() { + "use strict"; + var called = false; + var calledWith; + global.log = function(x) { called = true; calledWith = x; } + + assertInstanceof(new Function`log("test")`, Object); + assertTrue(called); + assertSame("test", calledWith); + delete global.log; +})(); + + +(function testCallNew2() { + "use strict"; + var log = []; + function tag(x) { + log.push(x); + if (!(this instanceof tag)) { + return tag; + } + this.x = x === void 0 ? null : x; + return this; + } + // No arguments passed to constructor + var instance = new tag`x``y``z`; + assertInstanceof(instance, tag); + assertSame(tag.prototype, Object.getPrototypeOf(instance)); + assertEquals({ x: null }, instance); + assertEquals([["x"], ["y"], ["z"], undefined], log); + + // Arguments passed to constructor + log.length = 0; + instance = new tag`x2` `y2` `z2` (`test`); + assertInstanceof(instance, tag); + assertSame(tag.prototype, Object.getPrototypeOf(instance)); + assertEquals({ x: "test" }, instance); + assertEquals([["x2"], ["y2"], ["z2"], "test"], log); +})(); + + +(function testCallResultOfTagFn() { + "use strict"; + var i = 0; + var raw = []; + function tag(cs) { + var args = Array.prototype.slice.call(arguments); + var text = String.raw.apply(null, args); + if (i++ < 2) { + raw.push("tag;" + text); + return tag; + } + + raw.push("raw;" + text); + return text; + } + assertEquals("test3", tag`test1``test2``test3`); + assertEquals([ + "tag;test1", + "tag;test2", + "raw;test3" + ], raw); +})(); + + +(function testToStringSubstitutions() { + var a = { + toString: function() { return "a"; }, + valueOf: function() { return "-a-"; } + }; + var b = { + toString: function() { return "b"; }, + valueOf: function() { return "-b-"; } + }; + assertEquals("a", `${a}`); + assertEquals("ab", `${a}${b}`); + assertEquals("-a--b-", `${a + b}`); + assertEquals("-a-", `${a + ""}`); + assertEquals("1a", `1${a}`); + assertEquals("1a2", `1${a}2`); + assertEquals("1a2b", `1${a}2${b}`); + assertEquals("1a2b3", `1${a}2${b}3`); +})(); + + +(function testToStringSubstitutionsOrder() { + var subs = []; + var log = []; + function getter(name, value) { + return { + get: function() { + log.push("get" + name); + return value; + }, + set: function(v) { + log.push("set" + name); + } + }; + } + Object.defineProperties(subs, { + 0: getter(0, "a"), + 1: getter(1, "b"), + 2: getter(2, "c") + }); + + assertEquals("-a-b-c-", `-${subs[0]}-${subs[1]}-${subs[2]}-`); + assertArrayEquals(["get0", "get1", "get2"], log); +})(); + + +(function testTaggedToStringSubstitutionsOrder() { + var subs = []; + var log = []; + var tagged = []; + function getter(name, value) { + return { + get: function() { + log.push("get" + name); + return value; + }, + set: function(v) { + log.push("set" + name); + } + }; + } + Object.defineProperties(subs, { + 0: getter(0, 1), + 1: getter(1, 2), + 2: getter(2, 3) + }); + + function tag(cs) { + var n_substitutions = arguments.length - 1; + var n_cooked = cs.length; + var e = cs[0]; + var i = 0; + assertEquals(n_cooked, n_substitutions + 1); + while (i < n_substitutions) { + var sub = arguments[i++ + 1]; + var tail = cs[i]; + tagged.push(sub); + e = e.concat(sub, tail); + } + return e; + } + + assertEquals("-1-2-3-", tag`-${subs[0]}-${subs[1]}-${subs[2]}-`); + assertArrayEquals(["get0", "get1", "get2"], log); + assertArrayEquals([1, 2, 3], tagged); + + tagged.length = 0; + log.length = 0; + assertEquals("-1-", tag`-${subs[0]}-`); + assertArrayEquals(["get0"], log); + assertArrayEquals([1], tagged); +})(); diff --git a/deps/v8/test/mjsunit/es7/object-observe.js b/deps/v8/test/mjsunit/es7/object-observe.js index 5af205eadf..b2853c4048 100644 --- a/deps/v8/test/mjsunit/es7/object-observe.js +++ b/deps/v8/test/mjsunit/es7/object-observe.js @@ -1142,7 +1142,9 @@ var properties = ["a", "1", 1, "length", "setPrototype", "name", "caller"]; function blacklisted(obj, prop) { return (obj instanceof Int32Array && prop == 1) || (obj instanceof Int32Array && prop === "length") || - (obj instanceof ArrayBuffer && prop == 1) + (obj instanceof ArrayBuffer && prop == 1) || + (obj instanceof Function && prop === "name") || // Has its own test. + (obj instanceof Function && prop === "length"); // Has its own test. } for (var i in objects) for (var j in properties) { @@ -1798,3 +1800,66 @@ for (var b1 = 0; b1 < 2; ++b1) for (var n = 0; n < 3; ++n) for (var i in mutationByIncr) TestFastElementsLength(mutationByIncr[i], b1 != 0, b2 != 0, 7*n, 7*n+1); + + +(function TestFunctionName() { + reset(); + + function fun() {} + Object.observe(fun, observer.callback); + fun.name = 'x'; // No change. Not writable. + Object.defineProperty(fun, 'name', {value: 'a'}); + Object.defineProperty(fun, 'name', {writable: true}); + fun.name = 'b'; + delete fun.name; + fun.name = 'x'; // No change. Function.prototype.name is non writable + Object.defineProperty(Function.prototype, 'name', {writable: true}); + fun.name = 'c'; + fun.name = 'c'; // Same, no update. + Object.deliverChangeRecords(observer.callback); + observer.assertCallbackRecords([ + { object: fun, type: 'update', name: 'name', oldValue: 'fun' }, + { object: fun, type: 'reconfigure', name: 'name'}, + { object: fun, type: 'update', name: 'name', oldValue: 'a' }, + { object: fun, type: 'delete', name: 'name', oldValue: 'b' }, + { object: fun, type: 'add', name: 'name' }, + ]); +})(); + + +(function TestFunctionLength() { + reset(); + + function fun(x) {} + Object.observe(fun, observer.callback); + fun.length = 'x'; // No change. Not writable. + Object.defineProperty(fun, 'length', {value: 'a'}); + Object.defineProperty(fun, 'length', {writable: true}); + fun.length = 'b'; + delete fun.length; + fun.length = 'x'; // No change. Function.prototype.length is non writable + Object.defineProperty(Function.prototype, 'length', {writable: true}); + fun.length = 'c'; + fun.length = 'c'; // Same, no update. + Object.deliverChangeRecords(observer.callback); + observer.assertCallbackRecords([ + { object: fun, type: 'update', name: 'length', oldValue: 1 }, + { object: fun, type: 'reconfigure', name: 'length'}, + { object: fun, type: 'update', name: 'length', oldValue: 'a' }, + { object: fun, type: 'delete', name: 'length', oldValue: 'b' }, + { object: fun, type: 'add', name: 'length' }, + ]); +})(); + + +(function TestObserveInvalidAcceptMessage() { + var ex; + try { + Object.observe({}, function(){}, "not an object"); + } catch (e) { + ex = e; + } + assertInstanceof(ex, TypeError); + assertEquals("Third argument to Object.observe must be an array of strings.", + ex.message); +})() diff --git a/deps/v8/test/mjsunit/function-length-accessor.js b/deps/v8/test/mjsunit/function-length-accessor.js index 97c9f65822..386ac99643 100644 --- a/deps/v8/test/mjsunit/function-length-accessor.js +++ b/deps/v8/test/mjsunit/function-length-accessor.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-scoping --lazy +// Flags: --lazy function foo(a, b, c, d) { "use strict" diff --git a/deps/v8/test/mjsunit/function-prototype.js b/deps/v8/test/mjsunit/function-prototype.js index 7eac6df121..76ab53cf07 100644 --- a/deps/v8/test/mjsunit/function-prototype.js +++ b/deps/v8/test/mjsunit/function-prototype.js @@ -34,6 +34,9 @@ function TestNonObjectPrototype(value) { var f = new F(); assertEquals(value, F.prototype); assertEquals(Object.prototype, f.__proto__); + // Test that map transitions don't break anything. + F.property = "value"; + assertEquals(value, F.prototype); } var values = [123, "asdf", true]; diff --git a/deps/v8/test/mjsunit/harmony/block-const-assign.js b/deps/v8/test/mjsunit/harmony/block-const-assign.js deleted file mode 100644 index c21a0a3480..0000000000 --- a/deps/v8/test/mjsunit/harmony/block-const-assign.js +++ /dev/null @@ -1,137 +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. - -// Flags: --harmony-scoping - -// Test that we throw early syntax errors in harmony mode -// when using an immutable binding in an assigment or with -// prefix/postfix decrement/increment operators. - -"use strict"; - -// Function local const. -function constDecl0(use) { - return "(function() { const constvar = 1; " + use + "; })();"; -} - - -function constDecl1(use) { - return "(function() { " + use + "; const constvar = 1; })();"; -} - - -// Function local const, assign from eval. -function constDecl2(use) { - use = "eval('(function() { " + use + " })')()"; - return "(function() { const constvar = 1; " + use + "; })();"; -} - - -function constDecl3(use) { - use = "eval('(function() { " + use + " })')()"; - return "(function() { " + use + "; const constvar = 1; })();"; -} - - -// Block local const. -function constDecl4(use) { - return "(function() { { const constvar = 1; " + use + "; } })();"; -} - - -function constDecl5(use) { - return "(function() { { " + use + "; const constvar = 1; } })();"; -} - - -// Block local const, assign from eval. -function constDecl6(use) { - use = "eval('(function() {" + use + "})')()"; - return "(function() { { const constvar = 1; " + use + "; } })();"; -} - - -function constDecl7(use) { - use = "eval('(function() {" + use + "})')()"; - return "(function() { { " + use + "; const constvar = 1; } })();"; -} - - -// Function expression name. -function constDecl8(use) { - return "(function constvar() { " + use + "; })();"; -} - - -// Function expression name, assign from eval. -function constDecl9(use) { - use = "eval('(function(){" + use + "})')()"; - return "(function constvar() { " + use + "; })();"; -} - -let decls = [ constDecl0, - constDecl1, - constDecl2, - constDecl3, - constDecl4, - constDecl5, - constDecl6, - constDecl7, - constDecl8, - constDecl9 - ]; -let declsForTDZ = new Set([constDecl1, constDecl3, constDecl5, constDecl7]); -let uses = [ 'constvar = 1;', - 'constvar += 1;', - '++constvar;', - 'constvar++;' - ]; - -function Test(d,u) { - 'use strict'; - try { - print(d(u)); - eval(d(u)); - } catch (e) { - if (declsForTDZ.has(d) && u !== uses[0]) { - // In these cases, read of a const variable occurs - // before a write to it, so TDZ kicks in before const check. - assertInstanceof(e, ReferenceError); - return; - } - assertInstanceof(e, TypeError); - assertTrue(e.toString().indexOf("Assignment to constant variable") >= 0); - return; - } - assertUnreachable(); -} - -for (var d = 0; d < decls.length; ++d) { - for (var u = 0; u < uses.length; ++u) { - Test(decls[d], uses[u]); - } -} diff --git a/deps/v8/test/mjsunit/harmony/computed-property-names-classes.js b/deps/v8/test/mjsunit/harmony/computed-property-names-classes.js index 4e50f8a461..ab5d39e867 100644 --- a/deps/v8/test/mjsunit/harmony/computed-property-names-classes.js +++ b/deps/v8/test/mjsunit/harmony/computed-property-names-classes.js @@ -312,41 +312,74 @@ function assertIteratorResult(value, done, result) { (function TestPrototype() { - // Normally a static prototype property is not allowed. - class C { - static ['prototype']() { - return 1; + assertThrows(function() { + class C { + static ['prototype']() { + return 1; + } } - } - assertEquals(1, C.prototype()); + }, TypeError); - class C2 { - static get ['prototype']() { - return 2; + assertThrows(function() { + class C2 { + static get ['prototype']() { + return 2; + } } - } - assertEquals(2, C2.prototype); + }, TypeError); - var calls = 0; - class C3 { - static set ['prototype'](x) { - assertEquals(3, x); - calls++; + assertThrows(function() { + class C3 { + static set ['prototype'](x) { + assertEquals(3, x); + } } - } - C3.prototype = 3; - assertEquals(1, calls); + }, TypeError); + + assertThrows(function() { + class C4 { + static *['prototype']() { + yield 1; + yield 2; + } + } + }, TypeError); +})(); - class C4 { - static *['prototype']() { - yield 1; - yield 2; + +(function TestPrototypeConcat() { + assertThrows(function() { + class C { + static ['pro' + 'tot' + 'ype']() { + return 1; + } } - } - var iter = C4.prototype(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - assertIteratorResult(undefined, true, iter.next()); + }, TypeError); + + assertThrows(function() { + class C2 { + static get ['pro' + 'tot' + 'ype']() { + return 2; + } + } + }, TypeError); + + assertThrows(function() { + class C3 { + static set ['pro' + 'tot' + 'ype'](x) { + assertEquals(3, x); + } + } + }, TypeError); + + assertThrows(function() { + class C4 { + static *['pro' + 'tot' + 'ype']() { + yield 1; + yield 2; + } + } + }, TypeError); })(); @@ -388,3 +421,45 @@ function assertIteratorResult(value, done, result) { assertIteratorResult(2, false, iter.next()); assertIteratorResult(undefined, true, iter.next()); })(); + + +(function TestExceptionInName() { + function MyError() {}; + function throwMyError() { + throw new MyError(); + } + assertThrows(function() { + class C { + [throwMyError()]() {} + } + }, MyError); + assertThrows(function() { + class C { + get [throwMyError()]() { return 42; } + } + }, MyError); + assertThrows(function() { + class C { + set [throwMyError()](_) { } + } + }, MyError); +})(); + + +(function TestTdzName() { + assertThrows(function() { + class C { + [C]() {} + } + }, ReferenceError); + assertThrows(function() { + class C { + get [C]() { return 42; } + } + }, ReferenceError); + assertThrows(function() { + class C { + set [C](_) { } + } + }, ReferenceError); +})(); diff --git a/deps/v8/test/mjsunit/harmony/computed-property-names.js b/deps/v8/test/mjsunit/harmony/computed-property-names.js index 69360771c1..36e1411169 100644 --- a/deps/v8/test/mjsunit/harmony/computed-property-names.js +++ b/deps/v8/test/mjsunit/harmony/computed-property-names.js @@ -277,3 +277,26 @@ function ID(x) { assertEquals('X', object.x); assertEquals(proto, Object.getPrototypeOf(object)); })(); + + +(function TestExceptionInName() { + function MyError() {}; + function throwMyError() { + throw new MyError(); + } + assertThrows(function() { + var o = { + [throwMyError()]: 42 + }; + }, MyError); + assertThrows(function() { + var o = { + get [throwMyError()]() { return 42; } + }; + }, MyError); + assertThrows(function() { + var o = { + set [throwMyError()](_) { } + }; + }, MyError); +})(); diff --git a/deps/v8/test/mjsunit/harmony/module-linking.js b/deps/v8/test/mjsunit/harmony/module-linking.js index 3a5bc89793..faaf7f2e49 100644 --- a/deps/v8/test/mjsunit/harmony/module-linking.js +++ b/deps/v8/test/mjsunit/harmony/module-linking.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-modules --harmony-scoping +// Flags: --harmony-modules // Test basic module linking and initialization. diff --git a/deps/v8/test/mjsunit/harmony/module-resolution.js b/deps/v8/test/mjsunit/harmony/module-resolution.js index 1a95347d14..7f1e431313 100644 --- a/deps/v8/test/mjsunit/harmony/module-resolution.js +++ b/deps/v8/test/mjsunit/harmony/module-resolution.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --harmony-modules --harmony-scoping +// Flags: --harmony-modules // Test basic module interface inference. diff --git a/deps/v8/test/mjsunit/harmony/private.js b/deps/v8/test/mjsunit/harmony/private.js index 218094c3d5..c08daf1050 100644 --- a/deps/v8/test/mjsunit/harmony/private.js +++ b/deps/v8/test/mjsunit/harmony/private.js @@ -196,25 +196,20 @@ TestSet() function TestCollections() { var set = new Set var map = new Map - var weakmap = new WeakMap for (var i in symbols) { set.add(symbols[i]) map.set(symbols[i], i) - weakmap.set(symbols[i], i) } assertEquals(symbols.length, set.size) assertEquals(symbols.length, map.size) for (var i in symbols) { assertTrue(set.has(symbols[i])) assertTrue(map.has(symbols[i])) - assertTrue(weakmap.has(symbols[i])) assertEquals(i, map.get(symbols[i])) - assertEquals(i, weakmap.get(symbols[i])) } for (var i in symbols) { assertTrue(set.delete(symbols[i])) assertTrue(map.delete(symbols[i])) - assertTrue(weakmap.delete(symbols[i])) } assertEquals(0, set.size) assertEquals(0, map.size) diff --git a/deps/v8/test/mjsunit/harmony/reflect-apply.js b/deps/v8/test/mjsunit/harmony/reflect-apply.js new file mode 100644 index 0000000000..2cfb98282b --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/reflect-apply.js @@ -0,0 +1,212 @@ +// 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: --harmony-reflect + + +(function testReflectApplyArity() { + assertEquals(3, Reflect.apply.length); +})(); + + +(function testReflectApplyNonConstructor() { + assertThrows(function() { + new Reflect.apply(function(){}, null, []); + }, TypeError); +})(); + + +(function testAppliedReceiverSloppy() { + function returnThis() { return this; } + var receiver = {}; + + assertSame(this, Reflect.apply(returnThis, void 0, [])); + assertSame(this, Reflect.apply(returnThis, null, [])); + assertSame(this, Reflect.apply(returnThis, this, [])); + assertSame(receiver, Reflect.apply(returnThis, receiver, [])); + + // Wrap JS values + assertSame(String.prototype, + Object.getPrototypeOf(Reflect.apply(returnThis, "str", []))); + assertSame(Number.prototype, + Object.getPrototypeOf(Reflect.apply(returnThis, 123, []))); + assertSame(Boolean.prototype, + Object.getPrototypeOf(Reflect.apply(returnThis, true, []))); + assertSame(Symbol.prototype, + Object.getPrototypeOf( + Reflect.apply(returnThis, Symbol("test"), []))); +})(); + + +(function testAppliedReceiverStrict() { + function returnThis() { 'use strict'; return this; } + var receiver = {}; + + assertSame(void 0, Reflect.apply(returnThis, void 0, [])); + assertSame(this, Reflect.apply(returnThis, this, [])); + assertSame(receiver, Reflect.apply(returnThis, receiver, [])); + + // Don't wrap value types + var regexp = /123/; + var symbol = Symbol("test"); + assertSame("str", Reflect.apply(returnThis, "str", [])); + assertSame(123, Reflect.apply(returnThis, 123, [])); + assertSame(true, Reflect.apply(returnThis, true, [])); + assertSame(regexp, Reflect.apply(returnThis, regexp, [])); + assertSame(symbol, Reflect.apply(returnThis, symbol, [])); +})(); + + +(function testAppliedArgumentsLength() { + function returnLengthStrict() { 'use strict'; return arguments.length; } + function returnLengthSloppy() { return arguments.length; } + + assertEquals(0, Reflect.apply(returnLengthStrict, this, [])); + assertEquals(0, Reflect.apply(returnLengthSloppy, this, [])); + assertEquals(0, Reflect.apply(returnLengthStrict, this, {})); + assertEquals(0, Reflect.apply(returnLengthSloppy, this, {})); + + for (var i = 0; i < 256; ++i) { + assertEquals(i, Reflect.apply(returnLengthStrict, this, new Array(i))); + assertEquals(i, Reflect.apply(returnLengthSloppy, this, new Array(i))); + assertEquals(i, Reflect.apply(returnLengthStrict, this, { length: i })); + assertEquals(i, Reflect.apply(returnLengthSloppy, this, { length: i })); + } +})(); + + +(function testAppliedArgumentsLengthThrows() { + function noopStrict() { 'use strict'; } + function noopSloppy() { } + function MyError() {} + + var argsList = {}; + Object.defineProperty(argsList, "length", { + get: function() { throw new MyError(); } + }); + + assertThrows(function() { + Reflect.apply(noopStrict, this, argsList); + }, MyError); + + assertThrows(function() { + Reflect.apply(noopSloppy, this, argsList); + }, MyError); +})(); + + +(function testAppliedArgumentsElementThrows() { + function noopStrict() { 'use strict'; } + function noopSloppy() { } + function MyError() {} + + var argsList = { length: 1 }; + Object.defineProperty(argsList, "0", { + get: function() { throw new MyError(); } + }); + + assertThrows(function() { + Reflect.apply(noopStrict, this, argsList); + }, MyError); + + assertThrows(function() { + Reflect.apply(noopSloppy, this, argsList); + }, MyError); +})(); + + +(function testAppliedNonFunctionStrict() { + 'use strict'; + assertThrows(function() { Reflect.apply(void 0); }, TypeError); + assertThrows(function() { Reflect.apply(null); }, TypeError); + assertThrows(function() { Reflect.apply(123); }, TypeError); + assertThrows(function() { Reflect.apply("str"); }, TypeError); + assertThrows(function() { Reflect.apply(Symbol("x")); }, TypeError); + assertThrows(function() { Reflect.apply(/123/); }, TypeError); + assertThrows(function() { Reflect.apply(NaN); }, TypeError); + assertThrows(function() { Reflect.apply({}); }, TypeError); + assertThrows(function() { Reflect.apply([]); }, TypeError); +})(); + + +(function testAppliedNonFunctionSloppy() { + assertThrows(function() { Reflect.apply(void 0); }, TypeError); + assertThrows(function() { Reflect.apply(null); }, TypeError); + assertThrows(function() { Reflect.apply(123); }, TypeError); + assertThrows(function() { Reflect.apply("str"); }, TypeError); + assertThrows(function() { Reflect.apply(Symbol("x")); }, TypeError); + assertThrows(function() { Reflect.apply(/123/); }, TypeError); + assertThrows(function() { Reflect.apply(NaN); }, TypeError); + assertThrows(function() { Reflect.apply({}); }, TypeError); + assertThrows(function() { Reflect.apply([]); }, TypeError); +})(); + + +(function testAppliedArgumentsNonList() { + function noopStrict() { 'use strict'; } + function noopSloppy() {} + var R = void 0; + assertThrows(function() { Reflect.apply(noopStrict, R, null); }, TypeError); + assertThrows(function() { Reflect.apply(noopSloppy, R, null); }, TypeError); + assertThrows(function() { Reflect.apply(noopStrict, R, 1); }, TypeError); + assertThrows(function() { Reflect.apply(noopSloppy, R, 1); }, TypeError); + assertThrows(function() { Reflect.apply(noopStrict, R, "BAD"); }, TypeError); + assertThrows(function() { Reflect.apply(noopSloppy, R, "BAD"); }, TypeError); + assertThrows(function() { Reflect.apply(noopStrict, R, true); }, TypeError); + assertThrows(function() { Reflect.apply(noopSloppy, R, true); }, TypeError); + var sym = Symbol("x"); + assertThrows(function() { Reflect.apply(noopStrict, R, sym); }, TypeError); + assertThrows(function() { Reflect.apply(noopSloppy, R, sym); }, TypeError); +})(); + + +(function testAppliedArgumentValue() { + function returnFirstStrict(a) { 'use strict'; return a; } + function returnFirstSloppy(a) { return a; } + function returnLastStrict(a) { + 'use strict'; return arguments[arguments.length - 1]; } + function returnLastSloppy(a) { return arguments[arguments.length - 1]; } + function returnSumStrict() { + 'use strict'; + var sum = arguments[0]; + for (var i = 1; i < arguments.length; ++i) { + sum += arguments[i]; + } + return sum; + } + function returnSumSloppy() { + var sum = arguments[0]; + for (var i = 1; i < arguments.length; ++i) { + sum += arguments[i]; + } + return sum; + } + + assertEquals("OK!", Reflect.apply(returnFirstStrict, this, ["OK!"])); + assertEquals("OK!", Reflect.apply(returnFirstSloppy, this, ["OK!"])); + assertEquals("OK!", Reflect.apply(returnFirstStrict, this, + { 0: "OK!", length: 1 })); + assertEquals("OK!", Reflect.apply(returnFirstSloppy, this, + { 0: "OK!", length: 1 })); + assertEquals("OK!", Reflect.apply(returnLastStrict, this, + [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"])); + assertEquals("OK!", Reflect.apply(returnLastSloppy, this, + [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"])); + assertEquals("OK!", Reflect.apply(returnLastStrict, this, + { 9: "OK!", length: 10 })); + assertEquals("OK!", Reflect.apply(returnLastSloppy, this, + { 9: "OK!", length: 10 })); + assertEquals("TEST", Reflect.apply(returnSumStrict, this, + ["T", "E", "S", "T"])); + assertEquals("TEST!!", Reflect.apply(returnSumStrict, this, + ["T", "E", "S", "T", "!", "!"])); + assertEquals(10, Reflect.apply(returnSumStrict, this, + { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 })); + assertEquals("TEST", Reflect.apply(returnSumSloppy, this, + ["T", "E", "S", "T"])); + assertEquals("TEST!!", Reflect.apply(returnSumSloppy, this, + ["T", "E", "S", "T", "!", "!"])); + assertEquals(10, Reflect.apply(returnSumSloppy, this, + { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 })); +})(); diff --git a/deps/v8/test/mjsunit/harmony/reflect-construct.js b/deps/v8/test/mjsunit/harmony/reflect-construct.js new file mode 100644 index 0000000000..2211e3f783 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/reflect-construct.js @@ -0,0 +1,277 @@ +// 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: --harmony-reflect + + +(function testReflectConstructArity() { + assertEquals(2, Reflect.construct.length); +})(); + + +(function testReflectConstructNonConstructor() { + assertThrows(function() { + new Reflect.construct(function(){}, []); + }, TypeError); +})(); + + +(function testReflectConstructBasic() { + function Constructor() { "use strict"; } + assertInstanceof(Reflect.construct(Constructor, []), Constructor); +})(); + + +(function testReflectConstructBasicSloppy() { + function Constructor() {} + assertInstanceof(Reflect.construct(Constructor, []), Constructor); +})(); + + +(function testReflectConstructReturnSomethingElseStrict() { + var R = {}; + function Constructor() { "use strict"; return R; } + assertSame(R, Reflect.construct(Constructor, [])); +})(); + + +(function testReflectConstructReturnSomethingElseSloppy() { + var R = {}; + function Constructor() { return R; } + assertSame(R, Reflect.construct(Constructor, [])); +})(); + + +(function testReflectConstructNewTargetStrict() { + "use strict"; + function Constructor() { this[9] = 1; } + var O = Reflect.construct(Constructor, [], Array); + assertEquals(1, O[9]); + // Ordinary object with Array.prototype --- no exotic Array magic + assertFalse(Array.isArray(O)); + assertEquals(0, O.length); + assertSame(Array.prototype, Object.getPrototypeOf(O)); +})(); + + +(function testReflectConstructNewTargetSloppy() { + function Constructor() { this[9] = 1; } + var O = Reflect.construct(Constructor, [], Array); + assertEquals(1, O[9]); + // Ordinary object with Array.prototype --- no exotic Array magic + assertFalse(Array.isArray(O)); + assertEquals(0, O.length); + assertSame(Array.prototype, Object.getPrototypeOf(O)); +})(); + + +(function testReflectConstructNewTargetStrict2() { + "use strict"; + function Constructor() { this[9] = 1; } + Constructor.prototype.add = function(x) { + this[this.length] = x; return this; + } + var O = Reflect.construct(Array, [1, 2, 3], Constructor); + // Exotic Array object with Constructor.prototype + assertTrue(Array.isArray(O)); + assertSame(Constructor.prototype, Object.getPrototypeOf(O)); + assertFalse(O instanceof Array); + assertEquals(3, O.length); + assertEquals(undefined, O[9]); + assertSame(O, O.add(4)); + assertEquals(4, O.length); + assertEquals(4, O[3]); +})(); + + +(function testReflectConstructNewTargetSloppy2() { + function Constructor() { this[9] = 1; } + Constructor.prototype.add = function(x) { + this[this.length] = x; return this; + } + var O = Reflect.construct(Array, [1, 2, 3], Constructor); + // Exotic Array object with Constructor.prototype + assertTrue(Array.isArray(O)); + assertSame(Constructor.prototype, Object.getPrototypeOf(O)); + assertFalse(O instanceof Array); + assertEquals(3, O.length); + assertEquals(undefined, O[9]); + assertSame(O, O.add(4)); + assertEquals(4, O.length); + assertEquals(4, O[3]); +})(); + + +(function testReflectConstructNewTargetStrict3() { + "use strict"; + function A() {} + function B() {} + var O = Reflect.construct(A, [], B); + // TODO(caitp): bug: newTarget prototype is not used if it is not + // explicitly set. + //assertSame(B.prototype, Object.getPrototypeOf(O)); +})(); + + +(function testReflectConstructNewTargetSloppy3() { + function A() {} + function B() {} + var O = Reflect.construct(A, [], B); + // TODO(caitp): bug: newTarget prototype is not used if it is not + // explicitly set. + //assertSame(B.prototype, Object.getPrototypeOf(O)); +})(); + + +(function testAppliedArgumentsLength() { + function lengthStrict() { 'use strict'; this.a = arguments.length; } + function lengthSloppy() { this.a = arguments.length; } + + assertEquals(0, Reflect.construct(lengthStrict, []).a); + assertEquals(0, Reflect.construct(lengthSloppy, []).a); + assertEquals(0, Reflect.construct(lengthStrict, {}).a); + assertEquals(0, Reflect.construct(lengthSloppy, {}).a); + + for (var i = 0; i < 256; ++i) { + assertEquals(i, Reflect.construct(lengthStrict, new Array(i)).a); + assertEquals(i, Reflect.construct(lengthSloppy, new Array(i)).a); + assertEquals(i, Reflect.construct(lengthStrict, { length: i }).a); + assertEquals(i, Reflect.construct(lengthSloppy, { length: i }).a); + } +})(); + + +(function testAppliedArgumentsLengthThrows() { + function noopStrict() { 'use strict'; } + function noopSloppy() { } + function MyError() {} + + var argsList = {}; + Object.defineProperty(argsList, "length", { + get: function() { throw new MyError(); } + }); + + assertThrows(function() { + Reflect.construct(noopStrict, argsList); + }, MyError); + + assertThrows(function() { + Reflect.construct(noopSloppy, argsList); + }, MyError); +})(); + + +(function testAppliedArgumentsElementThrows() { + function noopStrict() { 'use strict'; } + function noopSloppy() { } + function MyError() {} + + var argsList = { length: 1 }; + Object.defineProperty(argsList, "0", { + get: function() { throw new MyError(); } + }); + + assertThrows(function() { + Reflect.construct(noopStrict, argsList); + }, MyError); + + assertThrows(function() { + Reflect.construct(noopSloppy, argsList); + }, MyError); +})(); + + +(function testAppliedNonFunctionStrict() { + 'use strict'; + assertThrows(function() { Reflect.construct(void 0, []); }, TypeError); + assertThrows(function() { Reflect.construct(null, []); }, TypeError); + assertThrows(function() { Reflect.construct(123, []); }, TypeError); + assertThrows(function() { Reflect.construct("str", []); }, TypeError); + assertThrows(function() { Reflect.construct(Symbol("x"), []); }, TypeError); + assertThrows(function() { Reflect.construct(/123/, []); }, TypeError); + assertThrows(function() { Reflect.construct(NaN, []); }, TypeError); + assertThrows(function() { Reflect.construct({}, []); }, TypeError); + assertThrows(function() { Reflect.construct([], []); }, TypeError); +})(); + + +(function testAppliedNonFunctionSloppy() { + assertThrows(function() { Reflect.construct(void 0, []); }, TypeError); + assertThrows(function() { Reflect.construct(null, []); }, TypeError); + assertThrows(function() { Reflect.construct(123, []); }, TypeError); + assertThrows(function() { Reflect.construct("str", []); }, TypeError); + assertThrows(function() { Reflect.construct(Symbol("x"), []); }, TypeError); + assertThrows(function() { Reflect.construct(/123/, []); }, TypeError); + assertThrows(function() { Reflect.construct(NaN, []); }, TypeError); + assertThrows(function() { Reflect.construct({}, []); }, TypeError); + assertThrows(function() { Reflect.construct([], []); }, TypeError); +})(); + + +(function testAppliedArgumentsNonList() { + function noopStrict() { 'use strict'; } + function noopSloppy() {} + assertThrows(function() { Reflect.construct(noopStrict, null); }, TypeError); + assertThrows(function() { Reflect.construct(noopSloppy, null); }, TypeError); + assertThrows(function() { Reflect.construct(noopStrict, 1); }, TypeError); + assertThrows(function() { Reflect.construct(noopSloppy, 1); }, TypeError); + assertThrows(function() { Reflect.construct(noopStrict, "BAD"); }, TypeError); + assertThrows(function() { Reflect.construct(noopSloppy, "BAD"); }, TypeError); + assertThrows(function() { Reflect.construct(noopStrict, true); }, TypeError); + assertThrows(function() { Reflect.construct(noopSloppy, true); }, TypeError); + var sym = Symbol("x"); + assertThrows(function() { Reflect.construct(noopStrict, sym); }, TypeError); + assertThrows(function() { Reflect.construct(noopSloppy, sym); }, TypeError); +})(); + + +(function testAppliedArgumentValue() { + function firstStrict(a) { 'use strict'; this.a = a; } + function firstSloppy(a) { this.a = a; } + function lastStrict(a) { + 'use strict'; this.a = arguments[arguments.length - 1]; } + function lastSloppy(a) { this.a = arguments[arguments.length - 1]; } + function sumStrict() { + 'use strict'; + var sum = arguments[0]; + for (var i = 1; i < arguments.length; ++i) { + sum += arguments[i]; + } + this.a = sum; + } + function sumSloppy() { + var sum = arguments[0]; + for (var i = 1; i < arguments.length; ++i) { + sum += arguments[i]; + } + this.a = sum; + } + + assertEquals("OK!", Reflect.construct(firstStrict, ["OK!"]).a); + assertEquals("OK!", Reflect.construct(firstSloppy, ["OK!"]).a); + assertEquals("OK!", Reflect.construct(firstStrict, + { 0: "OK!", length: 1 }).a); + assertEquals("OK!", Reflect.construct(firstSloppy, + { 0: "OK!", length: 1 }).a); + assertEquals("OK!", Reflect.construct(lastStrict, + [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"]).a); + assertEquals("OK!", Reflect.construct(lastSloppy, + [0, 1, 2, 3, 4, 5, 6, 7, 8, "OK!"]).a); + assertEquals("OK!", Reflect.construct(lastStrict, + { 9: "OK!", length: 10 }).a); + assertEquals("OK!", Reflect.construct(lastSloppy, + { 9: "OK!", length: 10 }).a); + assertEquals("TEST", Reflect.construct(sumStrict, + ["T", "E", "S", "T"]).a); + assertEquals("TEST!!", Reflect.construct(sumStrict, + ["T", "E", "S", "T", "!", "!"]).a); + assertEquals(10, Reflect.construct(sumStrict, + { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }).a); + assertEquals("TEST", Reflect.construct(sumSloppy, + ["T", "E", "S", "T"]).a); + assertEquals("TEST!!", Reflect.construct(sumSloppy, + ["T", "E", "S", "T", "!", "!"]).a); + assertEquals(10, Reflect.construct(sumSloppy, + { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }).a); +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-3501.js b/deps/v8/test/mjsunit/harmony/regress/regress-3501.js index 4b449e458f..4b449e458f 100644 --- a/deps/v8/test/mjsunit/regress/regress-3501.js +++ b/deps/v8/test/mjsunit/harmony/regress/regress-3501.js diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-448730.js b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-448730.js index 31d276aa83..31d276aa83 100644 --- a/deps/v8/test/mjsunit/regress/regress-crbug-448730.js +++ b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-448730.js diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-451770.js b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-451770.js index 942814a316..942814a316 100644 --- a/deps/v8/test/mjsunit/regress/regress-crbug-451770.js +++ b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-451770.js diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-crbug-461520.js b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-461520.js new file mode 100644 index 0000000000..c30260db72 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-461520.js @@ -0,0 +1,18 @@ +// Copyright 2015 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: --harmony-proxies + +var fuse = 1; +var handler = { + get: function() { return function() {} }, + getPropertyDescriptor: function() { + if (fuse-- == 0) throw "please die"; + return {value: function() {}, configurable: true}; + } +}; + +var p = Proxy.create(handler); +var o = Object.create(p); +with (o) { f() } diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-crbug-465671-null.js b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-465671-null.js new file mode 100644 index 0000000000..d24599c385 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-465671-null.js @@ -0,0 +1,16 @@ +// Copyright 2015 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: --harmony-arrow-functions + +// This used to trigger a segfault because of NULL being accessed. +function f() { + var a = [10]; + try { + f(); + } catch(e) { + a.map((v) => v + 1); + } +} +f(); diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-crbug-465671.js b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-465671.js new file mode 100644 index 0000000000..24f4d05475 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-465671.js @@ -0,0 +1,16 @@ +// Copyright 2015 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: --harmony-arrow-functions + +// This used to trigger crash because of an unhandled stack overflow. +function f() { + var a = [10]; + try { + f(); + } catch(e) { + a.map(v => v + 1); + } +} +f(); diff --git a/deps/v8/test/mjsunit/harmony/rest-params.js b/deps/v8/test/mjsunit/harmony/rest-params.js index 5bb258ee68..341cb33087 100644 --- a/deps/v8/test/mjsunit/harmony/rest-params.js +++ b/deps/v8/test/mjsunit/harmony/rest-params.js @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-rest-parameters +// Flags: --harmony-rest-parameters --harmony-classes (function testRestIndex() { assertEquals(5, (function(...args) { return args.length; })(1,2,3,4,5)); @@ -180,3 +180,35 @@ var O = { assertEquals([], ((...args) => args)()); assertEquals([1,2,3], ((...args) => args)(1,2,3)); })();*/ + + +(function testRestParamsWithNewTarget() { + "use strict"; + class Base { + constructor(...a) { + this.base = a; + assertEquals(arguments.length, a.length); + var args = []; + for (var i = 0; i < arguments.length; ++i) { + args.push(arguments[i]); + } + assertEquals(args, a); + } + } + class Child extends Base { + constructor(...b) { + super(1, 2, 3); + this.child = b; + assertEquals(arguments.length, b.length); + var args = []; + for (var i = 0; i < arguments.length; ++i) { + args.push(arguments[i]); + } + assertEquals(args, b); + } + } + + var c = new Child(1, 2, 3); + assertEquals([1, 2, 3], c.child); + assertEquals([1, 2, 3], c.base); +})(); diff --git a/deps/v8/test/mjsunit/harmony/typedarrays.js b/deps/v8/test/mjsunit/harmony/typedarrays.js index a4d6e7927a..0cdb7ed396 100644 --- a/deps/v8/test/mjsunit/harmony/typedarrays.js +++ b/deps/v8/test/mjsunit/harmony/typedarrays.js @@ -530,7 +530,7 @@ function TestTypedArraysWithIllegalIndices() { * assertEquals(undefined, a[-Infinity]); */ a[1.5] = 10; - assertEquals(undefined, a[1.5]); + assertEquals(10, a[1.5]); var nan = Math.sqrt(-1); a[nan] = 5; assertEquals(5, a[nan]); @@ -579,7 +579,7 @@ function TestTypedArraysWithIllegalIndicesStrict() { * assertEquals(undefined, a[-Infinity]); */ a[1.5] = 10; - assertEquals(undefined, a[1.5]); + assertEquals(10, a[1.5]); var nan = Math.sqrt(-1); a[nan] = 5; assertEquals(5, a[nan]); diff --git a/deps/v8/test/mjsunit/json2.js b/deps/v8/test/mjsunit/json2.js index f048f05290..f68c76c92a 100644 --- a/deps/v8/test/mjsunit/json2.js +++ b/deps/v8/test/mjsunit/json2.js @@ -183,3 +183,8 @@ try { externalizeString(str, true); } catch (e) { } TestStringify("\"external\"", str, null, 0); + +var o = {}; +o.somespecialproperty = 10; +o["\x19"] = 10; +assertThrows("JSON.parse('{\"somespecialproperty\":100, \"\x19\":10}')"); diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status index dc96a1de35..4b3ae5dd7c 100644 --- a/deps/v8/test/mjsunit/mjsunit.status +++ b/deps/v8/test/mjsunit/mjsunit.status @@ -68,6 +68,7 @@ 'compare-known-objects-slow': [PASS, NO_VARIANTS], 'elements-kind': [PASS, NO_VARIANTS], 'opt-elements-kind': [PASS, NO_VARIANTS], + 'smi-representation': [PASS, NO_VARIANTS], # Some tests are just too slow to run for now. 'big-object-literal': [PASS, NO_VARIANTS], @@ -95,25 +96,11 @@ 'debug-evaluate-locals': [PASS, NO_VARIANTS], 'debug-liveedit-check-stack': [PASS, NO_VARIANTS], # only in no-snap mode. 'debug-liveedit-double-call': [PASS, NO_VARIANTS], - 'debug-step-stub-callfunction': [PASS, NO_VARIANTS], 'debug-set-variable-value': [PASS, NO_VARIANTS], - 'debug-stepin-accessor': [PASS, NO_VARIANTS], - 'debug-stepin-builtin': [PASS, NO_VARIANTS], - 'debug-stepin-constructor': [PASS, NO_VARIANTS], - 'debug-stepin-function-call': [PASS, NO_VARIANTS], - 'debug-stepnext-do-while': [PASS, NO_VARIANTS], 'debug-stepout-scope-part1': [PASS, NO_VARIANTS], 'debug-stepout-scope-part2': [PASS, NO_VARIANTS], 'debug-stepout-scope-part3': [PASS, NO_VARIANTS], - 'es6/debug-stepin-microtasks': [PASS, NO_VARIANTS], - 'es6/debug-stepnext-for': [PASS, NO_VARIANTS], - 'harmony/debug-evaluate-blockscopes': [PASS, NO_VARIANTS], - - # TODO(jarin): Some tests don't like --turbo-deoptimzation very much. - 'asm/embenchen/lua_binarytrees': [SKIP], - 'es6/symbols': [PASS, NO_VARIANTS], - 'regress/regress-354433': [PASS, NO_VARIANTS], # only on ARM simulator. - 'regress/regress-crbug-259300': [PASS, NO_VARIANTS], + 'es6/debug-evaluate-blockscopes': [PASS, NO_VARIANTS], ############################################################################## # Too slow in debug mode with --stress-opt mode. @@ -123,6 +110,11 @@ 'regress/regress-create-exception': [PASS, ['mode == debug', SKIP]], ############################################################################## + # Too slow in debug mode for validation of elements. + 'regress/regress-430201': [PASS, ['mode == debug', SKIP]], + 'regress/regress-430201b': [PASS, ['mode == debug', SKIP]], + + ############################################################################## # Too slow in debug mode for GC stress mode. 'regress/regress-crbug-217858': [PASS, ['mode == debug', SKIP]], @@ -139,6 +131,7 @@ # Very slow on ARM and MIPS, contains no architecture dependent code. 'unicode-case-overoptimization': [PASS, NO_VARIANTS, ['arch == arm or arch == android_arm or arch == android_arm64 or arch == mipsel or arch == mips64el or arch == mips', TIMEOUT]], + 'regress/regress-3976': [PASS, NO_VARIANTS, ['arch == arm or arch == android_arm or arch == android_arm64 or arch == mipsel or arch == mips64el or arch == mips', SKIP]], ############################################################################## # This test expects to reach a certain recursion depth, which may not work @@ -185,6 +178,10 @@ # nosse2. Also for arm novfp3. 'regress/regress-2989': [FAIL, NO_VARIANTS, ['system == linux and arch == x87 or arch == arm and simulator == True', PASS]], + # BUG(v8:3985). Wrong materialization of arguments object after throwing + # an exception. + 'regress/regress-3985': [PASS, FAIL], + # Skip endain dependent test for mips due to different typed views of the same # array buffer. 'nans': [PASS, ], @@ -194,6 +191,9 @@ # Too slow for slow variants. 'asm/embenchen/*': [PASS, SLOW, FAST_VARIANTS], + + # BUG(v8:3838). + 'regress/regress-3116': [PASS, ['isolates', FLAKY]], }], # ALWAYS ############################################################################## @@ -210,7 +210,7 @@ 'fast-prototype': [SKIP], 'field-type-tracking': [SKIP], 'getters-on-elements': [SKIP], - 'harmony/block-let-crankshaft': [SKIP], + 'es6/block-let-crankshaft': [SKIP], 'opt-elements-kind': [SKIP], 'osr-elements-kind': [SKIP], 'regress/regress-crbug-137689': [SKIP], @@ -244,8 +244,10 @@ # Issue 3723. 'regress/regress-3717': [SKIP], - # Issue 3776. - 'debug-stepframe': [SKIP], + # Issue 3924. + 'mjsunit/debug-clearbreakpointgroup': [SKIP], + # Issue 3969. + 'mjsunit/debug-references': [SKIP], }], # 'gc_stress == True' ############################################################################## @@ -585,7 +587,17 @@ 'readonly': [SKIP], 'array-feedback': [SKIP], + # Deopting uses just enough memory to make this one OOM. + 'regress/regress-3976': [SKIP], + # Deopt every n garbage collections collides with deopt every n times. 'regress/regress-2653': [SKIP], }], # 'deopt_fuzzer == True' + +############################################################################## +['arch == ppc and simulator_run == True or arch == ppc64 and simulator_run == True', { + + # take too long with the simulator. + 'regress/regress-1132': [SKIP], +}], # 'arch == ppc and simulator_run == True' ] diff --git a/deps/v8/test/mjsunit/regexp-stack-overflow.js b/deps/v8/test/mjsunit/regexp-stack-overflow.js new file mode 100644 index 0000000000..63f6971ace --- /dev/null +++ b/deps/v8/test/mjsunit/regexp-stack-overflow.js @@ -0,0 +1,18 @@ +// Copyright 2015 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: --stack-size=100 + +var re = /\w/; +re.test("a"); // Trigger regexp compile. + +function rec() { + try { + return rec(); + } catch (e) { + return re.test("b"); + } +} + +assertTrue(rec()); diff --git a/deps/v8/test/mjsunit/regress/regress-1530.js b/deps/v8/test/mjsunit/regress/regress-1530.js index 20d1f265c0..fa86f62ce5 100644 --- a/deps/v8/test/mjsunit/regress/regress-1530.js +++ b/deps/v8/test/mjsunit/regress/regress-1530.js @@ -80,8 +80,10 @@ assertFalse(Object.getOwnPropertyDescriptor(f, 'prototype').writable); assertThrows("'use strict'; f.prototype = {}"); assertThrows("Object.defineProperty(f, 'prototype', { value: {} })"); -// Verify that non-writability of other properties is respected. -assertThrows("Object.defineProperty(f, 'name', { value: {} })"); -assertThrows("Object.defineProperty(f, 'length', { value: {} })"); +// Verify that non-configurability of other properties is respected, but +// non-writability is ignored by Object.defineProperty(). +// name and length are configurable in ES6 +Object.defineProperty(f, 'name', { value: {} }); +Object.defineProperty(f, 'length', { value: {} }); assertThrows("Object.defineProperty(f, 'caller', { value: {} })"); assertThrows("Object.defineProperty(f, 'arguments', { value: {} })"); diff --git a/deps/v8/test/mjsunit/regress/regress-270142.js b/deps/v8/test/mjsunit/regress/regress-270142.js index 6e0865c4f8..63f4d1414e 100644 --- a/deps/v8/test/mjsunit/regress/regress-270142.js +++ b/deps/v8/test/mjsunit/regress/regress-270142.js @@ -39,7 +39,7 @@ function g(x) { function checkNameDescriptor(f) { var descriptor = Object.getOwnPropertyDescriptor(f, "name"); - assertFalse(descriptor.configurable); + assertTrue(descriptor.configurable); assertFalse(descriptor.enumerable); assertFalse(descriptor.writable); } diff --git a/deps/v8/test/mjsunit/regress/regress-330046.js b/deps/v8/test/mjsunit/regress/regress-330046.js index d94b804ac0..eb0d3f38a2 100644 --- a/deps/v8/test/mjsunit/regress/regress-330046.js +++ b/deps/v8/test/mjsunit/regress/regress-330046.js @@ -58,4 +58,4 @@ f(10, o3); // The old code is already deoptimized, but f still points to it. // Disassembling it will crash. -%DebugDisassembleFunction(f); +%DisassembleFunction(f); diff --git a/deps/v8/test/mjsunit/regress/regress-3960.js b/deps/v8/test/mjsunit/regress/regress-3960.js new file mode 100644 index 0000000000..4aaab0b067 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-3960.js @@ -0,0 +1,36 @@ +// Copyright 2015 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 + +// Test that setting break point is works correctly when the debugger is +// activated late, which leads to duplicate shared function infos. + +(function() { + var Debug = %GetDebugContext().Debug; + + function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + assertTrue(/foo/.test(exec_state.frame(0).sourceLineText())); + break_count++; + } catch (e) { + exception = e; + } + } + + for (var i = 0; i < 3; i++) { + var foo = function() { a = 1; } + var exception = null; + var break_count = 0; + Debug.setListener(listener); + if (i < 2) Debug.setBreakPoint(foo, 0, 0); + assertTrue(/\[B\d\]a = 1/.test(Debug.showBreakPoints(foo))); + foo(); + assertEquals(1, break_count); + assertNull(exception); + } + + Debug.setListener(null); +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-3969.js b/deps/v8/test/mjsunit/regress/regress-3969.js new file mode 100644 index 0000000000..4659e1caf8 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-3969.js @@ -0,0 +1,36 @@ +// Copyright 2015 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 + +function Inner() { + this.property = "OK"; + this.o2 = 1; +} + +function Outer(inner) { + this.inner = inner; +} + +var inner = new Inner(); +var outer = new Outer(inner); + +Outer.prototype.boom = function() { + return this.inner.property; +} + +assertEquals("OK", outer.boom()); +assertEquals("OK", outer.boom()); +%OptimizeFunctionOnNextCall(Outer.prototype.boom); +assertEquals("OK", outer.boom()); + +inner = undefined; +%SetAllocationTimeout(0 /*interval*/, 2 /*timeout*/); +// Call something that will do GC while holding a handle to outer's map. +// The key is that this lets inner's map die while keeping outer's map alive. +delete outer.inner; + +outer = new Outer({field: 1.51, property: "OK"}); + +assertEquals("OK", outer.boom()); diff --git a/deps/v8/test/mjsunit/regress/regress-3976.js b/deps/v8/test/mjsunit/regress/regress-3976.js new file mode 100644 index 0000000000..c151f689f4 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-3976.js @@ -0,0 +1,80 @@ +// Copyright 2015 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. + +// Flags: --max-old-space-size=60 + +table = []; + +for (var i = 0; i < 32; i++) { + table[i] = String.fromCharCode(i + 0x410); +} + + +var random = (function() { + var seed = 10; + return function() { + seed = (seed * 1009) % 8831; + return seed; + }; +})(); + + +function key(length) { + var s = ""; + for (var i = 0; i < length; i++) { + s += table[random() % 32]; + } + return '"' + s + '"'; +} + + +function value() { + return '[{' + '"field1" : ' + random() + ', "field2" : ' + random() + '}]'; +} + + +function generate(n) { + var s = '{'; + for (var i = 0; i < n; i++) { + if (i > 0) s += ', '; + s += key(random() % 10 + 7); + s += ':'; + s += value(); + } + s += '}'; + return s; +} + + +print("generating"); + +var str = generate(50000); + +print("parsing " + str.length); +JSON.parse(str); + +print("done"); diff --git a/deps/v8/test/mjsunit/regress/regress-3985.js b/deps/v8/test/mjsunit/regress/regress-3985.js new file mode 100644 index 0000000000..6dbc4bdadd --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-3985.js @@ -0,0 +1,45 @@ +// Copyright 2015 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 + +var shouldThrow = false; + +function h() { + try { // Prevent inlining in Crankshaft. + } catch(e) { } + var res = g.arguments[0].x; + if (shouldThrow) { + throw res; + } + return res; +} + +function g(o) { h(); } + +function f1() { + var o = { x : 1 }; + g(o); + return o.x; +} + +function f2() { + var o = { x : 2 }; + g(o); + return o.x; +} + +f1(); +f2(); +f1(); +f2(); +%OptimizeFunctionOnNextCall(f1); +%OptimizeFunctionOnNextCall(f2); +shouldThrow = true; +try { f1(); } catch(e) { + assertEquals(e, 1); +} +try { f2(); } catch(e) { + assertEquals(e, 2); +} diff --git a/deps/v8/test/mjsunit/regress/regress-4023.js b/deps/v8/test/mjsunit/regress/regress-4023.js new file mode 100644 index 0000000000..902741f6f5 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-4023.js @@ -0,0 +1,67 @@ +// Copyright 2015 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 --expose-gc --block-concurrent-recompilation + +function Inner() { + this.property = "OK"; + this.prop2 = 1; +} + +function Outer() { + this.o = "u"; +} +function KeepMapAlive(o) { + return o.o; +} +function SetInner(o, i) { + o.inner_field = i; +} +function Crash(o) { + return o.inner_field.property; +} + +var inner = new Inner(); +var outer = new Outer(); + +// Collect type feedback. +SetInner(new Outer(), inner); +SetInner(outer, inner); + +// This function's only purpose is to stash away a Handle that keeps +// outer's map alive during the gc() call below. We store this handle +// on the compiler thread :-) +KeepMapAlive(outer); +KeepMapAlive(outer); +%OptimizeFunctionOnNextCall(KeepMapAlive, "concurrent"); +KeepMapAlive(outer); + +// So far, all is well. Collect type feedback and optimize. +print(Crash(outer)); +print(Crash(outer)); +%OptimizeFunctionOnNextCall(Crash); +print(Crash(outer)); + +// Null out references and perform GC. This will keep outer's map alive +// (due to the handle created above), but will let inner's map die. Hence, +// inner_field's field type stored in outer's map will get cleared. +inner = undefined; +outer = undefined; +gc(); + +// We could unblock the compiler thread now. But why bother? + +// Now optimize SetInner while inner_field's type is still cleared! +// This will generate optimized code that stores arbitrary objects +// into inner_field without checking their type against the field type. +%OptimizeFunctionOnNextCall(SetInner); + +// Use the optimized code to store an arbitrary object into +// o2's inner_field, without triggering any dependent code deopts... +var o2 = new Outer(); +SetInner(o2, { invalid: 1.51, property: "OK" }); +// ...and then use the existing code expecting an Inner-class object to +// read invalid data (in this case, a raw double). +// We crash trying to convert the raw double into a printable string. +print(Crash(o2)); diff --git a/deps/v8/test/mjsunit/regress/regress-4027.js b/deps/v8/test/mjsunit/regress/regress-4027.js new file mode 100644 index 0000000000..3a5d11b8e5 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-4027.js @@ -0,0 +1,60 @@ +// Copyright 2015 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 --expose-gc + +function Inner() { + this.inner_name = "inner"; +} + +function Boom() { + this.boom = "boom"; +} + +function Outer() { + this.outer_name = "outer"; +} + +function SetInner(inner, value) { + inner.prop = value; +} + +function SetOuter(outer, value) { + outer.inner = value; +} + +var inner1 = new Inner(); +var inner2 = new Inner(); + +SetInner(inner1, 10); +SetInner(inner2, 10); + +var outer1 = new Outer(); +var outer2 = new Outer(); +var outer3 = new Outer(); + +SetOuter(outer1, inner1); +SetOuter(outer1, inner1); +SetOuter(outer1, inner1); + +SetOuter(outer2, inner2); +SetOuter(outer2, inner2); +SetOuter(outer2, inner2); + +SetOuter(outer3, inner2); +SetOuter(outer3, inner2); +SetOuter(outer3, inner2); + + +SetInner(inner2, 6.5); + +outer1 = null; +inner1 = null; + +gc(); + +var boom = new Boom(); +SetOuter(outer2, boom); + +gc(); diff --git a/deps/v8/test/preparser/strict-const.js b/deps/v8/test/mjsunit/regress/regress-430201b.js index 97b908128e..056504d1d7 100644 --- a/deps/v8/test/preparser/strict-const.js +++ b/deps/v8/test/mjsunit/regress/regress-430201b.js @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2010 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -24,8 +24,20 @@ // 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. -// -// Flags: --noharmony-scoping -"use strict"; -const x = 42; +// Flags: --allow-natives-syntax --expose-gc + +(function() { + var array_1 = []; + + %SetFlags("--stress-compaction"); + for (var a = 0; a < 10000; a++) { array_1[a * 100] = 0; } + + gc(); + gc(); + + var array_2 = []; + for (var i = 0; i < 321361; i++) { + array_2[i] = String.fromCharCode(i)[0]; + } +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-460937.js b/deps/v8/test/mjsunit/regress/regress-460937.js new file mode 100644 index 0000000000..cd57f93328 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-460937.js @@ -0,0 +1,19 @@ +// Copyright 2015 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 + +function f() { + var a = new Array(100000); + var i = 0; + while (!%HasFastDoubleElements(a)) { + a[i] = i; + i += 0.1; + } + a[1] = 1.5; +} + +f(); +%OptimizeFunctionOnNextCall(f); +f(); diff --git a/deps/v8/test/mjsunit/regress/regress-463028.js b/deps/v8/test/mjsunit/regress/regress-463028.js new file mode 100644 index 0000000000..1454ef1aea --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-463028.js @@ -0,0 +1,18 @@ +// Copyright 2015 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 + +var o = {} +Object.defineProperty(o, "z", { + set: function() { + %DeoptimizeFunction(f); + }, +}); + +function f(o) { + return 19 + (void(o.z = 12)); +} + +f(o); diff --git a/deps/v8/test/mjsunit/regress/regress-469605.js b/deps/v8/test/mjsunit/regress/regress-469605.js new file mode 100644 index 0000000000..65725117bd --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-469605.js @@ -0,0 +1,43 @@ +// Copyright 2015 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 counter() { + var i = 100; + return function() { + if (i-- > 0) return i; + throw "done"; + } +} + +var c1 = counter(); +var c2 = counter(); + +var f = (function() { + "use asm"; + return function f(i) { + i = i|0; + do { + if (i > 0) c1(); + else c2(); + } while (true); + } +})(); + +assertThrows(function() { f(0); }); +assertThrows(function() { f(1); }); + +var c3 = counter(); + +var g = (function() { + "use asm"; + return function g(i) { + i = i + 1; + do { + i = c3(i); + } while (true); + } +})(); + +assertThrows(function() { g(0); }); +assertThrows(function() { g(1); }); diff --git a/deps/v8/test/mjsunit/regress/regress-470804.js b/deps/v8/test/mjsunit/regress/regress-470804.js new file mode 100644 index 0000000000..cebb91f7e0 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-470804.js @@ -0,0 +1,53 @@ +// Copyright 2015 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-gc + +function f() { + this.foo00 = 0; + this.foo01 = 0; + this.foo02 = 0; + this.foo03 = 0; + this.foo04 = 0; + this.foo05 = 0; + this.foo06 = 0; + this.foo07 = 0; + this.foo08 = 0; + this.foo09 = 0; + this.foo0a = 0; + this.foo0b = 0; + this.foo0c = 0; + this.foo0d = 0; + this.foo0e = 0; + this.foo0f = 0; + this.foo10 = 0; + this.foo11 = 0; + this.foo12 = 0; + this.foo13 = 0; + this.foo14 = 0; + this.foo15 = 0; + this.foo16 = 0; + this.foo17 = 0; + this.foo18 = 0; + this.foo19 = 0; + this.foo1a = 0; + this.foo1b = 0; + this.foo1c = 0; + this.foo1d = 0; + this.foo1e = 0; + this.foo1f = 0; + this.d = 1.3; + gc(); + this.boom = 230; + this.boom = 1.4; +} + +function g() { + return new f(); +} +g(); +g(); +var o = g(); +assertEquals(0, o.foo00); +assertEquals(1.4, o.boom); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-385002.js b/deps/v8/test/mjsunit/regress/regress-crbug-385002.js index 34713e27d4..e9023e1d6d 100644 --- a/deps/v8/test/mjsunit/regress/regress-crbug-385002.js +++ b/deps/v8/test/mjsunit/regress/regress-crbug-385002.js @@ -4,7 +4,7 @@ // Flags: --stack-size=200 --allow-natives-syntax -%Break(); // Schedule an interrupt that does not go away. +%ScheduleBreak(); // Schedule an interrupt that does not go away. function f() { f(); } assertThrows(f, RangeError); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-401915.js b/deps/v8/test/mjsunit/regress/regress-crbug-401915.js index 96dce04868..67ea19158e 100644 --- a/deps/v8/test/mjsunit/regress/regress-crbug-401915.js +++ b/deps/v8/test/mjsunit/regress/regress-crbug-401915.js @@ -10,7 +10,7 @@ Debug.setBreakOnException(); try { try { - %DebugPushPromise(new Promise(function() {})); + %DebugPushPromise(new Promise(function() {}), function() {}); } catch (e) { } throw new Error(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-465564.js b/deps/v8/test/mjsunit/regress/regress-crbug-465564.js new file mode 100644 index 0000000000..ea0c8dcf66 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-465564.js @@ -0,0 +1,7 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --cache=code + +assertEquals(-1, %StringCompare("a", "b")); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-467047.js b/deps/v8/test/mjsunit/regress/regress-crbug-467047.js new file mode 100644 index 0000000000..373e984a2c --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-467047.js @@ -0,0 +1,17 @@ +// Copyright 2015 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: --stack-size=100 + +function captureMatch(re) { + var local_variable = 0; + "abcd".replace(re, function() { }); + assertEquals("abcd", RegExp.input); + assertEquals("a", RegExp.leftContext); + assertEquals("bc", RegExp.lastMatch); + assertEquals("d", RegExp.rightContext); + assertEquals("foo", captureMatch(/^bar/)); +} + +assertThrows(function() { captureMatch(/(bc)/) }, RangeError); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-467531.js b/deps/v8/test/mjsunit/regress/regress-crbug-467531.js new file mode 100644 index 0000000000..73256c7acc --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-467531.js @@ -0,0 +1,25 @@ +// Copyright 2015 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: --turbo-filter=* --always-opt + +assertThrows(function() { + "use strict"; + try { + x = ref_error; + let x = 0; + } catch (e) { + throw e; + } +}, ReferenceError); + +assertThrows(function() { + "use strict"; + try { + x = ref_error; + let x = 0; + } finally { + // re-throw + } +}, ReferenceError); diff --git a/deps/v8/test/mjsunit/regress/regress-filter-contexts.js b/deps/v8/test/mjsunit/regress/regress-filter-contexts.js new file mode 100644 index 0000000000..d2abe00325 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-filter-contexts.js @@ -0,0 +1,14 @@ +// Copyright 2015 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 + +function f() { return f.x; } +f.__proto__ = null; +f.prototype = ""; + +f(); +f(); +%OptimizeFunctionOnNextCall(f); +f(); diff --git a/deps/v8/test/mjsunit/regress/regress-function-length-strict.js b/deps/v8/test/mjsunit/regress/regress-function-length-strict.js index 700f34a67a..77cca24054 100644 --- a/deps/v8/test/mjsunit/regress/regress-function-length-strict.js +++ b/deps/v8/test/mjsunit/regress/regress-function-length-strict.js @@ -37,5 +37,5 @@ var desc = Object.getOwnPropertyDescriptor(foo, 'length'); assertEquals(3, desc.value); assertFalse(desc.writable); assertFalse(desc.enumerable); -assertFalse(desc.configurable); +assertTrue(desc.configurable); assertThrows(function() { foo.length = 2; }, TypeError); diff --git a/deps/v8/test/mjsunit/regress/string-compare-memcmp.js b/deps/v8/test/mjsunit/regress/string-compare-memcmp.js index 45f47343ee..ae4b33ace9 100644 --- a/deps/v8/test/mjsunit/regress/string-compare-memcmp.js +++ b/deps/v8/test/mjsunit/regress/string-compare-memcmp.js @@ -4,4 +4,4 @@ // Flags: --allow-natives-syntax -assertEquals(-1, %StringCompare("abc\u0102", "abc\u0201")); +assertEquals(-1, %StringCompareRT("abc\u0102", "abc\u0201")); diff --git a/deps/v8/test/mjsunit/stack-traces.js b/deps/v8/test/mjsunit/stack-traces.js index f80a627b24..b256033b53 100644 --- a/deps/v8/test/mjsunit/stack-traces.js +++ b/deps/v8/test/mjsunit/stack-traces.js @@ -94,6 +94,37 @@ function testAnonymousMethod() { (function () { FAIL }).call([1, 2, 3]); } +function testFunctionName() { + function gen(name, counter) { + var f = function foo() { + if (counter === 0) { + FAIL; + } + gen(name, counter - 1)(); + } + if (counter === 4) { + Object.defineProperty(f, 'name', {get: function(){ throw 239; }}); + } else if (counter == 3) { + Object.defineProperty(f, 'name', {value: 'boo' + '_' + counter}); + } else { + Object.defineProperty(f, 'name', {writable: true}); + if (counter === 2) + f.name = 42; + else + f.name = name + '_' + counter; + } + return f; + } + gen('foo', 4)(); +} + +function testFunctionInferredName() { + var f = function() { + FAIL; + } + f(); +} + function CustomError(message, stripPoint) { this.message = message; Error.captureStackTrace(this, stripPoint); @@ -261,6 +292,9 @@ testTrace("testValue", testValue, ["at Number.causeError"]); testTrace("testConstructor", testConstructor, ["new Plonk"]); testTrace("testRenamedMethod", testRenamedMethod, ["Wookie.a$b$c$d [as d]"]); testTrace("testAnonymousMethod", testAnonymousMethod, ["Array.<anonymous>"]); +testTrace("testFunctionName", testFunctionName, + [" at foo_0 ", " at foo_1", " at foo ", " at boo_3 ", " at foo "]); +testTrace("testFunctionInferredName", testFunctionInferredName, [" at f "]); testTrace("testDefaultCustomError", testDefaultCustomError, ["hep-hey", "new CustomError"], ["collectStackTrace"]); diff --git a/deps/v8/test/mjsunit/strict-mode.js b/deps/v8/test/mjsunit/strict-mode.js index d0839ba0fb..c97429f7b7 100644 --- a/deps/v8/test/mjsunit/strict-mode.js +++ b/deps/v8/test/mjsunit/strict-mode.js @@ -25,8 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --turbo-deoptimization --noharmony-scoping -// Flags: --noharmony-classes --noharmony-object-literals +// Flags: --turbo-deoptimization function CheckStrictMode(code, exception) { assertDoesNotThrow(code); @@ -287,19 +286,6 @@ CheckStrictMode("function strict() { print(--arguments); }", SyntaxError); CheckStrictMode("function strict() { var x = --eval; }", SyntaxError); CheckStrictMode("function strict() { var x = --arguments; }", SyntaxError); -// Use of const in strict mode is disallowed in anticipation of ES Harmony. -CheckStrictMode("const x = 0;", SyntaxError); -CheckStrictMode("for (const x = 0; false;) {}", SyntaxError); -CheckStrictMode("function strict() { const x = 0; }", SyntaxError); - -// Strict mode only allows functions in StatementList -CheckStrictMode("if (true) { function invalid() {} }", SyntaxError); -CheckStrictMode("for (;false;) { function invalid() {} }", SyntaxError); -CheckStrictMode("{ function invalid() {} }", SyntaxError); -CheckStrictMode("try { function invalid() {} } catch(e) {}", SyntaxError); -CheckStrictMode("try { } catch(e) { function invalid() {} }", SyntaxError); -CheckStrictMode("function outer() {{ function invalid() {} }}", SyntaxError); - // Delete of an unqualified identifier CheckStrictMode("delete unqualified;", SyntaxError); CheckStrictMode("function strict() { delete unqualified; }", SyntaxError); diff --git a/deps/v8/test/mjsunit/string-concat.js b/deps/v8/test/mjsunit/string-concat.js new file mode 100644 index 0000000000..c669b3bd4b --- /dev/null +++ b/deps/v8/test/mjsunit/string-concat.js @@ -0,0 +1,14 @@ +// Copyright 2015 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 Stringified(toString) { + var valueOf = "-" + toString + "-"; + return { + toString: function() { return toString; }, + valueOf: function() { return valueOf; } + }; +} + +assertEquals("a.b.", "a.".concat(Stringified("b."))); +assertEquals("a.b.c.", "a.".concat(Stringified("b."), Stringified("c."))); diff --git a/deps/v8/test/mjsunit/string-index.js b/deps/v8/test/mjsunit/string-index.js index 315708ca5f..1c0e3d915d 100644 --- a/deps/v8/test/mjsunit/string-index.js +++ b/deps/v8/test/mjsunit/string-index.js @@ -25,6 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Flags: --allow-natives-syntax + /** * @fileoverview Test indexing on strings with []. */ @@ -250,6 +252,20 @@ for (var i = 0; i < 100; ++i) { assertEquals(expected, actual); } +// Test out of range with a heap number case. +var num = Math.floor(4) * 0.5; +// TODO(mvstanton): figure out a reliable way to get a heap number every time. +// assertFalse(!%_IsSmi(num)); +var keys = [0, num]; +var str = 'ab', arr = ['a', undefined]; +for (var i = 0; i < 100; ++i) { + var index = Math.floor(i / 50); + var key = keys[index]; + var expected = arr[index]; + var actual = str[key]; + assertEquals(expected, actual); +} + // Test two byte string. var str = '\u0427', arr = ['\u0427']; for (var i = 0; i < 50; ++i) { diff --git a/deps/v8/test/mjsunit/strong/arrays.js b/deps/v8/test/mjsunit/strong/arrays.js new file mode 100644 index 0000000000..b9e4fad357 --- /dev/null +++ b/deps/v8/test/mjsunit/strong/arrays.js @@ -0,0 +1,12 @@ +// Copyright 2015 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: --strong-mode + +(function NoEllisions() { + assertThrows("'use strong'; [,]", SyntaxError); + assertThrows("'use strong'; [,3]", SyntaxError); + assertThrows("'use strong'; [3,,4]", SyntaxError); + assertTrue(eval("'use strong'; [3,] !== [3,4,]")); +})(); diff --git a/deps/v8/test/mjsunit/strong/classes.js b/deps/v8/test/mjsunit/strong/classes.js index 3c7caf5f84..e33742af3f 100644 --- a/deps/v8/test/mjsunit/strong/classes.js +++ b/deps/v8/test/mjsunit/strong/classes.js @@ -3,15 +3,58 @@ // found in the LICENSE file. // Flags: --strong-mode +// Flags: --harmony-classes --harmony-arrow-functions 'use strong'; class C {} +function assertTypeError(script) { assertThrows(script, TypeError) } +function assertSyntaxError(script) { assertThrows(script, SyntaxError) } +function assertReferenceError(script) { assertThrows(script, ReferenceError) } + (function ImmutableClassBindings() { class D {} - assertThrows(function(){ eval("C = 0") }, TypeError); - assertThrows(function(){ eval("D = 0") }, TypeError); + assertTypeError(function(){ eval("C = 0") }); + assertTypeError(function(){ eval("D = 0") }); assertEquals('function', typeof C); assertEquals('function', typeof D); })(); + +function constructor(body) { + return "'use strong'; " + + "(class extends Object { constructor() { " + body + " } })"; +} + +(function NoMissingSuper() { + assertReferenceError(constructor("")); + assertReferenceError(constructor("1")); +})(); + +(function NoNestedSuper() { + assertSyntaxError(constructor("(super());")); + assertSyntaxError(constructor("(() => super())();")); + assertSyntaxError(constructor("{ super(); }")); + assertSyntaxError(constructor("if (1) super();")); +})(); + +(function NoDuplicateSuper() { + assertSyntaxError(constructor("super(), super();")); + assertSyntaxError(constructor("super(); super();")); + assertSyntaxError(constructor("super(); (super());")); + assertSyntaxError(constructor("super(); { super() }")); + assertSyntaxError(constructor("super(); (() => super())();")); +})(); + +(function NoReturnValue() { + assertSyntaxError(constructor("return {};")); + assertSyntaxError(constructor("return undefined;")); + assertSyntaxError(constructor("{ return {}; }")); + assertSyntaxError(constructor("if (1) return {};")); +})(); + +(function NoReturnBeforeSuper() { + assertSyntaxError(constructor("return; super();")); + assertSyntaxError(constructor("if (0) return; super();")); + assertSyntaxError(constructor("{ return; } super();")); +})(); diff --git a/deps/v8/test/mjsunit/strong/declaration-after-use.js b/deps/v8/test/mjsunit/strong/declaration-after-use.js new file mode 100644 index 0000000000..aa5ff67283 --- /dev/null +++ b/deps/v8/test/mjsunit/strong/declaration-after-use.js @@ -0,0 +1,258 @@ +// Copyright 2015 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: --strong-mode --harmony_rest_parameters --harmony_arrow_functions --harmony_classes --harmony_computed-property_names + +// Note that it's essential for these tests that the reference is inside dead +// code (because we already produce ReferenceErrors for run-time unresolved +// variables and don't want to confuse those with strong mode errors). But the +// errors should *not* be inside lazy, unexecuted functions, since lazy parsing +// doesn't produce strong mode scoping errors). + +// In addition, assertThrows will call eval and that changes variable binding +// types (see e.g., UNBOUND_EVAL_SHADOWED). We can avoid unwanted side effects +// by wrapping the code to be tested inside an outer function. +function assertThrowsHelper(code) { + "use strict"; + let prologue = "(function outer() { if (false) { "; + let epilogue = " } })();"; + + assertThrows("'use strong'; " + prologue + code + epilogue, ReferenceError); + + // Make sure the error happens only in strong mode (note that we need strict + // mode here because of let). + assertDoesNotThrow("'use strict'; " + prologue + code + epilogue); +} + +(function DeclarationAfterUse() { + // Note that these tests only test cases where the declaration is found but is + // after the use. In particular, we cannot yet detect cases where the use can + // possibly bind to a global variable. + assertThrowsHelper("x; let x = 0;"); + assertThrowsHelper("function f() { x; let x = 0; }"); + assertThrowsHelper("function f() { x; } let x = 0;"); + + // These tests needs to be done a bit more manually, since var is not allowed + // in strong mode: + assertThrows( + `(function outer() { + function f() { 'use strong'; if (false) { x; } } var x = 0; f(); + })()`, + ReferenceError); + assertDoesNotThrow( + "(function outer() {\n" + + " function f() { if (false) { x; } } var x = 0; f(); \n" + + "})()"); + + assertThrows( + "(function outer() {\n" + + " function f() { 'use strong'; if (false) { x; } } var x; f(); \n" + + "})()", + ReferenceError); + assertDoesNotThrow( + "(function outer() {\n" + + " function f() { if (false) { x; } } var x; f(); \n" + + "})()"); + + // Errors are also detected when the declaration and the use are in the same + // eval scope. + assertThrows("'use strong'; eval('if (false) { x; let x = 0;}')", + ReferenceError); + assertDoesNotThrow("'use strict'; eval('if (false) { x; let x = 0; }')"); + + // Use occurring in the initializer of the declaration: + assertThrowsHelper("let x = x + 1;"); + assertThrowsHelper("let x = x;"); + assertThrowsHelper("let x = y, y = 4;"); + assertThrowsHelper("let x = function() { x; }"); + assertThrowsHelper("let x = a => { x; }"); + assertThrowsHelper("function f(x) { return x; }; let x = f(x);"); + assertThrowsHelper("const x = x;"); + assertThrowsHelper("const x = function() { x; }"); + assertThrowsHelper("const x = a => { x; }"); + assertThrowsHelper("function f(x) {return x}; const x = f(x);"); + + assertThrowsHelper("for (let x = x; ; ) { }"); + assertThrowsHelper("for (const x = x; ; ) { }"); + assertThrowsHelper("for (let x = y, y; ; ) { }"); + assertThrowsHelper("for (const x = y, y = 0; ; ) { }"); + + // Computed property names + assertThrowsHelper("let o = { 'a': 'b', [o.a]: 'c'};"); +})(); + + +(function DeclarationAfterUseInClasses() { + assertThrowsHelper("class C extends C { }"); + assertThrowsHelper("let C = class C2 extends C { }"); + assertThrowsHelper("let C = class C2 extends C2 { }"); + + assertThrowsHelper("let C = class C2 { constructor() { C; } }"); + assertThrowsHelper("let C = class C2 { method() { C; } }"); + assertThrowsHelper("let C = class C2 { *generator_method() { C; } }"); + + assertThrowsHelper( + `let C = class C2 { + static a() { return 'A'; } + [C.a()]() { return 'B'; } + };`); + + assertThrowsHelper( + `let C = class C2 { + static a() { return 'A'; } + [C2.a()]() { return 'B'; } + };`); + + assertThrowsHelper( + `let C = class C2 { + [(function() { C; return 'A';})()]() { return 'B'; } + };`); + + // The reference to C or C2 is inside a function, but not a method. + assertThrowsHelper( + `let C = class C2 { + [(function() { C2; return 'A';})()]() { return 'B'; } + };`); + + assertThrowsHelper( + `let C = class C2 { + [(function() { C; return 'A';})()]() { return 'B'; } + };`); + + // The reference to C or C2 is inside a method, but it's not a method of the + // relevant class (C2). + assertThrowsHelper( + `let C = class C2 { + [(new (class D { m() { C2; return 'A'; } })).m()]() { + return 'B'; + } + }`); + + assertThrowsHelper( + `let C = class C2 { + [(new (class D { m() { C; return 'A'; } })).m()]() { + return 'B'; + } + }`); + + assertThrowsHelper( + `let C = class C2 { + [({m() { C2; return 'A'; }}).m()]() { return 'B'; } + }`); + + assertThrowsHelper( + `let C = class C2 { + [({m() { C; return 'A'; }}).m()]() { return 'B'; } + }`); + + assertThrowsHelper( + `class COuter { + m() { + class CInner { + [({ m() { CInner; return 'A'; } }).m()]() { + return 'B'; + } + } + } + }`); +})(); + + +(function UsesWhichAreFine() { + "use strong"; + + let var1 = 0; + var1; + + let var2a = 0, var2b = var2a + 1, var2c = 2 + var2b; + + for (let var3 = 0; var3 < 1; var3++) { + var3; + } + + for (let var4a = 0, var4b = var4a; var4a + var4b < 4; var4a++, var4b++) { + var4a; + var4b; + } + + let var5 = 5; + for (; var5 < 10; ++var5) { } + + let arr = [1, 2]; + for (let i of arr) { + i; + } + + let var6 = [1, 2]; + // The second var6 resolves to outside (not to the first var6). + for (let var6 of var6) { var6; } + + try { + throw "error"; + } catch (e) { + e; + } + + function func1() { func1; this; } + func1(); + func1; + + function * func2() { func2; this; } + func2(); + func2; + + function func4(p, ...rest) { p; rest; this; func2; } + func4(); + + let func5 = (p1, p2) => { p1; p2; }; + func5(); + + let func5b = p1 => p1; + func5b(); + + function func6() { + var1, var2a, var2b, var2c; + } + + (function eval1() { + let var7 = 0; // Declaration position will be something large. + // But use position will be something small, however, this is not an error, + // since the use is inside an eval scope. + eval("var7;"); + })(); + + + class C1 { constructor() { C1; } }; new C1(); + let C2 = class C3 { constructor() { C3; } }; new C2(); + + class C4 { method() { C4; } *generator_method() { C4; } }; new C4(); + let C5 = class C6 { method() { C6; } *generator_method() { C6; } }; new C5(); + + class C7 { static method() { C7; } }; new C7(); + let C8 = class C9 { static method() { C9; } }; new C8(); + + class C10 { get x() { C10; } }; new C10(); + let C11 = class C12 { get x() { C12; } }; new C11(); + + // Regression test for unnamed classes. + let C13 = class { m() { var1; } }; + + class COuter { + m() { + class CInner { + // Here we can refer to COuter but not to CInner (see corresponding + // assertion test): + [({ m() { COuter; return 'A'; } }).m()]() { return 'B'; } + // And here we can refer to both: + n() { COuter; CInner; } + } + return new CInner(); + } + } + (new COuter()).m().n(); + + // Making sure the check which is supposed to prevent "object literal inside + // computed property name references the class name" is not too generic: + class C14 { m() { let obj = { n() { C14 } }; obj.n(); } }; (new C14()).m(); +})(); diff --git a/deps/v8/test/mjsunit/strong/functions.js b/deps/v8/test/mjsunit/strong/functions.js index 4869ac6dfa..6956462e5d 100644 --- a/deps/v8/test/mjsunit/strong/functions.js +++ b/deps/v8/test/mjsunit/strong/functions.js @@ -6,28 +6,82 @@ 'use strong'; +function f() {} +function* g() {} + (function NoArguments() { assertThrows("'use strong'; arguments", SyntaxError); assertThrows("'use strong'; function f() { arguments }", SyntaxError); + assertThrows("'use strong'; function* g() { arguments }", SyntaxError); assertThrows("'use strong'; let f = function() { arguments }", SyntaxError); + assertThrows("'use strong'; let g = function*() { arguments }", SyntaxError); assertThrows("'use strong'; let f = () => arguments", SyntaxError); // The following are strict mode errors already. assertThrows("'use strong'; let arguments", SyntaxError); assertThrows("'use strong'; function f(arguments) {}", SyntaxError); + assertThrows("'use strong'; function* g(arguments) {}", SyntaxError); assertThrows("'use strong'; let f = (arguments) => {}", SyntaxError); })(); -function g() {} +(function NoArgumentsProperty() { + assertFalse(f.hasOwnProperty("arguments")); + assertFalse(g.hasOwnProperty("arguments")); + assertThrows(function(){ f.arguments = 0 }, TypeError); + assertThrows(function(){ g.arguments = 0 }, TypeError); +})(); + +(function NoCaller() { + assertFalse(f.hasOwnProperty("caller")); + assertFalse(g.hasOwnProperty("caller")); + assertThrows(function(){ f.caller = 0 }, TypeError); + assertThrows(function(){ g.caller = 0 }, TypeError); +})(); + +(function NoCallee() { + assertFalse("callee" in f); + assertFalse("callee" in g); + assertThrows(function(){ f.callee = 0 }, TypeError); + assertThrows(function(){ g.callee = 0 }, TypeError); +})(); -(function LexicalFunctionBindings(global) { +(function LexicalBindings(global) { + assertEquals('function', typeof f); assertEquals('function', typeof g); + assertEquals(undefined, global.f); assertEquals(undefined, global.g); })(this); -(function ImmutableFunctionBindings() { - function f() {} - assertThrows(function(){ eval("g = 0") }, TypeError); - assertThrows(function(){ eval("f = 0") }, TypeError); - assertEquals('function', typeof g); +(function ImmutableBindings() { + function f2() {} + function* g2() {} + assertThrows(function(){ f = 0 }, TypeError); + assertThrows(function(){ g = 0 }, TypeError); + assertThrows(function(){ f2 = 0 }, TypeError); + assertThrows(function(){ g2 = 0 }, TypeError); assertEquals('function', typeof f); + assertEquals('function', typeof g); + assertEquals('function', typeof f2); + assertEquals('function', typeof g2); +})(); + +(function NonExtensible() { + assertThrows(function(){ f.a = 0 }, TypeError); + assertThrows(function(){ g.a = 0 }, TypeError); + assertThrows(function(){ Object.defineProperty(f, "a", {value: 0}) }, TypeError); + assertThrows(function(){ Object.defineProperty(g, "a", {value: 0}) }, TypeError); + assertThrows(function(){ Object.setPrototypeOf(f, {}) }, TypeError); + assertThrows(function(){ Object.setPrototypeOf(g, {}) }, TypeError); +})(); + +(function NoPrototype() { + assertFalse("prototype" in f); + assertFalse(g.hasOwnProperty("prototype")); + assertThrows(function(){ f.prototype = 0 }, TypeError); + assertThrows(function(){ g.prototype = 0 }, TypeError); + assertThrows(function(){ f.prototype.a = 0 }, TypeError); +})(); + +(function NonConstructor() { + assertThrows(function(){ new f }, TypeError); + assertThrows(function(){ new g }, TypeError); })(); diff --git a/deps/v8/test/mozilla/mozilla.status b/deps/v8/test/mozilla/mozilla.status index 0d6baf0e22..a1254dbd09 100644 --- a/deps/v8/test/mozilla/mozilla.status +++ b/deps/v8/test/mozilla/mozilla.status @@ -61,6 +61,19 @@ # TODO(turbofan): Large switch statements crash. 'js1_5/Regress/regress-398085-01': [PASS, NO_VARIANTS], + ############################ INVALID TESTS ############################# + + # Function length properties are configurable in ES6 + 'ecma/Array/15.4.4.3-1': [FAIL], + 'ecma/Array/15.4.4.4-1': [FAIL], + 'ecma/Array/15.4.4.4-2': [FAIL], + 'ecma/String/15.5.4.10-1': [FAIL], + 'ecma/String/15.5.4.11-1': [FAIL], + 'ecma/String/15.5.4.7-2': [FAIL], + 'ecma/String/15.5.4.8-1': [FAIL], + 'ecma/String/15.5.4.9-1': [FAIL], + + ##################### SKIPPED TESTS ##################### # This test checks that we behave properly in an out-of-memory diff --git a/deps/v8/test/preparser/strict-function-statement.pyt b/deps/v8/test/preparser/strict-function-statement.pyt deleted file mode 100644 index cc3d7bb582..0000000000 --- a/deps/v8/test/preparser/strict-function-statement.pyt +++ /dev/null @@ -1,109 +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. - -# In strict mode, function declarations may only appear as source elements. - -# A template that performs the same strict-mode test in different -# scopes (global scope, function scope, and nested function scope). -def StrictTest(name, source, legacy): - if legacy: - extra_flags = [ - "--noharmony-scoping", - "--noharmony-classes", - "--noharmony-object-literals"] - else: - extra_flags = [] - Test(name, '"use strict";\n' + source, "strict_function", - extra_flags) - Test(name + '-infunc', - 'function foo() {\n "use strict";\n' + source +'\n}\n', - "strict_function", - extra_flags) - Test(name + '-infunc2', - 'function foo() {\n "use strict";\n function bar() {\n' + - source +'\n }\n}\n', - "strict_function", - extra_flags) - -# Not testing with-scope, since with is not allowed in strict mode at all. - -StrictTest("block", """ - { function foo() { } } -""", True) - -StrictTest("try-w-catch", """ - try { function foo() { } } catch (e) { } -""", True) - -StrictTest("try-w-finally", """ - try { function foo() { } } finally { } -""", True) - -StrictTest("catch", """ - try { } catch (e) { function foo() { } } -""", True) - -StrictTest("finally", """ - try { } finally { function foo() { } } -""", True) - -StrictTest("for", """ - for (;;) { function foo() { } } -""", True) - -StrictTest("while", """ - while (true) { function foo() { } } -""", True) - -StrictTest("do", """ - do { function foo() { } } while (true); -""", True) - -StrictTest("then", """ - if (true) { function foo() { } } -""", True) - - -StrictTest("then-w-else", """ - if (true) { function foo() { } } else { } -""", True) - - -StrictTest("else", """ - if (true) { } else { function foo() { } } -""", True) - -StrictTest("switch-case", """ - switch (true) { case true: function foo() { } } -""", False) - -StrictTest("labeled", """ - label: function foo() { } -""", False) - - - diff --git a/deps/v8/test/test262-es6/test262-es6.status b/deps/v8/test/test262-es6/test262-es6.status index fd93f295fa..c004242ce3 100644 --- a/deps/v8/test/test262-es6/test262-es6.status +++ b/deps/v8/test/test262-es6/test262-es6.status @@ -30,119 +30,119 @@ ############################### BUGS ################################### # BUG(v8:3455) - '11.2.3_b': [FAIL], - '12.2.3_b': [FAIL], + 'intl402/ch11/11.2/11.2.3_b': [FAIL], + 'intl402/ch12/12.2/12.2.3_b': [FAIL], # Unicode canonicalization is not available with i18n turned off. - '15.5.4.9_CE': [['no_i18n', SKIP]], + 'ch15/15.5/15.5.4/15.5.4.9/15.5.4.9_CE': [['no_i18n', SKIP]], ###################### NEEDS INVESTIGATION ####################### # Possibly same cause as S8.5_A2.1, below: floating-point tests. - 'S15.8.2.16_A7': [PASS, FAIL_OK], - 'S15.8.2.18_A7': [PASS, FAIL_OK], - 'S15.8.2.7_A7': [PASS, FAIL_OK], + 'ch15/15.8/15.8.2/15.8.2.16/S15.8.2.16_A7': [PASS, FAIL_OK], + 'ch15/15.8/15.8.2/15.8.2.18/S15.8.2.18_A7': [PASS, FAIL_OK], + 'ch15/15.8/15.8.2/15.8.2.7/S15.8.2.7_A7': [PASS, FAIL_OK], # This is an incompatibility between ES5 and V8 on enumerating # shadowed elements in a for..in loop. # https://code.google.com/p/v8/issues/detail?id=705 - '12.6.4-2': [PASS, FAIL_OK], + 'ch12/12.6/12.6.4/12.6.4-2': [PASS, FAIL_OK], ###################### MISSING ES6 FEATURES ####################### # Array.fill (currently requires --harmony-arrays) - 'S22.1.3.6_T1': [FAIL], + 'es6/ch22/22.1/22.1.3/S22.1.3.6_T1': [FAIL], # Array.find (currently requires --harmony-arrays) - 'S22.1.2.3_T1': [FAIL], - 'S22.1.2.3_T2': [FAIL], - 'Array.prototype.find_empty-array-undefined': [FAIL], - 'Array.prototype.find_length-property': [FAIL], - 'Array.prototype.find_modify-after-start': [FAIL], - 'Array.prototype.find_non-returning-predicate': [FAIL], - 'Array.prototype.find_predicate-arguments': [FAIL], - 'Array.prototype.find_push-after-start': [FAIL], - 'Array.prototype.find_remove-after-start': [FAIL], - 'Array.prototype.find_return-found-value': [FAIL], - 'Array.prototype.find_skip-empty': [FAIL], - 'Array.prototype.find_this-defined': [FAIL], - 'Array.prototype.find_this-is-object': [FAIL], - 'Array.prototype.find_this-undefined': [FAIL], + 'es6/ch22/22.1/22.1.2/S22.1.2.3_T1': [FAIL], + 'es6/ch22/22.1/22.1.2/S22.1.2.3_T2': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_empty-array-undefined': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_length-property': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_modify-after-start': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_non-returning-predicate': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_predicate-arguments': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_push-after-start': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_remove-after-start': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_return-found-value': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_skip-empty': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_this-defined': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_this-is-object': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_this-undefined': [FAIL], # Array.from - 'S22.1.2.1_T1': [FAIL], - 'S22.1.2.1_T2': [FAIL], + 'es6/ch22/22.1/22.1.2/S22.1.2.1_T1': [FAIL], + 'es6/ch22/22.1/22.1.2/S22.1.2.1_T2': [FAIL], # Direct proxies - 'Array.prototype.find_callable-predicate': [FAIL], + 'es6/Array.prototype.find/Array.prototype.find_callable-predicate': [FAIL], ######################## OBSOLETED BY ES6 ########################### # ES6 allows duplicate properties - '11.1.5-4-4-a-1-s': [FAIL], - '11.1.5_4-4-b-1': [FAIL], - '11.1.5_4-4-b-2': [FAIL], - '11.1.5_4-4-c-1': [FAIL], - '11.1.5_4-4-c-2': [FAIL], - '11.1.5_4-4-d-1': [FAIL], - '11.1.5_4-4-d-2': [FAIL], - '11.1.5_4-4-d-3': [FAIL], - '11.1.5_4-4-d-4': [FAIL], + 'ch11/11.1/11.1.5/11.1.5-4-4-a-1-s': [FAIL], + 'ch11/11.1/11.1.5/11.1.5_4-4-b-1': [FAIL], + 'ch11/11.1/11.1.5/11.1.5_4-4-b-2': [FAIL], + 'ch11/11.1/11.1.5/11.1.5_4-4-c-1': [FAIL], + 'ch11/11.1/11.1.5/11.1.5_4-4-c-2': [FAIL], + 'ch11/11.1/11.1.5/11.1.5_4-4-d-1': [FAIL], + 'ch11/11.1/11.1.5/11.1.5_4-4-d-2': [FAIL], + 'ch11/11.1/11.1.5/11.1.5_4-4-d-3': [FAIL], + 'ch11/11.1/11.1.5/11.1.5_4-4-d-4': [FAIL], # ES6 does ToObject for Object.prototype.getOwnPropertyNames - '15.2.3.4-1': [FAIL], - '15.2.3.4-1-4': [FAIL], - '15.2.3.4-1-5': [FAIL], + 'ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1': [FAIL], + 'ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-4': [FAIL], + 'ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-5': [FAIL], # ES6 allows block-local functions. - 'Sbp_A1_T1': [FAIL], - 'Sbp_A2_T1': [FAIL], - 'Sbp_A2_T2': [FAIL], - 'Sbp_A3_T1': [FAIL], - 'Sbp_A3_T2': [FAIL], - 'Sbp_A4_T1': [FAIL], - 'Sbp_A4_T2': [FAIL], - 'Sbp_A5_T1': [PASS], # Test is broken (strict reference to unbound variable) - 'Sbp_A5_T2': [FAIL], + 'bestPractice/Sbp_A1_T1': [FAIL], + 'bestPractice/Sbp_A2_T1': [FAIL], + 'bestPractice/Sbp_A2_T2': [FAIL], + 'bestPractice/Sbp_A3_T1': [FAIL], + 'bestPractice/Sbp_A3_T2': [FAIL], + 'bestPractice/Sbp_A4_T1': [FAIL], + 'bestPractice/Sbp_A4_T2': [FAIL], + 'bestPractice/Sbp_A5_T1': [PASS], # Test is broken (strict reference to unbound variable) + 'bestPractice/Sbp_A5_T2': [FAIL], ######################## NEEDS INVESTIGATION ########################### # These test failures are specific to the intl402 suite and need investigation # to be either marked as bugs with issues filed for them or as deliberate # incompatibilities if the test cases turn out to be broken or ambiguous. - '6.2.3': [FAIL], - '9.2.1_2': [FAIL], - '9.2.6_2': [FAIL], - '10.1.1_a': [FAIL], - '10.1.1_19_c': [PASS, FAIL, NO_VARIANTS], - '10.1.2.1_4': [FAIL], - '10.2.3_b': [PASS, FAIL], - '10.3_a': [FAIL], - '11.1.1_17': [PASS, FAIL], - '11.1.1_19': [PASS, FAIL], - '11.1.1_20_c': [FAIL], - '11.1.1_a': [FAIL], - '11.1.2.1_4': [FAIL], - '11.3.2_FN_2': [PASS, FAIL], - '11.3.2_TRF': [PASS, FAIL], - '11.3_a': [FAIL], - '12.1.1_a': [FAIL], - '12.1.2.1_4': [FAIL], - '12.3.2_FDT_7_a_iv': [FAIL], - '12.3.3': [FAIL], - '12.3_a': [FAIL], - '15.5.4.9_3': [PASS, FAIL], + 'intl402/ch06/6.2/6.2.3': [FAIL], + 'intl402/ch09/9.2/9.2.1_2': [FAIL], + 'intl402/ch09/9.2/9.2.6_2': [FAIL], + 'intl402/ch10/10.1/10.1.1_a': [FAIL], + 'intl402/ch10/10.1/10.1.1_19_c': [PASS, FAIL, NO_VARIANTS], + 'intl402/ch10/10.1/10.1.2.1_4': [FAIL], + 'intl402/ch10/10.2/10.2.3_b': [PASS, FAIL], + 'intl402/ch10/10.3/10.3_a': [FAIL], + 'intl402/ch11/11.1/11.1.1_17': [PASS, FAIL], + 'intl402/ch11/11.1/11.1.1_19': [PASS, FAIL], + 'intl402/ch11/11.1/11.1.1_20_c': [FAIL], + 'intl402/ch11/11.1/11.1.1_a': [FAIL], + 'intl402/ch11/11.1/11.1.2.1_4': [FAIL], + 'intl402/ch11/11.3/11.3.2_FN_2': [PASS, FAIL], + 'intl402/ch11/11.3/11.3.2_TRF': [PASS, FAIL], + 'intl402/ch11/11.3/11.3_a': [FAIL], + 'intl402/ch12/12.1/12.1.1_a': [FAIL], + 'intl402/ch12/12.1/12.1.2.1_4': [FAIL], + 'intl402/ch12/12.3/12.3.2_FDT_7_a_iv': [FAIL], + 'intl402/ch12/12.3/12.3.3': [FAIL], + 'intl402/ch12/12.3/12.3_a': [FAIL], + 'intl402/ch15/15.5/15.5.4/15.5.4.915.5.4.9_3': [PASS, FAIL], ##################### DELIBERATE INCOMPATIBILITIES ##################### - 'S15.8.2.8_A6': [PASS, FAIL_OK], # Math.exp (less precise with --fast-math) + 'ch15/15.8/15.8.2/15.8.2.8/S15.8.2.8_A6': [PASS, FAIL_OK], # Math.exp (less precise with --fast-math) # Linux for ia32 (and therefore simulators) default to extended 80 bit # floating point formats, so these tests checking 64-bit FP precision fail. # The other platforms/arch's pass these tests. # We follow the other major JS engines by keeping this default. - 'S8.5_A2.1': [PASS, FAIL_OK], - 'S8.5_A2.2': [PASS, FAIL_OK], + 'ch08/8.5/S8.5_A2.1': [PASS, FAIL_OK], + 'ch08/8.5/S8.5_A2.2': [PASS, FAIL_OK], ############################ INVALID TESTS ############################# @@ -150,55 +150,181 @@ # tests in PST/PDT between first Sunday in March and first Sunday in April. # The DST switch was moved in 2007 whereas Test262 bases the reference value # on 2000. Test262 Bug: https://bugs.ecmascript.org/show_bug.cgi?id=293 - 'S15.9.3.1_A5_T1': [PASS, FAIL_OK], - 'S15.9.3.1_A5_T2': [PASS, FAIL_OK], - 'S15.9.3.1_A5_T3': [PASS, FAIL_OK], - 'S15.9.3.1_A5_T4': [PASS, FAIL_OK], - 'S15.9.3.1_A5_T5': [PASS, FAIL_OK], - 'S15.9.3.1_A5_T6': [PASS, FAIL_OK], + 'ch15/15.9/15.9.3/S15.9.3.1_A5_T1': [PASS, FAIL_OK], + 'ch15/15.9/15.9.3/S15.9.3.1_A5_T2': [PASS, FAIL_OK], + 'ch15/15.9/15.9.3/S15.9.3.1_A5_T3': [PASS, FAIL_OK], + 'ch15/15.9/15.9.3/S15.9.3.1_A5_T4': [PASS, FAIL_OK], + 'ch15/15.9/15.9.3/S15.9.3.1_A5_T5': [PASS, FAIL_OK], + 'ch15/15.9/15.9.3/S15.9.3.1_A5_T6': [PASS, FAIL_OK], # Test makes unjustified assumptions about the number of calls to SortCompare. # Test262 Bug: https://bugs.ecmascript.org/show_bug.cgi?id=596 - 'bug_596_1': [PASS, FAIL_OK], + 'es6/bug_596_1': [PASS, FAIL_OK], # Tests do not return boolean. - '15.2.3.14-1-1': [PASS, FAIL_OK], - '15.2.3.14-1-2': [PASS, FAIL_OK], - '15.2.3.14-1-3': [PASS, FAIL_OK], + 'ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-1': [PASS, FAIL_OK], + 'ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-2': [PASS, FAIL_OK], + 'ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-3': [PASS, FAIL_OK], # String.prototype.contains renamed to 'S.p.includes' - 'String.prototype.contains_FailBadLocation' : [FAIL_OK], - 'String.prototype.contains_FailLocation' : [FAIL_OK], - 'String.prototype.contains_FailMissingLetter' : [FAIL_OK], - 'String.prototype.contains_lengthProp' : [FAIL_OK], - 'String.prototype.contains_Success' : [FAIL_OK], - 'String.prototype.contains_SuccessNoLocation' : [FAIL_OK], - + 'es6/String.prototype.contains/String.prototype.contains_FailBadLocation' : [FAIL_OK], + 'es6/String.prototype.contains/String.prototype.contains_FailLocation' : [FAIL_OK], + 'es6/String.prototype.contains/String.prototype.contains_FailMissingLetter' : [FAIL_OK], + 'es6/String.prototype.contains/String.prototype.contains_lengthProp' : [FAIL_OK], + 'es6/String.prototype.contains/String.prototype.contains_Success' : [FAIL_OK], + 'es6/String.prototype.contains/String.prototype.contains_SuccessNoLocation' : [FAIL_OK], + + # Function length properties are configurable in ES6 + 'ch11/11.4/11.4.1/11.4.1-5-a-28-s': [FAIL], + 'ch13/13.2/13.2-15-1': [FAIL], + 'ch15/15.1/15.1.2/15.1.2.1/S15.1.2.1_A4.2': [FAIL], + 'ch15/15.1/15.1.2/15.1.2.2/S15.1.2.2_A9.2': [FAIL], + 'ch15/15.1/15.1.2/15.1.2.3/S15.1.2.3_A7.2': [FAIL], + 'ch15/15.1/15.1.2/15.1.2.4/S15.1.2.4_A2.2': [FAIL], + 'ch15/15.1/15.1.2/15.1.2.5/S15.1.2.5_A2.2': [FAIL], + 'ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A5.2': [FAIL], + 'ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A5.2': [FAIL], + 'ch15/15.1/15.1.3/15.1.3.3/S15.1.3.3_A5.2': [FAIL], + 'ch15/15.1/15.1.3/15.1.3.4/S15.1.3.4_A5.2': [FAIL], + 'ch15/15.10/15.10.6/15.10.6.2/S15.10.6.2_A9': [FAIL], + 'ch15/15.10/15.10.6/15.10.6.3/S15.10.6.3_A9': [FAIL], + 'ch15/15.10/15.10.6/15.10.6.4/S15.10.6.4_A9': [FAIL], + 'ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-186': [FAIL], + 'ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-187': [FAIL], + 'ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-191': [FAIL], + 'ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-194': [FAIL], + 'ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-201': [FAIL], + 'ch15/15.2/15.2.4/15.2.4.2/S15.2.4.2_A9': [FAIL], + 'ch15/15.2/15.2.4/15.2.4.3/S15.2.4.3_A9': [FAIL], + 'ch15/15.2/15.2.4/15.2.4.4/S15.2.4.4_A9': [FAIL], + 'ch15/15.2/15.2.4/15.2.4.5/S15.2.4.5_A9': [FAIL], + 'ch15/15.2/15.2.4/15.2.4.6/S15.2.4.6_A9': [FAIL], + 'ch15/15.2/15.2.4/15.2.4.7/S15.2.4.7_A9': [FAIL], + 'ch15/15.3/15.3.3/15.3.3.2/15.3.3.2-1': [FAIL], + 'ch15/15.3/15.3.4/15.3.4.2/S15.3.4.2_A9': [FAIL], + 'ch15/15.3/15.3.4/15.3.4.3/S15.3.4.3_A9': [FAIL], + 'ch15/15.3/15.3.4/15.3.4.4/S15.3.4.4_A9': [FAIL], + 'ch15/15.3/15.3.5/S15.3.5.1_A2_T1': [FAIL], + 'ch15/15.3/15.3.5/S15.3.5.1_A2_T2': [FAIL], + 'ch15/15.3/15.3.5/S15.3.5.1_A2_T3': [FAIL], + 'ch15/15.4/15.4.3/S15.4.3_A2.2': [FAIL], + 'ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A5.2': [FAIL], + 'ch15/15.4/15.4.4/15.4.4.11/S15.4.4.11_A7.2': [FAIL], + 'ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A5.2': [FAIL], + 'ch15/15.4/15.4.4/15.4.4.13/S15.4.4.13_A5.2': [FAIL], + 'ch15/15.4/15.4.4/15.4.4.2/S15.4.4.2_A4.2': [FAIL], + 'ch15/15.4/15.4.4/15.4.4.3/S15.4.4.3_A4.2': [FAIL], + 'ch15/15.4/15.4.4/15.4.4.4/S15.4.4.4_A4.2': [FAIL], + 'ch15/15.4/15.4.4/15.4.4.5/S15.4.4.5_A6.2': [FAIL], + 'ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A5.2': [FAIL], + 'ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A6.2': [FAIL], + 'ch15/15.4/15.4.4/15.4.4.8/S15.4.4.8_A5.2': [FAIL], + 'ch15/15.4/15.4.4/15.4.4.9/S15.4.4.9_A5.2': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.10/S15.5.4.10_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.11/S15.5.4.11_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.12/S15.5.4.12_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.13/S15.5.4.13_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.14/S15.5.4.14_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.15/S15.5.4.15_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.16/S15.5.4.16_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.17/S15.5.4.17_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.18/S15.5.4.18_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.19/S15.5.4.19_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.4/S15.5.4.4_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.5/S15.5.4.5_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.6/S15.5.4.6_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.7/S15.5.4.7_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.8/S15.5.4.8_A9': [FAIL], + 'ch15/15.5/15.5.4/15.5.4.9/S15.5.4.9_A9': [FAIL], + 'ch15/15.9/15.9.4/15.9.4.2/S15.9.4.2_A3_T2': [FAIL], + 'ch15/15.9/15.9.4/15.9.4.3/S15.9.4.3_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.1/S15.9.5.1_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.10/S15.9.5.10_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.11/S15.9.5.11_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.12/S15.9.5.12_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.13/S15.9.5.13_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.14/S15.9.5.14_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.15/S15.9.5.15_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.16/S15.9.5.16_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.17/S15.9.5.17_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.18/S15.9.5.18_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.19/S15.9.5.19_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.2/S15.9.5.2_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.20/S15.9.5.20_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.21/S15.9.5.21_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.22/S15.9.5.22_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.23/S15.9.5.23_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.24/S15.9.5.24_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.25/S15.9.5.25_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.26/S15.9.5.26_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.27/S15.9.5.27_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.28/S15.9.5.28_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.29/S15.9.5.29_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.3/S15.9.5.3_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.30/S15.9.5.30_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.31/S15.9.5.31_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.32/S15.9.5.32_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.33/S15.9.5.33_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.34/S15.9.5.34_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.35/S15.9.5.35_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.36/S15.9.5.36_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.37/S15.9.5.37_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.38/S15.9.5.38_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.39/S15.9.5.39_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.4/S15.9.5.4_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.40/S15.9.5.40_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.41/S15.9.5.41_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.42/S15.9.5.42_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.5/S15.9.5.5_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.6/S15.9.5.6_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.7/S15.9.5.7_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.8/S15.9.5.8_A3_T2': [FAIL], + 'ch15/15.9/15.9.5/15.9.5.9/S15.9.5.9_A3_T2': [FAIL], + 'intl402/ch10/10.1/10.1_L15': [FAIL], + 'intl402/ch10/10.2/10.2.2_L15': [FAIL], + 'intl402/ch10/10.3/10.3.2_1_a_L15': [FAIL], + 'intl402/ch10/10.3/10.3.2_L15': [FAIL], + 'intl402/ch10/10.3/10.3.3_L15': [FAIL], + 'intl402/ch11/11.1/11.1_L15': [FAIL], + 'intl402/ch11/11.2/11.2.2_L15': [FAIL], + 'intl402/ch11/11.3/11.3.2_1_a_L15': [FAIL], + 'intl402/ch11/11.3/11.3.2_L15': [FAIL], + 'intl402/ch11/11.3/11.3.3_L15': [FAIL], + 'intl402/ch12/12.1/12.1_L15': [FAIL], + 'intl402/ch12/12.2/12.2.2_L15': [FAIL], + 'intl402/ch12/12.3/12.3.2_1_a_L15': [FAIL], + 'intl402/ch12/12.3/12.3.2_L15': [FAIL], + 'intl402/ch12/12.3/12.3.3_L15': [FAIL], + 'intl402/ch13/13.1/13.1.1_L15': [FAIL], + 'intl402/ch13/13.2/13.2.1_L15': [FAIL], + 'intl402/ch13/13.3/13.3.1_L15': [FAIL], + 'intl402/ch13/13.3/13.3.2_L15': [FAIL], + 'intl402/ch13/13.3/13.3.3_L15': [FAIL], ############################ SKIPPED TESTS ############################# # These tests take a looong time to run in debug mode. - 'S15.1.3.1_A2.5_T1': [PASS, ['mode == debug', SKIP]], - 'S15.1.3.2_A2.5_T1': [PASS, ['mode == debug', SKIP]], + 'ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A2.5_T1': [PASS, ['mode == debug', SKIP]], + 'ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A2.5_T1': [PASS, ['mode == debug', SKIP]], }], # ALWAYS ['system == macos', { - '11.3.2_TRP': [FAIL], - '9.2.5_11_g_ii_2': [FAIL], + 'intl402/ch11/11.3/11.3.2_TRP': [FAIL], + 'intl402/ch09/9.2/9.2.5_11_g_ii_2': [FAIL], }], # system == macos ['arch == arm or arch == mipsel or arch == mips or arch == arm64 or arch == mips64el', { # TODO(mstarzinger): Causes stack overflow on simulators due to eager # compilation of parenthesized function literals. Needs investigation. - 'S13.2.1_A1_T1': [SKIP], + 'ch13/13.2/S13.2.1_A1_T1': [SKIP], # BUG(3251225): Tests that timeout with --nocrankshaft. - 'S15.1.3.1_A2.4_T1': [SKIP], - 'S15.1.3.1_A2.5_T1': [SKIP], - 'S15.1.3.2_A2.4_T1': [SKIP], - 'S15.1.3.2_A2.5_T1': [SKIP], - 'S15.1.3.3_A2.3_T1': [SKIP], - 'S15.1.3.4_A2.3_T1': [SKIP], + 'ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A2.4_T1': [SKIP], + 'ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A2.5_T1': [SKIP], + 'ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A2.4_T1': [SKIP], + 'ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A2.5_T1': [SKIP], + 'ch15/15.1/15.1.3/15.1.3.3/S15.1.3.3_A2.3_T1': [SKIP], + 'ch15/15.1/15.1.3/15.1.3.4/S15.1.3.4_A2.3_T1': [SKIP], }], # 'arch == arm or arch == mipsel or arch == mips or arch == arm64' ] diff --git a/deps/v8/test/test262-es6/testcfg.py b/deps/v8/test/test262-es6/testcfg.py index 0a894104a2..cb44da073a 100644 --- a/deps/v8/test/test262-es6/testcfg.py +++ b/deps/v8/test/test262-es6/testcfg.py @@ -57,9 +57,6 @@ class Test262TestSuite(testsuite.TestSuite): self.harness += [os.path.join(self.root, "harness-adapt.js")] self.ParseTestRecord = None - def CommonTestName(self, testcase): - return testcase.path.split(os.path.sep)[-1] - def ListTests(self, context): tests = [] for dirname, dirs, files in os.walk(self.testroot): diff --git a/deps/v8/test/test262/test262.status b/deps/v8/test/test262/test262.status index d1800c5fc5..8e7496bc25 100644 --- a/deps/v8/test/test262/test262.status +++ b/deps/v8/test/test262/test262.status @@ -62,6 +62,133 @@ '11.1.5_4-4-d-3': [FAIL], '11.1.5_4-4-d-4': [FAIL], + # Function length properties are configurable in ES6 + '10.1_L15': [FAIL], + '10.2.2_L15': [FAIL], + '10.3.2_1_a_L15': [FAIL], + '10.3.2_L15': [FAIL], + '10.3.3_L15': [FAIL], + '11.1_L15': [FAIL], + '11.2.2_L15': [FAIL], + '11.3.2_1_a_L15': [FAIL], + '11.3.2_L15': [FAIL], + '11.3.3_L15': [FAIL], + '11.4.1-5-a-28-s': [FAIL], + '12.1_L15': [FAIL], + '12.2.2_L15': [FAIL], + '12.3.2_1_a_L15': [FAIL], + '12.3.2_L15': [FAIL], + '12.3.3_L15': [FAIL], + '13.1.1_L15': [FAIL], + '13.2-15-1': [FAIL], + '13.2.1_L15': [FAIL], + '13.3.1_L15': [FAIL], + '13.3.2_L15': [FAIL], + '13.3.3_L15': [FAIL], + '15.2.3.3-4-186': [FAIL], + '15.2.3.3-4-187': [FAIL], + '15.2.3.3-4-191': [FAIL], + '15.2.3.3-4-194': [FAIL], + '15.2.3.3-4-201': [FAIL], + '15.3.3.2-1': [FAIL], + 'S15.1.2.1_A4.2': [FAIL], + 'S15.1.2.2_A9.2': [FAIL], + 'S15.1.2.3_A7.2': [FAIL], + 'S15.1.2.4_A2.2': [FAIL], + 'S15.1.2.5_A2.2': [FAIL], + 'S15.1.3.1_A5.2': [FAIL], + 'S15.1.3.2_A5.2': [FAIL], + 'S15.1.3.3_A5.2': [FAIL], + 'S15.1.3.4_A5.2': [FAIL], + 'S15.10.6.2_A9': [FAIL], + 'S15.10.6.3_A9': [FAIL], + 'S15.10.6.4_A9': [FAIL], + 'S15.2.4.2_A9': [FAIL], + 'S15.2.4.3_A9': [FAIL], + 'S15.2.4.4_A9': [FAIL], + 'S15.2.4.5_A9': [FAIL], + 'S15.2.4.6_A9': [FAIL], + 'S15.2.4.7_A9': [FAIL], + 'S15.3.4.2_A9': [FAIL], + 'S15.3.4.3_A9': [FAIL], + 'S15.3.4.4_A9': [FAIL], + 'S15.3.5.1_A2_T1': [FAIL], + 'S15.3.5.1_A2_T2': [FAIL], + 'S15.3.5.1_A2_T3': [FAIL], + 'S15.4.3_A2.2': [FAIL], + 'S15.4.4.10_A5.2': [FAIL], + 'S15.4.4.11_A7.2': [FAIL], + 'S15.4.4.12_A5.2': [FAIL], + 'S15.4.4.13_A5.2': [FAIL], + 'S15.4.4.2_A4.2': [FAIL], + 'S15.4.4.3_A4.2': [FAIL], + 'S15.4.4.4_A4.2': [FAIL], + 'S15.4.4.5_A6.2': [FAIL], + 'S15.4.4.6_A5.2': [FAIL], + 'S15.4.4.7_A6.2': [FAIL], + 'S15.4.4.8_A5.2': [FAIL], + 'S15.4.4.9_A5.2': [FAIL], + 'S15.5.4.10_A9': [FAIL], + 'S15.5.4.11_A9': [FAIL], + 'S15.5.4.12_A9': [FAIL], + 'S15.5.4.13_A9': [FAIL], + 'S15.5.4.14_A9': [FAIL], + 'S15.5.4.15_A9': [FAIL], + 'S15.5.4.16_A9': [FAIL], + 'S15.5.4.17_A9': [FAIL], + 'S15.5.4.18_A9': [FAIL], + 'S15.5.4.19_A9': [FAIL], + 'S15.5.4.4_A9': [FAIL], + 'S15.5.4.5_A9': [FAIL], + 'S15.5.4.6_A9': [FAIL], + 'S15.5.4.7_A9': [FAIL], + 'S15.5.4.8_A9': [FAIL], + 'S15.5.4.9_A9': [FAIL], + 'S15.9.4.2_A3_T2': [FAIL], + 'S15.9.4.3_A3_T2': [FAIL], + 'S15.9.5.10_A3_T2': [FAIL], + 'S15.9.5.11_A3_T2': [FAIL], + 'S15.9.5.12_A3_T2': [FAIL], + 'S15.9.5.13_A3_T2': [FAIL], + 'S15.9.5.14_A3_T2': [FAIL], + 'S15.9.5.15_A3_T2': [FAIL], + 'S15.9.5.16_A3_T2': [FAIL], + 'S15.9.5.17_A3_T2': [FAIL], + 'S15.9.5.18_A3_T2': [FAIL], + 'S15.9.5.19_A3_T2': [FAIL], + 'S15.9.5.1_A3_T2': [FAIL], + 'S15.9.5.20_A3_T2': [FAIL], + 'S15.9.5.21_A3_T2': [FAIL], + 'S15.9.5.22_A3_T2': [FAIL], + 'S15.9.5.23_A3_T2': [FAIL], + 'S15.9.5.24_A3_T2': [FAIL], + 'S15.9.5.25_A3_T2': [FAIL], + 'S15.9.5.26_A3_T2': [FAIL], + 'S15.9.5.27_A3_T2': [FAIL], + 'S15.9.5.28_A3_T2': [FAIL], + 'S15.9.5.29_A3_T2': [FAIL], + 'S15.9.5.2_A3_T2': [FAIL], + 'S15.9.5.30_A3_T2': [FAIL], + 'S15.9.5.31_A3_T2': [FAIL], + 'S15.9.5.32_A3_T2': [FAIL], + 'S15.9.5.33_A3_T2': [FAIL], + 'S15.9.5.34_A3_T2': [FAIL], + 'S15.9.5.35_A3_T2': [FAIL], + 'S15.9.5.36_A3_T2': [FAIL], + 'S15.9.5.37_A3_T2': [FAIL], + 'S15.9.5.38_A3_T2': [FAIL], + 'S15.9.5.39_A3_T2': [FAIL], + 'S15.9.5.3_A3_T2': [FAIL], + 'S15.9.5.40_A3_T2': [FAIL], + 'S15.9.5.41_A3_T2': [FAIL], + 'S15.9.5.42_A3_T2': [FAIL], + 'S15.9.5.4_A3_T2': [FAIL], + 'S15.9.5.5_A3_T2': [FAIL], + 'S15.9.5.6_A3_T2': [FAIL], + 'S15.9.5.7_A3_T2': [FAIL], + 'S15.9.5.8_A3_T2': [FAIL], + 'S15.9.5.9_A3_T2': [FAIL], + ######################## NEEDS INVESTIGATION ########################### # These test failures are specific to the intl402 suite and need investigation diff --git a/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc b/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc index 1fa0b10842..85e52488b4 100644 --- a/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc +++ b/deps/v8/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc @@ -2426,6 +2426,21 @@ TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) { } } + +TEST_F(InstructionSelectorTest, Word32Clz) { + StreamBuilder m(this, kMachUint32, kMachUint32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Word32Clz(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmClz, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc b/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc index 571dbecd14..02c8d2e06d 100644 --- a/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc +++ b/deps/v8/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc @@ -472,6 +472,36 @@ TEST_P(InstructionSelectorAddSubTest, ShiftByImmediateOnRight) { } +TEST_P(InstructionSelectorAddSubTest, ExtendByte) { + const AddSub dpi = GetParam(); + const MachineType type = dpi.mi.machine_type; + StreamBuilder m(this, type, type, type); + m.Return((m.*dpi.mi.constructor)( + m.Parameter(0), m.Word32And(m.Parameter(1), m.Int32Constant(0xff)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); +} + + +TEST_P(InstructionSelectorAddSubTest, ExtendHalfword) { + const AddSub dpi = GetParam(); + const MachineType type = dpi.mi.machine_type; + StreamBuilder m(this, type, type, type); + m.Return((m.*dpi.mi.constructor)( + m.Parameter(0), m.Word32And(m.Parameter(1), m.Int32Constant(0xffff)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); +} + + INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest, ::testing::ValuesIn(kAddSubInstructions)); @@ -616,6 +646,58 @@ TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) { } +TEST_F(InstructionSelectorTest, AddExtendByteOnLeft) { + { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xff)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, kMachInt64, kMachInt32, kMachInt64); + m.Return(m.Int64Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xff)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_UXTB, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_F(InstructionSelectorTest, AddExtendHalfwordOnLeft) { + { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xffff)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, kMachInt64, kMachInt32, kMachInt64); + m.Return(m.Int64Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xffff)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_UXTH, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + } +} + + // ----------------------------------------------------------------------------- // Data processing controlled branches. @@ -896,26 +978,6 @@ TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnRight) { EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1))); } - - TRACED_FORRANGE(int, bit, 0, 63) { - uint64_t mask = 1L << bit; - StreamBuilder m(this, kMachInt64, kMachInt64); - MLabel a, b; - m.Branch( - m.Word64BinaryNot(m.Word64And(m.Parameter(0), m.Int64Constant(mask))), - &a, &b); - m.Bind(&a); - m.Return(m.Int32Constant(1)); - m.Bind(&b); - m.Return(m.Int32Constant(0)); - Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode()); - EXPECT_EQ(kEqual, s[0]->flags_condition()); - EXPECT_EQ(4U, s[0]->InputCount()); - EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); - EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1))); - } } @@ -937,26 +999,6 @@ TEST_F(InstructionSelectorTest, Word64AndBranchWithOneBitMaskOnLeft) { EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1))); } - - TRACED_FORRANGE(int, bit, 0, 63) { - uint64_t mask = 1L << bit; - StreamBuilder m(this, kMachInt64, kMachInt64); - MLabel a, b; - m.Branch( - m.Word64BinaryNot(m.Word64And(m.Int64Constant(mask), m.Parameter(0))), - &a, &b); - m.Bind(&a); - m.Return(m.Int32Constant(1)); - m.Bind(&b); - m.Return(m.Int32Constant(0)); - Stream s = m.Build(); - ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kArm64TestAndBranch, s[0]->arch_opcode()); - EXPECT_EQ(kEqual, s[0]->flags_condition()); - EXPECT_EQ(4U, s[0]->InputCount()); - EXPECT_EQ(InstructionOperand::IMMEDIATE, s[0]->InputAt(1)->kind()); - EXPECT_EQ(bit, s.ToInt64(s[0]->InputAt(1))); - } } @@ -2200,6 +2242,21 @@ TEST_F(InstructionSelectorTest, Word32SarWithWord32Shl) { } } + +TEST_F(InstructionSelectorTest, Word32Clz) { + StreamBuilder m(this, kMachUint32, kMachUint32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Word32Clz(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Clz32, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/change-lowering-unittest.cc b/deps/v8/test/unittests/compiler/change-lowering-unittest.cc index 5b31f5e04c..5cfb8fdc41 100644 --- a/deps/v8/test/unittests/compiler/change-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/change-lowering-unittest.cc @@ -23,45 +23,15 @@ namespace v8 { namespace internal { namespace compiler { -class ChangeLoweringTest : public GraphTest { +class ChangeLoweringTest : public TypedGraphTest { public: ChangeLoweringTest() : simplified_(zone()) {} - ~ChangeLoweringTest() OVERRIDE {} virtual MachineType WordRepresentation() const = 0; protected: - int HeapNumberValueOffset() const { - STATIC_ASSERT(HeapNumber::kValueOffset % kApiPointerSize == 0); - return (HeapNumber::kValueOffset / kApiPointerSize) * PointerSize() - - kHeapObjectTag; - } bool Is32() const { return WordRepresentation() == kRepWord32; } - int PointerSize() const { - switch (WordRepresentation()) { - case kRepWord32: - return 4; - case kRepWord64: - return 8; - default: - break; - } - UNREACHABLE(); - return 0; - } - int SmiMaxValue() const { return -(SmiMinValue() + 1); } - int SmiMinValue() const { - return static_cast<int>(0xffffffffu << (SmiValueSize() - 1)); - } - int SmiShiftAmount() const { return kSmiTagSize + SmiShiftSize(); } - int SmiShiftSize() const { - return Is32() ? SmiTagging<4>::SmiShiftSize() - : SmiTagging<8>::SmiShiftSize(); - } - int SmiValueSize() const { - return Is32() ? SmiTagging<4>::SmiValueSize() - : SmiTagging<8>::SmiValueSize(); - } + bool Is64() const { return WordRepresentation() == kRepWord64; } Reduction Reduce(Node* node) { MachineOperatorBuilder machine(zone(), WordRepresentation()); @@ -80,15 +50,33 @@ class ChangeLoweringTest : public GraphTest { IsNumberConstant(BitEq(0.0)), effect_matcher, control_matcher); } + Matcher<Node*> IsChangeInt32ToSmi(const Matcher<Node*>& value_matcher) { + return Is64() ? IsWord64Shl(IsChangeInt32ToInt64(value_matcher), + IsSmiShiftBitsConstant()) + : IsWord32Shl(value_matcher, IsSmiShiftBitsConstant()); + } + Matcher<Node*> IsChangeSmiToInt32(const Matcher<Node*>& value_matcher) { + return Is64() ? IsTruncateInt64ToInt32( + IsWord64Sar(value_matcher, IsSmiShiftBitsConstant())) + : IsWord32Sar(value_matcher, IsSmiShiftBitsConstant()); + } + Matcher<Node*> IsChangeUint32ToSmi(const Matcher<Node*>& value_matcher) { + return Is64() ? IsWord64Shl(IsChangeUint32ToUint64(value_matcher), + IsSmiShiftBitsConstant()) + : IsWord32Shl(value_matcher, IsSmiShiftBitsConstant()); + } Matcher<Node*> IsLoadHeapNumber(const Matcher<Node*>& value_matcher, const Matcher<Node*>& control_matcher) { return IsLoad(kMachFloat64, value_matcher, - IsIntPtrConstant(HeapNumberValueOffset()), graph()->start(), - control_matcher); + IsIntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag), + graph()->start(), control_matcher); } Matcher<Node*> IsIntPtrConstant(int value) { return Is32() ? IsInt32Constant(value) : IsInt64Constant(value); } + Matcher<Node*> IsSmiShiftBitsConstant() { + return IsIntPtrConstant(kSmiShiftSize + kSmiTagSize); + } Matcher<Node*> IsWordEqual(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher) { return Is32() ? IsWord32Equal(lhs_matcher, rhs_matcher) @@ -115,51 +103,95 @@ class ChangeLoweringCommonTest TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBitToBool) { - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeBitToBool(), val); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - EXPECT_THAT(reduction.replacement(), - IsSelect(static_cast<MachineType>(kTypeBool | kRepTagged), val, - IsTrueConstant(), IsFalseConstant())); + Node* value = Parameter(Type::Boolean()); + Reduction r = + Reduce(graph()->NewNode(simplified()->ChangeBitToBool(), value)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsSelect(kMachAnyTagged, value, IsTrueConstant(), + IsFalseConstant())); } TARGET_TEST_P(ChangeLoweringCommonTest, ChangeBoolToBit) { - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - EXPECT_THAT(reduction.replacement(), IsWordEqual(val, IsTrueConstant())); + Node* value = Parameter(Type::Number()); + Reduction r = + Reduce(graph()->NewNode(simplified()->ChangeBoolToBit(), value)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsWordEqual(value, IsTrueConstant())); } TARGET_TEST_P(ChangeLoweringCommonTest, ChangeFloat64ToTagged) { - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeFloat64ToTagged(), val); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - Node* finish = reduction.replacement(); + Node* value = Parameter(Type::Number()); + Reduction r = + Reduce(graph()->NewNode(simplified()->ChangeFloat64ToTagged(), value)); + ASSERT_TRUE(r.Changed()); Capture<Node*> heap_number; EXPECT_THAT( - finish, + r.replacement(), IsFinish( AllOf(CaptureEq(&heap_number), - IsAllocateHeapNumber(IsValueEffect(val), graph()->start())), + IsAllocateHeapNumber(IsValueEffect(value), graph()->start())), IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier), CaptureEq(&heap_number), - IsIntPtrConstant(HeapNumberValueOffset()), val, - CaptureEq(&heap_number), graph()->start()))); + IsIntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag), + value, CaptureEq(&heap_number), graph()->start()))); +} + + +TARGET_TEST_P(ChangeLoweringCommonTest, ChangeInt32ToTaggedWithSignedSmall) { + Node* value = Parameter(Type::SignedSmall()); + Reduction r = + Reduce(graph()->NewNode(simplified()->ChangeInt32ToTagged(), value)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsChangeInt32ToSmi(value)); } -TARGET_TEST_P(ChangeLoweringCommonTest, StringAdd) { - Node* node = - graph()->NewNode(simplified()->StringAdd(), Parameter(0), Parameter(1)); - Reduction reduction = Reduce(node); - EXPECT_FALSE(reduction.Changed()); +TARGET_TEST_P(ChangeLoweringCommonTest, ChangeUint32ToTaggedWithUnsignedSmall) { + Node* value = Parameter(Type::UnsignedSmall()); + Reduction r = + Reduce(graph()->NewNode(simplified()->ChangeUint32ToTagged(), value)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsChangeUint32ToSmi(value)); +} + + +TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToInt32WithTaggedSigned) { + Node* value = Parameter(Type::TaggedSigned()); + Reduction r = + Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(), value)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsChangeSmiToInt32(value)); +} + + +TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToInt32WithTaggedPointer) { + Node* value = Parameter(Type::TaggedPointer()); + Reduction r = + Reduce(graph()->NewNode(simplified()->ChangeTaggedToInt32(), value)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsChangeFloat64ToInt32( + IsLoadHeapNumber(value, graph()->start()))); +} + + +TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToUint32WithTaggedSigned) { + Node* value = Parameter(Type::TaggedSigned()); + Reduction r = + Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(), value)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsChangeSmiToInt32(value)); +} + + +TARGET_TEST_P(ChangeLoweringCommonTest, ChangeTaggedToUint32WithTaggedPointer) { + Node* value = Parameter(Type::TaggedPointer()); + Reduction r = + Reduce(graph()->NewNode(simplified()->ChangeTaggedToUint32(), value)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsChangeFloat64ToUint32( + IsLoadHeapNumber(value, graph()->start()))); } @@ -179,26 +211,24 @@ class ChangeLowering32Test : public ChangeLoweringTest { TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) { - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val); - NodeProperties::SetBounds(val, Bounds(Type::None(), Type::Signed32())); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - Node* phi = reduction.replacement(); + Node* value = Parameter(Type::Integral32()); + Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), value); + Reduction r = Reduce(node); + ASSERT_TRUE(r.Changed()); Capture<Node*> add, branch, heap_number, if_true; EXPECT_THAT( - phi, + r.replacement(), IsPhi(kMachAnyTagged, IsFinish(AllOf(CaptureEq(&heap_number), IsAllocateHeapNumber(_, CaptureEq(&if_true))), IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier), CaptureEq(&heap_number), - IsIntPtrConstant(HeapNumberValueOffset()), - IsChangeInt32ToFloat64(val), + IsIntPtrConstant(HeapNumber::kValueOffset - + kHeapObjectTag), + IsChangeInt32ToFloat64(value), CaptureEq(&heap_number), CaptureEq(&if_true))), - IsProjection( - 0, AllOf(CaptureEq(&add), IsInt32AddWithOverflow(val, val))), + IsProjection(0, AllOf(CaptureEq(&add), + IsInt32AddWithOverflow(value, value))), IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), IsIfFalse(AllOf(CaptureEq(&branch), IsBranch(IsProjection(1, CaptureEq(&add)), @@ -206,43 +236,27 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) { } -TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTaggedSmall) { - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val); - NodeProperties::SetBounds(val, Bounds(Type::None(), Type::Signed31())); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - Node* change = reduction.replacement(); - Capture<Node*> add, branch, heap_number, if_true; - EXPECT_THAT(change, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount()))); -} - - TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) { STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - Node* phi = reduction.replacement(); + Node* value = Parameter(Type::Number()); + Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), value); + Reduction r = Reduce(node); + ASSERT_TRUE(r.Changed()); Capture<Node*> branch, if_true; EXPECT_THAT( - phi, - IsPhi( - kMachFloat64, IsLoadHeapNumber(val, CaptureEq(&if_true)), - IsChangeInt32ToFloat64( - IsWord32Sar(val, IsInt32Constant(SmiShiftAmount()))), - IsMerge( - AllOf(CaptureEq(&if_true), - IsIfTrue(AllOf( - CaptureEq(&branch), - IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)), - graph()->start())))), - IsIfFalse(CaptureEq(&branch))))); + r.replacement(), + IsPhi(kMachFloat64, IsLoadHeapNumber(value, CaptureEq(&if_true)), + IsChangeInt32ToFloat64(IsWord32Sar( + value, IsInt32Constant(kSmiTagSize + kSmiShiftSize))), + IsMerge(AllOf(CaptureEq(&if_true), + IsIfTrue(AllOf( + CaptureEq(&branch), + IsBranch(IsWord32And( + value, IsInt32Constant(kSmiTagMask)), + graph()->start())))), + IsIfFalse(CaptureEq(&branch))))); } @@ -250,23 +264,22 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) { STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - Node* phi = reduction.replacement(); + Node* value = Parameter(Type::Signed32()); + Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), value); + Reduction r = Reduce(node); + ASSERT_TRUE(r.Changed()); Capture<Node*> branch, if_true; EXPECT_THAT( - phi, - IsPhi(kMachInt32, - IsChangeFloat64ToInt32(IsLoadHeapNumber(val, CaptureEq(&if_true))), - IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())), - IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), - IsIfFalse(AllOf( - CaptureEq(&branch), - IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)), - graph()->start())))))); + r.replacement(), + IsPhi( + kMachInt32, + IsChangeFloat64ToInt32(IsLoadHeapNumber(value, CaptureEq(&if_true))), + IsWord32Sar(value, IsInt32Constant(kSmiTagSize + kSmiShiftSize)), + IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), + IsIfFalse(AllOf( + CaptureEq(&branch), + IsBranch(IsWord32And(value, IsInt32Constant(kSmiTagMask)), + graph()->start())))))); } @@ -274,23 +287,22 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToUint32) { STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - Node* phi = reduction.replacement(); + Node* value = Parameter(Type::Unsigned32()); + Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), value); + Reduction r = Reduce(node); + ASSERT_TRUE(r.Changed()); Capture<Node*> branch, if_true; EXPECT_THAT( - phi, - IsPhi(kMachUint32, - IsChangeFloat64ToUint32(IsLoadHeapNumber(val, CaptureEq(&if_true))), - IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())), - IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), - IsIfFalse(AllOf( - CaptureEq(&branch), - IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)), - graph()->start())))))); + r.replacement(), + IsPhi( + kMachUint32, + IsChangeFloat64ToUint32(IsLoadHeapNumber(value, CaptureEq(&if_true))), + IsWord32Sar(value, IsInt32Constant(kSmiTagSize + kSmiShiftSize)), + IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), + IsIfFalse(AllOf( + CaptureEq(&branch), + IsBranch(IsWord32And(value, IsInt32Constant(kSmiTagMask)), + graph()->start())))))); } @@ -298,30 +310,30 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeUint32ToTagged) { STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - Node* phi = reduction.replacement(); + Node* value = Parameter(Type::Number()); + Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), value); + Reduction r = Reduce(node); + ASSERT_TRUE(r.Changed()); Capture<Node*> branch, heap_number, if_false; EXPECT_THAT( - phi, + r.replacement(), IsPhi( - kMachAnyTagged, IsWord32Shl(val, IsInt32Constant(SmiShiftAmount())), + kMachAnyTagged, + IsWord32Shl(value, IsInt32Constant(kSmiTagSize + kSmiShiftSize)), IsFinish(AllOf(CaptureEq(&heap_number), IsAllocateHeapNumber(_, CaptureEq(&if_false))), IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier), CaptureEq(&heap_number), - IsInt32Constant(HeapNumberValueOffset()), - IsChangeUint32ToFloat64(val), + IsInt32Constant(HeapNumber::kValueOffset - + kHeapObjectTag), + IsChangeUint32ToFloat64(value), CaptureEq(&heap_number), CaptureEq(&if_false))), - IsMerge( - IsIfTrue(AllOf(CaptureEq(&branch), - IsBranch(IsUint32LessThanOrEqual( - val, IsInt32Constant(SmiMaxValue())), - graph()->start()))), - AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); + IsMerge(IsIfTrue(AllOf( + CaptureEq(&branch), + IsBranch(IsUint32LessThanOrEqual( + value, IsInt32Constant(Smi::kMaxValue)), + graph()->start()))), + AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); } @@ -337,14 +349,11 @@ class ChangeLowering64Test : public ChangeLoweringTest { TARGET_TEST_F(ChangeLowering64Test, ChangeInt32ToTagged) { - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - EXPECT_THAT(reduction.replacement(), - IsWord64Shl(IsChangeInt32ToInt64(val), - IsInt64Constant(SmiShiftAmount()))); + Node* value = Parameter(Type::Signed32()); + Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), value); + Reduction r = Reduce(node); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsChangeInt32ToSmi(value)); } @@ -352,26 +361,23 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) { STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - Node* phi = reduction.replacement(); + Node* value = Parameter(Type::Number()); + Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), value); + Reduction r = Reduce(node); + ASSERT_TRUE(r.Changed()); Capture<Node*> branch, if_true; EXPECT_THAT( - phi, - IsPhi( - kMachFloat64, IsLoadHeapNumber(val, CaptureEq(&if_true)), - IsChangeInt32ToFloat64(IsTruncateInt64ToInt32( - IsWord64Sar(val, IsInt64Constant(SmiShiftAmount())))), - IsMerge( - AllOf(CaptureEq(&if_true), - IsIfTrue(AllOf( - CaptureEq(&branch), - IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)), - graph()->start())))), - IsIfFalse(CaptureEq(&branch))))); + r.replacement(), + IsPhi(kMachFloat64, IsLoadHeapNumber(value, CaptureEq(&if_true)), + IsChangeInt32ToFloat64(IsTruncateInt64ToInt32(IsWord64Sar( + value, IsInt64Constant(kSmiTagSize + kSmiShiftSize)))), + IsMerge(AllOf(CaptureEq(&if_true), + IsIfTrue(AllOf( + CaptureEq(&branch), + IsBranch(IsWord64And( + value, IsInt64Constant(kSmiTagMask)), + graph()->start())))), + IsIfFalse(CaptureEq(&branch))))); } @@ -379,24 +385,23 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) { STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - Node* phi = reduction.replacement(); + Node* value = Parameter(Type::Signed32()); + Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), value); + Reduction r = Reduce(node); + ASSERT_TRUE(r.Changed()); Capture<Node*> branch, if_true; EXPECT_THAT( - phi, - IsPhi(kMachInt32, - IsChangeFloat64ToInt32(IsLoadHeapNumber(val, CaptureEq(&if_true))), - IsTruncateInt64ToInt32( - IsWord64Sar(val, IsInt64Constant(SmiShiftAmount()))), - IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), - IsIfFalse(AllOf( - CaptureEq(&branch), - IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)), - graph()->start())))))); + r.replacement(), + IsPhi( + kMachInt32, + IsChangeFloat64ToInt32(IsLoadHeapNumber(value, CaptureEq(&if_true))), + IsTruncateInt64ToInt32( + IsWord64Sar(value, IsInt64Constant(kSmiTagSize + kSmiShiftSize))), + IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), + IsIfFalse(AllOf( + CaptureEq(&branch), + IsBranch(IsWord64And(value, IsInt64Constant(kSmiTagMask)), + graph()->start())))))); } @@ -404,24 +409,23 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToUint32) { STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), val); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - Node* phi = reduction.replacement(); + Node* value = Parameter(Type::Unsigned32()); + Node* node = graph()->NewNode(simplified()->ChangeTaggedToUint32(), value); + Reduction r = Reduce(node); + ASSERT_TRUE(r.Changed()); Capture<Node*> branch, if_true; EXPECT_THAT( - phi, - IsPhi(kMachUint32, - IsChangeFloat64ToUint32(IsLoadHeapNumber(val, CaptureEq(&if_true))), - IsTruncateInt64ToInt32( - IsWord64Sar(val, IsInt64Constant(SmiShiftAmount()))), - IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), - IsIfFalse(AllOf( - CaptureEq(&branch), - IsBranch(IsWord64And(val, IsInt64Constant(kSmiTagMask)), - graph()->start())))))); + r.replacement(), + IsPhi( + kMachUint32, + IsChangeFloat64ToUint32(IsLoadHeapNumber(value, CaptureEq(&if_true))), + IsTruncateInt64ToInt32( + IsWord64Sar(value, IsInt64Constant(kSmiTagSize + kSmiShiftSize))), + IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))), + IsIfFalse(AllOf( + CaptureEq(&branch), + IsBranch(IsWord64And(value, IsInt64Constant(kSmiTagMask)), + graph()->start())))))); } @@ -429,31 +433,31 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) { STATIC_ASSERT(kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1); - Node* val = Parameter(0); - Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), val); - Reduction reduction = Reduce(node); - ASSERT_TRUE(reduction.Changed()); - - Node* phi = reduction.replacement(); + Node* value = Parameter(Type::Number()); + Node* node = graph()->NewNode(simplified()->ChangeUint32ToTagged(), value); + Reduction r = Reduce(node); + ASSERT_TRUE(r.Changed()); Capture<Node*> branch, heap_number, if_false; EXPECT_THAT( - phi, + r.replacement(), IsPhi( - kMachAnyTagged, IsWord64Shl(IsChangeUint32ToUint64(val), - IsInt64Constant(SmiShiftAmount())), + kMachAnyTagged, + IsWord64Shl(IsChangeUint32ToUint64(value), + IsInt64Constant(kSmiTagSize + kSmiShiftSize)), IsFinish(AllOf(CaptureEq(&heap_number), IsAllocateHeapNumber(_, CaptureEq(&if_false))), IsStore(StoreRepresentation(kMachFloat64, kNoWriteBarrier), CaptureEq(&heap_number), - IsInt64Constant(HeapNumberValueOffset()), - IsChangeUint32ToFloat64(val), + IsInt64Constant(HeapNumber::kValueOffset - + kHeapObjectTag), + IsChangeUint32ToFloat64(value), CaptureEq(&heap_number), CaptureEq(&if_false))), - IsMerge( - IsIfTrue(AllOf(CaptureEq(&branch), - IsBranch(IsUint32LessThanOrEqual( - val, IsInt32Constant(SmiMaxValue())), - graph()->start()))), - AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); + IsMerge(IsIfTrue(AllOf( + CaptureEq(&branch), + IsBranch(IsUint32LessThanOrEqual( + value, IsInt32Constant(Smi::kMaxValue)), + graph()->start()))), + AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); } } // namespace compiler diff --git a/deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc index 1f6044b97c..3b60e5b9bd 100644 --- a/deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/common-operator-reducer-unittest.cc @@ -4,9 +4,13 @@ #include "src/compiler/common-operator.h" #include "src/compiler/common-operator-reducer.h" +#include "src/compiler/js-graph.h" +#include "src/compiler/js-operator.h" +#include "src/compiler/machine-operator.h" #include "src/compiler/machine-type.h" #include "src/compiler/operator.h" #include "test/unittests/compiler/graph-unittest.h" +#include "test/unittests/compiler/node-test-utils.h" namespace v8 { namespace internal { @@ -15,14 +19,23 @@ namespace compiler { class CommonOperatorReducerTest : public GraphTest { public: explicit CommonOperatorReducerTest(int num_parameters = 1) - : GraphTest(num_parameters) {} + : GraphTest(num_parameters), machine_(zone()) {} ~CommonOperatorReducerTest() OVERRIDE {} protected: - Reduction Reduce(Node* node) { - CommonOperatorReducer reducer; + Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags = + MachineOperatorBuilder::kNoFlags) { + JSOperatorBuilder javascript(zone()); + MachineOperatorBuilder machine(zone(), kMachPtr, flags); + JSGraph jsgraph(isolate(), graph(), common(), &javascript, &machine); + CommonOperatorReducer reducer(&jsgraph); return reducer.Reduce(node); } + + MachineOperatorBuilder* machine() { return &machine_; } + + private: + MachineOperatorBuilder machine_; }; @@ -78,9 +91,14 @@ TEST_F(CommonOperatorReducerTest, RedundantPhi) { int const value_input_count = input_count - 1; TRACED_FOREACH(MachineType, type, kMachineTypes) { for (int i = 0; i < value_input_count; ++i) { + inputs[i] = graph()->start(); + } + Node* merge = graph()->NewNode(common()->Merge(value_input_count), + value_input_count, inputs); + for (int i = 0; i < value_input_count; ++i) { inputs[i] = input; } - inputs[value_input_count] = graph()->start(); + inputs[value_input_count] = merge; Reduction r = Reduce(graph()->NewNode( common()->Phi(type, value_input_count), input_count, inputs)); ASSERT_TRUE(r.Changed()); @@ -90,6 +108,27 @@ TEST_F(CommonOperatorReducerTest, RedundantPhi) { } +TEST_F(CommonOperatorReducerTest, PhiToFloat64MaxOrFloat64Min) { + Node* p0 = Parameter(0); + Node* p1 = Parameter(1); + Node* check = graph()->NewNode(machine()->Float64LessThan(), p0, p1); + Node* branch = graph()->NewNode(common()->Branch(), check, graph()->start()); + Node* if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* if_false = graph()->NewNode(common()->IfFalse(), branch); + Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); + Reduction r1 = + Reduce(graph()->NewNode(common()->Phi(kMachFloat64, 2), p1, p0, merge), + MachineOperatorBuilder::kFloat64Max); + ASSERT_TRUE(r1.Changed()); + EXPECT_THAT(r1.replacement(), IsFloat64Max(p1, p0)); + Reduction r2 = + Reduce(graph()->NewNode(common()->Phi(kMachFloat64, 2), p0, p1, merge), + MachineOperatorBuilder::kFloat64Min); + ASSERT_TRUE(r2.Changed()); + EXPECT_THAT(r2.replacement(), IsFloat64Min(p0, p1)); +} + + // ----------------------------------------------------------------------------- // Select @@ -106,6 +145,23 @@ TEST_F(CommonOperatorReducerTest, RedundantSelect) { } } + +TEST_F(CommonOperatorReducerTest, SelectToFloat64MaxOrFloat64Min) { + Node* p0 = Parameter(0); + Node* p1 = Parameter(1); + Node* check = graph()->NewNode(machine()->Float64LessThan(), p0, p1); + Reduction r1 = + Reduce(graph()->NewNode(common()->Select(kMachFloat64), check, p1, p0), + MachineOperatorBuilder::kFloat64Max); + ASSERT_TRUE(r1.Changed()); + EXPECT_THAT(r1.replacement(), IsFloat64Max(p1, p0)); + Reduction r2 = + Reduce(graph()->NewNode(common()->Select(kMachFloat64), check, p0, p1), + MachineOperatorBuilder::kFloat64Min); + ASSERT_TRUE(r2.Changed()); + EXPECT_THAT(r2.replacement(), IsFloat64Min(p0, p1)); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/common-operator-unittest.cc b/deps/v8/test/unittests/compiler/common-operator-unittest.cc index 6e60cfd12a..c0d25ea741 100644 --- a/deps/v8/test/unittests/compiler/common-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/common-operator-unittest.cc @@ -53,6 +53,8 @@ const SharedOperator kSharedOperators[] = { SHARED(End, Operator::kKontrol, 0, 0, 1, 0, 0, 0), SHARED(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1), SHARED(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1), + SHARED(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1), + SHARED(IfException, Operator::kKontrol, 0, 0, 1, 0, 0, 1), SHARED(Throw, Operator::kFoldable, 1, 1, 1, 0, 0, 1), SHARED(Return, Operator::kNoThrow, 1, 1, 1, 0, 0, 1) #undef SHARED diff --git a/deps/v8/test/unittests/compiler/control-equivalence-unittest.cc b/deps/v8/test/unittests/compiler/control-equivalence-unittest.cc index 17716ab1a9..515bd061ef 100644 --- a/deps/v8/test/unittests/compiler/control-equivalence-unittest.cc +++ b/deps/v8/test/unittests/compiler/control-equivalence-unittest.cc @@ -17,7 +17,7 @@ namespace compiler { do { \ Node* __n[] = {__VA_ARGS__}; \ ASSERT_TRUE(IsEquivalenceClass(arraysize(__n), __n)); \ - } while (false); + } while (false) class ControlEquivalenceTest : public GraphTest { public: diff --git a/deps/v8/test/unittests/compiler/control-flow-optimizer-unittest.cc b/deps/v8/test/unittests/compiler/control-flow-optimizer-unittest.cc index c083d4bab5..f300d07767 100644 --- a/deps/v8/test/unittests/compiler/control-flow-optimizer-unittest.cc +++ b/deps/v8/test/unittests/compiler/control-flow-optimizer-unittest.cc @@ -21,25 +21,32 @@ namespace compiler { class ControlFlowOptimizerTest : public GraphTest { public: explicit ControlFlowOptimizerTest(int num_parameters = 3) - : GraphTest(num_parameters), machine_(zone()) {} + : GraphTest(num_parameters), + machine_(zone()), + javascript_(zone()), + jsgraph_(isolate(), graph(), common(), javascript(), machine()) {} ~ControlFlowOptimizerTest() OVERRIDE {} protected: void Optimize() { - JSOperatorBuilder javascript(zone()); - JSGraph jsgraph(isolate(), graph(), common(), &javascript, machine()); - ControlFlowOptimizer optimizer(&jsgraph, zone()); + ControlFlowOptimizer optimizer(jsgraph(), zone()); optimizer.Optimize(); } + Node* EmptyFrameState() { return jsgraph()->EmptyFrameState(); } + + JSGraph* jsgraph() { return &jsgraph_; } + JSOperatorBuilder* javascript() { return &javascript_; } MachineOperatorBuilder* machine() { return &machine_; } private: MachineOperatorBuilder machine_; + JSOperatorBuilder javascript_; + JSGraph jsgraph_; }; -TEST_F(ControlFlowOptimizerTest, Switch) { +TEST_F(ControlFlowOptimizerTest, BuildSwitch1) { Node* index = Parameter(0); Node* branch0 = graph()->NewNode( common()->Branch(), @@ -65,6 +72,69 @@ TEST_F(ControlFlowOptimizerTest, Switch) { IsSwitch(index, start())))))); } + +TEST_F(ControlFlowOptimizerTest, BuildSwitch2) { + Node* input = Parameter(0); + Node* context = Parameter(1); + Node* index = FLAG_turbo_deoptimization + ? graph()->NewNode(javascript()->ToNumber(), input, context, + EmptyFrameState(), start(), start()) + : graph()->NewNode(javascript()->ToNumber(), input, context, + start(), start()); + Node* if_success = graph()->NewNode(common()->IfSuccess(), index); + Node* branch0 = graph()->NewNode( + common()->Branch(), + graph()->NewNode(machine()->Word32Equal(), index, Int32Constant(0)), + if_success); + Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); + Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); + Node* branch1 = graph()->NewNode( + common()->Branch(), + graph()->NewNode(machine()->Word32Equal(), index, Int32Constant(1)), + if_false0); + Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); + Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); + Node* merge = + graph()->NewNode(common()->Merge(3), if_true0, if_true1, if_false1); + graph()->SetEnd(graph()->NewNode(common()->End(), merge)); + Optimize(); + Capture<Node*> switch_capture; + EXPECT_THAT( + end(), + IsEnd(IsMerge(IsIfValue(0, CaptureEq(&switch_capture)), + IsIfValue(1, CaptureEq(&switch_capture)), + IsIfDefault(AllOf(CaptureEq(&switch_capture), + IsSwitch(index, IsIfSuccess(index))))))); +} + + +TEST_F(ControlFlowOptimizerTest, CloneBranch) { + Node* cond0 = Parameter(0); + Node* cond1 = Parameter(1); + Node* cond2 = Parameter(2); + Node* branch0 = graph()->NewNode(common()->Branch(), cond0, start()); + Node* control1 = graph()->NewNode(common()->IfTrue(), branch0); + Node* control2 = graph()->NewNode(common()->IfFalse(), branch0); + Node* merge0 = graph()->NewNode(common()->Merge(2), control1, control2); + Node* phi0 = + graph()->NewNode(common()->Phi(kRepBit, 2), cond1, cond2, merge0); + Node* branch = graph()->NewNode(common()->Branch(), phi0, merge0); + Node* if_true = graph()->NewNode(common()->IfTrue(), branch); + Node* if_false = graph()->NewNode(common()->IfFalse(), branch); + Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); + graph()->SetEnd(graph()->NewNode(common()->End(), merge)); + Optimize(); + Capture<Node*> branch1_capture, branch2_capture; + EXPECT_THAT( + end(), + IsEnd(IsMerge(IsMerge(IsIfTrue(CaptureEq(&branch1_capture)), + IsIfTrue(CaptureEq(&branch2_capture))), + IsMerge(IsIfFalse(AllOf(CaptureEq(&branch1_capture), + IsBranch(cond1, control1))), + IsIfFalse(AllOf(CaptureEq(&branch2_capture), + IsBranch(cond2, control2))))))); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc b/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc index afa1e94245..9138ab2ca6 100644 --- a/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc +++ b/deps/v8/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc @@ -11,9 +11,9 @@ namespace compiler { namespace { // Immediates (random subset). -static const int32_t kImmediates[] = { - kMinInt, -42, -1, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 16, 42, 0xff, 0xffff, 0x0f0f0f0f, kMaxInt}; +const int32_t kImmediates[] = {kMinInt, -42, -1, 0, 1, 2, + 3, 4, 5, 6, 7, 8, + 16, 42, 0xff, 0xffff, 0x0f0f0f0f, kMaxInt}; } // namespace @@ -666,6 +666,44 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) { } } + +// ----------------------------------------------------------------------------- +// Miscellaneous. + + +TEST_F(InstructionSelectorTest, Uint32LessThanWithLoadAndLoadStackPointer) { + StreamBuilder m(this, kMachBool); + Node* const sl = m.Load( + kMachPtr, + m.ExternalConstant(ExternalReference::address_of_stack_limit(isolate()))); + Node* const sp = m.LoadStackPointer(); + Node* const n = m.Uint32LessThan(sl, sp); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kIA32StackCheck, s[0]->arch_opcode()); + ASSERT_EQ(0U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kUnsignedGreaterThan, s[0]->flags_condition()); +} + + +TEST_F(InstructionSelectorTest, Word32Clz) { + StreamBuilder m(this, kMachUint32, kMachUint32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Word32Clz(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kIA32Lzcnt, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc b/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc index d3e00c642c..e52580dc64 100644 --- a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc +++ b/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc @@ -4,7 +4,8 @@ #include "test/unittests/compiler/instruction-selector-unittest.h" -#include "src/compiler/graph-inl.h" +#include "src/compiler/graph.h" +#include "src/compiler/schedule.h" #include "src/flags.h" #include "test/unittests/compiler/compiler-test-utils.h" @@ -346,9 +347,13 @@ TARGET_TEST_F(InstructionSelectorTest, CallJSFunctionWithDeopt) { Node* receiver = m.Parameter(1); Node* context = m.Parameter(2); - Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(1)); - Node* locals = m.NewNode(m.common()->StateValues(0)); - Node* stack = m.NewNode(m.common()->StateValues(0)); + ZoneVector<MachineType> int32_type(1, kMachInt32, zone()); + ZoneVector<MachineType> empty_types(zone()); + + Node* parameters = + m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(1)); + Node* locals = m.NewNode(m.common()->TypedStateValues(&empty_types)); + Node* stack = m.NewNode(m.common()->TypedStateValues(&empty_types)); Node* context_dummy = m.Int32Constant(0); Node* state_node = m.NewNode( @@ -386,10 +391,17 @@ TARGET_TEST_F(InstructionSelectorTest, CallFunctionStubWithDeopt) { Node* receiver = m.Parameter(1); Node* context = m.Int32Constant(1); // Context is ignored. + ZoneVector<MachineType> int32_type(1, kMachInt32, zone()); + ZoneVector<MachineType> float64_type(1, kMachFloat64, zone()); + ZoneVector<MachineType> tagged_type(1, kMachAnyTagged, zone()); + // Build frame state for the state before the call. - Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); - Node* locals = m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.5)); - Node* stack = m.NewNode(m.common()->StateValues(1), m.UndefinedConstant()); + Node* parameters = + m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43)); + Node* locals = m.NewNode(m.common()->TypedStateValues(&float64_type), + m.Float64Constant(0.5)); + Node* stack = m.NewNode(m.common()->TypedStateValues(&tagged_type), + m.UndefinedConstant()); Node* context_sentinel = m.Int32Constant(0); Node* frame_state_before = m.NewNode( @@ -472,10 +484,17 @@ TARGET_TEST_F(InstructionSelectorTest, Node* receiver = m.Parameter(1); Node* context = m.Int32Constant(66); + ZoneVector<MachineType> int32_type(1, kMachInt32, zone()); + ZoneVector<MachineType> int32x2_type(2, kMachInt32, zone()); + ZoneVector<MachineType> float64_type(1, kMachFloat64, zone()); + // Build frame state for the state before the call. - Node* parameters = m.NewNode(m.common()->StateValues(1), m.Int32Constant(63)); - Node* locals = m.NewNode(m.common()->StateValues(1), m.Int32Constant(64)); - Node* stack = m.NewNode(m.common()->StateValues(1), m.Int32Constant(65)); + Node* parameters = + m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(63)); + Node* locals = + m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(64)); + Node* stack = + m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(65)); Node* frame_state_parent = m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_parent, OutputFrameStateCombine::Ignore()), @@ -483,11 +502,11 @@ TARGET_TEST_F(InstructionSelectorTest, Node* context2 = m.Int32Constant(46); Node* parameters2 = - m.NewNode(m.common()->StateValues(1), m.Int32Constant(43)); - Node* locals2 = - m.NewNode(m.common()->StateValues(1), m.Float64Constant(0.25)); - Node* stack2 = m.NewNode(m.common()->StateValues(2), m.Int32Constant(44), - m.Int32Constant(45)); + m.NewNode(m.common()->TypedStateValues(&int32_type), m.Int32Constant(43)); + Node* locals2 = m.NewNode(m.common()->TypedStateValues(&float64_type), + m.Float64Constant(0.25)); + Node* stack2 = m.NewNode(m.common()->TypedStateValues(&int32x2_type), + m.Int32Constant(44), m.Int32Constant(45)); Node* frame_state_before = m.NewNode(m.common()->FrameState(JS_FRAME, bailout_id_before, OutputFrameStateCombine::Push()), diff --git a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc b/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc index 001fb11d13..c2e626fd59 100644 --- a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc +++ b/deps/v8/test/unittests/compiler/instruction-sequence-unittest.cc @@ -40,7 +40,6 @@ InstructionSequenceTest::InstructionSequenceTest() num_general_registers_(kDefaultNRegs), num_double_registers_(kDefaultNRegs), instruction_blocks_(zone()), - current_instruction_index_(-1), current_block_(nullptr), block_returns_(false) { InitializeRegisterNames(); @@ -100,8 +99,8 @@ void InstructionSequenceTest::StartBlock() { } -int InstructionSequenceTest::EndBlock(BlockCompletion completion) { - int instruction_index = kMinInt; +Instruction* InstructionSequenceTest::EndBlock(BlockCompletion completion) { + Instruction* result = nullptr; if (block_returns_) { CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough); completion.type_ = kBlockEnd; @@ -110,22 +109,22 @@ int InstructionSequenceTest::EndBlock(BlockCompletion completion) { case kBlockEnd: break; case kFallThrough: - instruction_index = EmitFallThrough(); + result = EmitFallThrough(); break; case kJump: CHECK(!block_returns_); - instruction_index = EmitJump(); + result = EmitJump(); break; case kBranch: CHECK(!block_returns_); - instruction_index = EmitBranch(completion.op_); + result = EmitBranch(completion.op_); break; } completions_.push_back(completion); CHECK(current_block_ != nullptr); sequence()->EndBlock(current_block_->rpo_number()); current_block_ = nullptr; - return instruction_index; + return result; } @@ -139,15 +138,15 @@ InstructionSequenceTest::VReg InstructionSequenceTest::Define( TestOperand output_op) { VReg vreg = NewReg(); InstructionOperand outputs[1]{ConvertOutputOp(vreg, output_op)}; - Emit(vreg.value_, kArchNop, 1, outputs); + Emit(kArchNop, 1, outputs); return vreg; } -int InstructionSequenceTest::Return(TestOperand input_op_0) { +Instruction* InstructionSequenceTest::Return(TestOperand input_op_0) { block_returns_ = true; InstructionOperand inputs[1]{ConvertInputOp(input_op_0)}; - return Emit(NewIndex(), kArchRet, 0, nullptr, 1, inputs); + return Emit(kArchRet, 0, nullptr, 1, inputs); } @@ -192,12 +191,12 @@ InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant( VReg vreg = NewReg(); sequence()->AddConstant(vreg.value_, Constant(imm)); InstructionOperand outputs[1]{ConstantOperand(vreg.value_)}; - Emit(vreg.value_, kArchNop, 1, outputs); + Emit(kArchNop, 1, outputs); return vreg; } -int InstructionSequenceTest::EmitNop() { return Emit(NewIndex(), kArchNop); } +Instruction* InstructionSequenceTest::EmitNop() { return Emit(kArchNop); } static size_t CountInputs(size_t size, @@ -210,16 +209,17 @@ static size_t CountInputs(size_t size, } -int InstructionSequenceTest::EmitI(size_t input_size, TestOperand* inputs) { +Instruction* InstructionSequenceTest::EmitI(size_t input_size, + TestOperand* inputs) { InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs); - return Emit(NewIndex(), kArchNop, 0, nullptr, input_size, mapped_inputs); + return Emit(kArchNop, 0, nullptr, input_size, mapped_inputs); } -int InstructionSequenceTest::EmitI(TestOperand input_op_0, - TestOperand input_op_1, - TestOperand input_op_2, - TestOperand input_op_3) { +Instruction* InstructionSequenceTest::EmitI(TestOperand input_op_0, + TestOperand input_op_1, + TestOperand input_op_2, + TestOperand input_op_3) { TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3}; return EmitI(CountInputs(arraysize(inputs), inputs), inputs); } @@ -230,7 +230,7 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI( VReg output_vreg = NewReg(); InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)}; InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs); - Emit(output_vreg.value_, kArchNop, 1, outputs, input_size, mapped_inputs); + Emit(kArchNop, 1, outputs, input_size, mapped_inputs); return output_vreg; } @@ -243,14 +243,36 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI( } +InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI( + TestOperand output_op_0, TestOperand output_op_1, size_t input_size, + TestOperand* inputs) { + VRegPair output_vregs = std::make_pair(NewReg(), NewReg()); + InstructionOperand outputs[2]{ + ConvertOutputOp(output_vregs.first, output_op_0), + ConvertOutputOp(output_vregs.second, output_op_1)}; + InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs); + Emit(kArchNop, 2, outputs, input_size, mapped_inputs); + return output_vregs; +} + + +InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI( + TestOperand output_op_0, TestOperand output_op_1, TestOperand input_op_0, + TestOperand input_op_1, TestOperand input_op_2, TestOperand input_op_3) { + TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3}; + return EmitOOI(output_op_0, output_op_1, + CountInputs(arraysize(inputs), inputs), inputs); +} + + InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall( TestOperand output_op, size_t input_size, TestOperand* inputs) { VReg output_vreg = NewReg(); InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)}; CHECK(UnallocatedOperand::cast(outputs[0]).HasFixedPolicy()); InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs); - Emit(output_vreg.value_, kArchCallCodeObject, 1, outputs, input_size, - mapped_inputs, 0, nullptr, true); + Emit(kArchCallCodeObject, 1, outputs, input_size, mapped_inputs, 0, nullptr, + true); return output_vreg; } @@ -263,36 +285,26 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall( } -const Instruction* InstructionSequenceTest::GetInstruction( - int instruction_index) { - auto it = instructions_.find(instruction_index); - CHECK(it != instructions_.end()); - return it->second; -} - - -int InstructionSequenceTest::EmitBranch(TestOperand input_op) { +Instruction* InstructionSequenceTest::EmitBranch(TestOperand input_op) { InstructionOperand inputs[4]{ConvertInputOp(input_op), ConvertInputOp(Imm()), ConvertInputOp(Imm()), ConvertInputOp(Imm())}; InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) | FlagsConditionField::encode(kEqual); - auto instruction = - NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl(); - return AddInstruction(NewIndex(), instruction); + auto instruction = NewInstruction(opcode, 0, nullptr, 4, inputs); + return AddInstruction(instruction); } -int InstructionSequenceTest::EmitFallThrough() { - auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl(); - return AddInstruction(NewIndex(), instruction); +Instruction* InstructionSequenceTest::EmitFallThrough() { + auto instruction = NewInstruction(kArchNop, 0, nullptr); + return AddInstruction(instruction); } -int InstructionSequenceTest::EmitJump() { +Instruction* InstructionSequenceTest::EmitJump() { InstructionOperand inputs[1]{ConvertInputOp(Imm())}; - auto instruction = - NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl(); - return AddInstruction(NewIndex(), instruction); + auto instruction = NewInstruction(kArchJmp, 0, nullptr, 1, inputs); + return AddInstruction(instruction); } @@ -359,6 +371,9 @@ InstructionOperand InstructionSequenceTest::ConvertInputOp(TestOperand op) { case kRegister: return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER, UnallocatedOperand::USED_AT_START); + case kSlot: + return Unallocated(op, UnallocatedOperand::MUST_HAVE_SLOT, + UnallocatedOperand::USED_AT_START); case kFixedRegister: CHECK(0 <= op.value_ && op.value_ < num_general_registers_); return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_); @@ -396,15 +411,14 @@ InstructionOperand InstructionSequenceTest::ConvertOutputOp(VReg vreg, InstructionBlock* InstructionSequenceTest::NewBlock() { CHECK(current_block_ == nullptr); - auto block_id = BasicBlock::Id::FromSize(instruction_blocks_.size()); - Rpo rpo = Rpo::FromInt(block_id.ToInt()); + Rpo rpo = Rpo::FromInt(static_cast<int>(instruction_blocks_.size())); Rpo loop_header = Rpo::Invalid(); Rpo loop_end = Rpo::Invalid(); if (!loop_blocks_.empty()) { auto& loop_data = loop_blocks_.back(); // This is a loop header. if (!loop_data.loop_header_.IsValid()) { - loop_end = Rpo::FromInt(block_id.ToInt() + loop_data.expected_blocks_); + loop_end = Rpo::FromInt(rpo.ToInt() + loop_data.expected_blocks_); loop_data.expected_blocks_--; loop_data.loop_header_ = rpo; } else { @@ -416,8 +430,8 @@ InstructionBlock* InstructionSequenceTest::NewBlock() { } } // Construct instruction block. - auto instruction_block = new (zone()) - InstructionBlock(zone(), block_id, rpo, loop_header, loop_end, false); + auto instruction_block = + new (zone()) InstructionBlock(zone(), rpo, loop_header, loop_end, false); instruction_blocks_.push_back(instruction_block); current_block_ = instruction_block; sequence()->StartBlock(rpo); @@ -458,23 +472,20 @@ void InstructionSequenceTest::WireBlock(size_t block_offset, int jump_offset) { } -int InstructionSequenceTest::Emit(int instruction_index, InstructionCode code, - size_t outputs_size, - InstructionOperand* outputs, - size_t inputs_size, - InstructionOperand* inputs, size_t temps_size, - InstructionOperand* temps, bool is_call) { +Instruction* InstructionSequenceTest::Emit( + InstructionCode code, size_t outputs_size, InstructionOperand* outputs, + size_t inputs_size, InstructionOperand* inputs, size_t temps_size, + InstructionOperand* temps, bool is_call) { auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size, inputs, temps_size, temps); if (is_call) instruction->MarkAsCall(); - return AddInstruction(instruction_index, instruction); + return AddInstruction(instruction); } -int InstructionSequenceTest::AddInstruction(int instruction_index, - Instruction* instruction) { +Instruction* InstructionSequenceTest::AddInstruction(Instruction* instruction) { sequence()->AddInstruction(instruction); - return instruction_index; + return instruction; } } // namespace compiler diff --git a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.h b/deps/v8/test/unittests/compiler/instruction-sequence-unittest.h index 613e25883e..2d75da7e47 100644 --- a/deps/v8/test/unittests/compiler/instruction-sequence-unittest.h +++ b/deps/v8/test/unittests/compiler/instruction-sequence-unittest.h @@ -18,7 +18,7 @@ class InstructionSequenceTest : public TestWithIsolateAndZone { static const int kDefaultNRegs = 4; static const int kNoValue = kMinInt; - typedef BasicBlock::RpoNumber Rpo; + typedef RpoNumber Rpo; struct VReg { VReg() : value_(kNoValue) {} @@ -27,6 +27,8 @@ class InstructionSequenceTest : public TestWithIsolateAndZone { int value_; }; + typedef std::pair<VReg, VReg> VRegPair; + enum TestOperandType { kInvalid, kSameAsFirst, @@ -125,14 +127,14 @@ class InstructionSequenceTest : public TestWithIsolateAndZone { void StartLoop(int loop_blocks); void EndLoop(); void StartBlock(); - int EndBlock(BlockCompletion completion = FallThrough()); + Instruction* EndBlock(BlockCompletion completion = FallThrough()); TestOperand Imm(int32_t imm = 0); VReg Define(TestOperand output_op); VReg Parameter(TestOperand output_op = Reg()) { return Define(output_op); } - int Return(TestOperand input_op_0); - int Return(VReg vreg) { return Return(Reg(vreg, 0)); } + Instruction* Return(TestOperand input_op_0); + Instruction* Return(VReg vreg) { return Return(Reg(vreg, 0)); } PhiInstruction* Phi(VReg incoming_vreg_0 = VReg(), VReg incoming_vreg_1 = VReg(), @@ -142,27 +144,30 @@ class InstructionSequenceTest : public TestWithIsolateAndZone { void SetInput(PhiInstruction* phi, size_t input, VReg vreg); VReg DefineConstant(int32_t imm = 0); - int EmitNop(); - int EmitI(size_t input_size, TestOperand* inputs); - int EmitI(TestOperand input_op_0 = TestOperand(), - TestOperand input_op_1 = TestOperand(), - TestOperand input_op_2 = TestOperand(), - TestOperand input_op_3 = TestOperand()); + Instruction* EmitNop(); + Instruction* EmitI(size_t input_size, TestOperand* inputs); + Instruction* EmitI(TestOperand input_op_0 = TestOperand(), + TestOperand input_op_1 = TestOperand(), + TestOperand input_op_2 = TestOperand(), + TestOperand input_op_3 = TestOperand()); VReg EmitOI(TestOperand output_op, size_t input_size, TestOperand* inputs); VReg EmitOI(TestOperand output_op, TestOperand input_op_0 = TestOperand(), TestOperand input_op_1 = TestOperand(), TestOperand input_op_2 = TestOperand(), TestOperand input_op_3 = TestOperand()); + VRegPair EmitOOI(TestOperand output_op_0, TestOperand output_op_1, + size_t input_size, TestOperand* inputs); + VRegPair EmitOOI(TestOperand output_op_0, TestOperand output_op_1, + TestOperand input_op_0 = TestOperand(), + TestOperand input_op_1 = TestOperand(), + TestOperand input_op_2 = TestOperand(), + TestOperand input_op_3 = TestOperand()); VReg EmitCall(TestOperand output_op, size_t input_size, TestOperand* inputs); VReg EmitCall(TestOperand output_op, TestOperand input_op_0 = TestOperand(), TestOperand input_op_1 = TestOperand(), TestOperand input_op_2 = TestOperand(), TestOperand input_op_3 = TestOperand()); - // Get defining instruction vreg or value returned at instruction creation - // time when there is no return value. - const Instruction* GetInstruction(int instruction_index); - InstructionBlock* current_block() const { return current_block_; } int num_general_registers() const { return num_general_registers_; } int num_double_registers() const { return num_double_registers_; } @@ -172,13 +177,12 @@ class InstructionSequenceTest : public TestWithIsolateAndZone { private: VReg NewReg() { return VReg(sequence()->NextVirtualRegister()); } - int NewIndex() { return current_instruction_index_--; } static TestOperand Invalid() { return TestOperand(kInvalid, VReg()); } - int EmitBranch(TestOperand input_op); - int EmitFallThrough(); - int EmitJump(); + Instruction* EmitBranch(TestOperand input_op); + Instruction* EmitFallThrough(); + Instruction* EmitJump(); Instruction* NewInstruction(InstructionCode code, size_t outputs_size, InstructionOperand* outputs, size_t inputs_size = 0, @@ -202,12 +206,13 @@ class InstructionSequenceTest : public TestWithIsolateAndZone { InstructionBlock* NewBlock(); void WireBlock(size_t block_offset, int jump_offset); - int Emit(int instruction_index, InstructionCode code, size_t outputs_size = 0, - InstructionOperand* outputs = nullptr, size_t inputs_size = 0, - InstructionOperand* inputs = nullptr, size_t temps_size = 0, - InstructionOperand* temps = nullptr, bool is_call = false); + Instruction* Emit(InstructionCode code, size_t outputs_size = 0, + InstructionOperand* outputs = nullptr, + size_t inputs_size = 0, + InstructionOperand* inputs = nullptr, size_t temps_size = 0, + InstructionOperand* temps = nullptr, bool is_call = false); - int AddInstruction(int instruction_index, Instruction* instruction); + Instruction* AddInstruction(Instruction* instruction); struct LoopData { Rpo loop_header_; @@ -226,7 +231,6 @@ class InstructionSequenceTest : public TestWithIsolateAndZone { // Block building state. InstructionBlocks instruction_blocks_; Instructions instructions_; - int current_instruction_index_; Completions completions_; LoopBlocks loop_blocks_; InstructionBlock* current_block_; diff --git a/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc b/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc index b5c688e147..5c508a5d4b 100644 --- a/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc @@ -62,58 +62,6 @@ Type* const kNumberTypes[] = { // ----------------------------------------------------------------------------- -// Math.abs - - -TEST_F(JSBuiltinReducerTest, MathAbs) { - Handle<JSFunction> f = MathFunction("abs"); - - TRACED_FOREACH(Type*, t0, kNumberTypes) { - Node* p0 = Parameter(t0, 0); - Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f)); - Node* call = - graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), - fun, UndefinedConstant(), p0); - Reduction r = Reduce(call); - - if (t0->Is(Type::Unsigned32())) { - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), p0); - } else { - Capture<Node*> branch; - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsSelect(kMachNone, - IsNumberLessThan(IsNumberConstant(BitEq(0.0)), p0), p0, - IsNumberSubtract(IsNumberConstant(BitEq(0.0)), p0))); - } - } -} - - -// ----------------------------------------------------------------------------- -// Math.sqrt - - -TEST_F(JSBuiltinReducerTest, MathSqrt) { - Handle<JSFunction> f = MathFunction("sqrt"); - - TRACED_FOREACH(Type*, t0, kNumberTypes) { - Node* p0 = Parameter(t0, 0); - Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f)); - Node* call = - graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), - fun, UndefinedConstant(), p0); - Reduction r = Reduce(call); - - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsFloat64Sqrt(p0)); - } -} - - -// ----------------------------------------------------------------------------- // Math.max @@ -223,79 +171,6 @@ TEST_F(JSBuiltinReducerTest, MathFround) { } } - -// ----------------------------------------------------------------------------- -// Math.floor - - -TEST_F(JSBuiltinReducerTest, MathFloorAvailable) { - Handle<JSFunction> f = MathFunction("floor"); - - TRACED_FOREACH(Type*, t0, kNumberTypes) { - Node* p0 = Parameter(t0, 0); - Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f)); - Node* call = - graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), - fun, UndefinedConstant(), p0); - Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kFloat64Floor); - - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsFloat64Floor(p0)); - } -} - - -TEST_F(JSBuiltinReducerTest, MathFloorUnavailable) { - Handle<JSFunction> f = MathFunction("floor"); - - TRACED_FOREACH(Type*, t0, kNumberTypes) { - Node* p0 = Parameter(t0, 0); - Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f)); - Node* call = - graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), - fun, UndefinedConstant(), p0); - Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kNoFlags); - - ASSERT_FALSE(r.Changed()); - } -} - - -// ----------------------------------------------------------------------------- -// Math.ceil - - -TEST_F(JSBuiltinReducerTest, MathCeilAvailable) { - Handle<JSFunction> f = MathFunction("ceil"); - - TRACED_FOREACH(Type*, t0, kNumberTypes) { - Node* p0 = Parameter(t0, 0); - Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f)); - Node* call = - graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), - fun, UndefinedConstant(), p0); - Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kFloat64Ceil); - - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsFloat64Ceil(p0)); - } -} - - -TEST_F(JSBuiltinReducerTest, MathCeilUnavailable) { - Handle<JSFunction> f = MathFunction("ceil"); - - TRACED_FOREACH(Type*, t0, kNumberTypes) { - Node* p0 = Parameter(t0, 0); - Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f)); - Node* call = - graph()->NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS), - fun, UndefinedConstant(), p0); - Reduction r = Reduce(call, MachineOperatorBuilder::Flag::kNoFlags); - - ASSERT_FALSE(r.Changed()); - } -} } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc index 20d5c069fe..8adbc54ac2 100644 --- a/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc @@ -27,8 +27,9 @@ class JSIntrinsicLoweringTest : public GraphTest { ~JSIntrinsicLoweringTest() OVERRIDE {} protected: - Reduction Reduce(Node* node) { - MachineOperatorBuilder machine(zone()); + Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags = + MachineOperatorBuilder::kNoFlags) { + MachineOperatorBuilder machine(zone(), kMachPtr, flags); JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine); JSIntrinsicLowering reducer(&jsgraph); return reducer.Reduce(node); @@ -42,6 +43,61 @@ class JSIntrinsicLoweringTest : public GraphTest { // ----------------------------------------------------------------------------- +// %_ConstructDouble + + +TEST_F(JSIntrinsicLoweringTest, InlineOptimizedConstructDouble) { + Node* const input0 = Parameter(0); + Node* const input1 = Parameter(1); + Node* const context = Parameter(2); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce(graph()->NewNode( + javascript()->CallRuntime(Runtime::kInlineConstructDouble, 2), input0, + input1, context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64InsertHighWord32( + IsFloat64InsertLowWord32( + IsNumberConstant(BitEq(0.0)), input1), + input0)); +} + + +// ----------------------------------------------------------------------------- +// %_DoubleLo + + +TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleLo) { + Node* const input = Parameter(0); + Node* const context = Parameter(1); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce( + graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleLo, 1), + input, context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64ExtractLowWord32(input)); +} + + +// ----------------------------------------------------------------------------- +// %_DoubleHi + + +TEST_F(JSIntrinsicLoweringTest, InlineOptimizedDoubleHi) { + Node* const input = Parameter(0); + Node* const context = Parameter(1); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce( + graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineDoubleHi, 1), + input, context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64ExtractHighWord32(input)); +} + + +// ----------------------------------------------------------------------------- // %_IsSmi @@ -169,6 +225,94 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) { // ----------------------------------------------------------------------------- +// %_JSValueGetValue + + +TEST_F(JSIntrinsicLoweringTest, InlineJSValueGetValue) { + Node* const input = Parameter(0); + Node* const context = Parameter(1); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce(graph()->NewNode( + javascript()->CallRuntime(Runtime::kInlineJSValueGetValue, 1), input, + context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsLoadField(AccessBuilder::ForValue(), input, effect, control)); +} + + +// ----------------------------------------------------------------------------- +// %_MathFloor + + +TEST_F(JSIntrinsicLoweringTest, InlineMathFloor) { + Node* const input = Parameter(0); + Node* const context = Parameter(1); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce( + graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathFloor, 1), + input, context, effect, control), + MachineOperatorBuilder::kFloat64RoundDown); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64RoundDown(input)); +} + + +// ----------------------------------------------------------------------------- +// %_MathSqrt + + +TEST_F(JSIntrinsicLoweringTest, InlineMathSqrt) { + Node* const input = Parameter(0); + Node* const context = Parameter(1); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce( + graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathSqrt, 1), + input, context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsFloat64Sqrt(input)); +} + + +// ----------------------------------------------------------------------------- +// %_StringGetLength + + +TEST_F(JSIntrinsicLoweringTest, InlineStringGetLength) { + Node* const input = Parameter(0); + Node* const context = Parameter(1); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce(graph()->NewNode( + javascript()->CallRuntime(Runtime::kInlineStringGetLength, 1), input, + context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsLoadField(AccessBuilder::ForStringLength(), + input, effect, control)); +} + + +// ----------------------------------------------------------------------------- +// %_MathClz32 + + +TEST_F(JSIntrinsicLoweringTest, InlineMathClz32) { + Node* const input = Parameter(0); + Node* const context = Parameter(1); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = Reduce( + graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineMathClz32, 1), + input, context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsWord32Clz(input)); +} + + +// ----------------------------------------------------------------------------- // %_ValueOf diff --git a/deps/v8/test/unittests/compiler/js-operator-unittest.cc b/deps/v8/test/unittests/compiler/js-operator-unittest.cc index 8f4622ae67..7ecaed016d 100644 --- a/deps/v8/test/unittests/compiler/js-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-operator-unittest.cc @@ -28,6 +28,7 @@ struct SharedOperator { int control_input_count; int value_output_count; int effect_output_count; + int control_output_count; }; @@ -39,48 +40,48 @@ std::ostream& operator<<(std::ostream& os, const SharedOperator& sop) { const SharedOperator kSharedOperators[] = { #define SHARED(Name, properties, value_input_count, frame_state_input_count, \ effect_input_count, control_input_count, value_output_count, \ - effect_output_count) \ + effect_output_count, control_output_count) \ { \ &JSOperatorBuilder::Name, IrOpcode::kJS##Name, properties, \ value_input_count, frame_state_input_count, effect_input_count, \ - control_input_count, value_output_count, effect_output_count \ + control_input_count, value_output_count, effect_output_count, \ + control_output_count \ } - SHARED(Equal, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(NotEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(StrictEqual, Operator::kPure, 2, 0, 0, 0, 1, 0), - SHARED(StrictNotEqual, Operator::kPure, 2, 0, 0, 0, 1, 0), - SHARED(LessThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(GreaterThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(BitwiseOr, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(BitwiseXor, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(BitwiseAnd, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(ShiftLeft, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(ShiftRight, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(ShiftRightLogical, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(Add, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(Subtract, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(Multiply, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(Divide, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(Modulus, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(UnaryNot, Operator::kPure, 1, 0, 0, 0, 1, 0), - SHARED(ToBoolean, Operator::kPure, 1, 0, 0, 0, 1, 0), - SHARED(ToNumber, Operator::kNoProperties, 1, 1, 1, 1, 1, 1), - SHARED(ToString, Operator::kNoProperties, 1, 0, 1, 1, 1, 1), - SHARED(ToName, Operator::kNoProperties, 1, 1, 1, 1, 1, 1), - SHARED(ToObject, Operator::kNoProperties, 1, 1, 1, 1, 1, 1), - SHARED(Yield, Operator::kNoProperties, 1, 0, 1, 1, 1, 1), - SHARED(Create, Operator::kEliminatable, 0, 0, 1, 1, 1, 1), - SHARED(HasProperty, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0), - SHARED(InstanceOf, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(Debugger, Operator::kNoProperties, 0, 0, 1, 1, 0, 1), - SHARED(CreateFunctionContext, Operator::kNoProperties, 1, 0, 1, 1, 1, 1), - SHARED(CreateWithContext, Operator::kNoProperties, 2, 1, 1, 1, 1, 1), - SHARED(CreateBlockContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1), - SHARED(CreateModuleContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1), - SHARED(CreateScriptContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1) + SHARED(Equal, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), + SHARED(NotEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), + SHARED(StrictEqual, Operator::kPure, 2, 0, 0, 0, 1, 0, 0), + SHARED(StrictNotEqual, Operator::kPure, 2, 0, 0, 0, 1, 0, 0), + SHARED(LessThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), + SHARED(GreaterThan, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), + SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), + SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), + SHARED(BitwiseOr, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(BitwiseXor, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(BitwiseAnd, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(ShiftLeft, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(ShiftRight, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(ShiftRightLogical, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(Add, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(Subtract, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(Multiply, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(Divide, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(Modulus, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(UnaryNot, Operator::kPure, 1, 0, 0, 0, 1, 0, 0), + SHARED(ToBoolean, Operator::kPure, 1, 0, 0, 0, 1, 0, 0), + SHARED(ToNumber, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), + SHARED(ToString, Operator::kNoProperties, 1, 0, 1, 1, 1, 1, 2), + SHARED(ToName, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), + SHARED(ToObject, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), + SHARED(Yield, Operator::kNoProperties, 1, 0, 1, 1, 1, 1, 2), + SHARED(Create, Operator::kEliminatable, 0, 0, 1, 0, 1, 1, 0), + SHARED(HasProperty, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), + SHARED(TypeOf, Operator::kPure, 1, 0, 0, 0, 1, 0, 0), + SHARED(InstanceOf, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), + SHARED(CreateFunctionContext, Operator::kNoProperties, 1, 0, 1, 1, 1, 1, 2), + SHARED(CreateWithContext, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), + SHARED(CreateBlockContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1, 2), + SHARED(CreateModuleContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1, 2), + SHARED(CreateScriptContext, Operator::kNoProperties, 2, 0, 1, 1, 1, 1, 2) #undef SHARED }; @@ -122,7 +123,7 @@ TEST_P(JSSharedOperatorTest, NumberOfInputsAndOutputs) { EXPECT_EQ(sop.value_output_count, op->ValueOutputCount()); EXPECT_EQ(sop.effect_output_count, op->EffectOutputCount()); - EXPECT_EQ(0, op->ControlOutputCount()); + EXPECT_EQ(sop.control_output_count, op->ControlOutputCount()); } @@ -169,7 +170,7 @@ TEST_P(JSStorePropertyOperatorTest, NumberOfInputsAndOutputs) { const Operator* op = javascript.StoreProperty(mode); // TODO(jarin): Get rid of this hack. - const int frame_state_input_count = FLAG_turbo_deoptimization ? 1 : 0; + const int frame_state_input_count = FLAG_turbo_deoptimization ? 2 : 0; EXPECT_EQ(3, op->ValueInputCount()); EXPECT_EQ(1, OperatorProperties::GetContextInputCount(op)); EXPECT_EQ(frame_state_input_count, @@ -181,7 +182,7 @@ TEST_P(JSStorePropertyOperatorTest, NumberOfInputsAndOutputs) { EXPECT_EQ(0, op->ValueOutputCount()); EXPECT_EQ(1, op->EffectOutputCount()); - EXPECT_EQ(0, op->ControlOutputCount()); + EXPECT_EQ(2, op->ControlOutputCount()); } diff --git a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc index d61a1817b2..d347c4139b 100644 --- a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc @@ -8,6 +8,7 @@ #include "src/compiler/js-typed-lowering.h" #include "src/compiler/machine-operator.h" #include "src/compiler/node-properties.h" +#include "src/compiler/operator-properties.h" #include "test/unittests/compiler/compiler-test-utils.h" #include "test/unittests/compiler/graph-unittest.h" #include "test/unittests/compiler/node-test-utils.h" @@ -119,6 +120,16 @@ TEST_F(JSTypedLoweringTest, JSUnaryNotWithBoolean) { } +TEST_F(JSTypedLoweringTest, JSUnaryNotWithOrderedNumber) { + Node* input = Parameter(Type::OrderedNumber(), 0); + Node* context = Parameter(Type::Any(), 1); + Reduction r = + Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberEqual(input, IsNumberConstant(0))); +} + + TEST_F(JSTypedLoweringTest, JSUnaryNotWithFalsish) { Node* input = Parameter( Type::Union( @@ -173,13 +184,25 @@ TEST_F(JSTypedLoweringTest, JSUnaryNotWithNonZeroPlainNumber) { } +TEST_F(JSTypedLoweringTest, JSUnaryNotWithString) { + Node* input = Parameter(Type::String(), 0); + Node* context = Parameter(Type::Any(), 1); + Reduction r = + Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsNumberEqual(IsLoadField(AccessBuilder::ForStringLength(), input, + graph()->start(), graph()->start()), + IsNumberConstant(0.0))); +} + + TEST_F(JSTypedLoweringTest, JSUnaryNotWithAny) { Node* input = Parameter(Type::Any(), 0); Node* context = Parameter(Type::Any(), 1); Reduction r = Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsBooleanNot(IsAnyToBoolean(input))); + ASSERT_FALSE(r.Changed()); } @@ -349,13 +372,37 @@ TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) { } +TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumber) { + Node* input = Parameter(Type::OrderedNumber(), 0); + Node* context = Parameter(Type::Any(), 1); + Reduction r = + Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsBooleanNot(IsNumberEqual(input, IsNumberConstant(0.0)))); +} + + +TEST_F(JSTypedLoweringTest, JSToBooleanWithString) { + Node* input = Parameter(Type::String(), 0); + Node* context = Parameter(Type::Any(), 1); + Reduction r = + Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsNumberLessThan(IsNumberConstant(0.0), + IsLoadField(AccessBuilder::ForStringLength(), input, + graph()->start(), graph()->start()))); +} + + TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) { Node* input = Parameter(Type::Any(), 0); Node* context = Parameter(Type::Any(), 1); Reduction r = Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsAnyToBoolean(input)); + ASSERT_FALSE(r.Changed()); } @@ -681,8 +728,9 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) { Node* control = graph()->start(); Node* node = graph()->NewNode(javascript()->StoreProperty(language_mode), base, key, value, context); - if (FLAG_turbo_deoptimization) { - node->AppendInput(zone(), UndefinedConstant()); + for (int i = 0; + i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) { + node->AppendInput(zone(), EmptyFrameState()); } node->AppendInput(zone(), effect); node->AppendInput(zone(), control); @@ -726,8 +774,9 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) { Node* control = graph()->start(); Node* node = graph()->NewNode(javascript()->StoreProperty(language_mode), base, key, value, context); - if (FLAG_turbo_deoptimization) { - node->AppendInput(zone(), UndefinedConstant()); + for (int i = 0; + i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) { + node->AppendInput(zone(), EmptyFrameState()); } node->AppendInput(zone(), effect); node->AppendInput(zone(), control); @@ -784,8 +833,9 @@ TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) { Node* control = graph()->start(); Node* node = graph()->NewNode(javascript()->StoreProperty(language_mode), base, key, value, context); - if (FLAG_turbo_deoptimization) { - node->AppendInput(zone(), UndefinedConstant()); + for (int i = 0; + i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) { + node->AppendInput(zone(), EmptyFrameState()); } node->AppendInput(zone(), effect); node->AppendInput(zone(), control); diff --git a/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc b/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc new file mode 100644 index 0000000000..f7d0db354d --- /dev/null +++ b/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc @@ -0,0 +1,373 @@ +// 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/js-graph.h" +#include "src/compiler/linkage.h" +#include "src/compiler/liveness-analyzer.h" +#include "src/compiler/node-matchers.h" +#include "src/compiler/state-values-utils.h" +#include "test/unittests/compiler/graph-unittest.h" +#include "test/unittests/compiler/node-test-utils.h" + +using testing::MakeMatcher; +using testing::MatcherInterface; +using testing::MatchResultListener; +using testing::StringMatchResultListener; + +namespace v8 { +namespace internal { +namespace compiler { + +class LivenessAnalysisTest : public GraphTest { + public: + explicit LivenessAnalysisTest(int locals_count = 4) + : locals_count_(locals_count), + machine_(zone(), kRepWord32), + javascript_(zone()), + jsgraph_(isolate(), graph(), common(), &javascript_, &machine_), + analyzer_(locals_count, zone()), + empty_values_(graph()->NewNode(common()->StateValues(0), 0, nullptr)), + next_checkpoint_id_(0), + current_block_(nullptr) {} + + + protected: + JSGraph* jsgraph() { return &jsgraph_; } + + LivenessAnalyzer* analyzer() { return &analyzer_; } + void Run() { + StateValuesCache cache(jsgraph()); + NonLiveFrameStateSlotReplacer replacer(&cache, + jsgraph()->UndefinedConstant(), + analyzer()->local_count(), zone()); + analyzer()->Run(&replacer); + } + + Node* Checkpoint() { + int ast_num = next_checkpoint_id_++; + int first_const = intconst_from_bailout_id(ast_num, locals_count_); + + const Operator* locals_op = common()->StateValues(locals_count_); + + ZoneVector<Node*> local_inputs(locals_count_, nullptr, zone()); + for (int i = 0; i < locals_count_; i++) { + local_inputs[i] = jsgraph()->Int32Constant(i + first_const); + } + Node* locals = + graph()->NewNode(locals_op, locals_count_, &local_inputs.front()); + + const Operator* op = common()->FrameState( + JS_FRAME, BailoutId(ast_num), OutputFrameStateCombine::Ignore()); + Node* result = graph()->NewNode(op, empty_values_, locals, empty_values_, + jsgraph()->UndefinedConstant(), + jsgraph()->UndefinedConstant()); + + current_block_->Checkpoint(result); + return result; + } + + void Bind(int var) { current_block()->Bind(var); } + void Lookup(int var) { current_block()->Lookup(var); } + + class CheckpointMatcher : public MatcherInterface<Node*> { + public: + explicit CheckpointMatcher(const char* liveness, Node* empty_values, + int locals_count, Node* replacement) + : liveness_(liveness), + empty_values_(empty_values), + locals_count_(locals_count), + replacement_(replacement) {} + + void DescribeTo(std::ostream* os) const OVERRIDE { + *os << "is a frame state with '" << liveness_ + << "' liveness, empty " + "parameters and empty expression stack"; + } + + bool MatchAndExplain(Node* frame_state, + MatchResultListener* listener) const OVERRIDE { + if (frame_state == NULL) { + *listener << "which is NULL"; + return false; + } + DCHECK(frame_state->opcode() == IrOpcode::kFrameState); + + FrameStateCallInfo state_info = + OpParameter<FrameStateCallInfo>(frame_state); + int ast_num = state_info.bailout_id().ToInt(); + int first_const = intconst_from_bailout_id(ast_num, locals_count_); + + if (empty_values_ != frame_state->InputAt(0)) { + *listener << "whose parameters are " << frame_state->InputAt(0) + << " but should have been " << empty_values_ << " (empty)"; + return false; + } + if (empty_values_ != frame_state->InputAt(2)) { + *listener << "whose expression stack is " << frame_state->InputAt(2) + << " but should have been " << empty_values_ << " (empty)"; + return false; + } + StateValuesAccess locals(frame_state->InputAt(1)); + if (locals_count_ != static_cast<int>(locals.size())) { + *listener << "whose number of locals is " << locals.size() + << " but should have been " << locals_count_; + return false; + } + int i = 0; + for (StateValuesAccess::TypedNode value : locals) { + if (liveness_[i] == 'L') { + StringMatchResultListener value_listener; + if (value.node == replacement_) { + *listener << "whose local #" << i << " was " << value.node->opcode() + << " but should have been 'undefined'"; + return false; + } else if (!IsInt32Constant(first_const + i) + .MatchAndExplain(value.node, &value_listener)) { + *listener << "whose local #" << i << " does not match"; + if (value_listener.str() != "") { + *listener << ", " << value_listener.str(); + } + return false; + } + } else if (liveness_[i] == '.') { + if (value.node != replacement_) { + *listener << "whose local #" << i << " is " << value.node + << " but should have been " << replacement_ + << " (undefined)"; + return false; + } + } else { + UNREACHABLE(); + } + i++; + } + return true; + } + + private: + const char* liveness_; + Node* empty_values_; + int locals_count_; + Node* replacement_; + }; + + Matcher<Node*> IsCheckpointModuloLiveness(const char* liveness) { + return MakeMatcher(new CheckpointMatcher(liveness, empty_values_, + locals_count_, + jsgraph()->UndefinedConstant())); + } + + LivenessAnalyzerBlock* current_block() { return current_block_; } + void set_current_block(LivenessAnalyzerBlock* block) { + current_block_ = block; + } + + private: + static int intconst_from_bailout_id(int ast_num, int locals_count) { + return (locals_count + 1) * ast_num + 1; + } + + int locals_count_; + MachineOperatorBuilder machine_; + JSOperatorBuilder javascript_; + JSGraph jsgraph_; + LivenessAnalyzer analyzer_; + Node* empty_values_; + int next_checkpoint_id_; + LivenessAnalyzerBlock* current_block_; +}; + + +TEST_F(LivenessAnalysisTest, EmptyBlock) { + set_current_block(analyzer()->NewBlock()); + + Node* c1 = Checkpoint(); + + Run(); + + // Nothing is live. + EXPECT_THAT(c1, IsCheckpointModuloLiveness("....")); +} + + +TEST_F(LivenessAnalysisTest, SimpleLookup) { + set_current_block(analyzer()->NewBlock()); + + Node* c1 = Checkpoint(); + Lookup(1); + Node* c2 = Checkpoint(); + + Run(); + + EXPECT_THAT(c1, IsCheckpointModuloLiveness(".L..")); + EXPECT_THAT(c2, IsCheckpointModuloLiveness("....")); +} + + +TEST_F(LivenessAnalysisTest, DiamondLookups) { + // Start block. + LivenessAnalyzerBlock* start = analyzer()->NewBlock(); + set_current_block(start); + Node* c1_start = Checkpoint(); + + // First branch. + LivenessAnalyzerBlock* b1 = analyzer()->NewBlock(start); + set_current_block(b1); + + Node* c1_b1 = Checkpoint(); + Lookup(1); + Node* c2_b1 = Checkpoint(); + Lookup(3); + Node* c3_b1 = Checkpoint(); + + // Second branch. + LivenessAnalyzerBlock* b2 = analyzer()->NewBlock(start); + set_current_block(b2); + + Node* c1_b2 = Checkpoint(); + Lookup(3); + Node* c2_b2 = Checkpoint(); + Lookup(2); + Node* c3_b2 = Checkpoint(); + + // Merge block. + LivenessAnalyzerBlock* m = analyzer()->NewBlock(b1); + m->AddPredecessor(b2); + set_current_block(m); + Node* c1_m = Checkpoint(); + Lookup(0); + Node* c2_m = Checkpoint(); + + Run(); + + EXPECT_THAT(c1_start, IsCheckpointModuloLiveness("LLLL")); + + EXPECT_THAT(c1_b1, IsCheckpointModuloLiveness("LL.L")); + EXPECT_THAT(c2_b1, IsCheckpointModuloLiveness("L..L")); + EXPECT_THAT(c3_b1, IsCheckpointModuloLiveness("L...")); + + EXPECT_THAT(c1_b2, IsCheckpointModuloLiveness("L.LL")); + EXPECT_THAT(c2_b2, IsCheckpointModuloLiveness("L.L.")); + EXPECT_THAT(c3_b2, IsCheckpointModuloLiveness("L...")); + + EXPECT_THAT(c1_m, IsCheckpointModuloLiveness("L...")); + EXPECT_THAT(c2_m, IsCheckpointModuloLiveness("....")); +} + + +TEST_F(LivenessAnalysisTest, DiamondLookupsAndBinds) { + // Start block. + LivenessAnalyzerBlock* start = analyzer()->NewBlock(); + set_current_block(start); + Node* c1_start = Checkpoint(); + Bind(0); + Node* c2_start = Checkpoint(); + + // First branch. + LivenessAnalyzerBlock* b1 = analyzer()->NewBlock(start); + set_current_block(b1); + + Node* c1_b1 = Checkpoint(); + Bind(2); + Bind(1); + Node* c2_b1 = Checkpoint(); + Bind(3); + Node* c3_b1 = Checkpoint(); + + // Second branch. + LivenessAnalyzerBlock* b2 = analyzer()->NewBlock(start); + set_current_block(b2); + + Node* c1_b2 = Checkpoint(); + Lookup(2); + Node* c2_b2 = Checkpoint(); + Bind(2); + Bind(3); + Node* c3_b2 = Checkpoint(); + + // Merge block. + LivenessAnalyzerBlock* m = analyzer()->NewBlock(b1); + m->AddPredecessor(b2); + set_current_block(m); + Node* c1_m = Checkpoint(); + Lookup(0); + Lookup(1); + Lookup(2); + Lookup(3); + Node* c2_m = Checkpoint(); + + Run(); + + EXPECT_THAT(c1_start, IsCheckpointModuloLiveness(".LL.")); + EXPECT_THAT(c2_start, IsCheckpointModuloLiveness("LLL.")); + + EXPECT_THAT(c1_b1, IsCheckpointModuloLiveness("L...")); + EXPECT_THAT(c2_b1, IsCheckpointModuloLiveness("LLL.")); + EXPECT_THAT(c3_b1, IsCheckpointModuloLiveness("LLLL")); + + EXPECT_THAT(c1_b2, IsCheckpointModuloLiveness("LLL.")); + EXPECT_THAT(c2_b2, IsCheckpointModuloLiveness("LL..")); + EXPECT_THAT(c3_b2, IsCheckpointModuloLiveness("LLLL")); + + EXPECT_THAT(c1_m, IsCheckpointModuloLiveness("LLLL")); + EXPECT_THAT(c2_m, IsCheckpointModuloLiveness("....")); +} + + +TEST_F(LivenessAnalysisTest, SimpleLoop) { + // Start block. + LivenessAnalyzerBlock* start = analyzer()->NewBlock(); + set_current_block(start); + Node* c1_start = Checkpoint(); + Bind(0); + Bind(1); + Bind(2); + Bind(3); + Node* c2_start = Checkpoint(); + + // Loop header block. + LivenessAnalyzerBlock* header = analyzer()->NewBlock(start); + set_current_block(header); + Node* c1_header = Checkpoint(); + Lookup(0); + Bind(2); + Node* c2_header = Checkpoint(); + + // Inside-loop block. + LivenessAnalyzerBlock* in_loop = analyzer()->NewBlock(header); + set_current_block(in_loop); + Node* c1_in_loop = Checkpoint(); + Bind(0); + Lookup(3); + Node* c2_in_loop = Checkpoint(); + + // Add back edge. + header->AddPredecessor(in_loop); + + // After-loop block. + LivenessAnalyzerBlock* end = analyzer()->NewBlock(header); + set_current_block(end); + Node* c1_end = Checkpoint(); + Lookup(1); + Lookup(2); + Node* c2_end = Checkpoint(); + + Run(); + + EXPECT_THAT(c1_start, IsCheckpointModuloLiveness("....")); + EXPECT_THAT(c2_start, IsCheckpointModuloLiveness("LL.L")); + + EXPECT_THAT(c1_header, IsCheckpointModuloLiveness("LL.L")); + EXPECT_THAT(c2_header, IsCheckpointModuloLiveness(".LLL")); + + EXPECT_THAT(c1_in_loop, IsCheckpointModuloLiveness(".L.L")); + EXPECT_THAT(c2_in_loop, IsCheckpointModuloLiveness("LL.L")); + + EXPECT_THAT(c1_end, IsCheckpointModuloLiveness(".LL.")); + EXPECT_THAT(c2_end, IsCheckpointModuloLiveness("....")); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc index f63e70da5a..11c679cb29 100644 --- a/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/machine-operator-reducer-unittest.cc @@ -233,6 +233,27 @@ const uint32_t kUint32Values[] = { 0x000fffff, 0x0007ffff, 0x0003ffff, 0x0001ffff, 0x0000ffff, 0x00007fff, 0x00003fff, 0x00001fff, 0x00000fff, 0x000007ff, 0x000003ff, 0x000001ff}; + +struct ComparisonBinaryOperator { + const Operator* (MachineOperatorBuilder::*constructor)(); + const char* constructor_name; +}; + + +std::ostream& operator<<(std::ostream& os, + ComparisonBinaryOperator const& cbop) { + return os << cbop.constructor_name; +} + + +const ComparisonBinaryOperator kComparisonBinaryOperators[] = { +#define OPCODE(Opcode) \ + { &MachineOperatorBuilder::Opcode, #Opcode } \ + , + MACHINE_COMPARE_BINOP_LIST(OPCODE) +#undef OPCODE +}; + } // namespace @@ -595,6 +616,33 @@ TEST_F(MachineOperatorReducerTest, Word32AndWithInt32AddAndConstant) { } +TEST_F(MachineOperatorReducerTest, Word32AndWithInt32MulAndConstant) { + Node* const p0 = Parameter(0); + + TRACED_FORRANGE(int32_t, l, 1, 31) { + TRACED_FOREACH(int32_t, k, kInt32Values) { + if ((k << l) == 0) continue; + + // (x * (K << L)) & (-1 << L) => x * (K << L) + Reduction const r1 = Reduce(graph()->NewNode( + machine()->Word32And(), + graph()->NewNode(machine()->Int32Mul(), p0, Int32Constant(k << l)), + Int32Constant(-1 << l))); + ASSERT_TRUE(r1.Changed()); + EXPECT_THAT(r1.replacement(), IsInt32Mul(p0, IsInt32Constant(k << l))); + + // ((K << L) * x) & (-1 << L) => x * (K << L) + Reduction const r2 = Reduce(graph()->NewNode( + machine()->Word32And(), + graph()->NewNode(machine()->Int32Mul(), Int32Constant(k << l), p0), + Int32Constant(-1 << l))); + ASSERT_TRUE(r2.Changed()); + EXPECT_THAT(r2.replacement(), IsInt32Mul(p0, IsInt32Constant(k << l))); + } + } +} + + TEST_F(MachineOperatorReducerTest, Word32AndWithInt32AddAndInt32MulAndConstant) { Node* const p0 = Parameter(0); @@ -632,6 +680,27 @@ TEST_F(MachineOperatorReducerTest, } +TEST_F(MachineOperatorReducerTest, Word32AndWithComparisonAndConstantOne) { + Node* const p0 = Parameter(0); + Node* const p1 = Parameter(1); + TRACED_FOREACH(ComparisonBinaryOperator, cbop, kComparisonBinaryOperators) { + Node* cmp = graph()->NewNode((machine()->*cbop.constructor)(), p0, p1); + + // cmp & 1 => cmp + Reduction const r1 = + Reduce(graph()->NewNode(machine()->Word32And(), cmp, Int32Constant(1))); + ASSERT_TRUE(r1.Changed()); + EXPECT_EQ(cmp, r1.replacement()); + + // 1 & cmp => cmp + Reduction const r2 = + Reduce(graph()->NewNode(machine()->Word32And(), Int32Constant(1), cmp)); + ASSERT_TRUE(r2.Changed()); + EXPECT_EQ(cmp, r2.replacement()); + } +} + + // ----------------------------------------------------------------------------- // Word32Xor @@ -773,6 +842,24 @@ TEST_F(MachineOperatorReducerTest, Word32RorWithConstants) { // Word32Sar +TEST_F(MachineOperatorReducerTest, Word32SarWithWord32ShlAndComparison) { + Node* const p0 = Parameter(0); + Node* const p1 = Parameter(1); + + TRACED_FOREACH(ComparisonBinaryOperator, cbop, kComparisonBinaryOperators) { + Node* cmp = graph()->NewNode((machine()->*cbop.constructor)(), p0, p1); + + // cmp << 31 >> 31 => 0 - cmp + Reduction const r = Reduce(graph()->NewNode( + machine()->Word32Sar(), + graph()->NewNode(machine()->Word32Shl(), cmp, Int32Constant(31)), + Int32Constant(31))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0), cmp)); + } +} + + TEST_F(MachineOperatorReducerTest, Word32SarWithWord32ShlAndLoad) { Node* const p0 = Parameter(0); Node* const p1 = Parameter(1); @@ -1190,6 +1277,28 @@ TEST_F(MachineOperatorReducerTest, Uint32ModWithParameters) { // ----------------------------------------------------------------------------- +// Int32Add + + +TEST_F(MachineOperatorReducerTest, Int32AddWithInt32SubWithConstantZero) { + Node* const p0 = Parameter(0); + Node* const p1 = Parameter(1); + + Reduction const r1 = Reduce(graph()->NewNode( + machine()->Int32Add(), + graph()->NewNode(machine()->Int32Sub(), Int32Constant(0), p0), p1)); + ASSERT_TRUE(r1.Changed()); + EXPECT_THAT(r1.replacement(), IsInt32Sub(p1, p0)); + + Reduction const r2 = Reduce(graph()->NewNode( + machine()->Int32Add(), p0, + graph()->NewNode(machine()->Int32Sub(), Int32Constant(0), p1))); + ASSERT_TRUE(r2.Changed()); + EXPECT_THAT(r2.replacement(), IsInt32Sub(p0, p1)); +} + + +// ----------------------------------------------------------------------------- // Int32AddWithOverflow @@ -1327,6 +1436,46 @@ TEST_F(MachineOperatorReducerTest, Float64MulWithMinusOne) { // ----------------------------------------------------------------------------- +// Float64InsertLowWord32 + + +TEST_F(MachineOperatorReducerTest, Float64InsertLowWord32WithConstant) { + TRACED_FOREACH(double, x, kFloat64Values) { + TRACED_FOREACH(uint32_t, y, kUint32Values) { + Reduction const r = + Reduce(graph()->NewNode(machine()->Float64InsertLowWord32(), + Float64Constant(x), Uint32Constant(y))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsFloat64Constant(BitEq(bit_cast<double>( + (bit_cast<uint64_t>(x) & V8_UINT64_C(0xFFFFFFFF00000000)) | y)))); + } + } +} + + +// ----------------------------------------------------------------------------- +// Float64InsertHighWord32 + + +TEST_F(MachineOperatorReducerTest, Float64InsertHighWord32WithConstant) { + TRACED_FOREACH(double, x, kFloat64Values) { + TRACED_FOREACH(uint32_t, y, kUint32Values) { + Reduction const r = + Reduce(graph()->NewNode(machine()->Float64InsertHighWord32(), + Float64Constant(x), Uint32Constant(y))); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFloat64Constant(BitEq(bit_cast<double>( + (bit_cast<uint64_t>(x) & V8_UINT64_C(0xFFFFFFFF)) | + (static_cast<uint64_t>(y) << 32))))); + } + } +} + + +// ----------------------------------------------------------------------------- // Store diff --git a/deps/v8/test/unittests/compiler/machine-operator-unittest.cc b/deps/v8/test/unittests/compiler/machine-operator-unittest.cc index 6e0df2ab44..71b3c0edd9 100644 --- a/deps/v8/test/unittests/compiler/machine-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/machine-operator-unittest.cc @@ -180,24 +180,24 @@ const PureOperator kPureOperators[] = { PURE(Word32And, 2, 0, 1), PURE(Word32Or, 2, 0, 1), PURE(Word32Xor, 2, 0, 1), PURE(Word32Shl, 2, 0, 1), PURE(Word32Shr, 2, 0, 1), PURE(Word32Sar, 2, 0, 1), PURE(Word32Ror, 2, 0, 1), - PURE(Word32Equal, 2, 0, 1), PURE(Word64And, 2, 0, 1), - PURE(Word64Or, 2, 0, 1), PURE(Word64Xor, 2, 0, 1), PURE(Word64Shl, 2, 0, 1), - PURE(Word64Shr, 2, 0, 1), PURE(Word64Sar, 2, 0, 1), - PURE(Word64Ror, 2, 0, 1), PURE(Word64Equal, 2, 0, 1), - PURE(Int32Add, 2, 0, 1), PURE(Int32AddWithOverflow, 2, 0, 2), - PURE(Int32Sub, 2, 0, 1), PURE(Int32SubWithOverflow, 2, 0, 2), - PURE(Int32Mul, 2, 0, 1), PURE(Int32MulHigh, 2, 0, 1), - PURE(Int32Div, 2, 1, 1), PURE(Uint32Div, 2, 1, 1), PURE(Int32Mod, 2, 1, 1), - PURE(Uint32Mod, 2, 1, 1), PURE(Int32LessThan, 2, 0, 1), - PURE(Int32LessThanOrEqual, 2, 0, 1), PURE(Uint32LessThan, 2, 0, 1), - PURE(Uint32LessThanOrEqual, 2, 0, 1), PURE(Int64Add, 2, 0, 1), - PURE(Int64Sub, 2, 0, 1), PURE(Int64Mul, 2, 0, 1), PURE(Int64Div, 2, 0, 1), - PURE(Uint64Div, 2, 0, 1), PURE(Int64Mod, 2, 0, 1), PURE(Uint64Mod, 2, 0, 1), - PURE(Int64LessThan, 2, 0, 1), PURE(Int64LessThanOrEqual, 2, 0, 1), - PURE(Uint64LessThan, 2, 0, 1), PURE(ChangeFloat32ToFloat64, 1, 0, 1), - PURE(ChangeFloat64ToInt32, 1, 0, 1), PURE(ChangeFloat64ToUint32, 1, 0, 1), - PURE(ChangeInt32ToInt64, 1, 0, 1), PURE(ChangeUint32ToFloat64, 1, 0, 1), - PURE(ChangeUint32ToUint64, 1, 0, 1), + PURE(Word32Equal, 2, 0, 1), PURE(Word32Clz, 1, 0, 1), + PURE(Word64And, 2, 0, 1), PURE(Word64Or, 2, 0, 1), PURE(Word64Xor, 2, 0, 1), + PURE(Word64Shl, 2, 0, 1), PURE(Word64Shr, 2, 0, 1), + PURE(Word64Sar, 2, 0, 1), PURE(Word64Ror, 2, 0, 1), + PURE(Word64Equal, 2, 0, 1), PURE(Int32Add, 2, 0, 1), + PURE(Int32AddWithOverflow, 2, 0, 2), PURE(Int32Sub, 2, 0, 1), + PURE(Int32SubWithOverflow, 2, 0, 2), PURE(Int32Mul, 2, 0, 1), + PURE(Int32MulHigh, 2, 0, 1), PURE(Int32Div, 2, 1, 1), + PURE(Uint32Div, 2, 1, 1), PURE(Int32Mod, 2, 1, 1), PURE(Uint32Mod, 2, 1, 1), + PURE(Int32LessThan, 2, 0, 1), PURE(Int32LessThanOrEqual, 2, 0, 1), + PURE(Uint32LessThan, 2, 0, 1), PURE(Uint32LessThanOrEqual, 2, 0, 1), + PURE(Int64Add, 2, 0, 1), PURE(Int64Sub, 2, 0, 1), PURE(Int64Mul, 2, 0, 1), + PURE(Int64Div, 2, 0, 1), PURE(Uint64Div, 2, 0, 1), PURE(Int64Mod, 2, 0, 1), + PURE(Uint64Mod, 2, 0, 1), PURE(Int64LessThan, 2, 0, 1), + PURE(Int64LessThanOrEqual, 2, 0, 1), PURE(Uint64LessThan, 2, 0, 1), + PURE(ChangeFloat32ToFloat64, 1, 0, 1), PURE(ChangeFloat64ToInt32, 1, 0, 1), + PURE(ChangeFloat64ToUint32, 1, 0, 1), PURE(ChangeInt32ToInt64, 1, 0, 1), + PURE(ChangeUint32ToFloat64, 1, 0, 1), PURE(ChangeUint32ToUint64, 1, 0, 1), PURE(TruncateFloat64ToFloat32, 1, 0, 1), PURE(TruncateFloat64ToInt32, 1, 0, 1), PURE(TruncateInt64ToInt32, 1, 0, 1), PURE(Float64Add, 2, 0, 1), PURE(Float64Sub, 2, 0, 1), @@ -205,8 +205,12 @@ const PureOperator kPureOperators[] = { PURE(Float64Mod, 2, 0, 1), PURE(Float64Sqrt, 1, 0, 1), PURE(Float64Equal, 2, 0, 1), PURE(Float64LessThan, 2, 0, 1), PURE(Float64LessThanOrEqual, 2, 0, 1), PURE(LoadStackPointer, 0, 0, 1), - PURE(Float64Floor, 1, 0, 1), PURE(Float64Ceil, 1, 0, 1), - PURE(Float64RoundTruncate, 1, 0, 1), PURE(Float64RoundTiesAway, 1, 0, 1) + PURE(Float64RoundDown, 1, 0, 1), PURE(Float64RoundTruncate, 1, 0, 1), + PURE(Float64RoundTiesAway, 1, 0, 1), PURE(Float64ExtractLowWord32, 1, 0, 1), + PURE(Float64ExtractHighWord32, 1, 0, 1), + PURE(Float64InsertLowWord32, 2, 0, 1), + PURE(Float64InsertHighWord32, 2, 0, 1), PURE(Float64Max, 2, 0, 1), + PURE(Float64Min, 2, 0, 1) #undef PURE }; diff --git a/deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc b/deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc index efe26d22b4..bafa89d581 100644 --- a/deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc +++ b/deps/v8/test/unittests/compiler/mips/instruction-selector-mips-unittest.cc @@ -800,6 +800,21 @@ TEST_F(InstructionSelectorTest, Word32EqualWithZero) { } } + +TEST_F(InstructionSelectorTest, Word32Clz) { + StreamBuilder m(this, kMachUint32, kMachUint32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Word32Clz(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kMipsClz, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc b/deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc index 41453337f2..0953de8c40 100644 --- a/deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc +++ b/deps/v8/test/unittests/compiler/mips64/instruction-selector-mips64-unittest.cc @@ -166,29 +166,28 @@ const IntCmp kCmpInstructions[] = { {{&RawMachineAssembler::WordNotEqual, "WordNotEqual", kMips64Cmp, kMachInt64}, 1U}, - {{&RawMachineAssembler::Word32Equal, "Word32Equal", kMips64Cmp32, - kMachInt32}, + {{&RawMachineAssembler::Word32Equal, "Word32Equal", kMips64Cmp, kMachInt32}, 1U}, - {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kMips64Cmp32, + {{&RawMachineAssembler::Word32NotEqual, "Word32NotEqual", kMips64Cmp, kMachInt32}, 1U}, - {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kMips64Cmp32, + {{&RawMachineAssembler::Int32LessThan, "Int32LessThan", kMips64Cmp, kMachInt32}, 1U}, {{&RawMachineAssembler::Int32LessThanOrEqual, "Int32LessThanOrEqual", - kMips64Cmp32, kMachInt32}, + kMips64Cmp, kMachInt32}, 1U}, - {{&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kMips64Cmp32, + {{&RawMachineAssembler::Int32GreaterThan, "Int32GreaterThan", kMips64Cmp, kMachInt32}, 1U}, {{&RawMachineAssembler::Int32GreaterThanOrEqual, "Int32GreaterThanOrEqual", - kMips64Cmp32, kMachInt32}, + kMips64Cmp, kMachInt32}, 1U}, - {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kMips64Cmp32, + {{&RawMachineAssembler::Uint32LessThan, "Uint32LessThan", kMips64Cmp, kMachUint32}, 1U}, {{&RawMachineAssembler::Uint32LessThanOrEqual, "Uint32LessThanOrEqual", - kMips64Cmp32, kMachUint32}, + kMips64Cmp, kMachUint32}, 1U}}; @@ -753,7 +752,7 @@ TEST_F(InstructionSelectorTest, Word32EqualWithZero) { m.Return(m.Word32Equal(m.Parameter(0), m.Int32Constant(0))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kMips64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode()); EXPECT_EQ(kMode_None, s[0]->addressing_mode()); ASSERT_EQ(2U, s[0]->InputCount()); EXPECT_EQ(1U, s[0]->OutputCount()); @@ -765,7 +764,7 @@ TEST_F(InstructionSelectorTest, Word32EqualWithZero) { m.Return(m.Word32Equal(m.Int32Constant(0), m.Parameter(0))); Stream s = m.Build(); ASSERT_EQ(1U, s.size()); - EXPECT_EQ(kMips64Cmp32, s[0]->arch_opcode()); + EXPECT_EQ(kMips64Cmp, s[0]->arch_opcode()); EXPECT_EQ(kMode_None, s[0]->addressing_mode()); ASSERT_EQ(2U, s[0]->InputCount()); EXPECT_EQ(1U, s[0]->OutputCount()); @@ -802,6 +801,21 @@ TEST_F(InstructionSelectorTest, Word64EqualWithZero) { } } + +TEST_F(InstructionSelectorTest, Word32Clz) { + StreamBuilder m(this, kMachUint32, kMachUint32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Word32Clz(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kMips64Clz, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/move-optimizer-unittest.cc b/deps/v8/test/unittests/compiler/move-optimizer-unittest.cc index b8375fab10..da887fe88a 100644 --- a/deps/v8/test/unittests/compiler/move-optimizer-unittest.cc +++ b/deps/v8/test/unittests/compiler/move-optimizer-unittest.cc @@ -124,6 +124,59 @@ TEST_F(MoveOptimizerTest, SplitsConstants) { CHECK(Contains(move, Reg(0), Slot(2))); } + +TEST_F(MoveOptimizerTest, SimpleMerge) { + StartBlock(); + EndBlock(Branch(Imm(), 1, 2)); + + StartBlock(); + EndBlock(Jump(2)); + AddMove(LastGap(), Reg(0), Reg(1)); + + StartBlock(); + EndBlock(Jump(1)); + AddMove(LastGap(), Reg(0), Reg(1)); + + StartBlock(); + EndBlock(Last()); + + Optimize(); + + auto move = LastGap()->parallel_moves()[0]; + CHECK_EQ(1, NonRedundantSize(move)); + CHECK(Contains(move, Reg(0), Reg(1))); +} + + +TEST_F(MoveOptimizerTest, SimpleMergeCycle) { + StartBlock(); + EndBlock(Branch(Imm(), 1, 2)); + + StartBlock(); + EndBlock(Jump(2)); + auto gap_0 = LastGap(); + AddMove(gap_0, Reg(0), Reg(1)); + AddMove(LastGap(), Reg(1), Reg(0)); + + StartBlock(); + EndBlock(Jump(1)); + auto gap_1 = LastGap(); + AddMove(gap_1, Reg(0), Reg(1)); + AddMove(gap_1, Reg(1), Reg(0)); + + StartBlock(); + EndBlock(Last()); + + Optimize(); + + CHECK(gap_0->IsRedundant()); + CHECK(gap_1->IsRedundant()); + auto move = LastGap()->parallel_moves()[0]; + CHECK_EQ(2, NonRedundantSize(move)); + CHECK(Contains(move, Reg(0), Reg(1))); + CHECK(Contains(move, Reg(1), Reg(0))); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/node-properties-unittest.cc b/deps/v8/test/unittests/compiler/node-properties-unittest.cc index bb471bd01e..2bec4faf4d 100644 --- a/deps/v8/test/unittests/compiler/node-properties-unittest.cc +++ b/deps/v8/test/unittests/compiler/node-properties-unittest.cc @@ -8,7 +8,9 @@ #include "testing/gmock/include/gmock/gmock.h" using testing::AnyOf; +using testing::ElementsAre; using testing::IsNull; +using testing::UnorderedElementsAre; namespace v8 { namespace internal { @@ -17,6 +19,64 @@ namespace compiler { typedef TestWithZone NodePropertiesTest; +namespace { + +const Operator kMockOperator(IrOpcode::kDead, Operator::kNoProperties, + "MockOperator", 0, 0, 0, 1, 0, 0); +const Operator kMockOpEffect(IrOpcode::kDead, Operator::kNoProperties, + "MockOpEffect", 0, 1, 0, 1, 1, 0); +const Operator kMockOpControl(IrOpcode::kDead, Operator::kNoProperties, + "MockOpControl", 0, 0, 1, 1, 0, 1); +const Operator kMockCallOperator(IrOpcode::kCall, Operator::kNoProperties, + "MockCallOperator", 0, 0, 0, 0, 0, 2); + +} // namespace + + +TEST_F(NodePropertiesTest, ReplaceWithValue_ValueUse) { + CommonOperatorBuilder common(zone()); + Node* node = Node::New(zone(), 0, &kMockOperator, 0, nullptr, false); + Node* use_value = Node::New(zone(), 0, common.Return(), 1, &node, false); + Node* replacement = Node::New(zone(), 0, &kMockOperator, 0, nullptr, false); + NodeProperties::ReplaceWithValue(node, replacement); + EXPECT_EQ(replacement, use_value->InputAt(0)); + EXPECT_EQ(0, node->UseCount()); + EXPECT_EQ(1, replacement->UseCount()); + EXPECT_THAT(replacement->uses(), ElementsAre(use_value)); +} + + +TEST_F(NodePropertiesTest, ReplaceWithValue_EffectUse) { + CommonOperatorBuilder common(zone()); + Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false); + Node* node = Node::New(zone(), 0, &kMockOpEffect, 1, &start, false); + Node* use_effect = Node::New(zone(), 0, common.EffectPhi(1), 1, &node, false); + Node* replacement = Node::New(zone(), 0, &kMockOperator, 0, nullptr, false); + NodeProperties::ReplaceWithValue(node, replacement); + EXPECT_EQ(start, use_effect->InputAt(0)); + EXPECT_EQ(0, node->UseCount()); + EXPECT_EQ(2, start->UseCount()); + EXPECT_EQ(0, replacement->UseCount()); + EXPECT_THAT(start->uses(), UnorderedElementsAre(use_effect, node)); +} + + +TEST_F(NodePropertiesTest, ReplaceWithValue_ControlUse) { + CommonOperatorBuilder common(zone()); + Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false); + Node* node = Node::New(zone(), 0, &kMockOpControl, 1, &start, false); + Node* success = Node::New(zone(), 0, common.IfSuccess(), 1, &node, false); + Node* use_control = Node::New(zone(), 0, common.Merge(1), 1, &success, false); + Node* replacement = Node::New(zone(), 0, &kMockOperator, 0, nullptr, false); + NodeProperties::ReplaceWithValue(node, replacement); + EXPECT_EQ(start, use_control->InputAt(0)); + EXPECT_EQ(0, node->UseCount()); + EXPECT_EQ(2, start->UseCount()); + EXPECT_EQ(0, replacement->UseCount()); + EXPECT_THAT(start->uses(), UnorderedElementsAre(use_control, node)); +} + + TEST_F(NodePropertiesTest, FindProjection) { CommonOperatorBuilder common(zone()); Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false); @@ -41,6 +101,18 @@ TEST_F(NodePropertiesTest, CollectControlProjections_Branch) { } +TEST_F(NodePropertiesTest, CollectControlProjections_Call) { + Node* result[2]; + CommonOperatorBuilder common(zone()); + Node* call = Node::New(zone(), 1, &kMockCallOperator, 0, nullptr, false); + Node* if_ex = Node::New(zone(), 2, common.IfException(), 1, &call, false); + Node* if_ok = Node::New(zone(), 3, common.IfSuccess(), 1, &call, false); + NodeProperties::CollectControlProjections(call, result, arraysize(result)); + EXPECT_EQ(if_ok, result[0]); + EXPECT_EQ(if_ex, result[1]); +} + + TEST_F(NodePropertiesTest, CollectControlProjections_Switch) { Node* result[3]; CommonOperatorBuilder common(zone()); diff --git a/deps/v8/test/unittests/compiler/node-test-utils.cc b/deps/v8/test/unittests/compiler/node-test-utils.cc index eccc96227e..5890b49b02 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.cc +++ b/deps/v8/test/unittests/compiler/node-test-utils.cc @@ -543,11 +543,23 @@ class IsEffectSetMatcher FINAL : public NodeMatcher { } bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL { - return (NodeMatcher::MatchAndExplain(node, listener) && - PrintMatchAndExplain(NodeProperties::GetEffectInput(node, 0), - "effect0", effect0_matcher_, listener) && - PrintMatchAndExplain(NodeProperties::GetEffectInput(node, 1), - "effect1", effect1_matcher_, listener)); + if (!NodeMatcher::MatchAndExplain(node, listener)) return false; + + Node* effect0 = NodeProperties::GetEffectInput(node, 0); + Node* effect1 = NodeProperties::GetEffectInput(node, 1); + + { + // Try matching in the reverse order first. + StringMatchResultListener value_listener; + if (effect0_matcher_.MatchAndExplain(effect1, &value_listener) && + effect1_matcher_.MatchAndExplain(effect0, &value_listener)) { + return true; + } + } + + return PrintMatchAndExplain(effect0, "effect0", effect0_matcher_, + listener) && + PrintMatchAndExplain(effect1, "effect1", effect1_matcher_, listener); } private: @@ -1303,6 +1315,12 @@ Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher) { } +Matcher<Node*> IsIfSuccess(const Matcher<Node*>& control_matcher) { + return MakeMatcher( + new IsControl1Matcher(IrOpcode::kIfSuccess, control_matcher)); +} + + Matcher<Node*> IsSwitch(const Matcher<Node*>& value_matcher, const Matcher<Node*>& control_matcher) { return MakeMatcher(new IsSwitchMatcher(value_matcher, control_matcher)); @@ -1584,7 +1602,11 @@ IS_BINOP_MATCHER(Int32MulHigh) IS_BINOP_MATCHER(Int32LessThan) IS_BINOP_MATCHER(Uint32LessThan) IS_BINOP_MATCHER(Uint32LessThanOrEqual) +IS_BINOP_MATCHER(Float64Max) +IS_BINOP_MATCHER(Float64Min) IS_BINOP_MATCHER(Float64Sub) +IS_BINOP_MATCHER(Float64InsertLowWord32) +IS_BINOP_MATCHER(Float64InsertHighWord32) #undef IS_BINOP_MATCHER @@ -1592,7 +1614,6 @@ IS_BINOP_MATCHER(Float64Sub) Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) { \ return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \ } -IS_UNOP_MATCHER(AnyToBoolean) IS_UNOP_MATCHER(BooleanNot) IS_UNOP_MATCHER(ChangeFloat64ToInt32) IS_UNOP_MATCHER(ChangeFloat64ToUint32) @@ -1604,14 +1625,16 @@ IS_UNOP_MATCHER(TruncateFloat64ToFloat32) IS_UNOP_MATCHER(TruncateFloat64ToInt32) IS_UNOP_MATCHER(TruncateInt64ToInt32) IS_UNOP_MATCHER(Float64Sqrt) -IS_UNOP_MATCHER(Float64Floor) -IS_UNOP_MATCHER(Float64Ceil) +IS_UNOP_MATCHER(Float64RoundDown) IS_UNOP_MATCHER(Float64RoundTruncate) IS_UNOP_MATCHER(Float64RoundTiesAway) +IS_UNOP_MATCHER(Float64ExtractLowWord32) +IS_UNOP_MATCHER(Float64ExtractHighWord32) IS_UNOP_MATCHER(NumberToInt32) IS_UNOP_MATCHER(NumberToUint32) IS_UNOP_MATCHER(ObjectIsSmi) IS_UNOP_MATCHER(ObjectIsNonNegativeSmi) +IS_UNOP_MATCHER(Word32Clz) #undef IS_UNOP_MATCHER } // namespace compiler diff --git a/deps/v8/test/unittests/compiler/node-test-utils.h b/deps/v8/test/unittests/compiler/node-test-utils.h index 03011972b7..7c306a2c9d 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.h +++ b/deps/v8/test/unittests/compiler/node-test-utils.h @@ -47,6 +47,7 @@ Matcher<Node*> IsLoop(const Matcher<Node*>& control0_matcher, const Matcher<Node*>& control2_matcher); Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher); Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher); +Matcher<Node*> IsIfSuccess(const Matcher<Node*>& control_matcher); Matcher<Node*> IsSwitch(const Matcher<Node*>& value_matcher, const Matcher<Node*>& control_matcher); Matcher<Node*> IsIfValue(const Matcher<int32_t>& value_matcher, @@ -100,7 +101,6 @@ Matcher<Node*> IsCall(const Matcher<CallDescriptor*>& descriptor_matcher, const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher); -Matcher<Node*> IsAnyToBoolean(const Matcher<Node*>& value_matcher); Matcher<Node*> IsBooleanNot(const Matcher<Node*>& value_matcher); Matcher<Node*> IsNumberEqual(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); @@ -169,6 +169,7 @@ Matcher<Node*> IsWord32Ror(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsWord32Equal(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); +Matcher<Node*> IsWord32Clz(const Matcher<Node*>& value_matcher); Matcher<Node*> IsWord64And(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsWord64Shl(const Matcher<Node*>& lhs_matcher, @@ -202,13 +203,22 @@ Matcher<Node*> IsChangeUint32ToUint64(const Matcher<Node*>& input_matcher); Matcher<Node*> IsTruncateFloat64ToFloat32(const Matcher<Node*>& input_matcher); Matcher<Node*> IsTruncateFloat64ToInt32(const Matcher<Node*>& input_matcher); Matcher<Node*> IsTruncateInt64ToInt32(const Matcher<Node*>& input_matcher); +Matcher<Node*> IsFloat64Max(const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher); +Matcher<Node*> IsFloat64Min(const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsFloat64Sub(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsFloat64Sqrt(const Matcher<Node*>& input_matcher); -Matcher<Node*> IsFloat64Floor(const Matcher<Node*>& input_matcher); -Matcher<Node*> IsFloat64Ceil(const Matcher<Node*>& input_matcher); +Matcher<Node*> IsFloat64RoundDown(const Matcher<Node*>& input_matcher); Matcher<Node*> IsFloat64RoundTruncate(const Matcher<Node*>& input_matcher); Matcher<Node*> IsFloat64RoundTiesAway(const Matcher<Node*>& input_matcher); +Matcher<Node*> IsFloat64ExtractLowWord32(const Matcher<Node*>& input_matcher); +Matcher<Node*> IsFloat64ExtractHighWord32(const Matcher<Node*>& input_matcher); +Matcher<Node*> IsFloat64InsertLowWord32(const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher); +Matcher<Node*> IsFloat64InsertHighWord32(const Matcher<Node*>& lhs_matcher, + const Matcher<Node*>& rhs_matcher); Matcher<Node*> IsToNumber(const Matcher<Node*>& base_matcher, const Matcher<Node*>& context_matcher, const Matcher<Node*>& effect_matcher, diff --git a/deps/v8/test/unittests/compiler/node-unittest.cc b/deps/v8/test/unittests/compiler/node-unittest.cc index f56d7d6f8c..1a6c1bdf37 100644 --- a/deps/v8/test/unittests/compiler/node-unittest.cc +++ b/deps/v8/test/unittests/compiler/node-unittest.cc @@ -48,15 +48,15 @@ TEST_F(NodeTest, NewWithInputs) { EXPECT_EQ(0, n0->InputCount()); Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false); EXPECT_EQ(1, n0->UseCount()); - EXPECT_EQ(n1, n0->UseAt(0)); + EXPECT_THAT(n0->uses(), UnorderedElementsAre(n1)); EXPECT_EQ(0, n1->UseCount()); EXPECT_EQ(1, n1->InputCount()); EXPECT_EQ(n0, n1->InputAt(0)); Node* n0_n1[] = {n0, n1}; Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false); EXPECT_EQ(2, n0->UseCount()); - EXPECT_EQ(n1, n0->UseAt(0)); - EXPECT_EQ(n2, n0->UseAt(1)); + EXPECT_THAT(n0->uses(), UnorderedElementsAre(n1, n2)); + EXPECT_THAT(n1->uses(), UnorderedElementsAre(n2)); EXPECT_EQ(2, n2->InputCount()); EXPECT_EQ(n0, n2->InputAt(0)); EXPECT_EQ(n1, n2->InputAt(1)); diff --git a/deps/v8/test/unittests/compiler/opcodes-unittest.cc b/deps/v8/test/unittests/compiler/opcodes-unittest.cc index ca79e8ac8b..3bb65c2e13 100644 --- a/deps/v8/test/unittests/compiler/opcodes-unittest.cc +++ b/deps/v8/test/unittests/compiler/opcodes-unittest.cc @@ -64,6 +64,21 @@ bool IsConstantOpcode(IrOpcode::Value opcode) { } +bool IsComparisonOpcode(IrOpcode::Value opcode) { + switch (opcode) { +#define OPCODE(Opcode) \ + case IrOpcode::k##Opcode: \ + return true; + JS_COMPARE_BINOP_LIST(OPCODE) + SIMPLIFIED_COMPARE_BINOP_LIST(OPCODE) + MACHINE_COMPARE_BINOP_LIST(OPCODE) +#undef OPCODE + default: + return false; + } +} + + const IrOpcode::Value kInvalidOpcode = static_cast<IrOpcode::Value>(123456789); } // namespace @@ -109,6 +124,16 @@ TEST(IrOpcodeTest, IsConstantOpcode) { } +TEST(IrOpcodeTest, IsComparisonOpcode) { + EXPECT_FALSE(IrOpcode::IsComparisonOpcode(kInvalidOpcode)); +#define OPCODE(Opcode) \ + EXPECT_EQ(IsComparisonOpcode(IrOpcode::k##Opcode), \ + IrOpcode::IsComparisonOpcode(IrOpcode::k##Opcode)); + ALL_OP_LIST(OPCODE) +#undef OPCODE +} + + TEST(IrOpcodeTest, Mnemonic) { EXPECT_STREQ("UnknownOpcode", IrOpcode::Mnemonic(kInvalidOpcode)); #define OPCODE(Opcode) \ diff --git a/deps/v8/test/unittests/compiler/ppc/OWNERS b/deps/v8/test/unittests/compiler/ppc/OWNERS new file mode 100644 index 0000000000..beecb3d0b1 --- /dev/null +++ b/deps/v8/test/unittests/compiler/ppc/OWNERS @@ -0,0 +1,3 @@ +joransiu@ca.ibm.com +mbrandy@us.ibm.com +michael_dawson@ca.ibm.com diff --git a/deps/v8/test/unittests/compiler/register-allocator-unittest.cc b/deps/v8/test/unittests/compiler/register-allocator-unittest.cc index c82cc3733e..873b4ecd2a 100644 --- a/deps/v8/test/unittests/compiler/register-allocator-unittest.cc +++ b/deps/v8/test/unittests/compiler/register-allocator-unittest.cc @@ -301,6 +301,31 @@ TEST_F(RegisterAllocatorTest, SplitBeforeInstruction) { } +TEST_F(RegisterAllocatorTest, SplitBeforeInstruction2) { + const int kNumRegs = 6; + SetNumRegs(kNumRegs, kNumRegs); + + StartBlock(); + + // Stack parameters/spilled values. + auto p_0 = Define(Slot(-1)); + auto p_1 = Define(Slot(-2)); + + // Fill registers. + VReg values[kNumRegs]; + for (size_t i = 0; i < arraysize(values); ++i) { + values[i] = Define(Reg(static_cast<int>(i))); + } + + // values[0] and [1] will be split in the second half of this instruction. + EmitOOI(Reg(0), Reg(1), Reg(p_0, 0), Reg(p_1, 1)); + EmitI(Reg(values[0]), Reg(values[1])); + EndBlock(Last()); + + Allocate(); +} + + TEST_F(RegisterAllocatorTest, NestedDiamondPhiMerge) { // Outer diamond. StartBlock(); @@ -466,6 +491,87 @@ TEST_F(RegisterAllocatorTest, RegressionLoadConstantBeforeSpill) { Allocate(); } + +namespace { + +enum class ParameterType { kFixedSlot, kSlot, kRegister, kFixedRegister }; + +const ParameterType kParameterTypes[] = { + ParameterType::kFixedSlot, ParameterType::kSlot, ParameterType::kRegister, + ParameterType::kFixedRegister}; + +class SlotConstraintTest : public RegisterAllocatorTest, + public ::testing::WithParamInterface< + ::testing::tuple<ParameterType, int>> { + public: + static const int kMaxVariant = 5; + + protected: + ParameterType parameter_type() const { + return ::testing::get<0>(B::GetParam()); + } + int variant() const { return ::testing::get<1>(B::GetParam()); } + + private: + typedef ::testing::WithParamInterface<::testing::tuple<ParameterType, int>> B; +}; +} + + +#if GTEST_HAS_COMBINE + +TEST_P(SlotConstraintTest, SlotConstraint) { + StartBlock(); + VReg p_0; + switch (parameter_type()) { + case ParameterType::kFixedSlot: + p_0 = Parameter(Slot(-1)); + break; + case ParameterType::kSlot: + p_0 = Parameter(Slot(-1)); + break; + case ParameterType::kRegister: + p_0 = Parameter(Reg()); + break; + case ParameterType::kFixedRegister: + p_0 = Parameter(Reg(1)); + break; + } + switch (variant()) { + case 0: + EmitI(Slot(p_0), Reg(p_0)); + break; + case 1: + EmitI(Slot(p_0)); + break; + case 2: + EmitI(Reg(p_0)); + EmitI(Slot(p_0)); + break; + case 3: + EmitI(Slot(p_0)); + EmitI(Reg(p_0)); + break; + case 4: + EmitI(Slot(p_0, -1), Slot(p_0), Reg(p_0), Reg(p_0, 1)); + break; + default: + UNREACHABLE(); + break; + } + EndBlock(Last()); + + Allocate(); +} + + +INSTANTIATE_TEST_CASE_P( + RegisterAllocatorTest, SlotConstraintTest, + ::testing::Combine(::testing::ValuesIn(kParameterTypes), + ::testing::Range(0, SlotConstraintTest::kMaxVariant))); + +#endif // GTEST_HAS_COMBINE + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/schedule-unittest.cc b/deps/v8/test/unittests/compiler/schedule-unittest.cc index 70fd4d50ad..bc825353c4 100644 --- a/deps/v8/test/unittests/compiler/schedule-unittest.cc +++ b/deps/v8/test/unittests/compiler/schedule-unittest.cc @@ -73,8 +73,10 @@ typedef TestWithZone ScheduleTest; namespace { +const Operator kCallOperator(IrOpcode::kCall, Operator::kNoProperties, + "MockCall", 0, 0, 0, 0, 0, 0); const Operator kBranchOperator(IrOpcode::kBranch, Operator::kNoProperties, - "Branch", 0, 0, 0, 0, 0, 0); + "MockBranch", 0, 0, 0, 0, 0, 0); const Operator kDummyOperator(IrOpcode::kParameter, Operator::kNoProperties, "Dummy", 0, 0, 0, 0, 0, 0); @@ -135,6 +137,35 @@ TEST_F(ScheduleTest, AddGoto) { } +TEST_F(ScheduleTest, AddCall) { + Schedule schedule(zone()); + BasicBlock* start = schedule.start(); + + Node* call = Node::New(zone(), 0, &kCallOperator, 0, nullptr, false); + BasicBlock* sblock = schedule.NewBasicBlock(); + BasicBlock* eblock = schedule.NewBasicBlock(); + schedule.AddCall(start, call, sblock, eblock); + + EXPECT_EQ(start, schedule.block(call)); + + EXPECT_EQ(0u, start->PredecessorCount()); + EXPECT_EQ(2u, start->SuccessorCount()); + EXPECT_EQ(sblock, start->SuccessorAt(0)); + EXPECT_EQ(eblock, start->SuccessorAt(1)); + EXPECT_THAT(start->successors(), ElementsAre(sblock, eblock)); + + EXPECT_EQ(1u, sblock->PredecessorCount()); + EXPECT_EQ(0u, sblock->SuccessorCount()); + EXPECT_EQ(start, sblock->PredecessorAt(0)); + EXPECT_THAT(sblock->predecessors(), ElementsAre(start)); + + EXPECT_EQ(1u, eblock->PredecessorCount()); + EXPECT_EQ(0u, eblock->SuccessorCount()); + EXPECT_EQ(start, eblock->PredecessorAt(0)); + EXPECT_THAT(eblock->predecessors(), ElementsAre(start)); +} + + TEST_F(ScheduleTest, AddBranch) { Schedule schedule(zone()); BasicBlock* start = schedule.start(); diff --git a/deps/v8/test/unittests/compiler/scheduler-unittest.cc b/deps/v8/test/unittests/compiler/scheduler-unittest.cc index 860d5cd325..eeb5bbc4d6 100644 --- a/deps/v8/test/unittests/compiler/scheduler-unittest.cc +++ b/deps/v8/test/unittests/compiler/scheduler-unittest.cc @@ -16,6 +16,9 @@ #include "src/compiler/verifier.h" #include "test/unittests/compiler/compiler-test-utils.h" #include "test/unittests/test-utils.h" +#include "testing/gmock/include/gmock/gmock.h" + +using testing::AnyOf; namespace v8 { namespace internal { @@ -26,31 +29,31 @@ class SchedulerTest : public TestWithZone { SchedulerTest() : graph_(zone()), common_(zone()), simplified_(zone()), js_(zone()) {} - static Schedule* ComputeAndVerifySchedule(int expected, Graph* graph) { + Schedule* ComputeAndVerifySchedule(size_t expected) { if (FLAG_trace_turbo) { OFStream os(stdout); - os << AsDOT(*graph); + os << AsDOT(*graph()); } - Schedule* schedule = Scheduler::ComputeSchedule(graph->zone(), graph, - Scheduler::kSplitNodes); + Schedule* schedule = + Scheduler::ComputeSchedule(zone(), graph(), Scheduler::kSplitNodes); if (FLAG_trace_turbo_scheduler) { OFStream os(stdout); os << *schedule << std::endl; } ScheduleVerifier::Run(schedule); - CHECK_EQ(expected, GetScheduledNodeCount(schedule)); + EXPECT_EQ(expected, GetScheduledNodeCount(schedule)); return schedule; } - static int GetScheduledNodeCount(const Schedule* schedule) { + size_t GetScheduledNodeCount(const Schedule* schedule) { size_t node_count = 0; for (auto block : *schedule->rpo_order()) { node_count += block->NodeCount(); if (block->control() != BasicBlock::kNone) ++node_count; } - return static_cast<int>(node_count); + return node_count; } Graph* graph() { return &graph_; } @@ -71,8 +74,8 @@ class SchedulerRPOTest : public SchedulerTest { SchedulerRPOTest() {} // TODO(titzer): pull RPO tests out to their own file. - static void CheckRPONumbers(BasicBlockVector* order, size_t expected, - bool loops_allowed) { + void CheckRPONumbers(BasicBlockVector* order, size_t expected, + bool loops_allowed) { CHECK(expected == order->size()); for (int i = 0; i < static_cast<int>(order->size()); i++) { CHECK(order->at(i)->rpo_number() == i); @@ -83,8 +86,7 @@ class SchedulerRPOTest : public SchedulerTest { } } - static void CheckLoop(BasicBlockVector* order, BasicBlock** blocks, - int body_size) { + void CheckLoop(BasicBlockVector* order, BasicBlock** blocks, int body_size) { BasicBlock* header = blocks[0]; BasicBlock* end = header->loop_end(); CHECK(end); @@ -110,11 +112,9 @@ class SchedulerRPOTest : public SchedulerTest { BasicBlock* header() { return nodes[0]; } BasicBlock* last() { return nodes[count - 1]; } ~TestLoop() { delete[] nodes; } - - void Check(BasicBlockVector* order) { CheckLoop(order, nodes, count); } }; - static TestLoop* CreateLoop(Schedule* schedule, int count) { + TestLoop* CreateLoop(Schedule* schedule, int count) { TestLoop* loop = new TestLoop(); loop->count = count; loop->nodes = new BasicBlock* [count]; @@ -130,75 +130,27 @@ class SchedulerRPOTest : public SchedulerTest { }; -class SchedulerTestWithIsolate : public SchedulerTest, public TestWithIsolate { - public: - SchedulerTestWithIsolate() {} - - Unique<HeapObject> GetUniqueUndefined() { - Handle<HeapObject> object = - Handle<HeapObject>(isolate()->heap()->undefined_value(), isolate()); - return Unique<HeapObject>::CreateUninitialized(object); - } -}; - namespace { +const Operator kHeapConstant(IrOpcode::kHeapConstant, Operator::kPure, + "HeapConstant", 0, 0, 0, 1, 0, 0); const Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0, 0, 1, 0, 0); +const Operator kMockCall(IrOpcode::kCall, Operator::kNoProperties, "MockCall", + 0, 0, 1, 1, 0, 2); } // namespace -TEST_F(SchedulerTest, BuildScheduleEmpty) { - graph()->SetStart(graph()->NewNode(common()->Start(0))); - graph()->SetEnd(graph()->NewNode(common()->End(), graph()->start())); - USE(Scheduler::ComputeSchedule(zone(), graph(), Scheduler::kNoFlags)); -} - - -TEST_F(SchedulerTest, BuildScheduleOneParameter) { - graph()->SetStart(graph()->NewNode(common()->Start(0))); - - Node* p1 = graph()->NewNode(common()->Parameter(0), graph()->start()); - Node* ret = graph()->NewNode(common()->Return(), p1, graph()->start(), - graph()->start()); - - graph()->SetEnd(graph()->NewNode(common()->End(), ret)); - - USE(Scheduler::ComputeSchedule(zone(), graph(), Scheduler::kNoFlags)); -} - - -TEST_F(SchedulerTest, BuildScheduleIfSplit) { - graph()->SetStart(graph()->NewNode(common()->Start(3))); - - Node* p1 = graph()->NewNode(common()->Parameter(0), graph()->start()); - Node* p2 = graph()->NewNode(common()->Parameter(1), graph()->start()); - Node* p3 = graph()->NewNode(common()->Parameter(2), graph()->start()); - Node* p4 = graph()->NewNode(common()->Parameter(3), graph()->start()); - Node* p5 = graph()->NewNode(common()->Parameter(4), graph()->start()); - Node* cmp = graph()->NewNode(js()->LessThanOrEqual(), p1, p2, p3, - graph()->start(), graph()->start()); - Node* branch = graph()->NewNode(common()->Branch(), cmp, graph()->start()); - Node* true_branch = graph()->NewNode(common()->IfTrue(), branch); - Node* false_branch = graph()->NewNode(common()->IfFalse(), branch); - - Node* ret1 = - graph()->NewNode(common()->Return(), p4, graph()->start(), true_branch); - Node* ret2 = - graph()->NewNode(common()->Return(), p5, graph()->start(), false_branch); - Node* merge = graph()->NewNode(common()->Merge(2), ret1, ret2); - graph()->SetEnd(graph()->NewNode(common()->End(), merge)); - - ComputeAndVerifySchedule(13, graph()); -} +// ----------------------------------------------------------------------------- +// Special reverse-post-order block ordering. TEST_F(SchedulerRPOTest, Degenerate1) { Schedule schedule(zone()); BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); CheckRPONumbers(order, 1, false); - CHECK_EQ(schedule.start(), order->at(0)); + EXPECT_EQ(schedule.start(), order->at(0)); } @@ -208,8 +160,8 @@ TEST_F(SchedulerRPOTest, Degenerate2) { schedule.AddGoto(schedule.start(), schedule.end()); BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); CheckRPONumbers(order, 2, false); - CHECK_EQ(schedule.start(), order->at(0)); - CHECK_EQ(schedule.end(), order->at(1)); + EXPECT_EQ(schedule.start(), order->at(0)); + EXPECT_EQ(schedule.end(), order->at(1)); } @@ -230,7 +182,7 @@ TEST_F(SchedulerRPOTest, Line) { for (size_t i = 0; i < schedule.BasicBlockCount(); i++) { BasicBlock* block = schedule.GetBlockById(BasicBlock::Id::FromSize(i)); if (block->rpo_number() >= 0 && block->SuccessorCount() == 1) { - CHECK(block->rpo_number() + 1 == block->SuccessorAt(0)->rpo_number()); + EXPECT_EQ(block->rpo_number() + 1, block->SuccessorAt(0)->rpo_number()); } } } @@ -265,7 +217,7 @@ TEST_F(SchedulerRPOTest, EndLoop) { schedule.AddSuccessorForTesting(schedule.start(), loop1->header()); BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); CheckRPONumbers(order, 3, true); - loop1->Check(order); + CheckLoop(order, loop1->nodes, loop1->count); } @@ -276,7 +228,7 @@ TEST_F(SchedulerRPOTest, EndLoopNested) { schedule.AddSuccessorForTesting(loop1->last(), schedule.start()); BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); CheckRPONumbers(order, 3, true); - loop1->Check(order); + CheckLoop(order, loop1->nodes, loop1->count); } @@ -296,10 +248,10 @@ TEST_F(SchedulerRPOTest, Diamond) { BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); CheckRPONumbers(order, 4, false); - CHECK_EQ(0, A->rpo_number()); - CHECK((B->rpo_number() == 1 && C->rpo_number() == 2) || - (B->rpo_number() == 2 && C->rpo_number() == 1)); - CHECK_EQ(3, D->rpo_number()); + EXPECT_EQ(0, A->rpo_number()); + EXPECT_THAT(B->rpo_number(), AnyOf(1, 2)); + EXPECT_THAT(C->rpo_number(), AnyOf(1, 2)); + EXPECT_EQ(3, D->rpo_number()); } @@ -464,11 +416,9 @@ TEST_F(SchedulerRPOTest, LoopFollow1) { BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()), - static_cast<int>(order->size())); - - loop1->Check(order); - loop2->Check(order); + EXPECT_EQ(schedule.BasicBlockCount(), order->size()); + CheckLoop(order, loop1->nodes, loop1->count); + CheckLoop(order, loop2->nodes, loop2->count); } @@ -489,10 +439,9 @@ TEST_F(SchedulerRPOTest, LoopFollow2) { BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()), - static_cast<int>(order->size())); - loop1->Check(order); - loop2->Check(order); + EXPECT_EQ(schedule.BasicBlockCount(), order->size()); + CheckLoop(order, loop1->nodes, loop1->count); + CheckLoop(order, loop2->nodes, loop2->count); } @@ -510,10 +459,9 @@ TEST_F(SchedulerRPOTest, LoopFollowN) { schedule.AddSuccessorForTesting(loop2->nodes[exit], E); BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()), - static_cast<int>(order->size())); - loop1->Check(order); - loop2->Check(order); + EXPECT_EQ(schedule.BasicBlockCount(), order->size()); + CheckLoop(order, loop1->nodes, loop1->count); + CheckLoop(order, loop2->nodes, loop2->count); } } } @@ -539,10 +487,9 @@ TEST_F(SchedulerRPOTest, NestedLoopFollow1) { BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()), - static_cast<int>(order->size())); - loop1->Check(order); - loop2->Check(order); + EXPECT_EQ(schedule.BasicBlockCount(), order->size()); + CheckLoop(order, loop1->nodes, loop1->count); + CheckLoop(order, loop2->nodes, loop2->count); BasicBlock* loop3[] = {B, loop1->nodes[0], loop2->nodes[0], C}; CheckLoop(order, loop3, 4); @@ -566,7 +513,7 @@ TEST_F(SchedulerRPOTest, LoopBackedges1) { BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); CheckRPONumbers(order, schedule.BasicBlockCount(), true); - loop1->Check(order); + CheckLoop(order, loop1->nodes, loop1->count); } } } @@ -591,7 +538,7 @@ TEST_F(SchedulerRPOTest, LoopOutedges1) { BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); CheckRPONumbers(order, schedule.BasicBlockCount(), true); - loop1->Check(order); + CheckLoop(order, loop1->nodes, loop1->count); } } } @@ -616,7 +563,7 @@ TEST_F(SchedulerRPOTest, LoopOutedges2) { BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); CheckRPONumbers(order, schedule.BasicBlockCount(), true); - loop1->Check(order); + CheckLoop(order, loop1->nodes, loop1->count); } } @@ -640,10 +587,10 @@ TEST_F(SchedulerRPOTest, LoopOutloops1) { BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); CheckRPONumbers(order, schedule.BasicBlockCount(), true); - loop1->Check(order); + CheckLoop(order, loop1->nodes, loop1->count); for (int j = 0; j < size; j++) { - loopN[j]->Check(order); + CheckLoop(order, loopN[j]->nodes, loopN[j]->count); delete loopN[j]; } delete[] loopN; @@ -676,7 +623,58 @@ TEST_F(SchedulerRPOTest, LoopMultibackedge) { } -TEST_F(SchedulerTestWithIsolate, BuildScheduleIfSplitWithEffects) { +// ----------------------------------------------------------------------------- +// Graph end-to-end scheduling. + + +TEST_F(SchedulerTest, BuildScheduleEmpty) { + graph()->SetStart(graph()->NewNode(common()->Start(0))); + graph()->SetEnd(graph()->NewNode(common()->End(), graph()->start())); + USE(Scheduler::ComputeSchedule(zone(), graph(), Scheduler::kNoFlags)); +} + + +TEST_F(SchedulerTest, BuildScheduleOneParameter) { + graph()->SetStart(graph()->NewNode(common()->Start(0))); + + Node* p1 = graph()->NewNode(common()->Parameter(0), graph()->start()); + Node* ret = graph()->NewNode(common()->Return(), p1, graph()->start(), + graph()->start()); + + graph()->SetEnd(graph()->NewNode(common()->End(), ret)); + + USE(Scheduler::ComputeSchedule(zone(), graph(), Scheduler::kNoFlags)); +} + + +TEST_F(SchedulerTest, BuildScheduleIfSplit) { + graph()->SetStart(graph()->NewNode(common()->Start(3))); + + Node* p1 = graph()->NewNode(common()->Parameter(0), graph()->start()); + Node* p2 = graph()->NewNode(common()->Parameter(1), graph()->start()); + Node* p3 = graph()->NewNode(common()->Parameter(2), graph()->start()); + Node* p4 = graph()->NewNode(common()->Parameter(3), graph()->start()); + Node* p5 = graph()->NewNode(common()->Parameter(4), graph()->start()); + Node* cmp = graph()->NewNode(js()->LessThanOrEqual(), p1, p2, p3, + graph()->start(), graph()->start()); + Node* branch = graph()->NewNode(common()->Branch(), cmp, graph()->start()); + Node* true_branch = graph()->NewNode(common()->IfTrue(), branch); + Node* false_branch = graph()->NewNode(common()->IfFalse(), branch); + + Node* ret1 = + graph()->NewNode(common()->Return(), p4, graph()->start(), true_branch); + Node* ret2 = + graph()->NewNode(common()->Return(), p5, graph()->start(), false_branch); + Node* merge = graph()->NewNode(common()->Merge(2), ret1, ret2); + graph()->SetEnd(graph()->NewNode(common()->End(), merge)); + + ComputeAndVerifySchedule(13); +} + + +TEST_F(SchedulerTest, BuildScheduleIfSplitWithEffects) { + FLAG_turbo_deoptimization = false; + const Operator* op; // Manually transcripted code for: @@ -720,7 +718,7 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleIfSplitWithEffects) { Node* n3 = graph()->NewNode(op, n0); USE(n3); n11->ReplaceInput(1, n3); - op = common()->HeapConstant(GetUniqueUndefined()); + op = &kHeapConstant; Node* n7 = graph()->NewNode(op); USE(n7); n11->ReplaceInput(2, n7); @@ -808,11 +806,13 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleIfSplitWithEffects) { graph()->SetStart(n0); graph()->SetEnd(n23); - ComputeAndVerifySchedule(20, graph()); + ComputeAndVerifySchedule(20); } -TEST_F(SchedulerTestWithIsolate, BuildScheduleSimpleLoop) { +TEST_F(SchedulerTest, BuildScheduleSimpleLoop) { + FLAG_turbo_deoptimization = false; + const Operator* op; // Manually transcripted code for: @@ -846,7 +846,7 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleSimpleLoop) { Node* n16 = graph()->NewNode(op, nil, nil, nil, nil); USE(n16); n16->ReplaceInput(0, n8); - op = common()->HeapConstant(GetUniqueUndefined()); + op = &kHeapConstant; Node* n5 = graph()->NewNode(op); USE(n5); n16->ReplaceInput(1, n5); @@ -911,11 +911,13 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleSimpleLoop) { graph()->SetStart(n0); graph()->SetEnd(n20); - ComputeAndVerifySchedule(19, graph()); + ComputeAndVerifySchedule(19); } -TEST_F(SchedulerTestWithIsolate, BuildScheduleComplexLoops) { +TEST_F(SchedulerTest, BuildScheduleComplexLoops) { + FLAG_turbo_deoptimization = false; + const Operator* op; // Manually transcripted code for: @@ -961,7 +963,7 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleComplexLoops) { Node* n18 = graph()->NewNode(op, nil, nil, nil, nil); USE(n18); n18->ReplaceInput(0, n9); - op = common()->HeapConstant(GetUniqueUndefined()); + op = &kHeapConstant; Node* n6 = graph()->NewNode(op); USE(n6); n18->ReplaceInput(1, n6); @@ -1149,11 +1151,13 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleComplexLoops) { graph()->SetStart(n0); graph()->SetEnd(n46); - ComputeAndVerifySchedule(46, graph()); + ComputeAndVerifySchedule(46); } -TEST_F(SchedulerTestWithIsolate, BuildScheduleBreakAndContinue) { +TEST_F(SchedulerTest, BuildScheduleBreakAndContinue) { + FLAG_turbo_deoptimization = false; + const Operator* op; // Manually transcripted code for: @@ -1201,7 +1205,7 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleBreakAndContinue) { Node* n20 = graph()->NewNode(op, nil, nil, nil, nil); USE(n20); n20->ReplaceInput(0, n10); - op = common()->HeapConstant(GetUniqueUndefined()); + op = &kHeapConstant; Node* n6 = graph()->NewNode(op); USE(n6); n20->ReplaceInput(1, n6); @@ -1469,11 +1473,13 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleBreakAndContinue) { graph()->SetStart(n0); graph()->SetEnd(n58); - ComputeAndVerifySchedule(62, graph()); + ComputeAndVerifySchedule(62); } -TEST_F(SchedulerTestWithIsolate, BuildScheduleSimpleLoopWithCodeMotion) { +TEST_F(SchedulerTest, BuildScheduleSimpleLoopWithCodeMotion) { + FLAG_turbo_deoptimization = false; + const Operator* op; // Manually transcripted code for: @@ -1533,7 +1539,7 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleSimpleLoopWithCodeMotion) { USE(n14); n14->ReplaceInput(0, n9); n14->ReplaceInput(1, n10); - op = common()->HeapConstant(GetUniqueUndefined()); + op = &kHeapConstant; Node* n6 = graph()->NewNode(op); USE(n6); n14->ReplaceInput(2, n6); @@ -1583,10 +1589,7 @@ TEST_F(SchedulerTestWithIsolate, BuildScheduleSimpleLoopWithCodeMotion) { graph()->SetStart(n0); graph()->SetEnd(n22); - Schedule* schedule = ComputeAndVerifySchedule(19, graph()); - // Make sure the integer-only add gets hoisted to a different block that the - // JSAdd. - CHECK(schedule->block(n19) != schedule->block(n20)); + ComputeAndVerifySchedule(19); } @@ -1617,7 +1620,7 @@ TARGET_TEST_F(SchedulerTest, FloatingDiamond1) { graph()->SetEnd(end); - ComputeAndVerifySchedule(13, graph()); + ComputeAndVerifySchedule(13); } @@ -1635,7 +1638,7 @@ TARGET_TEST_F(SchedulerTest, FloatingDiamond2) { graph()->SetEnd(end); - ComputeAndVerifySchedule(24, graph()); + ComputeAndVerifySchedule(24); } @@ -1654,7 +1657,7 @@ TARGET_TEST_F(SchedulerTest, FloatingDiamond3) { graph()->SetEnd(end); - ComputeAndVerifySchedule(33, graph()); + ComputeAndVerifySchedule(33); } @@ -1691,7 +1694,7 @@ TARGET_TEST_F(SchedulerTest, NestedFloatingDiamonds) { graph()->SetEnd(end); - ComputeAndVerifySchedule(23, graph()); + ComputeAndVerifySchedule(23); } @@ -1735,7 +1738,7 @@ TARGET_TEST_F(SchedulerTest, NestedFloatingDiamondWithChain) { graph()->SetEnd(end); - ComputeAndVerifySchedule(36, graph()); + ComputeAndVerifySchedule(36); } @@ -1769,7 +1772,7 @@ TARGET_TEST_F(SchedulerTest, NestedFloatingDiamondWithLoop) { graph()->SetEnd(end); - ComputeAndVerifySchedule(20, graph()); + ComputeAndVerifySchedule(20); } @@ -1802,7 +1805,7 @@ TARGET_TEST_F(SchedulerTest, LoopedFloatingDiamond1) { graph()->SetEnd(end); - ComputeAndVerifySchedule(20, graph()); + ComputeAndVerifySchedule(20); } @@ -1836,7 +1839,7 @@ TARGET_TEST_F(SchedulerTest, LoopedFloatingDiamond2) { graph()->SetEnd(end); - ComputeAndVerifySchedule(20, graph()); + ComputeAndVerifySchedule(20); } @@ -1882,7 +1885,7 @@ TARGET_TEST_F(SchedulerTest, LoopedFloatingDiamond3) { graph()->SetEnd(end); - ComputeAndVerifySchedule(28, graph()); + ComputeAndVerifySchedule(28); } @@ -1916,7 +1919,7 @@ TARGET_TEST_F(SchedulerTest, PhisPushedDownToDifferentBranches) { graph()->SetEnd(end); - ComputeAndVerifySchedule(24, graph()); + ComputeAndVerifySchedule(24); } @@ -1937,10 +1940,10 @@ TARGET_TEST_F(SchedulerTest, BranchHintTrue) { graph()->SetEnd(end); - Schedule* schedule = ComputeAndVerifySchedule(13, graph()); + Schedule* schedule = ComputeAndVerifySchedule(13); // Make sure the false block is marked as deferred. - CHECK(!schedule->block(t)->deferred()); - CHECK(schedule->block(f)->deferred()); + EXPECT_FALSE(schedule->block(t)->deferred()); + EXPECT_TRUE(schedule->block(f)->deferred()); } @@ -1961,10 +1964,38 @@ TARGET_TEST_F(SchedulerTest, BranchHintFalse) { graph()->SetEnd(end); - Schedule* schedule = ComputeAndVerifySchedule(13, graph()); + Schedule* schedule = ComputeAndVerifySchedule(13); // Make sure the true block is marked as deferred. - CHECK(schedule->block(t)->deferred()); - CHECK(!schedule->block(f)->deferred()); + EXPECT_TRUE(schedule->block(t)->deferred()); + EXPECT_FALSE(schedule->block(f)->deferred()); +} + + +TARGET_TEST_F(SchedulerTest, CallException) { + Node* start = graph()->NewNode(common()->Start(1)); + graph()->SetStart(start); + + Node* p0 = graph()->NewNode(common()->Parameter(0), start); + Node* c1 = graph()->NewNode(&kMockCall, start); + Node* ok1 = graph()->NewNode(common()->IfSuccess(), c1); + Node* ex1 = graph()->NewNode(common()->IfException(), c1); + Node* c2 = graph()->NewNode(&kMockCall, ok1); + Node* ok2 = graph()->NewNode(common()->IfSuccess(), c2); + Node* ex2 = graph()->NewNode(common()->IfException(), c2); + Node* hdl = graph()->NewNode(common()->Merge(2), ex1, ex2); + Node* m = graph()->NewNode(common()->Merge(2), ok2, hdl); + Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), c2, p0, m); + Node* ret = graph()->NewNode(common()->Return(), phi, start, m); + Node* end = graph()->NewNode(common()->End(), ret); + + graph()->SetEnd(end); + + Schedule* schedule = ComputeAndVerifySchedule(17); + // Make sure the exception blocks as well as the handler are deferred. + EXPECT_TRUE(schedule->block(ex1)->deferred()); + EXPECT_TRUE(schedule->block(ex2)->deferred()); + EXPECT_TRUE(schedule->block(hdl)->deferred()); + EXPECT_FALSE(schedule->block(m)->deferred()); } @@ -1987,7 +2018,7 @@ TARGET_TEST_F(SchedulerTest, Switch) { graph()->SetEnd(end); - ComputeAndVerifySchedule(16, graph()); + ComputeAndVerifySchedule(16); } @@ -2010,7 +2041,7 @@ TARGET_TEST_F(SchedulerTest, FloatingSwitch) { graph()->SetEnd(end); - ComputeAndVerifySchedule(16, graph()); + ComputeAndVerifySchedule(16); } } // namespace compiler diff --git a/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc b/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc index 38924123df..f8f9561af8 100644 --- a/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-operator-reducer-unittest.cc @@ -119,39 +119,6 @@ const double kNaNs[] = {-std::numeric_limits<double>::quiet_NaN(), // ----------------------------------------------------------------------------- -// AnyToBoolean - - -TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithBoolean) { - Node* p = Parameter(Type::Boolean()); - Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p)); - ASSERT_TRUE(r.Changed()); - EXPECT_EQ(p, r.replacement()); -} - - -TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithOrderedNumber) { - Node* p = Parameter(Type::OrderedNumber()); - Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsBooleanNot(IsNumberEqual(p, IsNumberConstant(0)))); -} - - -TEST_F(SimplifiedOperatorReducerTest, AnyToBooleanWithString) { - Node* p = Parameter(Type::String()); - Reduction r = Reduce(graph()->NewNode(simplified()->AnyToBoolean(), p)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsBooleanNot( - IsNumberEqual(IsLoadField(AccessBuilder::ForStringLength(), p, - graph()->start(), graph()->start()), - IsNumberConstant(0)))); -} - - -// ----------------------------------------------------------------------------- // BooleanNot diff --git a/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc b/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc index 680793023f..a5dad5a415 100644 --- a/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc @@ -38,7 +38,6 @@ const PureOperator kPureOperators[] = { &SimplifiedOperatorBuilder::Name, IrOpcode::k##Name, \ Operator::kPure | properties, input_count \ } - PURE(AnyToBoolean, Operator::kNoProperties, 1), PURE(BooleanNot, Operator::kNoProperties, 1), PURE(BooleanToNumber, Operator::kNoProperties, 1), PURE(NumberEqual, Operator::kCommutative, 2), diff --git a/deps/v8/test/unittests/compiler/state-values-utils-unittest.cc b/deps/v8/test/unittests/compiler/state-values-utils-unittest.cc new file mode 100644 index 0000000000..e6f4701598 --- /dev/null +++ b/deps/v8/test/unittests/compiler/state-values-utils-unittest.cc @@ -0,0 +1,149 @@ +// 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/state-values-utils.h" +#include "test/unittests/compiler/graph-unittest.h" +#include "test/unittests/compiler/node-test-utils.h" +#include "test/unittests/test-utils.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace v8 { +namespace internal { +namespace compiler { + +class StateValuesIteratorTest : public GraphTest { + public: + StateValuesIteratorTest() : GraphTest(3) {} + + Node* StateValuesFromVector(NodeVector* nodes) { + int count = static_cast<int>(nodes->size()); + return graph()->NewNode(common()->StateValues(count), count, + count == 0 ? nullptr : &(nodes->front())); + } +}; + + +TEST_F(StateValuesIteratorTest, SimpleIteration) { + NodeVector inputs(zone()); + const int count = 10; + for (int i = 0; i < count; i++) { + inputs.push_back(Int32Constant(i)); + } + Node* state_values = StateValuesFromVector(&inputs); + int i = 0; + for (StateValuesAccess::TypedNode node : StateValuesAccess(state_values)) { + EXPECT_THAT(node.node, IsInt32Constant(i)); + i++; + } + EXPECT_EQ(count, i); +} + + +TEST_F(StateValuesIteratorTest, EmptyIteration) { + NodeVector inputs(zone()); + Node* state_values = StateValuesFromVector(&inputs); + for (auto node : StateValuesAccess(state_values)) { + USE(node); + FAIL(); + } +} + + +TEST_F(StateValuesIteratorTest, NestedIteration) { + NodeVector inputs(zone()); + int count = 0; + for (int i = 0; i < 8; i++) { + if (i == 2) { + // Single nested in index 2. + NodeVector nested_inputs(zone()); + for (int j = 0; j < 8; j++) { + nested_inputs.push_back(Int32Constant(count++)); + } + inputs.push_back(StateValuesFromVector(&nested_inputs)); + } else if (i == 5) { + // Double nested at index 5. + NodeVector nested_inputs(zone()); + for (int j = 0; j < 8; j++) { + if (j == 7) { + NodeVector doubly_nested_inputs(zone()); + for (int k = 0; k < 2; k++) { + doubly_nested_inputs.push_back(Int32Constant(count++)); + } + nested_inputs.push_back(StateValuesFromVector(&doubly_nested_inputs)); + } else { + nested_inputs.push_back(Int32Constant(count++)); + } + } + inputs.push_back(StateValuesFromVector(&nested_inputs)); + } else { + inputs.push_back(Int32Constant(count++)); + } + } + Node* state_values = StateValuesFromVector(&inputs); + int i = 0; + for (StateValuesAccess::TypedNode node : StateValuesAccess(state_values)) { + EXPECT_THAT(node.node, IsInt32Constant(i)); + i++; + } + EXPECT_EQ(count, i); +} + + +TEST_F(StateValuesIteratorTest, TreeFromVector) { + int sizes[] = {0, 1, 2, 100, 5000, 30000}; + TRACED_FOREACH(int, count, sizes) { + JSOperatorBuilder javascript(zone()); + MachineOperatorBuilder machine(zone()); + JSGraph jsgraph(isolate(), graph(), common(), &javascript, &machine); + + // Generate the input vector. + NodeVector inputs(zone()); + for (int i = 0; i < count; i++) { + inputs.push_back(Int32Constant(i)); + } + + // Build the tree. + StateValuesCache builder(&jsgraph); + Node* values_node = builder.GetNodeForValues( + inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size()); + + // Check the tree contents with vector. + int i = 0; + for (StateValuesAccess::TypedNode node : StateValuesAccess(values_node)) { + EXPECT_THAT(node.node, IsInt32Constant(i)); + i++; + } + EXPECT_EQ(inputs.size(), static_cast<size_t>(i)); + } +} + + +TEST_F(StateValuesIteratorTest, BuildTreeIdentical) { + int sizes[] = {0, 1, 2, 100, 5000, 30000}; + TRACED_FOREACH(int, count, sizes) { + JSOperatorBuilder javascript(zone()); + MachineOperatorBuilder machine(zone()); + JSGraph jsgraph(isolate(), graph(), common(), &javascript, &machine); + + // Generate the input vector. + NodeVector inputs(zone()); + for (int i = 0; i < count; i++) { + inputs.push_back(Int32Constant(i)); + } + + // Build two trees from the same data. + StateValuesCache builder(&jsgraph); + Node* node1 = builder.GetNodeForValues( + inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size()); + Node* node2 = builder.GetNodeForValues( + inputs.size() == 0 ? nullptr : &(inputs.front()), inputs.size()); + + // The trees should be equal since the data was the same. + EXPECT_EQ(node1, node2); + } +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc b/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc index 1f374c0f85..a83deafe7d 100644 --- a/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc +++ b/deps/v8/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc @@ -1030,6 +1030,25 @@ TEST_F(InstructionSelectorTest, Float64BinopArithmetic) { // Miscellaneous. +TEST_F(InstructionSelectorTest, Uint64LessThanWithLoadAndLoadStackPointer) { + StreamBuilder m(this, kMachBool); + Node* const sl = m.Load( + kMachPtr, + m.ExternalConstant(ExternalReference::address_of_stack_limit(isolate()))); + Node* const sp = m.LoadStackPointer(); + Node* const n = m.Uint64LessThan(sl, sp); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64StackCheck, s[0]->arch_opcode()); + ASSERT_EQ(0U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); + EXPECT_EQ(kFlags_set, s[0]->flags_mode()); + EXPECT_EQ(kUnsignedGreaterThan, s[0]->flags_condition()); +} + + TEST_F(InstructionSelectorTest, Word64ShlWithChangeInt32ToInt64) { TRACED_FORRANGE(int64_t, x, 32, 63) { StreamBuilder m(this, kMachInt64, kMachInt32); @@ -1127,6 +1146,21 @@ TEST_F(InstructionSelectorTest, Word32AndWith0xffff) { } } + +TEST_F(InstructionSelectorTest, Word32Clz) { + StreamBuilder m(this, kMachUint32, kMachUint32); + Node* const p0 = m.Parameter(0); + Node* const n = m.Word32Clz(p0); + m.Return(n); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kX64Lzcnt32, s[0]->arch_opcode()); + ASSERT_EQ(1U, s[0]->InputCount()); + EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0))); + ASSERT_EQ(1U, s[0]->OutputCount()); + EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output())); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/heap/gc-idle-time-handler-unittest.cc b/deps/v8/test/unittests/heap/gc-idle-time-handler-unittest.cc index 2076e604fa..ed33259775 100644 --- a/deps/v8/test/unittests/heap/gc-idle-time-handler-unittest.cc +++ b/deps/v8/test/unittests/heap/gc-idle-time-handler-unittest.cc @@ -168,7 +168,7 @@ TEST_F(GCIdleTimeHandlerTest, DoScavengeHighScavengeSpeed) { TEST_F(GCIdleTimeHandlerTest, ShouldDoMarkCompact) { - size_t idle_time_in_ms = 16; + size_t idle_time_in_ms = GCIdleTimeHandler::kMaxScheduledIdleTime; EXPECT_TRUE(GCIdleTimeHandler::ShouldDoMarkCompact(idle_time_in_ms, 0, 0)); } @@ -440,5 +440,55 @@ TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeDoNothingButStartIdleRound) { EXPECT_EQ(DO_NOTHING, action.type); } + +TEST_F(GCIdleTimeHandlerTest, KeepDoingDoNothingWithZeroIdleTime) { + GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); + for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimesPerIdleRound; + i++) { + GCIdleTimeAction action = handler()->Compute(0, heap_state); + EXPECT_EQ(DO_NOTHING, action.type); + } + // Should still return DO_NOTHING if we have been given 0 deadline yet. + GCIdleTimeAction action = handler()->Compute(0, heap_state); + EXPECT_EQ(DO_NOTHING, action.type); +} + + +TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnSweeping) { + GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); + + // Simulate sweeping being in-progress but not complete. + heap_state.incremental_marking_stopped = true; + heap_state.can_start_incremental_marking = false; + heap_state.sweeping_in_progress = true; + double idle_time_ms = 10.0; + for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimesPerIdleRound; + i++) { + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DO_NOTHING, action.type); + } + // We should return DONE after not making progress for some time. + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DONE, action.type); +} + + +TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnIncrementalMarking) { + GCIdleTimeHandler::HeapState heap_state = DefaultHeapState(); + + // Simulate incremental marking stopped and not eligible to start. + heap_state.incremental_marking_stopped = true; + heap_state.can_start_incremental_marking = false; + double idle_time_ms = 10.0; + for (int i = 0; i < GCIdleTimeHandler::kMaxNoProgressIdleTimesPerIdleRound; + i++) { + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DO_NOTHING, action.type); + } + // We should return DONE after not making progress for some time. + GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); + EXPECT_EQ(DONE, action.type); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/unittests.gyp b/deps/v8/test/unittests/unittests.gyp index a12d5e7f4b..2ed05b8adc 100644 --- a/deps/v8/test/unittests/unittests.gyp +++ b/deps/v8/test/unittests/unittests.gyp @@ -57,6 +57,7 @@ 'compiler/js-intrinsic-lowering-unittest.cc', 'compiler/js-operator-unittest.cc', 'compiler/js-typed-lowering-unittest.cc', + 'compiler/liveness-analyzer-unittest.cc', 'compiler/load-elimination-unittest.cc', 'compiler/loop-peeling-unittest.cc', 'compiler/machine-operator-reducer-unittest.cc', @@ -74,6 +75,7 @@ 'compiler/scheduler-unittest.cc', 'compiler/simplified-operator-reducer-unittest.cc', 'compiler/simplified-operator-unittest.cc', + 'compiler/state-values-utils-unittest.cc', 'compiler/typer-unittest.cc', 'compiler/value-numbering-reducer-unittest.cc', 'compiler/zone-pool-unittest.cc', diff --git a/deps/v8/test/webkit/fast/js/kde/prototype_length-expected.txt b/deps/v8/test/webkit/fast/js/kde/prototype_length-expected.txt index 7c4c2e25d8..5cf2bd5db8 100644 --- a/deps/v8/test/webkit/fast/js/kde/prototype_length-expected.txt +++ b/deps/v8/test/webkit/fast/js/kde/prototype_length-expected.txt @@ -39,7 +39,7 @@ PASS Array.prototype.length is 6 PASS Function.prototype.length is 0 PASS String.prototype.length is 0 PASS delete Array.prototype.length is false -PASS delete Function.prototype.length is false +PASS delete Function.prototype.length is true PASS delete String.prototype.length is false PASS foundArrayPrototypeLength is false PASS foundFunctionPrototypeLength is false diff --git a/deps/v8/test/webkit/fast/js/kde/prototype_length.js b/deps/v8/test/webkit/fast/js/kde/prototype_length.js index 4eb888c3da..48357005d1 100644 --- a/deps/v8/test/webkit/fast/js/kde/prototype_length.js +++ b/deps/v8/test/webkit/fast/js/kde/prototype_length.js @@ -43,7 +43,7 @@ shouldBe("String.prototype.length","0"); // check DontDelete shouldBe("delete Array.prototype.length","false"); -shouldBe("delete Function.prototype.length","false"); +shouldBe("delete Function.prototype.length","true"); shouldBe("delete String.prototype.length","false"); // check DontEnum diff --git a/deps/v8/test/webkit/webkit.status b/deps/v8/test/webkit/webkit.status index fb8d77d8d2..d8c6864105 100644 --- a/deps/v8/test/webkit/webkit.status +++ b/deps/v8/test/webkit/webkit.status @@ -56,10 +56,10 @@ ['arch == arm64 and simulator_run == True', { 'dfg-int-overflow-in-loop': [SKIP], }], # 'arch == arm64 and simulator_run == True' -['dcheck_always_on == True and arch == arm64', { - # Doesn't work with gcc 4.6 on arm64 for some reason. +['dcheck_always_on == True and (arch == arm or arch == arm64)', { + # Doesn't work with gcc 4.6 on arm or arm64 for some reason. 'reentrant-caching': [SKIP], -}], # 'dcheck_always_on == True and arch == arm64' +}], # 'dcheck_always_on == True and (arch == arm or arch == arm64)' ############################################################################## |