diff options
author | Ali Ijaz Sheikh <ofrobots@google.com> | 2016-04-07 14:06:55 -0700 |
---|---|---|
committer | Ali Ijaz Sheikh <ofrobots@google.com> | 2016-04-14 10:03:39 -0700 |
commit | 52af5c4eebf4de8638aef0338bd826656312a02a (patch) | |
tree | 628dc9fb0b558c3a73a2160706fef368876fe548 /deps/v8/test | |
parent | 6e3e8acc7cc7ebd3d67db5ade1247b8b558efe09 (diff) | |
download | android-node-v8-52af5c4eebf4de8638aef0338bd826656312a02a.tar.gz android-node-v8-52af5c4eebf4de8638aef0338bd826656312a02a.tar.bz2 android-node-v8-52af5c4eebf4de8638aef0338bd826656312a02a.zip |
deps: upgrade V8 to 5.0.71.32
* Pick up the branch head for V8 5.0 stable [1]
* Edit v8 gitignore to allow trace_event copy
* Update V8 DEP trace_event as per deps/v8/DEPS [2]
[1] https://chromium.googlesource.com/v8/v8.git/+/3c67831
[2] https://chromium.googlesource.com/chromium/src/base/trace_event/common/+/4b09207e447ae5bd34643b4c6321bee7b76d35f9
Ref: https://github.com/nodejs/node/pull/5945
PR-URL: https://github.com/nodejs/node/pull/6111
Reviewed-By: targos - Michaƫl Zasso <mic.besace@gmail.com>
Reviewed-By: bnoordhuis - Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: indutny - Fedor Indutny <fedor.indutny@gmail.com>
Diffstat (limited to 'deps/v8/test')
323 files changed, 22565 insertions, 9407 deletions
diff --git a/deps/v8/test/bot_default.gyp b/deps/v8/test/bot_default.gyp index ccdf42a7d7..9b39f58412 100644 --- a/deps/v8/test/bot_default.gyp +++ b/deps/v8/test/bot_default.gyp @@ -11,6 +11,7 @@ 'type': 'none', 'dependencies': [ 'cctest/cctest.gyp:cctest_run', + 'fuzzer/fuzzer.gyp:fuzzer_run', 'intl/intl.gyp:intl_run', 'message/message.gyp:message_run', 'mjsunit/mjsunit.gyp:mjsunit_run', diff --git a/deps/v8/test/bot_default.isolate b/deps/v8/test/bot_default.isolate index 32773587c2..d6e4aa3474 100644 --- a/deps/v8/test/bot_default.isolate +++ b/deps/v8/test/bot_default.isolate @@ -2,8 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. { + 'variables': { + 'command': [ + '../tools/run-tests.py', + ], + }, 'includes': [ 'cctest/cctest.isolate', + 'fuzzer/fuzzer.isolate', 'intl/intl.isolate', 'message/message.isolate', 'mjsunit/mjsunit.isolate', diff --git a/deps/v8/test/cctest/cctest.gyp b/deps/v8/test/cctest/cctest.gyp index 708b767a10..3b76ce1778 100644 --- a/deps/v8/test/cctest/cctest.gyp +++ b/deps/v8/test/cctest/cctest.gyp @@ -90,6 +90,8 @@ 'expression-type-collector.h', 'interpreter/test-bytecode-generator.cc', 'interpreter/test-interpreter.cc', + 'interpreter/bytecode-expectations-printer.cc', + 'interpreter/bytecode-expectations-printer.h', 'gay-fixed.cc', 'gay-precision.cc', 'gay-shortest.cc', @@ -343,12 +345,35 @@ } ], }, + { + 'target_name': 'generate-bytecode-expectations', + 'type': 'executable', + 'dependencies': [ + '../../tools/gyp/v8.gyp:v8_libplatform', + ], + 'conditions': [ + ['component=="shared_library"', { + # Same as cctest, we need to depend on the underlying static target. + 'dependencies': ['../../tools/gyp/v8.gyp:v8_maybe_snapshot'], + }, { + 'dependencies': ['../../tools/gyp/v8.gyp:v8'], + }], + ], + 'include_dirs+': [ + '../..', + ], + 'sources': [ + 'interpreter/bytecode-expectations-printer.cc', + 'interpreter/bytecode-expectations-printer.h', + 'interpreter/generate-bytecode-expectations.cc', + ], + }, ], 'conditions': [ ['test_isolation_mode != "noop"', { 'targets': [ { - 'target_name': 'cctest_run', + 'target_name': 'cctest_exe_run', 'type': 'none', 'dependencies': [ 'cctest', @@ -357,6 +382,19 @@ '../../build/isolate.gypi', ], 'sources': [ + 'cctest_exe.isolate', + ], + }, + { + 'target_name': 'cctest_run', + 'type': 'none', + 'dependencies': [ + 'cctest_exe_run', + ], + 'includes': [ + '../../build/isolate.gypi', + ], + 'sources': [ 'cctest.isolate', ], }, diff --git a/deps/v8/test/cctest/cctest.isolate b/deps/v8/test/cctest/cctest.isolate index aee8d83f85..ab55466214 100644 --- a/deps/v8/test/cctest/cctest.isolate +++ b/deps/v8/test/cctest/cctest.isolate @@ -4,13 +4,12 @@ { 'variables': { 'files': [ - '<(PRODUCT_DIR)/cctest<(EXECUTABLE_SUFFIX)', './cctest.status', './testcfg.py', ], }, 'includes': [ - '../../src/base.isolate', + 'cctest_exe.isolate', '../../tools/testrunner/testrunner.isolate', ], -}
\ No newline at end of file +} diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index 80837534ce..8eaa9515b1 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -71,20 +71,9 @@ # This tests API threading, no point in running several variants. 'test-api/Threading*': [PASS, NO_VARIANTS], - # The cpu profiler tests are notoriously flaky. - # BUG(2999). (test/cpu-profiler/CollectCpuProfile) - # BUG(3287). (test-cpu-profiler/SampleWhenFrameIsNotSetup) - '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], + # BUG(2999). The cpu profiler tests are notoriously flaky. 'test-cpu-profiler/CpuProfileDeepStack': [SKIP], - 'test-cpu-profiler/JsNativeJsSample': [SKIP], - 'test-cpu-profiler/JsNativeJsRuntimeJsSample': [SKIP], - 'test-cpu-profiler/JsNative1JsNative2JsSample': [SKIP], + 'test-cpu-profiler/HotDeoptNoFrameEntry': [SKIP], # BUG(3525). Test crashes flakily. 'test-debug/RecursiveBreakpoints': [PASS, FLAKY], @@ -100,6 +89,10 @@ 'test-func-name-inference/UpperCaseClass': [FAIL], 'test-func-name-inference/LowerCaseClass': [FAIL], + # BUG(3956). Strong mode is being deprecated. Decide about these tests. + 'test-api/StrongModeAccessCheckAllowed': [FAIL], + 'test-api/StrongModeAccessCheckBlocked': [FAIL], + ############################################################################## # TurboFan compiler failures. @@ -256,8 +249,11 @@ ############################################################################## ['byteorder == big', { # TODO(mips-team): Fix Wasm for big-endian. + 'test-run-wasm-module/Run_WasmModule_CallAdd': [SKIP], 'test-run-wasm-module/Run_WasmModule_CallAdd_rev': [SKIP], + 'test-run-wasm-module/Run_WasmModule_CallMain_recursive': [SKIP], 'test-run-wasm-module/Run_WasmModule_ReadLoadedDataSegment': [SKIP], + 'test-run-wasm-module/Run_WasmModule_Return114': [SKIP], 'test-run-wasm-module/Run_WasmModule_CheckMemoryIsZero': [SKIP], 'test-run-wasm-module/Run_WasmModule_Global': [SKIP], 'test-run-wasm/Run_WasmInt32*': [SKIP], @@ -271,6 +267,12 @@ 'test-run-wasm/Run_Wasm_LoadStoreI64_sx': [SKIP], 'test-run-wasm/Run_WASM_Int64DivS_byzero_const': [SKIP], 'test-run-wasm/Run_TestI64WasmRunner': [SKIP], + 'test-run-wasm-js/Run_JSSelect_1': [SKIP], + 'test-run-wasm-js/Run_JSSelect_2': [SKIP], + 'test-run-wasm-js/Run_JSSelect_3': [SKIP], + 'test-run-wasm-js/Run_JSSelect_4': [SKIP], + 'test-run-wasm-js/Run_JSSelect_5': [SKIP], + 'test-run-wasm-js/Run_JSSelect_6': [SKIP], }], # 'byteorder == big' ############################################################################## @@ -497,93 +499,120 @@ }], # 'arch == ppc64 and simulator_run == True' ['ignition == True', { - 'test-api/*' : [SKIP], - 'test-cpu-profiler/*' : [SKIP], - 'test-debug/*' : [SKIP], - 'test-func-name-inference/*' : [SKIP], - 'test-inobject-slack-tracking/*' : [SKIP], - 'test-run-jsexceptions/*' : [SKIP], - 'test-serialize/*' : [SKIP], - - 'test-api-interceptors/InterceptorCallICInvalidatedConstantFunctionViaGlobal': [SKIP], - 'test-api-interceptors/InterceptorLoadICInvalidatedCallbackViaGlobal': [SKIP], - 'test-api-interceptors/InterceptorLoadICInvalidatedFieldViaGlobal': [SKIP], - 'test-bytecode-generator/TryCatch': [SKIP], - 'test-bytecode-generator/TryFinally': [SKIP], - 'test-compiler/C2JSFrames': [SKIP], - 'test-compiler/FeedbackVectorPreservedAcrossRecompiles': [SKIP], - 'test-compiler/FeedbackVectorUnaffectedByScopeChanges': [SKIP], - 'test-compiler/OptimizedCodeSharing2': [SKIP], - 'test-compiler/OptimizedCodeSharing3': [SKIP], - 'test-compiler/Print': [SKIP], - 'test-compiler/UncaughtThrow': [SKIP], - 'test-decls/CrossScriptDynamicLookup': [SKIP], - 'test-decls/Regress425510': [SKIP], - 'test-feedback-vector/VectorCallICStates': [SKIP], - 'test-heap/AddInstructionChangesNewSpacePromotion': [SKIP], - 'test-heap/ArrayShiftSweeping': [SKIP], - 'test-heap/CanonicalSharedFunctionInfo': [SKIP], - 'test-heap/CellsInOptimizedCodeAreWeak': [SKIP], - 'test-heap/CompilationCacheCachingBehavior': [SKIP], - 'test-heap/CountForcedGC': [SKIP], - 'test-heap/IncrementalMarkingClearsMonomorphicConstructor': [SKIP], - 'test-heap/IncrementalMarkingPreservesMonomorphicCallIC': [SKIP], - 'test-heap/IncrementalMarkingPreservesMonomorphicConstructor': [SKIP], - 'test-heap/NoWeakHashTableLeakWithIncrementalMarking': [SKIP], - 'test-heap-profiler/HeapSnapshotCollection': [SKIP], - 'test-heap-profiler/HeapSnapshotSimd': [SKIP], - 'test-heap-profiler/HeapSnapshotWeakCollection': [SKIP], - 'test-heap/OptimizedAllocationAlwaysInNewSpace': [SKIP], - 'test-heap/PromotionQueue': [SKIP], - 'test-heap/Regress169209': [SKIP], - 'test-heap/Regress1878': [SKIP], - 'test-heap/Regress357137': [SKIP], - 'test-heap/Regress3631': [SKIP], - 'test-heap/Regress388880': [SKIP], - 'test-heap/TestCodeFlushingIncrementalAbort': [SKIP], - 'test-heap/TestCodeFlushingIncrementalScavenge': [SKIP], - 'test-heap/TestCodeFlushingIncremental': [SKIP], - 'test-heap/TestCodeFlushingPreAged': [SKIP], - 'test-heap/TestCodeFlushing': [SKIP], - 'test-heap/WeakFunctionInConstructor': [SKIP], - 'test-log-stack-tracer/CFromJSStackTrace': [SKIP], - 'test-log-stack-tracer/JsEntrySp': [SKIP], - 'test-log-stack-tracer/PureCStackTrace': [SKIP], - 'test-log-stack-tracer/PureJSStackTrace': [SKIP], - 'test-parsing/DestructuringNegativeTests': [SKIP], - 'test-parsing/StrongModeFreeVariablesDeclaredByLanguage': [SKIP], - 'test-parsing/StrongModeFreeVariablesDeclaredByPreviousScript': [SKIP], - 'test-parsing/StrongModeFreeVariablesDeclaredInGlobalPrototype': [SKIP], - 'test-pipeline/PipelineGeneric': [SKIP], - 'test-pipeline/PipelineTyped': [SKIP], - 'test-profile-generator/BailoutReason': [SKIP], - 'test-profile-generator/LineNumber': [SKIP], - 'test-profile-generator/ProfileNodeScriptId': [SKIP], - 'test-profile-generator/RecordStackTraceAtStartProfiling': [SKIP], - 'test-run-inlining/InlineTwice': [SKIP], - 'test-run-jsbranches/ForOfContinueStatement': [SKIP], - 'test-run-jscalls/LookupCall': [SKIP], - 'test-run-jsobjects/ArgumentsRest': [SKIP], - 'test-run-jsops/ClassLiteral': [SKIP], - 'test-run-jsops/LookupLoad': [SKIP], - 'test-run-jsops/LookupStore': [SKIP], - 'test-run-variables/ContextInitializeVariables': [SKIP], - 'test-run-variables/ContextLoadVariables': [SKIP], - 'test-run-variables/ContextStoreVariables': [SKIP], - 'test-run-variables/StackInitializeVariables': [SKIP], - 'test-run-variables/StackLoadVariables': [SKIP], - 'test-run-variables/StackStoreVariables': [SKIP], - 'test-sampler-api/StackFramesConsistent': [SKIP], - 'test-thread-termination/TerminateCancelTerminateFromThreadItself': [SKIP], - 'test-thread-termination/TerminateFromOtherThreadWhileMicrotaskRunning': [SKIP], - 'test-thread-termination/TerminateOnlyV8ThreadFromThreadItselfNoLoop': [SKIP], - 'test-thread-termination/TerminationInInnerTryCall': [SKIP], - 'test-unscopables-hidden-prototype/Unscopables': [SKIP], + # TODO(yangguo,4690): Test failures in debugger tests. + 'test-debug/DebugStepLocals': [FAIL], + 'test-debug/DebugStepKeyedLoadLoop': [FAIL], + 'test-debug/DebugStepKeyedStoreLoop': [FAIL], + 'test-debug/DebugStepIf': [FAIL], + 'test-debug/DebugStepNamedLoadLoop': [FAIL], + 'test-debug/DebugStepDeclarations': [FAIL], + 'test-debug/BreakPointConstructCallWithGC': [PASS, FAIL], + 'test-debug/DebugStepNamedStoreLoop': [FAIL], + 'test-debug/DebugStepLinearMixedICs': [FAIL], + 'test-debug/DebugStepSwitch': [FAIL], + 'test-debug/DebugStepWhile': [FAIL], + 'test-debug/DebugStepFor': [FAIL], + 'test-debug/DebugStepForContinue': [FAIL], + 'test-debug/DebugStepForIn': [FAIL], + 'test-debug/DebugStepDoWhile': [FAIL], + 'test-debug/DebugConditional': [FAIL], + 'test-debug/DebugStepForBreak': [FAIL], + 'test-debug/DebugStepWith': [FAIL], + 'test-debug/DebugStepFunctionApply': [FAIL], + 'test-debug/StepInOutBranch': [FAIL], + 'test-debug/DebugStepFunctionCall': [FAIL], + + # TODO(yangguo,4690): Required DebuggerStatement support. + 'test-profile-generator/BailoutReason': [FAIL], + + # TODO(rmcilroy,4680): Check failed: toplevel_test_code_event_found. + 'test-serialize/SerializeToplevelIsolates': [FAIL], + + # BUG(4333). Function name inferrer does not work for ES6 clases. + 'test-func-name-inference/UpperCaseClass': [TIMEOUT], + 'test-func-name-inference/LowerCaseClass': [TIMEOUT], + + # TODO(rmcilroy,4681): Requires support for generators. + 'test-inobject-slack-tracking/JSGeneratorObjectBasic': [FAIL], + 'test-inobject-slack-tracking/JSGeneratorObjectBasicNoInlineNew': [FAIL], + 'test-api/IsGeneratorFunctionOrObject': [FAIL], + + # TODO(rmcilroy,4680): Strong mode failures. + 'test-api/AccessorShouldThrowOnError': [FAIL], + 'test-api/InterceptorShouldThrowOnError': [FAIL], + + # TODO(rmcilroy,4680): The function_data field should be a BytecodeArray on interpreter entry + 'test-api/SetFunctionEntryHook': [FAIL], + + # TODO(rmcilroy,4680): Fail on shared_function_data()->IsUndefined in + #compiler.cc + 'test-heap/CanonicalSharedFunctionInfo': [PASS, ['mode == debug or dcheck_always_on == True', FAIL]], + + # TODO(rmcilroy,4680): Check failed: !function->shared()->is_compiled() || function->IsOptimized(). + 'test-heap/TestCodeFlushingPreAged': [FAIL], + 'test-heap/TestCodeFlushingIncrementalScavenge': [FAIL], + 'test-heap/TestCodeFlushing': [FAIL], + 'test-heap/TestCodeFlushingIncremental': [FAIL], + 'test-heap/TestCodeFlushingIncrementalAbort': [PASS, ['mode == debug or dcheck_always_on == True', FAIL]], + + # TODO(rmcilroy,4680): Check failed: fun1->IsOptimized() || !CcTest::i_isolate()->use_crankshaft(). + 'test-compiler/OptimizedCodeSharing2': [FAIL], + 'test-compiler/OptimizedCodeSharing3': [FAIL], + + # TODO(rmcilroy,4689): Stack trace line number failures. + 'test-run-jsexceptions/ThrowMessagePosition': [FAIL], + 'test-api/TryCatchMixedNesting': [FAIL], + + # TODO(rmcilroy,4680): Test assert errors. + 'test-cpu-profiler/CodeEvents': [FAIL], + 'test-cpu-profiler/TickEvents': [FAIL], + 'test-cpu-profiler/BoundFunctionCall': [FAIL], + 'test-cpu-profiler/CollectCpuProfile': [FAIL], + 'test-cpu-profiler/CollectSampleAPI': [FAIL], + 'test-cpu-profiler/CpuProfileDeepStack': [FAIL], + 'test-cpu-profiler/FunctionApplySample': [FAIL], + 'test-cpu-profiler/FunctionCallSample': [FAIL], + 'test-cpu-profiler/FunctionDetails': [FAIL], + 'test-cpu-profiler/HotDeoptNoFrameEntry': [FAIL], + 'test-cpu-profiler/JsNative1JsNative2JsSample': [FAIL], + 'test-cpu-profiler/JsNativeJsRuntimeJsSample': [FAIL], + 'test-cpu-profiler/JsNativeJsRuntimeJsSampleMultiple': [FAIL], + 'test-cpu-profiler/JsNativeJsSample': [FAIL], + 'test-cpu-profiler/NativeMethodUninitializedIC': [FAIL], + 'test-cpu-profiler/NativeMethodMonomorphicIC': [FAIL], + 'test-cpu-profiler/NativeAccessorUninitializedIC': [FAIL], + 'test-cpu-profiler/NativeAccessorMonomorphicIC': [FAIL], + 'test-cpu-profiler/SampleWhenFrameIsNotSetup': [FAIL], + 'test-sampler-api/StackFramesConsistent': [FAIL], + 'test-profile-generator/LineNumber': [FAIL], + 'test-profile-generator/ProfileNodeScriptId': [FAIL], + 'test-profile-generator/RecordStackTraceAtStartProfiling': [FAIL], + 'test-feedback-vector/VectorCallICStates': [FAIL], + 'test-compiler/FeedbackVectorPreservedAcrossRecompiles': [FAIL], + 'test-api/PromiseRejectCallback': [FAIL], + 'test-api/SetJitCodeEventHandler': [FAIL], + 'test-heap/WeakFunctionInConstructor': [FAIL], + 'test-heap/Regress169209': [FAIL], + 'test-heap/IncrementalMarkingClearsMonomorphicConstructor': [FAIL], + 'test-heap/IncrementalMarkingPreservesMonomorphicConstructor': [FAIL], + 'test-heap/IncrementalMarkingPreservesMonomorphicCallIC': [FAIL], + 'test-heap/CompilationCacheCachingBehavior': [FAIL], + 'test-heap/CellsInOptimizedCodeAreWeak': [FAIL], + 'test-run-inlining/InlineTwice': [FAIL], + 'test-serialize/SerializeInternalReference': [FAIL, ['arch == arm or arch == arm64', PASS]], }], # ignition == True -['ignition == True and arch == arm64', { - 'test-js-arm64-variables/lookup_slots': [SKIP], - 'test-spaces/SizeOfFirstPageIsLargeEnough': [SKIP], -}], # ignition == True and arch == arm64 +['ignition == True and arch == x64', { + # TODO(rmcilroy,4680): The function_data field should be a BytecodeArray on interpreter entry + 'test-serialize/PerIsolateSnapshotBlobsOutdatedContextWithOverflow': [PASS, ['mode == debug', FAIL]], + 'test-serialize/PerIsolateSnapshotBlobsWithLocker': [PASS, ['mode == debug', FAIL]], + 'test-serialize/SnapshotBlobsStackOverflow': [PASS, ['mode == debug', FAIL]], + 'test-serialize/PerIsolateSnapshotBlobs': [PASS, ['mode == debug', FAIL]], + 'test-serialize/SerializationMemoryStats': [PASS, ['mode == debug', FAIL]], + + # TODO(rmcilroy,4680): Test assert errors. + 'test-heap-profiler/HeapSnapshotSimd': [PASS, ['mode == debug', FAIL]], + 'test-api/InitializeDefaultIsolateOnSecondaryThread1': [PASS, ['mode == debug', FAIL]], +}], ] diff --git a/deps/v8/test/cctest/cctest_exe.isolate b/deps/v8/test/cctest/cctest_exe.isolate new file mode 100644 index 0000000000..da5327846e --- /dev/null +++ b/deps/v8/test/cctest/cctest_exe.isolate @@ -0,0 +1,13 @@ +# Copyright 2016 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. +{ + 'variables': { + 'files': [ + '<(PRODUCT_DIR)/cctest<(EXECUTABLE_SUFFIX)', + ], + }, + 'includes': [ + '../../src/base.isolate', + ], +} diff --git a/deps/v8/test/cctest/compiler/c-signature.h b/deps/v8/test/cctest/compiler/c-signature.h index 13ef38aaed..1c2f9638f4 100644 --- a/deps/v8/test/cctest/compiler/c-signature.h +++ b/deps/v8/test/cctest/compiler/c-signature.h @@ -53,16 +53,16 @@ class CSignature : public MachineSignature { public: template <typename P1 = void, typename P2 = void, typename P3 = void, typename P4 = void, typename P5 = void> - void VerifyParams() { + static void VerifyParams(MachineSignature* sig) { // Verifies the C signature against the machine types. Maximum {5} params. - CHECK_LT(parameter_count(), 6u); + CHECK_LT(sig->parameter_count(), 6u); const int kMax = 5; MachineType params[] = {MachineTypeForC<P1>(), MachineTypeForC<P2>(), MachineTypeForC<P3>(), MachineTypeForC<P4>(), MachineTypeForC<P5>()}; for (int p = kMax - 1; p >= 0; p--) { - if (p < static_cast<int>(parameter_count())) { - CHECK_EQ(GetParam(p), params[p]); + if (p < static_cast<int>(sig->parameter_count())) { + CHECK_EQ(sig->GetParam(p), params[p]); } else { CHECK_EQ(MachineType::None(), params[p]); } diff --git a/deps/v8/test/cctest/compiler/call-tester.h b/deps/v8/test/cctest/compiler/call-tester.h index e60f7172fa..8ee6b99f3b 100644 --- a/deps/v8/test/cctest/compiler/call-tester.h +++ b/deps/v8/test/cctest/compiler/call-tester.h @@ -119,7 +119,7 @@ struct ParameterTraits<uint32_t> { template <typename R> class CallHelper { public: - explicit CallHelper(Isolate* isolate, CSignature* csig) + explicit CallHelper(Isolate* isolate, MachineSignature* csig) : csig_(csig), isolate_(isolate) { USE(isolate_); } @@ -127,47 +127,47 @@ class CallHelper { R Call() { typedef R V8_CDECL FType(); - csig_->VerifyParams(); + CSignature::VerifyParams(csig_); return DoCall(FUNCTION_CAST<FType*>(Generate())); } template <typename P1> R Call(P1 p1) { typedef R V8_CDECL FType(P1); - csig_->VerifyParams<P1>(); + CSignature::VerifyParams<P1>(csig_); return DoCall(FUNCTION_CAST<FType*>(Generate()), p1); } template <typename P1, typename P2> R Call(P1 p1, P2 p2) { typedef R V8_CDECL FType(P1, P2); - csig_->VerifyParams<P1, P2>(); + CSignature::VerifyParams<P1, P2>(csig_); return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2); } template <typename P1, typename P2, typename P3> R Call(P1 p1, P2 p2, P3 p3) { typedef R V8_CDECL FType(P1, P2, P3); - csig_->VerifyParams<P1, P2, P3>(); + CSignature::VerifyParams<P1, P2, P3>(csig_); return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3); } template <typename P1, typename P2, typename P3, typename P4> R Call(P1 p1, P2 p2, P3 p3, P4 p4) { typedef R V8_CDECL FType(P1, P2, P3, P4); - csig_->VerifyParams<P1, P2, P3, P4>(); + CSignature::VerifyParams<P1, P2, P3, P4>(csig_); return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4); } template <typename P1, typename P2, typename P3, typename P4, typename P5> R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { typedef R V8_CDECL FType(P1, P2, P3, P4, P5); - csig_->VerifyParams<P1, P2, P3, P4, P5>(); + CSignature::VerifyParams<P1, P2, P3, P4, P5>(csig_); return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4, p5); } protected: - CSignature* csig_; + MachineSignature* csig_; virtual byte* Generate() = 0; @@ -342,7 +342,7 @@ class CallHelper { template <typename T> class CodeRunner : public CallHelper<T> { public: - CodeRunner(Isolate* isolate, Handle<Code> code, CSignature* csig) + CodeRunner(Isolate* isolate, Handle<Code> code, MachineSignature* csig) : CallHelper<T>(isolate, csig), code_(code) {} virtual ~CodeRunner() {} diff --git a/deps/v8/test/cctest/compiler/codegen-tester.h b/deps/v8/test/cctest/compiler/codegen-tester.h index 56e90c65b7..5d670bfee8 100644 --- a/deps/v8/test/cctest/compiler/codegen-tester.h +++ b/deps/v8/test/cctest/compiler/codegen-tester.h @@ -35,10 +35,13 @@ class RawMachineAssemblerTester : public HandleAndZoneScope, Linkage::GetSimplifiedCDescriptor( main_zone(), CSignature::New(main_zone(), MachineTypeForC<ReturnType>(), p0, - p1, p2, p3, p4)), + p1, p2, p3, p4), + true), MachineType::PointerRepresentation(), InstructionSelector::SupportedMachineOperatorFlags()) {} + virtual ~RawMachineAssemblerTester() {} + void CheckNumber(double expected, Object* number) { CHECK(this->isolate()->factory()->NewNumber(expected)->SameValue(number)); } @@ -85,6 +88,7 @@ class BufferedRawMachineAssemblerTester : BufferedRawMachineAssemblerTester(ComputeParameterCount(p0, p1, p2, p3), p0, p1, p2, p3) {} + virtual byte* Generate() { return RawMachineAssemblerTester::Generate(); } // The BufferedRawMachineAssemblerTester does not pass parameters directly // to the constructed IR graph. Instead it passes a pointer to the parameter @@ -92,11 +96,10 @@ class BufferedRawMachineAssemblerTester // parameters from memory. Thereby it is possible to pass 64 bit parameters // to the IR graph. Node* Parameter(size_t index) { - CHECK(index >= 0 && index < 4); + CHECK(index < 4); return parameter_nodes_[index]; } - // The BufferedRawMachineAssemblerTester adds a Store node to the IR graph // to store the graph's return value in memory. The memory address for the // Store node is provided as a parameter. By storing the return value in @@ -110,7 +113,7 @@ class BufferedRawMachineAssemblerTester ReturnType Call() { ReturnType return_value; - test_graph_signature_->VerifyParams(); + CSignature::VerifyParams(test_graph_signature_); CallHelper<int32_t>::Call(reinterpret_cast<void*>(&return_value)); return return_value; } @@ -118,7 +121,7 @@ class BufferedRawMachineAssemblerTester template <typename P0> ReturnType Call(P0 p0) { ReturnType return_value; - test_graph_signature_->VerifyParams<P0>(); + CSignature::VerifyParams<P0>(test_graph_signature_); CallHelper<int32_t>::Call(reinterpret_cast<void*>(&p0), reinterpret_cast<void*>(&return_value)); return return_value; @@ -127,7 +130,7 @@ class BufferedRawMachineAssemblerTester template <typename P0, typename P1> ReturnType Call(P0 p0, P1 p1) { ReturnType return_value; - test_graph_signature_->VerifyParams<P0, P1>(); + CSignature::VerifyParams<P0, P1>(test_graph_signature_); CallHelper<int32_t>::Call(reinterpret_cast<void*>(&p0), reinterpret_cast<void*>(&p1), reinterpret_cast<void*>(&return_value)); @@ -137,7 +140,7 @@ class BufferedRawMachineAssemblerTester template <typename P0, typename P1, typename P2> ReturnType Call(P0 p0, P1 p1, P2 p2) { ReturnType return_value; - test_graph_signature_->VerifyParams<P0, P1, P2>(); + CSignature::VerifyParams<P0, P1, P2>(test_graph_signature_); CallHelper<int32_t>::Call( reinterpret_cast<void*>(&p0), reinterpret_cast<void*>(&p1), reinterpret_cast<void*>(&p2), reinterpret_cast<void*>(&return_value)); @@ -147,7 +150,7 @@ class BufferedRawMachineAssemblerTester template <typename P0, typename P1, typename P2, typename P3> ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) { ReturnType return_value; - test_graph_signature_->VerifyParams<P0, P1, P2, P3>(); + CSignature::VerifyParams<P0, P1, P2, P3>(test_graph_signature_); CallHelper<int32_t>::Call( reinterpret_cast<void*>(&p0), reinterpret_cast<void*>(&p1), reinterpret_cast<void*>(&p2), reinterpret_cast<void*>(&p3), @@ -245,6 +248,7 @@ class BufferedRawMachineAssemblerTester<void> : Load(p3, RawMachineAssembler::Parameter(3)); } + virtual byte* Generate() { return RawMachineAssemblerTester::Generate(); } // The BufferedRawMachineAssemblerTester does not pass parameters directly // to the constructed IR graph. Instead it passes a pointer to the parameter @@ -258,26 +262,26 @@ class BufferedRawMachineAssemblerTester<void> void Call() { - test_graph_signature_->VerifyParams(); + CSignature::VerifyParams(test_graph_signature_); CallHelper<void>::Call(); } template <typename P0> void Call(P0 p0) { - test_graph_signature_->VerifyParams<P0>(); + CSignature::VerifyParams<P0>(test_graph_signature_); CallHelper<void>::Call(reinterpret_cast<void*>(&p0)); } template <typename P0, typename P1> void Call(P0 p0, P1 p1) { - test_graph_signature_->VerifyParams<P0, P1>(); + CSignature::VerifyParams<P0, P1>(test_graph_signature_); CallHelper<void>::Call(reinterpret_cast<void*>(&p0), reinterpret_cast<void*>(&p1)); } template <typename P0, typename P1, typename P2> void Call(P0 p0, P1 p1, P2 p2) { - test_graph_signature_->VerifyParams<P0, P1, P2>(); + CSignature::VerifyParams<P0, P1, P2>(test_graph_signature_); CallHelper<void>::Call(reinterpret_cast<void*>(&p0), reinterpret_cast<void*>(&p1), reinterpret_cast<void*>(&p2)); @@ -285,7 +289,7 @@ class BufferedRawMachineAssemblerTester<void> template <typename P0, typename P1, typename P2, typename P3> void Call(P0 p0, P1 p1, P2 p2, P3 p3) { - test_graph_signature_->VerifyParams<P0, P1, P2, P3>(); + CSignature::VerifyParams<P0, P1, P2, P3>(test_graph_signature_); CallHelper<void>::Call( reinterpret_cast<void*>(&p0), reinterpret_cast<void*>(&p1), reinterpret_cast<void*>(&p2), reinterpret_cast<void*>(&p3)); @@ -397,7 +401,6 @@ class Uint32BinopTester : public BinopTester<uint32_t, USE_RETURN_REGISTER> { // A helper class for testing code sequences that take two float parameters and // return a float value. -// TODO(titzer): figure out how to return floats correctly on ia32. class Float32BinopTester : public BinopTester<float, USE_RESULT_BUFFER> { public: explicit Float32BinopTester(RawMachineAssemblerTester<int32_t>* tester) @@ -407,7 +410,6 @@ class Float32BinopTester : public BinopTester<float, USE_RESULT_BUFFER> { // A helper class for testing code sequences that take two double parameters and // return a double value. -// TODO(titzer): figure out how to return doubles correctly on ia32. class Float64BinopTester : public BinopTester<double, USE_RESULT_BUFFER> { public: explicit Float64BinopTester(RawMachineAssemblerTester<int32_t>* tester) @@ -524,7 +526,8 @@ class BinopGen { // and run the generated code to ensure it produces the correct results. class Int32BinopInputShapeTester { public: - explicit Int32BinopInputShapeTester(BinopGen<int32_t>* g) : gen(g) {} + explicit Int32BinopInputShapeTester(BinopGen<int32_t>* g) + : gen(g), input_a(0), input_b(0) {} void TestAllInputShapes(); @@ -537,24 +540,6 @@ class Int32BinopInputShapeTester { void RunLeft(RawMachineAssemblerTester<int32_t>* m); void RunRight(RawMachineAssemblerTester<int32_t>* m); }; - -// TODO(bmeurer): Drop this crap once we switch to GTest/Gmock. -static inline void CheckFloatEq(volatile float x, volatile float y) { - if (std::isnan(x)) { - CHECK(std::isnan(y)); - } else { - CHECK_EQ(x, y); - } -} - -static inline void CheckDoubleEq(volatile double x, volatile double y) { - if (std::isnan(x)) { - CHECK(std::isnan(y)); - } else { - CHECK_EQ(x, y); - } -} - } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/compiler/function-tester.h b/deps/v8/test/cctest/compiler/function-tester.h index 2fcd35398c..c6093ce6e4 100644 --- a/deps/v8/test/cctest/compiler/function-tester.h +++ b/deps/v8/test/cctest/compiler/function-tester.h @@ -162,15 +162,26 @@ class FunctionTester : public InitializedHandleScope { Handle<Object> false_value() { return isolate->factory()->false_value(); } + static Handle<JSFunction> ForMachineGraph(Graph* graph, int param_count) { + JSFunction* p = NULL; + { // because of the implicit handle scope of FunctionTester. + FunctionTester f(graph, param_count); + p = *f.function; + } + return Handle<JSFunction>(p); // allocated in outer handle scope. + } + + private: + uint32_t flags_; + Handle<JSFunction> Compile(Handle<JSFunction> function) { -// TODO(titzer): make this method private. Zone zone; ParseInfo parse_info(&zone, function); CompilationInfo info(&parse_info); info.MarkAsDeoptimizationEnabled(); CHECK(Parser::ParseStatic(info.parse_info())); - info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code())); + info.SetOptimizing(); if (flags_ & CompilationInfo::kFunctionContextSpecializing) { info.MarkAsFunctionContextSpecializing(); } @@ -192,26 +203,13 @@ class FunctionTester : public InitializedHandleScope { return function; } - static Handle<JSFunction> ForMachineGraph(Graph* graph, int param_count) { - JSFunction* p = NULL; - { // because of the implicit handle scope of FunctionTester. - FunctionTester f(graph, param_count); - p = *f.function; - } - return Handle<JSFunction>(p); // allocated in outer handle scope. - } - - private: - uint32_t flags_; - std::string BuildFunction(int param_count) { std::string function_string = "(function("; if (param_count > 0) { - char next = 'a'; - function_string += next; - while (param_count-- > 0) { + function_string += 'a'; + for (int i = 1; i < param_count; i++) { function_string += ','; - function_string += ++next; + function_string += static_cast<char>('a' + i); } } function_string += "){})"; @@ -231,8 +229,7 @@ class FunctionTester : public InitializedHandleScope { CompilationInfo info(&parse_info); CHECK(Parser::ParseStatic(info.parse_info())); - info.SetOptimizing(BailoutId::None(), - Handle<Code>(function->shared()->code())); + info.SetOptimizing(); CHECK(Compiler::Analyze(info.parse_info())); CHECK(Compiler::EnsureDeoptimizationSupport(&info)); diff --git a/deps/v8/test/cctest/compiler/test-code-stub-assembler.cc b/deps/v8/test/cctest/compiler/test-code-stub-assembler.cc index d7a7a8198a..0306561020 100644 --- a/deps/v8/test/cctest/compiler/test-code-stub-assembler.cc +++ b/deps/v8/test/cctest/compiler/test-code-stub-assembler.cc @@ -16,7 +16,7 @@ class CodeStubAssemblerTester : public CodeStubAssembler { CodeStubAssemblerTester(Isolate* isolate, const CallInterfaceDescriptor& descriptor) : CodeStubAssembler(isolate, isolate->runtime_zone(), descriptor, - Code::STUB, "test"), + Code::ComputeFlags(Code::STUB), "test"), scope_(isolate) {} private: @@ -120,6 +120,133 @@ TEST(SimpleTailCallRuntime2Arg) { CHECK_EQ(16, Handle<Smi>::cast(result.ToHandleChecked())->value()); } +TEST(VariableMerge1) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); + CodeStubAssembler::Label l1(&m), l2(&m), merge(&m); + Node* temp = m.Int32Constant(0); + var1.Bind(temp); + m.Branch(m.Int32Constant(1), &l1, &l2); + m.Bind(&l1); + CHECK_EQ(var1.value(), temp); + m.Goto(&merge); + m.Bind(&l2); + CHECK_EQ(var1.value(), temp); + m.Goto(&merge); + m.Bind(&merge); + CHECK_EQ(var1.value(), temp); +} + +TEST(VariableMerge2) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); + CodeStubAssembler::Label l1(&m), l2(&m), merge(&m); + Node* temp = m.Int32Constant(0); + var1.Bind(temp); + m.Branch(m.Int32Constant(1), &l1, &l2); + m.Bind(&l1); + CHECK_EQ(var1.value(), temp); + m.Goto(&merge); + m.Bind(&l2); + Node* temp2 = m.Int32Constant(2); + var1.Bind(temp2); + CHECK_EQ(var1.value(), temp2); + m.Goto(&merge); + m.Bind(&merge); + CHECK_NE(var1.value(), temp); +} + +TEST(VariableMerge3) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); + CodeStubAssembler::Variable var2(&m, MachineRepresentation::kTagged); + CodeStubAssembler::Label l1(&m), l2(&m), merge(&m); + Node* temp = m.Int32Constant(0); + var1.Bind(temp); + var2.Bind(temp); + m.Branch(m.Int32Constant(1), &l1, &l2); + m.Bind(&l1); + CHECK_EQ(var1.value(), temp); + m.Goto(&merge); + m.Bind(&l2); + Node* temp2 = m.Int32Constant(2); + var1.Bind(temp2); + CHECK_EQ(var1.value(), temp2); + m.Goto(&merge); + m.Bind(&merge); + CHECK_NE(var1.value(), temp); + CHECK_NE(var1.value(), temp2); + CHECK_EQ(var2.value(), temp); +} + +TEST(VariableMergeBindFirst) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); + CodeStubAssembler::Label l1(&m), l2(&m), merge(&m, &var1), end(&m); + Node* temp = m.Int32Constant(0); + var1.Bind(temp); + m.Branch(m.Int32Constant(1), &l1, &l2); + m.Bind(&l1); + CHECK_EQ(var1.value(), temp); + m.Goto(&merge); + m.Bind(&merge); + CHECK(var1.value() != temp); + CHECK(var1.value() != nullptr); + m.Goto(&end); + m.Bind(&l2); + Node* temp2 = m.Int32Constant(2); + var1.Bind(temp2); + CHECK_EQ(var1.value(), temp2); + m.Goto(&merge); + m.Bind(&end); + CHECK(var1.value() != temp); + CHECK(var1.value() != nullptr); +} + +TEST(VariableMergeSwitch) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); + CodeStubAssembler::Label l1(&m), l2(&m), default_label(&m); + CodeStubAssembler::Label* labels[] = {&l1, &l2}; + int32_t values[] = {1, 2}; + Node* temp = m.Int32Constant(0); + var1.Bind(temp); + m.Switch(m.Int32Constant(2), &default_label, values, labels, 2); + m.Bind(&l1); + DCHECK_EQ(temp, var1.value()); + m.Return(temp); + m.Bind(&l2); + DCHECK_EQ(temp, var1.value()); + m.Return(temp); + m.Bind(&default_label); + DCHECK_EQ(temp, var1.value()); + m.Return(temp); +} + +TEST(FixedArrayAccessSmiIndex) { + Isolate* isolate(CcTest::InitIsolateOnce()); + VoidDescriptor descriptor(isolate); + CodeStubAssemblerTester m(isolate, descriptor); + Handle<FixedArray> array = isolate->factory()->NewFixedArray(5); + array->set(4, Smi::FromInt(733)); + m.Return(m.LoadFixedArrayElementSmiIndex(m.HeapConstant(array), + m.SmiTag(m.Int32Constant(4)))); + Handle<Code> code = m.GenerateCode(); + FunctionTester ft(descriptor, code); + MaybeHandle<Object> result = ft.Call(); + CHECK_EQ(733, Handle<Smi>::cast(result.ToHandleChecked())->value()); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/compiler/test-js-context-specialization.cc b/deps/v8/test/cctest/compiler/test-js-context-specialization.cc index 43b7665459..c7cd47a55c 100644 --- a/deps/v8/test/cctest/compiler/test-js-context-specialization.cc +++ b/deps/v8/test/cctest/compiler/test-js-context-specialization.cc @@ -225,8 +225,8 @@ TEST(SpecializeToContext) { t.graph()->NewNode(t.simplified()->ChangeTaggedToInt32(), other_load); Node* add = t.graph()->NewNode( - t.javascript()->Add(LanguageMode::SLOPPY, BinaryOperationHints::Any()), - value_use, other_use, param_context, t.jsgraph()->EmptyFrameState(), + t.javascript()->Add(BinaryOperationHints::Any()), value_use, other_use, + param_context, t.jsgraph()->EmptyFrameState(), t.jsgraph()->EmptyFrameState(), other_load, start); Node* ret = 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 c8b7734eb2..24db6a532e 100644 --- a/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc +++ b/deps/v8/test/cctest/compiler/test-js-typed-lowering.cc @@ -17,19 +17,6 @@ namespace v8 { namespace internal { namespace compiler { -#ifndef TEST_WITH_STRONG -#define TEST_WITH_STRONG(Name) \ - static void Test##Name(); \ - static void TestWithStrong##Name(LanguageMode language_mode); \ - CcTest register_test_##Name(Test##Name, __FILE__, #Name, NULL, true, true); \ - static void Test##Name() { \ - TestWithStrong##Name(LanguageMode::SLOPPY); \ - TestWithStrong##Name(LanguageMode::STRONG); \ - } \ - static void TestWithStrong##Name(LanguageMode language_mode) -#endif - - class JSTypedLoweringTester : public HandleAndZoneScope { public: explicit JSTypedLoweringTester(int num_parameters = 0) @@ -163,17 +150,8 @@ class JSTypedLoweringTester : public HandleAndZoneScope { } Node* UseForEffect(Node* node) { - // TODO(titzer): use EffectPhi after fixing EffectCount - if (OperatorProperties::GetFrameStateInputCount(javascript.ToNumber()) > - 0) { - CHECK_EQ(1, OperatorProperties::GetFrameStateInputCount( - javascript.ToNumber())); - return graph.NewNode(javascript.ToNumber(), node, context(), - EmptyFrameState(context()), node, control()); - } else { - return graph.NewNode(javascript.ToNumber(), node, context(), node, - control()); - } + Node* merge = graph.NewNode(common.Merge(1), start()); + return graph.NewNode(common.EffectPhi(1), node, merge); } void CheckEffectInput(Node* effect, Node* use) { @@ -240,7 +218,7 @@ static IrOpcode::Value NumberToI32(bool is_signed) { // TODO(turbofan): Lowering of StringAdd is disabled for now. #if 0 -TEST_WITH_STRONG(StringBinops) { +TEST(StringBinops) { JSTypedLoweringTester R; for (size_t i = 0; i < arraysize(kStringTypes); ++i) { @@ -249,7 +227,7 @@ TEST_WITH_STRONG(StringBinops) { for (size_t j = 0; j < arraysize(kStringTypes); ++j) { Node* p1 = R.Parameter(kStringTypes[j], 1); - Node* add = R.Binop(R.javascript.Add(language_mode), p0, p1); + Node* add = R.Binop(R.javascript.Add(), p0, p1); Node* r = R.reduce(add); R.CheckBinop(IrOpcode::kStringAdd, r); @@ -260,14 +238,12 @@ TEST_WITH_STRONG(StringBinops) { } #endif - -TEST_WITH_STRONG(AddNumber1) { +TEST(AddNumber1) { JSTypedLoweringTester R; for (size_t i = 0; i < arraysize(kNumberTypes); ++i) { Node* p0 = R.Parameter(kNumberTypes[i], 0); Node* p1 = R.Parameter(kNumberTypes[i], 1); - Node* add = R.Binop( - R.javascript.Add(language_mode, BinaryOperationHints::Any()), p0, p1); + Node* add = R.Binop(R.javascript.Add(BinaryOperationHints::Any()), p0, p1); Node* r = R.reduce(add); R.CheckBinop(IrOpcode::kNumberAdd, r); @@ -276,20 +252,14 @@ TEST_WITH_STRONG(AddNumber1) { } } - -TEST_WITH_STRONG(NumberBinops) { +TEST(NumberBinops) { JSTypedLoweringTester R; const Operator* ops[] = { - R.javascript.Add(language_mode, R.hints), - R.simplified.NumberAdd(), - R.javascript.Subtract(language_mode, R.hints), - R.simplified.NumberSubtract(), - R.javascript.Multiply(language_mode, R.hints), - R.simplified.NumberMultiply(), - R.javascript.Divide(language_mode, R.hints), - R.simplified.NumberDivide(), - R.javascript.Modulus(language_mode, R.hints), - R.simplified.NumberModulus(), + R.javascript.Add(R.hints), R.simplified.NumberAdd(), + R.javascript.Subtract(R.hints), R.simplified.NumberSubtract(), + R.javascript.Multiply(R.hints), R.simplified.NumberMultiply(), + R.javascript.Divide(R.hints), R.simplified.NumberDivide(), + R.javascript.Modulus(R.hints), R.simplified.NumberModulus(), }; for (size_t i = 0; i < arraysize(kNumberTypes); ++i) { @@ -329,14 +299,13 @@ static void CheckToI32(Node* old_input, Node* new_input, bool is_signed) { // A helper class for testing lowering of bitwise shift operators. class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester { public: - explicit JSBitwiseShiftTypedLoweringTester(LanguageMode language_mode) - : JSTypedLoweringTester(), language_mode_(language_mode) { + JSBitwiseShiftTypedLoweringTester() : JSTypedLoweringTester() { int i = 0; - set(i++, javascript.ShiftLeft(language_mode_, hints), true); + set(i++, javascript.ShiftLeft(hints), true); set(i++, simplified.NumberShiftLeft(), false); - set(i++, javascript.ShiftRight(language_mode_, hints), true); + set(i++, javascript.ShiftRight(hints), true); set(i++, simplified.NumberShiftRight(), false); - set(i++, javascript.ShiftRightLogical(language_mode_, hints), false); + set(i++, javascript.ShiftRightLogical(hints), false); set(i++, simplified.NumberShiftRightLogical(), false); } static const int kNumberOps = 6; @@ -344,7 +313,6 @@ class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester { bool signedness[kNumberOps]; private: - LanguageMode language_mode_; void set(int idx, const Operator* op, bool s) { ops[idx] = op; signedness[idx] = s; @@ -353,7 +321,7 @@ class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester { TEST(Int32BitwiseShifts) { - JSBitwiseShiftTypedLoweringTester R(LanguageMode::SLOPPY); + JSBitwiseShiftTypedLoweringTester R; Type* types[] = { Type::SignedSmall(), Type::UnsignedSmall(), Type::Negative32(), @@ -387,14 +355,13 @@ TEST(Int32BitwiseShifts) { // A helper class for testing lowering of bitwise operators. class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester { public: - explicit JSBitwiseTypedLoweringTester(LanguageMode language_mode) - : JSTypedLoweringTester(), language_mode_(language_mode) { + JSBitwiseTypedLoweringTester() : JSTypedLoweringTester() { int i = 0; - set(i++, javascript.BitwiseOr(language_mode_, hints), true); + set(i++, javascript.BitwiseOr(hints), true); set(i++, simplified.NumberBitwiseOr(), true); - set(i++, javascript.BitwiseXor(language_mode_, hints), true); + set(i++, javascript.BitwiseXor(hints), true); set(i++, simplified.NumberBitwiseXor(), true); - set(i++, javascript.BitwiseAnd(language_mode_, hints), true); + set(i++, javascript.BitwiseAnd(hints), true); set(i++, simplified.NumberBitwiseAnd(), true); } static const int kNumberOps = 6; @@ -402,7 +369,6 @@ class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester { bool signedness[kNumberOps]; private: - LanguageMode language_mode_; void set(int idx, const Operator* op, bool s) { ops[idx] = op; signedness[idx] = s; @@ -411,7 +377,7 @@ class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester { TEST(Int32BitwiseBinops) { - JSBitwiseTypedLoweringTester R(LanguageMode::SLOPPY); + JSBitwiseTypedLoweringTester R; Type* types[] = { Type::SignedSmall(), Type::UnsignedSmall(), Type::Unsigned32(), @@ -558,7 +524,6 @@ TEST(JSToString1) { { // ToString(number) Node* r = R.ReduceUnop(op, Type::Number()); - // TODO(titzer): could remove effects CHECK_EQ(IrOpcode::kJSToString, r->opcode()); } @@ -602,17 +567,14 @@ TEST(JSToString_replacement) { } } - -TEST_WITH_STRONG(StringComparison) { +TEST(StringComparison) { JSTypedLoweringTester R; const Operator* ops[] = { - R.javascript.LessThan(language_mode), R.simplified.StringLessThan(), - R.javascript.LessThanOrEqual(language_mode), - R.simplified.StringLessThanOrEqual(), - R.javascript.GreaterThan(language_mode), R.simplified.StringLessThan(), - R.javascript.GreaterThanOrEqual(language_mode), - R.simplified.StringLessThanOrEqual()}; + R.javascript.LessThan(), R.simplified.StringLessThan(), + R.javascript.LessThanOrEqual(), R.simplified.StringLessThanOrEqual(), + R.javascript.GreaterThan(), R.simplified.StringLessThan(), + R.javascript.GreaterThanOrEqual(), R.simplified.StringLessThanOrEqual()}; for (size_t i = 0; i < arraysize(kStringTypes); i++) { Node* p0 = R.Parameter(kStringTypes[i], 0); @@ -652,17 +614,14 @@ static void CheckIsConvertedToNumber(Node* val, Node* converted) { } } - -TEST_WITH_STRONG(NumberComparison) { +TEST(NumberComparison) { JSTypedLoweringTester R; const Operator* ops[] = { - R.javascript.LessThan(language_mode), R.simplified.NumberLessThan(), - R.javascript.LessThanOrEqual(language_mode), - R.simplified.NumberLessThanOrEqual(), - R.javascript.GreaterThan(language_mode), R.simplified.NumberLessThan(), - R.javascript.GreaterThanOrEqual(language_mode), - R.simplified.NumberLessThanOrEqual()}; + R.javascript.LessThan(), R.simplified.NumberLessThan(), + R.javascript.LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), + R.javascript.GreaterThan(), R.simplified.NumberLessThan(), + R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual()}; Node* const p0 = R.Parameter(Type::Number(), 0); Node* const p1 = R.Parameter(Type::Number(), 1); @@ -684,8 +643,7 @@ TEST_WITH_STRONG(NumberComparison) { } } - -TEST_WITH_STRONG(MixedComparison1) { +TEST(MixedComparison1) { JSTypedLoweringTester R; Type* types[] = {Type::Number(), Type::String(), @@ -697,16 +655,15 @@ TEST_WITH_STRONG(MixedComparison1) { for (size_t j = 0; j < arraysize(types); j++) { Node* p1 = R.Parameter(types[j], 1); { - const Operator* less_than = R.javascript.LessThan(language_mode); + const Operator* less_than = R.javascript.LessThan(); Node* cmp = R.Binop(less_than, p0, p1); Node* r = R.reduce(cmp); if (types[i]->Is(Type::String()) && types[j]->Is(Type::String())) { R.CheckBinop(R.simplified.StringLessThan(), r); } else if ((types[i]->Is(Type::Number()) && types[j]->Is(Type::Number())) || - (!is_strong(language_mode) && - (!types[i]->Maybe(Type::String()) || - !types[j]->Maybe(Type::String())))) { + (!types[i]->Maybe(Type::String()) || + !types[j]->Maybe(Type::String()))) { R.CheckBinop(R.simplified.NumberLessThan(), r); } else { // No reduction of mixed types. @@ -717,8 +674,7 @@ TEST_WITH_STRONG(MixedComparison1) { } } - -TEST_WITH_STRONG(RemoveToNumberEffects) { +TEST(RemoveToNumberEffects) { JSTypedLoweringTester R; Node* effect_use = NULL; @@ -744,14 +700,14 @@ TEST_WITH_STRONG(RemoveToNumberEffects) { case 2: effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start()); case 3: - effect_use = R.graph.NewNode(R.javascript.Add(language_mode, R.hints), - ton, ton, R.context(), frame_state, - frame_state, ton, R.start()); + effect_use = + R.graph.NewNode(R.javascript.Add(R.hints), ton, ton, R.context(), + frame_state, frame_state, ton, R.start()); break; case 4: - effect_use = R.graph.NewNode(R.javascript.Add(language_mode, R.hints), - p0, p0, R.context(), frame_state, - frame_state, ton, R.start()); + effect_use = + R.graph.NewNode(R.javascript.Add(R.hints), p0, p0, R.context(), + frame_state, frame_state, ton, R.start()); break; case 5: effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start()); @@ -896,9 +852,16 @@ TEST(StrictEqualityForRefEqualTypes) { Node* p1 = R.Parameter(types[i]); CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kReferenceEqual); } - // TODO(titzer): Equal(RefEqualTypes) } +TEST(StrictEqualityForUnique) { + JSTypedLoweringTester R; + + Node* p0 = R.Parameter(Type::Unique()); + Node* p1 = R.Parameter(Type::Unique()); + CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kReferenceEqual); + CheckEqualityReduction(&R, true, p1, p0, IrOpcode::kReferenceEqual); +} TEST(StringEquality) { JSTypedLoweringTester R; @@ -909,27 +872,18 @@ TEST(StringEquality) { CheckEqualityReduction(&R, false, p0, p1, IrOpcode::kStringEqual); } - -TEST_WITH_STRONG(RemovePureNumberBinopEffects) { +TEST(RemovePureNumberBinopEffects) { JSTypedLoweringTester R; const Operator* ops[] = { - R.javascript.Equal(), - R.simplified.NumberEqual(), - R.javascript.Add(language_mode, R.hints), - R.simplified.NumberAdd(), - R.javascript.Subtract(language_mode, R.hints), - R.simplified.NumberSubtract(), - R.javascript.Multiply(language_mode, R.hints), - R.simplified.NumberMultiply(), - R.javascript.Divide(language_mode, R.hints), - R.simplified.NumberDivide(), - R.javascript.Modulus(language_mode, R.hints), - R.simplified.NumberModulus(), - R.javascript.LessThan(language_mode), - R.simplified.NumberLessThan(), - R.javascript.LessThanOrEqual(language_mode), - R.simplified.NumberLessThanOrEqual(), + R.javascript.Equal(), R.simplified.NumberEqual(), + R.javascript.Add(R.hints), R.simplified.NumberAdd(), + R.javascript.Subtract(R.hints), R.simplified.NumberSubtract(), + R.javascript.Multiply(R.hints), R.simplified.NumberMultiply(), + R.javascript.Divide(R.hints), R.simplified.NumberDivide(), + R.javascript.Modulus(R.hints), R.simplified.NumberModulus(), + R.javascript.LessThan(), R.simplified.NumberLessThan(), + R.javascript.LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), }; for (size_t j = 0; j < arraysize(ops); j += 2) { @@ -950,12 +904,9 @@ TEST(OrderNumberBinopEffects1) { JSTypedLoweringTester R; const Operator* ops[] = { - R.javascript.Subtract(LanguageMode::SLOPPY, R.hints), - R.simplified.NumberSubtract(), - R.javascript.Multiply(LanguageMode::SLOPPY, R.hints), - R.simplified.NumberMultiply(), - R.javascript.Divide(LanguageMode::SLOPPY, R.hints), - R.simplified.NumberDivide(), + R.javascript.Subtract(R.hints), R.simplified.NumberSubtract(), + R.javascript.Multiply(R.hints), R.simplified.NumberMultiply(), + R.javascript.Divide(R.hints), R.simplified.NumberDivide(), }; for (size_t j = 0; j < arraysize(ops); j += 2) { @@ -978,14 +929,10 @@ TEST(OrderNumberBinopEffects2) { JSTypedLoweringTester R; const Operator* ops[] = { - R.javascript.Add(LanguageMode::SLOPPY, R.hints), - R.simplified.NumberAdd(), - R.javascript.Subtract(LanguageMode::SLOPPY, R.hints), - R.simplified.NumberSubtract(), - R.javascript.Multiply(LanguageMode::SLOPPY, R.hints), - R.simplified.NumberMultiply(), - R.javascript.Divide(LanguageMode::SLOPPY, R.hints), - R.simplified.NumberDivide(), + R.javascript.Add(R.hints), R.simplified.NumberAdd(), + R.javascript.Subtract(R.hints), R.simplified.NumberSubtract(), + R.javascript.Multiply(R.hints), R.simplified.NumberMultiply(), + R.javascript.Divide(R.hints), R.simplified.NumberDivide(), }; for (size_t j = 0; j < arraysize(ops); j += 2) { @@ -1020,10 +967,8 @@ TEST(OrderCompareEffects) { JSTypedLoweringTester R; const Operator* ops[] = { - R.javascript.GreaterThan(LanguageMode::SLOPPY), - R.simplified.NumberLessThan(), - R.javascript.GreaterThanOrEqual(LanguageMode::SLOPPY), - R.simplified.NumberLessThanOrEqual(), + R.javascript.GreaterThan(), R.simplified.NumberLessThan(), + R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual(), }; for (size_t j = 0; j < arraysize(ops); j += 2) { @@ -1070,7 +1015,7 @@ TEST(OrderCompareEffects) { TEST(Int32BinopEffects) { - JSBitwiseTypedLoweringTester R(LanguageMode::SLOPPY); + JSBitwiseTypedLoweringTester R; for (int j = 0; j < R.kNumberOps; j += 2) { bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1]; BinopEffectsTester B(R.ops[j], I32Type(signed_left), I32Type(signed_right)); @@ -1150,10 +1095,9 @@ TEST(Int32BinopEffects) { } } - -TEST_WITH_STRONG(Int32AddNarrowing) { +TEST(Int32AddNarrowing) { { - JSBitwiseTypedLoweringTester R(language_mode); + JSBitwiseTypedLoweringTester R; for (int o = 0; o < R.kNumberOps; o += 2) { for (size_t i = 0; i < arraysize(kInt32Types); i++) { @@ -1176,7 +1120,7 @@ TEST_WITH_STRONG(Int32AddNarrowing) { } } { - JSBitwiseShiftTypedLoweringTester R(language_mode); + JSBitwiseShiftTypedLoweringTester R; for (int o = 0; o < R.kNumberOps; o += 2) { for (size_t i = 0; i < arraysize(kInt32Types); i++) { @@ -1199,7 +1143,7 @@ TEST_WITH_STRONG(Int32AddNarrowing) { } } { - JSBitwiseTypedLoweringTester R(language_mode); + JSBitwiseTypedLoweringTester R; for (int o = 0; o < R.kNumberOps; o += 2) { Node* n0 = R.Parameter(I32Type(R.signedness[o])); @@ -1222,8 +1166,7 @@ TEST_WITH_STRONG(Int32AddNarrowing) { } } - -TEST_WITH_STRONG(Int32Comparisons) { +TEST(Int32Comparisons) { JSTypedLoweringTester R; struct Entry { @@ -1235,17 +1178,16 @@ TEST_WITH_STRONG(Int32Comparisons) { }; Entry ops[] = { - {R.javascript.LessThan(language_mode), R.machine.Uint32LessThan(), + {R.javascript.LessThan(), R.machine.Uint32LessThan(), R.machine.Int32LessThan(), R.simplified.NumberLessThan(), false}, - {R.javascript.LessThanOrEqual(language_mode), - R.machine.Uint32LessThanOrEqual(), R.machine.Int32LessThanOrEqual(), - R.simplified.NumberLessThanOrEqual(), false}, - {R.javascript.GreaterThan(language_mode), R.machine.Uint32LessThan(), + {R.javascript.LessThanOrEqual(), R.machine.Uint32LessThanOrEqual(), + R.machine.Int32LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), + false}, + {R.javascript.GreaterThan(), R.machine.Uint32LessThan(), R.machine.Int32LessThan(), R.simplified.NumberLessThan(), true}, - {R.javascript.GreaterThanOrEqual(language_mode), - R.machine.Uint32LessThanOrEqual(), R.machine.Int32LessThanOrEqual(), - R.simplified.NumberLessThanOrEqual(), true} - }; + {R.javascript.GreaterThanOrEqual(), R.machine.Uint32LessThanOrEqual(), + R.machine.Int32LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), + true}}; for (size_t o = 0; o < arraysize(ops); o++) { for (size_t i = 0; i < arraysize(kNumberTypes); i++) { diff --git a/deps/v8/test/cctest/compiler/test-jump-threading.cc b/deps/v8/test/cctest/compiler/test-jump-threading.cc index 8c02012e0a..71f774f562 100644 --- a/deps/v8/test/cctest/compiler/test-jump-threading.cc +++ b/deps/v8/test/cctest/compiler/test-jump-threading.cc @@ -108,7 +108,7 @@ class TestCode : public HandleAndZoneScope { void VerifyForwarding(TestCode& code, int count, int* expected) { Zone local_zone; ZoneVector<RpoNumber> result(&local_zone); - JumpThreading::ComputeForwarding(&local_zone, result, &code.sequence_); + JumpThreading::ComputeForwarding(&local_zone, result, &code.sequence_, true); CHECK(count == static_cast<int>(result.size())); for (int i = 0; i < count; i++) { diff --git a/deps/v8/test/cctest/compiler/test-linkage.cc b/deps/v8/test/cctest/compiler/test-linkage.cc index 939b144731..6722f59d60 100644 --- a/deps/v8/test/cctest/compiler/test-linkage.cc +++ b/deps/v8/test/cctest/compiler/test-linkage.cc @@ -71,20 +71,6 @@ TEST(TestLinkageJSFunctionIncoming) { } -TEST(TestLinkageCodeStubIncoming) { - Isolate* isolate = CcTest::InitIsolateOnce(); - Zone zone; - ToNumberStub stub(isolate); - CompilationInfo info(&stub, isolate, &zone); - CallDescriptor* descriptor = Linkage::ComputeIncoming(&zone, &info); - CHECK(descriptor); - CHECK_EQ(0, static_cast<int>(descriptor->StackParameterCount())); - CHECK_EQ(1, static_cast<int>(descriptor->ReturnCount())); - CHECK_EQ(Operator::kNoProperties, descriptor->properties()); - CHECK_EQ(false, descriptor->IsJSFunctionCall()); -} - - TEST(TestLinkageJSCall) { HandleAndZoneScope handles; Handle<JSFunction> function = Compile("a + c"); @@ -109,6 +95,20 @@ TEST(TestLinkageRuntimeCall) { TEST(TestLinkageStubCall) { + Isolate* isolate = CcTest::InitIsolateOnce(); + Zone zone; + ToNumberStub stub(isolate); + CompilationInfo info("test", isolate, &zone, Code::ComputeFlags(Code::STUB)); + CallInterfaceDescriptor interface_descriptor = + stub.GetCallInterfaceDescriptor(); + CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( + isolate, &zone, interface_descriptor, stub.GetStackParameterCount(), + CallDescriptor::kNoFlags, Operator::kNoProperties); + CHECK(descriptor); + CHECK_EQ(0, static_cast<int>(descriptor->StackParameterCount())); + CHECK_EQ(1, static_cast<int>(descriptor->ReturnCount())); + CHECK_EQ(Operator::kNoProperties, descriptor->properties()); + CHECK_EQ(false, descriptor->IsJSFunctionCall()); // TODO(titzer): test linkage creation for outgoing stub calls. } diff --git a/deps/v8/test/cctest/compiler/test-pipeline.cc b/deps/v8/test/cctest/compiler/test-pipeline.cc index f4ffd02296..35e342765b 100644 --- a/deps/v8/test/cctest/compiler/test-pipeline.cc +++ b/deps/v8/test/cctest/compiler/test-pipeline.cc @@ -18,7 +18,7 @@ static void RunPipeline(Zone* zone, const char* source) { ParseInfo parse_info(zone, function); CHECK(Compiler::ParseAndAnalyze(&parse_info)); CompilationInfo info(&parse_info); - info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code())); + info.SetOptimizing(); Pipeline pipeline(&info); Handle<Code> code = pipeline.GenerateCode(); diff --git a/deps/v8/test/cctest/compiler/test-run-bytecode-graph-builder.cc b/deps/v8/test/cctest/compiler/test-run-bytecode-graph-builder.cc index 88555b7d57..9a038221a1 100644 --- a/deps/v8/test/cctest/compiler/test-run-bytecode-graph-builder.cc +++ b/deps/v8/test/cctest/compiler/test-run-bytecode-graph-builder.cc @@ -16,6 +16,14 @@ namespace v8 { namespace internal { namespace compiler { +#define SHARD_TEST_BY_2(x) \ + TEST(x##_0) { Test##x(0); } \ + TEST(x##_1) { Test##x(1); } +#define SHARD_TEST_BY_4(x) \ + TEST(x##_0) { Test##x(0); } \ + TEST(x##_1) { Test##x(1); } \ + TEST(x##_2) { Test##x(2); } \ + TEST(x##_3) { Test##x(3); } static const char kFunctionName[] = "f"; @@ -70,7 +78,7 @@ class BytecodeGraphTester { i::FLAG_ignition = true; i::FLAG_always_opt = false; i::FLAG_allow_natives_syntax = true; - i::FLAG_ignition_fallback_on_eval_and_catch = false; + i::FLAG_loop_assignment_analysis = false; // Set ignition filter flag via SetFlagsFromString to avoid double-free // (or potential leak with StrDup() based on ownership confusion). ScopedVector<char> ignition_filter(64); @@ -119,13 +127,13 @@ class BytecodeGraphTester { Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function)); CHECK(function->shared()->HasBytecodeArray()); + // TODO(mstarzinger): We should be able to prime CompilationInfo without + // having to instantiate a ParseInfo first. Fix this! ParseInfo parse_info(zone_, function); CompilationInfo compilation_info(&parse_info); - compilation_info.SetOptimizing(BailoutId::None(), Handle<Code>()); + compilation_info.SetOptimizing(); compilation_info.MarkAsDeoptimizationEnabled(); - // TODO(mythria): Remove this step once parse_info is not needed. - CHECK(Compiler::ParseAndAnalyze(&parse_info)); compiler::Pipeline pipeline(&compilation_info); Handle<Code> code = pipeline.GenerateCode(); function->ReplaceCode(*code); @@ -205,8 +213,7 @@ TEST(BytecodeGraphBuilderReturnStatements) { {"return 'catfood';", {factory->NewStringFromStaticChars("catfood")}}, {"return NaN;", {factory->nan_value()}}}; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -233,8 +240,7 @@ TEST(BytecodeGraphBuilderPrimitiveExpressions) { {"return 25 % 7;", {factory->NewNumberFromInt(4)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -292,8 +298,7 @@ TEST(BytecodeGraphBuilderTwoParameterTests) { factory->NewStringFromStaticChars("abc"), factory->NewStringFromStaticChars("def")}}}; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1, p2) { %s }\n%s(0, 0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -337,8 +342,7 @@ TEST(BytecodeGraphBuilderNamedLoad) { BytecodeGraphTester::NewObject("({ name : 'abc'})")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(2048); SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -394,8 +398,7 @@ TEST(BytecodeGraphBuilderKeyedLoad) { factory->NewNumberFromInt(100)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(2048); SNPrintF(script, "function %s(p1, p2) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -409,8 +412,7 @@ TEST(BytecodeGraphBuilderKeyedLoad) { } } - -TEST(BytecodeGraphBuilderNamedStore) { +void TestBytecodeGraphBuilderNamedStore(size_t shard) { HandleAndZoneScope scope; Isolate* isolate = scope.main_isolate(); Zone* zone = scope.main_zone(); @@ -445,8 +447,8 @@ TEST(BytecodeGraphBuilderNamedStore) { BytecodeGraphTester::NewObject("({ name : 'abc'})")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { + if ((i % 2) != shard) continue; ScopedVector<char> script(3072); SNPrintF(script, "function %s(p1) { %s };\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -459,8 +461,9 @@ TEST(BytecodeGraphBuilderNamedStore) { } } +SHARD_TEST_BY_2(BytecodeGraphBuilderNamedStore) -TEST(BytecodeGraphBuilderKeyedStore) { +void TestBytecodeGraphBuilderKeyedStore(size_t shard) { HandleAndZoneScope scope; Isolate* isolate = scope.main_isolate(); Zone* zone = scope.main_zone(); @@ -503,8 +506,8 @@ TEST(BytecodeGraphBuilderKeyedStore) { factory->NewNumberFromInt(100)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { + if ((i % 2) != shard) continue; ScopedVector<char> script(2048); SNPrintF(script, "function %s(p1, p2) { %s };\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -517,6 +520,7 @@ TEST(BytecodeGraphBuilderKeyedStore) { } } +SHARD_TEST_BY_2(BytecodeGraphBuilderKeyedStore) TEST(BytecodeGraphBuilderPropertyCall) { HandleAndZoneScope scope; @@ -538,8 +542,7 @@ TEST(BytecodeGraphBuilderPropertyCall) { " return a + b + c + d + e + f + g + h;}})")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(2048); SNPrintF(script, "function %s(p1) { %s };\n%s({func() {}});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -582,8 +585,7 @@ TEST(BytecodeGraphBuilderCallNew) { {factory->NewNumberFromInt(25)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); auto callable = tester.GetCallable<>(); Handle<Object> return_value = callable().ToHandleChecked(); @@ -621,8 +623,7 @@ TEST(BytecodeGraphBuilderCreateClosure) { {factory->NewNumberFromInt(25)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); auto callable = tester.GetCallable<>(); Handle<Object> return_value = callable().ToHandleChecked(); @@ -649,8 +650,7 @@ TEST(BytecodeGraphBuilderCallRuntime) { BytecodeGraphTester::NewObject("[1, 2, 3]")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); auto callable = tester.GetCallable<Handle<Object>>(); Handle<Object> return_value = @@ -659,8 +659,7 @@ TEST(BytecodeGraphBuilderCallRuntime) { } } - -TEST(BytecodeGraphBuilderGlobals) { +void TestBytecodeGraphBuilderGlobals(size_t shard) { HandleAndZoneScope scope; Isolate* isolate = scope.main_isolate(); Zone* zone = scope.main_zone(); @@ -700,8 +699,8 @@ TEST(BytecodeGraphBuilderGlobals) { {factory->NewStringFromStaticChars("number")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { + if ((i % 2) != shard) continue; BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); auto callable = tester.GetCallable<>(); Handle<Object> return_value = callable().ToHandleChecked(); @@ -709,6 +708,7 @@ TEST(BytecodeGraphBuilderGlobals) { } } +SHARD_TEST_BY_2(BytecodeGraphBuilderGlobals) TEST(BytecodeGraphBuilderToObject) { // TODO(mythria): tests for ToObject. Needs ForIn. @@ -746,8 +746,7 @@ TEST(BytecodeGraphBuilderToName) { {factory->NewNumberFromInt(10)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s() { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -778,8 +777,7 @@ TEST(BytecodeGraphBuilderLogicalNot) { {factory->false_value(), factory->NewStringFromStaticChars("abc")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -816,8 +814,7 @@ TEST(BytecodeGraphBuilderTypeOf) { factory->NewStringFromStaticChars("abc")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -871,8 +868,7 @@ TEST(BytecodeGraphBuilderCountOperation) { {factory->nan_value(), factory->NewStringFromStaticChars("String")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -911,8 +907,7 @@ TEST(BytecodeGraphBuilderDelete) { BytecodeGraphTester::NewObject("({val : 10, name:'abc'})")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -966,8 +961,7 @@ TEST(BytecodeGraphBuilderDeleteGlobal) { {factory->true_value()}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s %s({});", snippets[i].code_snippet, kFunctionName); @@ -1003,8 +997,7 @@ TEST(BytecodeGraphBuilderDeleteLookupSlot) { {"return delete z;", {factory->false_value()}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet, function_epilogue); @@ -1045,8 +1038,7 @@ TEST(BytecodeGraphBuilderLookupSlot) { {"'use strict'; obj.val = 23.456; return obj.val;", {factory->NewNumber(23.456)}}}; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet, function_epilogue); @@ -1089,8 +1081,7 @@ TEST(BytecodeGraphBuilderLookupSlotWide) { {"'use strict';" REPEAT_256(SPACE, "y = 2.3;") "return obj.val = 23.456;", {factory->NewNumber(23.456)}}}; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(3072); SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet, function_epilogue); @@ -1120,8 +1111,7 @@ TEST(BytecodeGraphBuilderCallLookupSlot) { {handle(Smi::FromInt(30), isolate)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1173,8 +1163,7 @@ TEST(BytecodeGraphBuilderEval) { {factory->NewStringFromStaticChars("object")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1202,8 +1191,7 @@ TEST(BytecodeGraphBuilderEvalParams) { {handle(Smi::FromInt(30), isolate), handle(Smi::FromInt(20), isolate)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1) { %s }\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1234,8 +1222,7 @@ TEST(BytecodeGraphBuilderEvalGlobal) { {factory->NewStringFromStaticChars("undefined")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet); auto callable = tester.GetCallable<>(); Handle<Object> return_value = callable().ToHandleChecked(); @@ -1366,8 +1353,7 @@ TEST(BytecodeGraphBuilderTestIn) { factory->NewNumberFromInt(1)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1, p2) { %s }\n%s({}, {});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1399,8 +1385,7 @@ TEST(BytecodeGraphBuilderTestInstanceOf) { {factory->true_value(), factory->undefined_value()}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1413,6 +1398,98 @@ TEST(BytecodeGraphBuilderTestInstanceOf) { } } +TEST(BytecodeGraphBuilderTryCatch) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0> snippets[] = { + {"var a = 1; try { a = 2 } catch(e) { a = 3 }; return a;", + {handle(Smi::FromInt(2), isolate)}}, + {"var a; try { undef.x } catch(e) { a = 2 }; return a;", + {handle(Smi::FromInt(2), isolate)}}, + {"var a; try { throw 1 } catch(e) { a = e + 2 }; return a;", + {handle(Smi::FromInt(3), isolate)}}, + {"var a; try { throw 1 } catch(e) { a = e + 2 };" + " try { throw a } catch(e) { a = e + 3 }; return a;", + {handle(Smi::FromInt(6), isolate)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} + +TEST(BytecodeGraphBuilderTryFinally1) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0> snippets[] = { + {"var a = 1; try { a = a + 1; } finally { a = a + 2; }; return a;", + {handle(Smi::FromInt(4), isolate)}}, + {"var a = 1; try { a = 2; return 23; } finally { a = 3 }; return a;", + {handle(Smi::FromInt(23), isolate)}}, + {"var a = 1; try { a = 2; throw 23; } finally { return a; };", + {handle(Smi::FromInt(2), isolate)}}, + {"var a = 1; for (var i = 10; i < 20; i += 5) {" + " try { a = 2; break; } finally { a = 3; }" + "} return a + i;", + {handle(Smi::FromInt(13), isolate)}}, + {"var a = 1; for (var i = 10; i < 20; i += 5) {" + " try { a = 2; continue; } finally { a = 3; }" + "} return a + i;", + {handle(Smi::FromInt(23), isolate)}}, + {"var a = 1; try { a = 2;" + " try { a = 3; throw 23; } finally { a = 4; }" + "} catch(e) { a = a + e; } return a;", + {handle(Smi::FromInt(27), isolate)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} + +TEST(BytecodeGraphBuilderTryFinally2) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0, const char*> snippets[] = { + {"var a = 1; try { a = 2; throw 23; } finally { a = 3 }; return a;", + {"Uncaught 23"}}, + {"var a = 1; try { a = 2; throw 23; } finally { throw 42; };", + {"Uncaught 42"}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); + v8::Local<v8::String> expected_string = v8_str(snippets[i].return_value()); + CHECK( + message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) + .FromJust()); + } +} TEST(BytecodeGraphBuilderThrow) { HandleAndZoneScope scope; @@ -1426,15 +1503,14 @@ TEST(BytecodeGraphBuilderThrow) { {"throw 1;", {"Uncaught 1"}}, {"throw 'Error';", {"Uncaught Error"}}, {"throw 'Error1'; throw 'Error2'", {"Uncaught Error1"}}, - // TODO(mythria): Enable these tests when JumpIfTrue is supported. - // {"var a = true; if (a) { throw 'Error'; }", {"Error"}}, + {"var a = true; if (a) { throw 'Error'; }", {"Uncaught Error"}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); + BytecodeGraphTester tester(isolate, zone, script.start()); v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); v8::Local<v8::String> expected_string = v8_str(snippets[i].return_value()); @@ -1492,8 +1568,7 @@ TEST(BytecodeGraphBuilderContext) { {factory->NewStringFromStaticChars("innermost inner_changed outer")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s", snippets[i].code_snippet); @@ -1558,8 +1633,7 @@ TEST(BytecodeGraphBuilderLoadContext) { "f(0);", {factory->NewNumberFromInt(24), factory->NewNumberFromInt(4)}}}; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s", snippets[i].code_snippet); @@ -1585,10 +1659,13 @@ TEST(BytecodeGraphBuilderCreateArgumentsNoParameters) { {factory->undefined_value()}}, {"function f(a) {'use strict'; return arguments[0];}", {factory->undefined_value()}}, + {"function f(...restArgs) {return restArgs[0];}", + {factory->undefined_value()}}, + {"function f(a, ...restArgs) {return restArgs[0];}", + {factory->undefined_value()}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName); @@ -1631,8 +1708,7 @@ TEST(BytecodeGraphBuilderCreateArguments) { factory->NewNumberFromInt(2), factory->NewNumberFromInt(30)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(1024); SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName); @@ -1647,6 +1723,48 @@ TEST(BytecodeGraphBuilderCreateArguments) { } } +TEST(BytecodeGraphBuilderCreateRestArguments) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + Factory* factory = isolate->factory(); + + ExpectedSnippet<3> snippets[] = { + {"function f(...restArgs) {return restArgs[0];}", + {factory->NewNumberFromInt(1), factory->NewNumberFromInt(1), + factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, + {"function f(a, b, ...restArgs) {return restArgs[0];}", + {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1), + factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, + {"function f(a, b, ...restArgs) {return arguments[2];}", + {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1), + factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, + {"function f(a, ...restArgs) { return restArgs[2];}", + {factory->undefined_value(), factory->NewNumberFromInt(1), + factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, + {"function f(a, ...restArgs) { return arguments[0] + restArgs[1];}", + {factory->NewNumberFromInt(4), factory->NewNumberFromInt(1), + factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, + {"function inline_func(a, ...restArgs) { return restArgs[0] }" + "function f(a, b, c) {return inline_func(b, c) + arguments[0];}", + {factory->NewNumberFromInt(31), factory->NewNumberFromInt(1), + factory->NewNumberFromInt(2), factory->NewNumberFromInt(30)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = + tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>(); + Handle<Object> return_value = + callable(snippets[i].parameter(0), snippets[i].parameter(1), + snippets[i].parameter(2)) + .ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} TEST(BytecodeGraphBuilderRegExpLiterals) { HandleAndZoneScope scope; @@ -1671,8 +1789,7 @@ TEST(BytecodeGraphBuilderRegExpLiterals) { {factory->NewStringFromStaticChars("AbC")}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(4096); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1712,8 +1829,7 @@ TEST(BytecodeGraphBuilderArrayLiterals) { {"var t = 't'; return [[t, t + 'est'], [1 + t]][1][0];", {factory->NewStringFromStaticChars("1t")}}}; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(4096); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1778,8 +1894,7 @@ TEST(BytecodeGraphBuilderObjectLiterals) { {factory->NewNumberFromInt(987)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(4096); SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1856,10 +1971,38 @@ TEST(BytecodeGraphBuilderIf) { " if (p1 < -10) { return -2; } else { return -1; }\n" "}", {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(-10)}}, + {"var b = 20, c;" + "if (p1 >= 0) {\n" + " if (b > 0) { c = 2; } else { c = 3; }\n" + "} else {\n" + " if (b < -10) { c = -2; } else { c = -1; }\n" + "}" + "return c;", + {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(-1)}}, + {"var b = 20, c = 10;" + "if (p1 >= 0) {\n" + " if (b < 0) { c = 2; }\n" + "} else {\n" + " if (b < -10) { c = -2; } else { c = -1; }\n" + "}" + "return c;", + {factory->NewNumberFromInt(10), factory->NewNumberFromInt(1)}}, + {"var x = 2, a = 10, b = 20, c, d;" + "x = 0;" + "if (a) {\n" + " b = x;" + " if (b > 0) { c = 2; } else { c = 3; }\n" + " x = 4; d = 2;" + "} else {\n" + " d = 3;\n" + "}" + "x = d;" + "function f1() {x}" + "return x + c;", + {factory->NewNumberFromInt(5), factory->NewNumberFromInt(-1)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(2048); SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1890,8 +2033,7 @@ TEST(BytecodeGraphBuilderConditionalOperator) { {factory->NewNumberFromInt(-10), factory->NewNumberFromInt(20)}}, }; - size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); - for (size_t i = 0; i < num_snippets; i++) { + for (size_t i = 0; i < arraysize(snippets); i++) { ScopedVector<char> script(2048); SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, snippets[i].code_snippet, kFunctionName); @@ -1952,6 +2094,54 @@ TEST(BytecodeGraphBuilderSwitch) { } } +TEST(BytecodeGraphBuilderSwitchMerge) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + Factory* factory = isolate->factory(); + + const char* switch_code = + "var x = 10;" + "switch (p1) {\n" + " case 1: x = 0;\n" + " case 2: x = 1;\n" + " case 3:\n" + " case 4: x = 2; break;\n" + " case 5: x = 3;\n" + " case 9: break;\n" + " default: x = 4;\n" + "}\n" + "return x;"; + + ExpectedSnippet<1> snippets[] = { + {switch_code, + {factory->NewNumberFromInt(2), factory->NewNumberFromInt(1)}}, + {switch_code, + {factory->NewNumberFromInt(2), factory->NewNumberFromInt(2)}}, + {switch_code, + {factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}}, + {switch_code, + {factory->NewNumberFromInt(2), factory->NewNumberFromInt(4)}}, + {switch_code, + {factory->NewNumberFromInt(3), factory->NewNumberFromInt(5)}}, + {switch_code, + {factory->NewNumberFromInt(10), factory->NewNumberFromInt(9)}}, + {switch_code, + {factory->NewNumberFromInt(4), factory->NewNumberFromInt(6)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(2048); + SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<Handle<Object>>(); + Handle<Object> return_value = + callable(snippets[i].parameter(0)).ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} TEST(BytecodeGraphBuilderNestedSwitch) { HandleAndZoneScope scope; @@ -2294,12 +2484,102 @@ TEST(BytecodeGraphBuilderForIn) { } -TEST(JumpWithConstantsAndWideConstants) { +TEST(BytecodeGraphBuilderForOf) { HandleAndZoneScope scope; - auto isolate = scope.main_isolate(); - const int kStep = 19; - int start = 7; - for (int constants = start; constants < 256 + 3 * kStep; constants += kStep) { + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + Factory* factory = isolate->factory(); + ExpectedSnippet<0> snippets[] = { + {" var r = 0;\n" + " for (var a of [0,6,7,9]) { r += a; }\n" + " return r;\n", + {handle(Smi::FromInt(22), isolate)}}, + {" var r = '';\n" + " for (var a of 'foobar') { r = a + r; }\n" + " return r;\n", + {factory->NewStringFromStaticChars("raboof")}}, + {" var a = [1, 2, 3];\n" + " a.name = 4;\n" + " var r = 0;\n" + " for (var x of a) { r += x; }\n" + " return r;\n", + {handle(Smi::FromInt(6), isolate)}}, + {" var r = '';\n" + " var data = [1, 2, 3]; \n" + " for (a of data) { delete data[0]; r += a; } return r;", + {factory->NewStringFromStaticChars("123")}}, + {" var r = '';\n" + " var data = [1, 2, 3]; \n" + " for (a of data) { delete data[2]; r += a; } return r;", + {factory->NewStringFromStaticChars("12undefined")}}, + {" var r = '';\n" + " var data = [1, 2, 3]; \n" + " for (a of data) { delete data; r += a; } return r;", + {factory->NewStringFromStaticChars("123")}}, + {" var r = '';\n" + " var input = 'foobar';\n" + " for (var a of input) {\n" + " if (a == 'b') break;\n" + " r += a;\n" + " }\n" + " return r;\n", + {factory->NewStringFromStaticChars("foo")}}, + {" var r = '';\n" + " var input = 'foobar';\n" + " for (var a of input) {\n" + " if (a == 'b') continue;\n" + " r += a;\n" + " }\n" + " return r;\n", + {factory->NewStringFromStaticChars("fooar")}}, + {" var r = '';\n" + " var data = [1, 2, 3, 4]; \n" + " for (a of data) { data[2] = 567; r += a; }\n" + " return r;\n", + {factory->NewStringFromStaticChars("125674")}}, + {" var r = '';\n" + " var data = [1, 2, 3, 4]; \n" + " for (a of data) { data[4] = 567; r += a; }\n" + " return r;\n", + {factory->NewStringFromStaticChars("1234567")}}, + {" var r = '';\n" + " var data = [1, 2, 3, 4]; \n" + " for (a of data) { data[5] = 567; r += a; }\n" + " return r;\n", + {factory->NewStringFromStaticChars("1234undefined567")}}, + {" var r = '';\n" + " var obj = new Object();\n" + " obj[Symbol.iterator] = function() { return {\n" + " index: 3,\n" + " data: ['a', 'b', 'c', 'd']," + " next: function() {" + " return {" + " done: this.index == -1,\n" + " value: this.index < 0 ? undefined : this.data[this.index--]\n" + " }\n" + " }\n" + " }}\n" + " for (a of obj) { r += a }\n" + " return r;\n", + {factory->NewStringFromStaticChars("dcba")}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} + +void TestJumpWithConstantsAndWideConstants(size_t shard) { + const int kStep = 46; + int start = static_cast<int>(7 + 17 * shard); + for (int constants = start; constants < 300; constants += kStep) { std::stringstream filler_os; // Generate a string that consumes constant pool entries and // spread out branch distances in script below. @@ -2321,11 +2601,14 @@ TEST(JumpWithConstantsAndWideConstants) { script_os << "}\n"; script_os << kFunctionName << "(0);\n"; std::string script(script_os.str()); + + HandleAndZoneScope scope; + auto isolate = scope.main_isolate(); auto factory = isolate->factory(); auto zone = scope.main_zone(); + BytecodeGraphTester tester(isolate, zone, script.c_str()); + auto callable = tester.GetCallable<Handle<Object>>(); for (int a = 0; a < 3; a++) { - BytecodeGraphTester tester(isolate, zone, script.c_str()); - auto callable = tester.GetCallable<Handle<Object>>(); Handle<Object> return_val = callable(factory->NewNumberFromInt(a)).ToHandleChecked(); static const int results[] = {11, 12, 2}; @@ -2334,6 +2617,368 @@ TEST(JumpWithConstantsAndWideConstants) { } } +SHARD_TEST_BY_4(JumpWithConstantsAndWideConstants) + +TEST(BytecodeGraphBuilderDoExpressions) { + bool old_flag = FLAG_harmony_do_expressions; + FLAG_harmony_do_expressions = true; + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + Factory* factory = isolate->factory(); + ExpectedSnippet<0> snippets[] = { + {"var a = do {}; return a;", {factory->undefined_value()}}, + {"var a = do { var x = 100; }; return a;", {factory->undefined_value()}}, + {"var a = do { var x = 100; }; return a;", {factory->undefined_value()}}, + {"var a = do { var x = 100; x++; }; return a;", + {handle(Smi::FromInt(100), isolate)}}, + {"var i = 0; for (; i < 5;) { i = do { if (i == 3) { break; }; i + 1; }};" + "return i;", + {handle(Smi::FromInt(3), isolate)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } + + FLAG_harmony_do_expressions = old_flag; +} + +TEST(BytecodeGraphBuilderWithStatement) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0> snippets[] = { + {"with({x:42}) return x;", {handle(Smi::FromInt(42), isolate)}}, + {"with({}) { var y = 10; return y;}", + {handle(Smi::FromInt(10), isolate)}}, + {"var y = {x:42};" + " function inner() {" + " var x = 20;" + " with(y) return x;" + "}" + "return inner();", + {handle(Smi::FromInt(42), isolate)}}, + {"var y = {x:42};" + " function inner(o) {" + " var x = 20;" + " with(o) return x;" + "}" + "return inner(y);", + {handle(Smi::FromInt(42), isolate)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} + +TEST(BytecodeGraphBuilderConstDeclaration) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + Factory* factory = isolate->factory(); + + ExpectedSnippet<0> snippets[] = { + {"const x = 3; return x;", {handle(Smi::FromInt(3), isolate)}}, + {"let x = 10; x = x + 20; return x;", + {handle(Smi::FromInt(30), isolate)}}, + {"let x = 10; x = 20; return x;", {handle(Smi::FromInt(20), isolate)}}, + {"let x; x = 20; return x;", {handle(Smi::FromInt(20), isolate)}}, + {"let x; return x;", {factory->undefined_value()}}, + {"var x = 10; { let x = 30; } return x;", + {handle(Smi::FromInt(10), isolate)}}, + {"let x = 10; { let x = 20; } return x;", + {handle(Smi::FromInt(10), isolate)}}, + {"var x = 10; eval('let x = 20;'); return x;", + {handle(Smi::FromInt(10), isolate)}}, + {"var x = 10; eval('const x = 20;'); return x;", + {handle(Smi::FromInt(10), isolate)}}, + {"var x = 10; { const x = 20; } return x;", + {handle(Smi::FromInt(10), isolate)}}, + {"var x = 10; { const x = 20; return x;} return -1;", + {handle(Smi::FromInt(20), isolate)}}, + {"var a = 10;\n" + "for (var i = 0; i < 10; ++i) {\n" + " const x = i;\n" // const declarations are block scoped. + " a = a + x;\n" + "}\n" + "return a;\n", + {handle(Smi::FromInt(55), isolate)}}, + }; + + // Tests for sloppy mode. + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } + + // Tests for strict mode. + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() {'use strict'; %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} + +TEST(BytecodeGraphBuilderConstDeclarationLookupSlots) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + Factory* factory = isolate->factory(); + + ExpectedSnippet<0> snippets[] = { + {"const x = 3; function f1() {return x;}; return x;", + {handle(Smi::FromInt(3), isolate)}}, + {"let x = 10; x = x + 20; function f1() {return x;}; return x;", + {handle(Smi::FromInt(30), isolate)}}, + {"let x; x = 20; function f1() {return x;}; return x;", + {handle(Smi::FromInt(20), isolate)}}, + {"let x; function f1() {return x;}; return x;", + {factory->undefined_value()}}, + }; + + // Tests for sloppy mode. + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } + + // Tests for strict mode. + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() {'use strict'; %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } +} + +TEST(BytecodeGraphBuilderConstInLookupContextChain) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + const char* prologue = + "function OuterMost() {\n" + " const outerConst = 10;\n" + " let outerLet = 20;\n" + " function Outer() {\n" + " function Inner() {\n" + " this.innerFunc = function() { "; + const char* epilogue = + " }\n" + " }\n" + " this.getInnerFunc =" + " function() {return new Inner().innerFunc;}\n" + " }\n" + " this.getOuterFunc =" + " function() {return new Outer().getInnerFunc();}" + "}\n" + "var f = new OuterMost().getOuterFunc();\n" + "f();\n"; + + // Tests for let / constant. + ExpectedSnippet<0> const_decl[] = { + {"return outerConst;", {handle(Smi::FromInt(10), isolate)}}, + {"return outerLet;", {handle(Smi::FromInt(20), isolate)}}, + {"outerLet = 30; return outerLet;", {handle(Smi::FromInt(30), isolate)}}, + {"var outerLet = 40; return outerLet;", + {handle(Smi::FromInt(40), isolate)}}, + {"var outerConst = 50; return outerConst;", + {handle(Smi::FromInt(50), isolate)}}, + {"try { outerConst = 30 } catch(e) { return -1; }", + {handle(Smi::FromInt(-1), isolate)}}}; + + for (size_t i = 0; i < arraysize(const_decl); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "%s %s %s", prologue, const_decl[i].code_snippet, + epilogue); + + BytecodeGraphTester tester(isolate, zone, script.start(), "*"); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*const_decl[i].return_value())); + } + + // Tests for Legacy constant. + bool old_flag_legacy_const = FLAG_legacy_const; + FLAG_legacy_const = true; + + ExpectedSnippet<0> legacy_const_decl[] = { + {"return outerConst = 23;", {handle(Smi::FromInt(23), isolate)}}, + {"outerConst = 30; return outerConst;", + {handle(Smi::FromInt(10), isolate)}}, + }; + + for (size_t i = 0; i < arraysize(legacy_const_decl); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "%s %s %s", prologue, legacy_const_decl[i].code_snippet, + epilogue); + + BytecodeGraphTester tester(isolate, zone, script.start(), "*"); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*legacy_const_decl[i].return_value())); + } + + FLAG_legacy_const = old_flag_legacy_const; +} + +TEST(BytecodeGraphBuilderIllegalConstDeclaration) { + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0, const char*> illegal_const_decl[] = { + {"const x = x = 10 + 3; return x;", + {"Uncaught ReferenceError: x is not defined"}}, + {"const x = 10; x = 20; return x;", + {"Uncaught TypeError: Assignment to constant variable."}}, + {"const x = 10; { x = 20; } return x;", + {"Uncaught TypeError: Assignment to constant variable."}}, + {"const x = 10; eval('x = 20;'); return x;", + {"Uncaught TypeError: Assignment to constant variable."}}, + {"let x = x + 10; return x;", + {"Uncaught ReferenceError: x is not defined"}}, + {"'use strict'; (function f1() { f1 = 123; })() ", + {"Uncaught TypeError: Assignment to constant variable."}}, + }; + + // Tests for sloppy mode. + for (size_t i = 0; i < arraysize(illegal_const_decl); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + illegal_const_decl[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); + v8::Local<v8::String> expected_string = + v8_str(illegal_const_decl[i].return_value()); + CHECK( + message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) + .FromJust()); + } + + // Tests for strict mode. + for (size_t i = 0; i < arraysize(illegal_const_decl); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() {'use strict'; %s }\n%s();", kFunctionName, + illegal_const_decl[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); + v8::Local<v8::String> expected_string = + v8_str(illegal_const_decl[i].return_value()); + CHECK( + message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) + .FromJust()); + } +} + +TEST(BytecodeGraphBuilderLegacyConstDeclaration) { + bool old_flag_legacy_const = FLAG_legacy_const; + FLAG_legacy_const = true; + + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0> snippets[] = { + {"const x = (x = 10) + 3; return x;", + {handle(Smi::FromInt(13), isolate)}}, + {"const x = 10; x = 20; return x;", {handle(Smi::FromInt(10), isolate)}}, + {"var a = 10;\n" + "for (var i = 0; i < 10; ++i) {\n" + " const x = i;\n" // Legacy constants are not block scoped. + " a = a + x;\n" + "}\n" + "return a;\n", + {handle(Smi::FromInt(10), isolate)}}, + {"const x = 20; eval('x = 10;'); return x;", + {handle(Smi::FromInt(20), isolate)}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippets[i].code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippets[i].return_value())); + } + + FLAG_legacy_const = old_flag_legacy_const; +} + +TEST(BytecodeGraphBuilderDebuggerStatement) { + FLAG_expose_debug_as = "debug"; + HandleAndZoneScope scope; + Isolate* isolate = scope.main_isolate(); + Zone* zone = scope.main_zone(); + + ExpectedSnippet<0> snippet = { + "var Debug = debug.Debug;" + "var count = 0;" + "function f() {" + " debugger;" + "}" + "function listener(event) {" + " if (event == Debug.DebugEvent.Break) count++;" + "}" + "Debug.setListener(listener);" + "f();" + "Debug.setListener(null);" + "return count;", + {handle(Smi::FromInt(1), isolate)}}; + + ScopedVector<char> script(1024); + SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName, + snippet.code_snippet, kFunctionName); + + BytecodeGraphTester tester(isolate, zone, script.start()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*snippet.return_value())); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/compiler/test-run-deopt.cc b/deps/v8/test/cctest/compiler/test-run-deopt.cc index 8b4c9dccb1..76dc9acae3 100644 --- a/deps/v8/test/cctest/compiler/test-run-deopt.cc +++ b/deps/v8/test/cctest/compiler/test-run-deopt.cc @@ -84,7 +84,6 @@ TEST(DeoptExceptionHandlerCatch) { TEST(DeoptExceptionHandlerFinally) { FLAG_allow_natives_syntax = true; - FLAG_turbo_try_finally = true; FunctionTester T( "(function f() {" @@ -98,9 +97,7 @@ TEST(DeoptExceptionHandlerFinally) { CompileRun("function DeoptAndThrow(f) { %DeoptimizeFunction(f); throw 0; }"); InstallIsOptimizedHelper(CcTest::isolate()); -#if 0 // TODO(4195,mstarzinger): Reproduces on MIPS64, re-enable once fixed. T.CheckCall(T.false_value()); -#endif } diff --git a/deps/v8/test/cctest/compiler/test-run-intrinsics.cc b/deps/v8/test/cctest/compiler/test-run-intrinsics.cc index b2017114b4..6e9ebf2282 100644 --- a/deps/v8/test/cctest/compiler/test-run-intrinsics.cc +++ b/deps/v8/test/cctest/compiler/test-run-intrinsics.cc @@ -104,18 +104,6 @@ TEST(IsFunction) { } -TEST(IsMinusZero) { - FunctionTester T("(function(a) { return %_IsMinusZero(a); })", flags); - - T.CheckFalse(T.Val(1)); - T.CheckFalse(T.Val(1.1)); - T.CheckTrue(T.Val(-0.0)); - T.CheckFalse(T.Val(-2)); - T.CheckFalse(T.Val(-2.3)); - T.CheckFalse(T.undefined()); -} - - TEST(IsRegExp) { FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags); @@ -148,19 +136,6 @@ TEST(IsSmi) { } -TEST(ObjectEquals) { - FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })", flags); - CompileRun("var o = {}"); - - T.CheckTrue(T.NewObject("(o)"), T.NewObject("(o)")); - T.CheckTrue(T.Val("internal"), T.Val("internal")); - T.CheckTrue(T.true_value(), T.true_value()); - T.CheckFalse(T.true_value(), T.false_value()); - T.CheckFalse(T.NewObject("({})"), T.NewObject("({})")); - T.CheckFalse(T.Val("a"), T.Val("b")); -} - - TEST(OneByteSeqStringGetChar) { FunctionTester T("(function(a,b) { return %_OneByteSeqStringGetChar(a,b); })", flags); @@ -192,15 +167,6 @@ TEST(OneByteSeqStringSetChar) { } -TEST(SetValueOf) { - FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })", flags); - - T.CheckCall(T.Val("a"), T.NewObject("(new String)"), T.Val("a")); - T.CheckCall(T.Val(123), T.NewObject("(new Number)"), T.Val(123)); - T.CheckCall(T.Val("x"), T.undefined(), T.Val("x")); -} - - TEST(StringAdd) { FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags); diff --git a/deps/v8/test/cctest/compiler/test-run-jscalls.cc b/deps/v8/test/cctest/compiler/test-run-jscalls.cc index 474453da7d..c28295857e 100644 --- a/deps/v8/test/cctest/compiler/test-run-jscalls.cc +++ b/deps/v8/test/cctest/compiler/test-run-jscalls.cc @@ -21,37 +21,36 @@ TEST(SimpleCall) { TEST(SimpleCall2) { FunctionTester T("(function(foo,a) { return foo(a); })"); - Handle<JSFunction> foo = T.NewFunction("(function(a) { return a; })"); - T.Compile(foo); + FunctionTester U("(function(a) { return a; })"); - T.CheckCall(T.Val(3), foo, T.Val(3)); - T.CheckCall(T.Val(3.1), foo, T.Val(3.1)); - T.CheckCall(foo, foo, foo); - T.CheckCall(T.Val("Abba"), foo, T.Val("Abba")); + T.CheckCall(T.Val(3), U.function, T.Val(3)); + T.CheckCall(T.Val(3.1), U.function, T.Val(3.1)); + T.CheckCall(U.function, U.function, U.function); + T.CheckCall(T.Val("Abba"), U.function, T.Val("Abba")); } TEST(ConstCall) { FunctionTester T("(function(foo,a) { return foo(a,3); })"); - Handle<JSFunction> foo = T.NewFunction("(function(a,b) { return a + b; })"); - T.Compile(foo); + FunctionTester U("(function(a,b) { return a + b; })"); - T.CheckCall(T.Val(6), foo, T.Val(3)); - T.CheckCall(T.Val(6.1), foo, T.Val(3.1)); - T.CheckCall(T.Val("function (a,b) { return a + b; }3"), foo, foo); - T.CheckCall(T.Val("Abba3"), foo, T.Val("Abba")); + T.CheckCall(T.Val(6), U.function, T.Val(3)); + T.CheckCall(T.Val(6.1), U.function, T.Val(3.1)); + T.CheckCall(T.Val("function (a,b) { return a + b; }3"), U.function, + U.function); + T.CheckCall(T.Val("Abba3"), U.function, T.Val("Abba")); } TEST(ConstCall2) { FunctionTester T("(function(foo,a) { return foo(a,\"3\"); })"); - Handle<JSFunction> foo = T.NewFunction("(function(a,b) { return a + b; })"); - T.Compile(foo); + FunctionTester U("(function(a,b) { return a + b; })"); - T.CheckCall(T.Val("33"), foo, T.Val(3)); - T.CheckCall(T.Val("3.13"), foo, T.Val(3.1)); - T.CheckCall(T.Val("function (a,b) { return a + b; }3"), foo, foo); - T.CheckCall(T.Val("Abba3"), foo, T.Val("Abba")); + T.CheckCall(T.Val("33"), U.function, T.Val(3)); + T.CheckCall(T.Val("3.13"), U.function, T.Val(3.1)); + T.CheckCall(T.Val("function (a,b) { return a + b; }3"), U.function, + U.function); + T.CheckCall(T.Val("Abba3"), U.function, T.Val("Abba")); } @@ -130,7 +129,6 @@ TEST(ConstructorCall) { } -// TODO(titzer): factor these out into test-runtime-calls.cc TEST(RuntimeCallCPP2) { FLAG_allow_natives_syntax = true; FunctionTester T("(function(a,b) { return %NumberImul(a, b); })"); diff --git a/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc b/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc index 37b2a2d243..ab8c42a979 100644 --- a/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc +++ b/deps/v8/test/cctest/compiler/test-run-jsexceptions.cc @@ -61,7 +61,6 @@ TEST(ThrowMessageDirectly) { TEST(ThrowMessageIndirectly) { - i::FLAG_turbo_try_finally = true; static const char* src = "(function(a, b) {" " try {" @@ -170,7 +169,6 @@ TEST(CatchCall) { TEST(Finally) { - i::FLAG_turbo_try_finally = true; const char* src = "(function(a,b) {" " var r = '-';" @@ -188,7 +186,6 @@ TEST(Finally) { TEST(FinallyBreak) { - i::FLAG_turbo_try_finally = true; const char* src = "(function(a,b) {" " var r = '-';" @@ -244,7 +241,6 @@ TEST(DeoptCatch) { TEST(DeoptFinallyReturn) { - i::FLAG_turbo_try_finally = true; const char* src = "(function f(a) {" " try {" @@ -261,7 +257,6 @@ TEST(DeoptFinallyReturn) { TEST(DeoptFinallyReThrow) { - i::FLAG_turbo_try_finally = true; const char* src = "(function f(a) {" " try {" @@ -272,9 +267,7 @@ TEST(DeoptFinallyReThrow) { "})"; FunctionTester T(src); -#if 0 // TODO(mstarzinger): Enable once we can. T.CheckThrows(T.NewObject("new Error"), T.Val(1)); -#endif } } // namespace compiler diff --git a/deps/v8/test/cctest/compiler/test-run-machops.cc b/deps/v8/test/cctest/compiler/test-run-machops.cc index 11a3582cbb..fba9e0e1a5 100644 --- a/deps/v8/test/cctest/compiler/test-run-machops.cc +++ b/deps/v8/test/cctest/compiler/test-run-machops.cc @@ -29,6 +29,25 @@ TEST(RunInt32Add) { } +TEST(RunWord32ReverseBits) { + BufferedRawMachineAssemblerTester<uint32_t> m(MachineType::Uint32()); + if (!m.machine()->Word32ReverseBits().IsSupported()) { + // We can only test the operator if it exists on the testing platform. + return; + } + m.Return(m.AddNode(m.machine()->Word32ReverseBits().op(), m.Parameter(0))); + + CHECK_EQ(uint32_t(0x00000000), m.Call(uint32_t(0x00000000))); + CHECK_EQ(uint32_t(0x12345678), m.Call(uint32_t(0x1e6a2c48))); + CHECK_EQ(uint32_t(0xfedcba09), m.Call(uint32_t(0x905d3b7f))); + CHECK_EQ(uint32_t(0x01010101), m.Call(uint32_t(0x80808080))); + CHECK_EQ(uint32_t(0x01020408), m.Call(uint32_t(0x10204080))); + CHECK_EQ(uint32_t(0xf0703010), m.Call(uint32_t(0x080c0e0f))); + CHECK_EQ(uint32_t(0x1f8d0a3a), m.Call(uint32_t(0x5c50b1f8))); + CHECK_EQ(uint32_t(0xffffffff), m.Call(uint32_t(0xffffffff))); +} + + TEST(RunWord32Ctz) { BufferedRawMachineAssemblerTester<int32_t> m(MachineType::Uint32()); if (!m.machine()->Word32Ctz().IsSupported()) { @@ -72,7 +91,6 @@ TEST(RunWord32Ctz) { CHECK_EQ(0, m.Call(uint32_t(0x9afdbc81))); } - TEST(RunWord32Clz) { BufferedRawMachineAssemblerTester<int32_t> m(MachineType::Uint32()); m.Return(m.Word32Clz(m.Parameter(0))); @@ -133,6 +151,25 @@ TEST(RunWord32Popcnt) { #if V8_TARGET_ARCH_64_BIT +TEST(RunWord64ReverseBits) { + RawMachineAssemblerTester<uint64_t> m(MachineType::Uint64()); + if (!m.machine()->Word64ReverseBits().IsSupported()) { + return; + } + + m.Return(m.AddNode(m.machine()->Word64ReverseBits().op(), m.Parameter(0))); + + CHECK_EQ(uint64_t(0x0000000000000000), m.Call(uint64_t(0x0000000000000000))); + CHECK_EQ(uint64_t(0x1234567890abcdef), m.Call(uint64_t(0xf7b3d5091e6a2c48))); + CHECK_EQ(uint64_t(0xfedcba0987654321), m.Call(uint64_t(0x84c2a6e1905d3b7f))); + CHECK_EQ(uint64_t(0x0101010101010101), m.Call(uint64_t(0x8080808080808080))); + CHECK_EQ(uint64_t(0x0102040803060c01), m.Call(uint64_t(0x803060c010204080))); + CHECK_EQ(uint64_t(0xf0703010e060200f), m.Call(uint64_t(0xf0040607080c0e0f))); + CHECK_EQ(uint64_t(0x2f8a6df01c21fa3b), m.Call(uint64_t(0xdc5f84380fb651f4))); + CHECK_EQ(uint64_t(0xffffffffffffffff), m.Call(uint64_t(0xffffffffffffffff))); +} + + TEST(RunWord64Clz) { BufferedRawMachineAssemblerTester<int32_t> m(MachineType::Uint64()); m.Return(m.Word64Clz(m.Parameter(0))); @@ -3534,7 +3571,7 @@ static void RunLoadImmIndex(MachineType rep) { const int kNumElems = 3; Type buffer[kNumElems]; - // initialize the buffer with raw data. + // initialize the buffer with some raw data. byte* raw = reinterpret_cast<byte*>(buffer); for (size_t i = 0; i < sizeof(buffer); i++) { raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA); @@ -3543,14 +3580,14 @@ static void RunLoadImmIndex(MachineType rep) { // Test with various large and small offsets. for (int offset = -1; offset <= 200000; offset *= -5) { for (int i = 0; i < kNumElems; i++) { - RawMachineAssemblerTester<Type> m; + BufferedRawMachineAssemblerTester<Type> m; Node* base = m.PointerConstant(buffer - offset); Node* index = m.Int32Constant((offset + i) * sizeof(buffer[0])); m.Return(m.Load(rep, base, index)); - Type expected = buffer[i]; - Type actual = m.Call(); - CHECK(expected == actual); + volatile Type expected = buffer[i]; + volatile Type actual = m.Call(); + CHECK_EQ(expected, actual); } } } @@ -3564,9 +3601,11 @@ TEST(RunLoadImmIndex) { RunLoadImmIndex<int32_t>(MachineType::Int32()); RunLoadImmIndex<uint32_t>(MachineType::Uint32()); RunLoadImmIndex<int32_t*>(MachineType::AnyTagged()); - - // TODO(titzer): test kRepBit loads - // TODO(titzer): test MachineType::Float64() loads + RunLoadImmIndex<float>(MachineType::Float32()); + RunLoadImmIndex<double>(MachineType::Float64()); + if (kPointerSize == 8) { + RunLoadImmIndex<int64_t>(MachineType::Int64()); + } // TODO(titzer): test various indexing modes. } @@ -4124,6 +4163,43 @@ TEST(RunChangeUint32ToFloat64) { } +TEST(RunTruncateFloat32ToInt32) { + BufferedRawMachineAssemblerTester<int32_t> m(MachineType::Float32()); + m.Return(m.TruncateFloat32ToInt32(m.Parameter(0))); + FOR_FLOAT32_INPUTS(i) { + if (*i <= static_cast<float>(std::numeric_limits<int32_t>::max()) && + *i >= static_cast<float>(std::numeric_limits<int32_t>::min())) { + CheckFloatEq(static_cast<int32_t>(*i), m.Call(*i)); + } + } +} + + +TEST(RunTruncateFloat32ToUint32) { + BufferedRawMachineAssemblerTester<uint32_t> m(MachineType::Float32()); + m.Return(m.TruncateFloat32ToUint32(m.Parameter(0))); + { + FOR_UINT32_INPUTS(i) { + float input = static_cast<float>(*i); + // This condition on 'input' is required because + // static_cast<float>(std::numeric_limits<uint32_t>::max()) results in a + // value outside uint32 range. + if (input < static_cast<float>(std::numeric_limits<uint32_t>::max())) { + CHECK_EQ(static_cast<uint32_t>(input), m.Call(input)); + } + } + } + { + FOR_FLOAT32_INPUTS(i) { + if (*i <= static_cast<float>(std::numeric_limits<uint32_t>::max()) && + *i >= static_cast<float>(std::numeric_limits<uint32_t>::min())) { + CheckFloatEq(static_cast<uint32_t>(*i), m.Call(*i)); + } + } + } +} + + TEST(RunChangeFloat64ToInt32_A) { BufferedRawMachineAssemblerTester<int32_t> m; double magic = 11.1; @@ -5577,6 +5653,79 @@ TEST(RunCallCFunction8) { } #endif // USE_SIMULATOR +template <typename T> +void TestExternalReferenceFunction( + BufferedRawMachineAssemblerTester<int32_t>* m, ExternalReference ref, + T (*comparison)(T)) { + T parameter; + + Node* function = m->ExternalConstant(ref); + m->CallCFunction1(MachineType::Pointer(), MachineType::Pointer(), function, + m->PointerConstant(¶meter)); + m->Return(m->Int32Constant(4356)); + FOR_FLOAT64_INPUTS(i) { + parameter = *i; + m->Call(); + CheckDoubleEq(comparison(*i), parameter); + } +} + +TEST(RunCallExternalReferenceF32Trunc) { + BufferedRawMachineAssemblerTester<int32_t> m; + ExternalReference ref = + ExternalReference::f32_trunc_wrapper_function(m.isolate()); + TestExternalReferenceFunction<float>(&m, ref, truncf); +} + +TEST(RunCallExternalReferenceF32Floor) { + BufferedRawMachineAssemblerTester<int32_t> m; + ExternalReference ref = + ExternalReference::f32_floor_wrapper_function(m.isolate()); + TestExternalReferenceFunction<float>(&m, ref, floorf); +} + +TEST(RunCallExternalReferenceF32Ceil) { + BufferedRawMachineAssemblerTester<int32_t> m; + ExternalReference ref = + ExternalReference::f32_ceil_wrapper_function(m.isolate()); + TestExternalReferenceFunction<float>(&m, ref, ceilf); +} + +TEST(RunCallExternalReferenceF32RoundTiesEven) { + BufferedRawMachineAssemblerTester<int32_t> m; + ExternalReference ref = + ExternalReference::f32_nearest_int_wrapper_function(m.isolate()); + TestExternalReferenceFunction<float>(&m, ref, nearbyintf); +} + +TEST(RunCallExternalReferenceF64Trunc) { + BufferedRawMachineAssemblerTester<int32_t> m; + ExternalReference ref = + ExternalReference::f64_trunc_wrapper_function(m.isolate()); + TestExternalReferenceFunction<double>(&m, ref, trunc); +} + +TEST(RunCallExternalReferenceF64Floor) { + BufferedRawMachineAssemblerTester<int32_t> m; + ExternalReference ref = + ExternalReference::f64_floor_wrapper_function(m.isolate()); + TestExternalReferenceFunction<double>(&m, ref, floor); +} + +TEST(RunCallExternalReferenceF64Ceil) { + BufferedRawMachineAssemblerTester<int32_t> m; + ExternalReference ref = + ExternalReference::f64_ceil_wrapper_function(m.isolate()); + TestExternalReferenceFunction<double>(&m, ref, ceil); +} + +TEST(RunCallExternalReferenceF64RoundTiesEven) { + BufferedRawMachineAssemblerTester<int32_t> m; + ExternalReference ref = + ExternalReference::f64_nearest_int_wrapper_function(m.isolate()); + TestExternalReferenceFunction<double>(&m, ref, nearbyint); +} + #if V8_TARGET_ARCH_64_BIT // TODO(titzer): run int64 tests on all platforms when supported. TEST(RunCheckedLoadInt64) { @@ -6001,6 +6150,26 @@ TEST(RunBitcastFloat32ToInt32) { } +TEST(RunRoundInt32ToFloat32) { + BufferedRawMachineAssemblerTester<float> m(MachineType::Int32()); + m.Return(m.RoundInt32ToFloat32(m.Parameter(0))); + FOR_INT32_INPUTS(i) { + volatile float expected = static_cast<float>(*i); + CHECK_EQ(expected, m.Call(*i)); + } +} + + +TEST(RunRoundUint32ToFloat32) { + BufferedRawMachineAssemblerTester<float> m(MachineType::Uint32()); + m.Return(m.RoundUint32ToFloat32(m.Parameter(0))); + FOR_UINT32_INPUTS(i) { + volatile float expected = static_cast<float>(*i); + CHECK_EQ(expected, m.Call(*i)); + } +} + + TEST(RunBitcastInt32ToFloat32) { int32_t input = 1; float output = 0.0; @@ -6068,6 +6237,27 @@ TEST(RunComputedCodeObject) { CHECK_EQ(44, r.Call(0)); } +TEST(ParentFramePointer) { + RawMachineAssemblerTester<int32_t> r(MachineType::Int32()); + RawMachineLabel tlabel; + RawMachineLabel flabel; + RawMachineLabel merge; + Node* frame = r.LoadFramePointer(); + Node* parent_frame = r.LoadParentFramePointer(); + frame = r.Load(MachineType::IntPtr(), frame); + r.Branch(r.WordEqual(frame, parent_frame), &tlabel, &flabel); + r.Bind(&tlabel); + Node* fa = r.Int32Constant(1); + r.Goto(&merge); + r.Bind(&flabel); + Node* fb = r.Int32Constant(0); + r.Goto(&merge); + r.Bind(&merge); + Node* phi = r.Phi(MachineRepresentation::kWord32, fa, fb); + r.Return(phi); + CHECK_EQ(1, r.Call(1)); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/compiler/test-run-native-calls.cc b/deps/v8/test/cctest/compiler/test-run-native-calls.cc index 791b0d7ae5..89114097d8 100644 --- a/deps/v8/test/cctest/compiler/test-run-native-calls.cc +++ b/deps/v8/test/cctest/compiler/test-run-native-calls.cc @@ -1157,6 +1157,99 @@ TEST(MixedParams_1) { MixedParamTest(1); } TEST(MixedParams_2) { MixedParamTest(2); } TEST(MixedParams_3) { MixedParamTest(3); } +template <typename T> +void TestStackSlot(MachineType slot_type, T expected) { + // Test: Generate with a function f which reserves a stack slot, call an inner + // function g from f which writes into the stack slot of f. + + if (RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) + ->num_allocatable_double_registers() < 2) + return; + + Isolate* isolate = CcTest::InitIsolateOnce(); + + // Lots of code to generate the build descriptor for the inner function. + int parray_gp[] = { + RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) + ->GetAllocatableGeneralCode(0), + RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) + ->GetAllocatableGeneralCode(1)}; + int rarray_gp[] = { + RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) + ->GetAllocatableGeneralCode(0)}; + int parray_fp[] = { + RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) + ->GetAllocatableDoubleCode(0), + RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) + ->GetAllocatableDoubleCode(1)}; + int rarray_fp[] = { + RegisterConfiguration::ArchDefault(RegisterConfiguration::TURBOFAN) + ->GetAllocatableDoubleCode(0)}; + Allocator palloc(parray_gp, 2, parray_fp, 2); + Allocator ralloc(rarray_gp, 1, rarray_fp, 1); + RegisterConfig config(palloc, ralloc); + + Zone zone; + HandleScope scope(isolate); + MachineSignature::Builder builder(&zone, 1, 12); + builder.AddReturn(MachineType::Int32()); + for (int i = 0; i < 10; i++) { + builder.AddParam(MachineType::Int32()); + } + builder.AddParam(slot_type); + builder.AddParam(MachineType::Pointer()); + MachineSignature* sig = builder.Build(); + CallDescriptor* desc = config.Create(&zone, sig); + + // Create inner function g. g has lots of parameters so that they are passed + // over the stack. + Handle<Code> inner; + Graph graph(&zone); + RawMachineAssembler g(isolate, &graph, desc); + + g.Store(slot_type.representation(), g.Parameter(11), g.Parameter(10), + WriteBarrierKind::kNoWriteBarrier); + g.Return(g.Parameter(9)); + inner = CompileGraph("Compute", desc, &graph, g.Export()); + + // Create function f with a stack slot which calls the inner function g. + BufferedRawMachineAssemblerTester<T> f(slot_type); + Node* target = f.HeapConstant(inner); + Node* stack_slot = f.StackSlot(slot_type.representation()); + Node* args[12]; + for (int i = 0; i < 10; i++) { + args[i] = f.Int32Constant(i); + } + args[10] = f.Parameter(0); + args[11] = stack_slot; + + f.CallN(desc, target, args); + f.Return(f.Load(slot_type, stack_slot, f.IntPtrConstant(0))); + + CHECK_EQ(expected, f.Call(expected)); +} + +TEST(RunStackSlotInt32) { + int32_t magic = 0x12345678; + TestStackSlot(MachineType::Int32(), magic); +} + +#if !V8_TARGET_ARCH_32_BIT +TEST(RunStackSlotInt64) { + int64_t magic = 0x123456789abcdef0; + TestStackSlot(MachineType::Int64(), magic); +} +#endif + +TEST(RunStackSlotFloat32) { + float magic = 1234.125f; + TestStackSlot(MachineType::Float32(), magic); +} + +TEST(RunStackSlotFloat64) { + double magic = 3456.375; + TestStackSlot(MachineType::Float64(), magic); +} } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/compiler/test-run-stubs.cc b/deps/v8/test/cctest/compiler/test-run-stubs.cc index 7a2a09405c..c7452191bf 100644 --- a/deps/v8/test/cctest/compiler/test-run-stubs.cc +++ b/deps/v8/test/cctest/compiler/test-run-stubs.cc @@ -27,8 +27,13 @@ TEST(RunStringLengthStub) { // Create code and an accompanying descriptor. StringLengthStub stub(isolate); Handle<Code> code = stub.GenerateCode(); - CompilationInfo info(&stub, isolate, zone); - CallDescriptor* descriptor = Linkage::ComputeIncoming(zone, &info); + CompilationInfo info("test", isolate, zone, + Code::ComputeFlags(Code::HANDLER)); + CallInterfaceDescriptor interface_descriptor = + stub.GetCallInterfaceDescriptor(); + CallDescriptor* descriptor = Linkage::GetStubCallDescriptor( + isolate, zone, interface_descriptor, stub.GetStackParameterCount(), + CallDescriptor::kNoFlags, Operator::kNoProperties); // Create a function to call the code using the descriptor. Graph graph(zone); diff --git a/deps/v8/test/cctest/compiler/value-helper.h b/deps/v8/test/cctest/compiler/value-helper.h index cbde9a7417..83cd33c5b0 100644 --- a/deps/v8/test/cctest/compiler/value-helper.h +++ b/deps/v8/test/cctest/compiler/value-helper.h @@ -312,6 +312,23 @@ class ValueHelper { #define FOR_UINT32_SHIFTS(var) for (uint32_t var = 0; var < 32; var++) +// TODO(bmeurer): Drop this crap once we switch to GTest/Gmock. +static inline void CheckFloatEq(volatile float x, volatile float y) { + if (std::isnan(x)) { + CHECK(std::isnan(y)); + } else { + CHECK_EQ(x, y); + } +} + +static inline void CheckDoubleEq(volatile double x, volatile double y) { + if (std::isnan(x)) { + CHECK(std::isnan(y)); + } else { + CHECK_EQ(x, y); + } +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/heap/heap-tester.h b/deps/v8/test/cctest/heap/heap-tester.h index 0a0860bcc4..5d098f57ab 100644 --- a/deps/v8/test/cctest/heap/heap-tester.h +++ b/deps/v8/test/cctest/heap/heap-tester.h @@ -28,9 +28,9 @@ V(StressHandles) \ V(TestMemoryReducerSampleJsCalls) \ V(TestSizeOfObjects) \ + V(Regress587004) \ V(WriteBarriersInCopyJSObject) - #define HEAP_TEST(Name) \ CcTest register_test_##Name(v8::internal::HeapTester::Test##Name, __FILE__, \ #Name, NULL, true, true); \ @@ -59,25 +59,6 @@ class HeapTester { /* test-api.cc */ static void ResetWeakHandle(bool global_gc); - - /* test-spaces.cc */ - static CompactionSpaceCollection** InitializeCompactionSpaces(Heap* heap, - int num_spaces); - static void DestroyCompactionSpaces(CompactionSpaceCollection** spaces, - int num_spaces); - static void MergeCompactionSpaces(PagedSpace* space, - CompactionSpaceCollection** spaces, - int num_spaces); - static void AllocateInCompactionSpaces(CompactionSpaceCollection** spaces, - AllocationSpace id, int num_spaces, - int num_objects, int object_size); - static void CompactionStats(CompactionSpaceCollection** spaces, - AllocationSpace id, int num_spaces, - intptr_t* capacity, intptr_t* size); - static void TestCompactionSpaceDivide(int num_additional_objects, - int object_size, - int num_compaction_spaces, - int additional_capacity_in_bytes); }; } // namespace internal diff --git a/deps/v8/test/cctest/heap/test-heap.cc b/deps/v8/test/cctest/heap/test-heap.cc index 726887a23a..88aee8adf8 100644 --- a/deps/v8/test/cctest/heap/test-heap.cc +++ b/deps/v8/test/cctest/heap/test-heap.cc @@ -33,6 +33,7 @@ #include "src/deoptimizer.h" #include "src/execution.h" #include "src/factory.h" +#include "src/field-type.h" #include "src/global-handles.h" #include "src/heap/gc-tracer.h" #include "src/heap/memory-reducer.h" @@ -1515,6 +1516,50 @@ TEST(TestCodeFlushingIncrementalAbort) { CHECK(function->is_compiled() || !function->IsOptimized()); } +TEST(TestUseOfIncrementalBarrierOnCompileLazy) { + // Turn off always_opt because it interferes with running the built-in for + // the last call to g(). + i::FLAG_always_opt = false; + i::FLAG_allow_natives_syntax = true; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + Heap* heap = isolate->heap(); + v8::HandleScope scope(CcTest::isolate()); + + CompileRun( + "function make_closure(x) {" + " return function() { return x + 3 };" + "}" + "var f = make_closure(5); f();" + "var g = make_closure(5);"); + + // Check f is compiled. + Handle<String> f_name = factory->InternalizeUtf8String("f"); + Handle<Object> f_value = + Object::GetProperty(isolate->global_object(), f_name).ToHandleChecked(); + Handle<JSFunction> f_function = Handle<JSFunction>::cast(f_value); + CHECK(f_function->is_compiled()); + + // Check g is not compiled. + Handle<String> g_name = factory->InternalizeUtf8String("g"); + Handle<Object> g_value = + Object::GetProperty(isolate->global_object(), g_name).ToHandleChecked(); + Handle<JSFunction> g_function = Handle<JSFunction>::cast(g_value); + // TODO(mvstanton): change to check that g is *not* compiled when optimized + // cache + // map lookup moves to the compile lazy builtin. + CHECK(g_function->is_compiled()); + + SimulateIncrementalMarking(heap); + CompileRun("%OptimizeFunctionOnNextCall(f); f();"); + + // g should now have available an optimized function, unmarked by gc. The + // CompileLazy built-in will discover it and install it in the closure, and + // the incremental write barrier should be used. + CompileRun("g();"); + CHECK(g_function->is_compiled()); +} TEST(CompilationCacheCachingBehavior) { // If we do not flush code, or have the compilation cache turned off, this @@ -3514,6 +3559,13 @@ TEST(ReleaseOverReservedPages) { // The optimizer can allocate stuff, messing up the test. i::FLAG_crankshaft = false; i::FLAG_always_opt = false; + // Parallel compaction increases fragmentation, depending on how existing + // memory is distributed. Since this is non-deterministic because of + // concurrent sweeping, we disable it for this test. + i::FLAG_parallel_compaction = false; + // Concurrent sweeping adds non determinism, depending on when memory is + // available for further reuse. + i::FLAG_concurrent_sweeping = false; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); @@ -4163,9 +4215,6 @@ TEST(Regress169209) { CHECK(shared1->code()->gc_metadata() != NULL); // Optimize function and make sure the unoptimized code is replaced. -#ifdef DEBUG - FLAG_stop_at = "f"; -#endif CompileRun("%OptimizeFunctionOnNextCall(g);" "g(false);"); @@ -5555,8 +5604,8 @@ TEST(Regress507979) { Handle<FixedArray> o1 = isolate->factory()->NewFixedArray(kFixedArrayLen); Handle<FixedArray> o2 = isolate->factory()->NewFixedArray(kFixedArrayLen); - CHECK(heap->InNewSpace(o1->address())); - CHECK(heap->InNewSpace(o2->address())); + CHECK(heap->InNewSpace(*o1)); + CHECK(heap->InNewSpace(*o2)); HeapIterator it(heap, i::HeapIterator::kFilterUnreachable); @@ -5571,33 +5620,6 @@ TEST(Regress507979) { } -TEST(ArrayShiftSweeping) { - i::FLAG_expose_gc = true; - CcTest::InitializeVM(); - v8::HandleScope scope(CcTest::isolate()); - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - - v8::Local<v8::Value> result = CompileRun( - "var array = new Array(400);" - "var tmp = new Array(1000);" - "array[0] = 10;" - "gc();" - "gc();" - "array.shift();" - "array;"); - - Handle<JSObject> o = Handle<JSObject>::cast( - v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(result))); - CHECK(heap->InOldSpace(o->elements())); - CHECK(heap->InOldSpace(*o)); - Page* page = Page::FromAddress(o->elements()->address()); - CHECK(page->parallel_sweeping_state().Value() <= - MemoryChunk::kSweepingFinalize || - Marking::IsBlack(Marking::MarkBitFrom(o->elements()))); -} - - UNINITIALIZED_TEST(PromotionQueue) { i::FLAG_expose_gc = true; i::FLAG_max_semi_space_size = 2 * (Page::kPageSize / MB); @@ -5681,10 +5703,12 @@ TEST(Regress388880) { Heap* heap = isolate->heap(); Handle<Map> map1 = Map::Create(isolate, 1); + Handle<String> name = factory->NewStringFromStaticChars("foo"); + name = factory->InternalizeString(name); Handle<Map> map2 = - Map::CopyWithField(map1, factory->NewStringFromStaticChars("foo"), - HeapType::Any(isolate), NONE, Representation::Tagged(), - OMIT_TRANSITION).ToHandleChecked(); + Map::CopyWithField(map1, name, FieldType::Any(isolate), NONE, + Representation::Tagged(), OMIT_TRANSITION) + .ToHandleChecked(); int desired_offset = Page::kPageSize - map1->instance_size(); @@ -6232,7 +6256,6 @@ TEST(MessageObjectLeak) { const char* flag = "--turbo-filter=*"; FlagList::SetFlagsFromString(flag, StrLength(flag)); FLAG_always_opt = true; - FLAG_turbo_try_finally = true; CompileRun(test); } @@ -6470,6 +6493,43 @@ HEAP_TEST(TestMemoryReducerSampleJsCalls) { CheckDoubleEquals(2, calls_per_ms); } +HEAP_TEST(Regress587004) { + FLAG_concurrent_sweeping = false; +#ifdef VERIFY_HEAP + FLAG_verify_heap = false; +#endif + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Heap* heap = CcTest::heap(); + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + const int N = (Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) / + kPointerSize; + Handle<FixedArray> array = factory->NewFixedArray(N, TENURED); + CHECK(heap->old_space()->Contains(*array)); + Handle<Object> number = factory->NewHeapNumber(1.0); + CHECK(heap->InNewSpace(*number)); + for (int i = 0; i < N; i++) { + array->set(i, *number); + } + heap->CollectGarbage(OLD_SPACE); + SimulateFullSpace(heap->old_space()); + heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*array, N - 1); + heap->mark_compact_collector()->EnsureSweepingCompleted(); + ByteArray* byte_array; + const int M = 256; + // Don't allow old space expansion. The test works without this flag too, + // but becomes very slow. + heap->set_force_oom(true); + while (heap->AllocateByteArray(M, TENURED).To(&byte_array)) { + for (int j = 0; j < M; j++) { + byte_array->set(j, 0x31); + } + } + // Re-enable old space expansion to avoid OOM crash. + heap->set_force_oom(false); + heap->CollectGarbage(NEW_SPACE); +} } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/heap/test-spaces.cc b/deps/v8/test/cctest/heap/test-spaces.cc index 2fe099d2e3..41345bc7d1 100644 --- a/deps/v8/test/cctest/heap/test-spaces.cc +++ b/deps/v8/test/cctest/heap/test-spaces.cc @@ -448,236 +448,6 @@ TEST(CompactionSpace) { } -TEST(CompactionSpaceUsingExternalMemory) { - const int kObjectSize = 512; - - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - MemoryAllocator* allocator = new MemoryAllocator(isolate); - CHECK(allocator != nullptr); - CHECK(allocator->SetUp(heap->MaxReserved(), heap->MaxExecutableSize())); - TestMemoryAllocatorScope test_scope(isolate, allocator); - - CompactionSpaceCollection* collection = new CompactionSpaceCollection(heap); - CompactionSpace* compaction_space = collection->Get(OLD_SPACE); - CHECK(compaction_space != NULL); - CHECK(compaction_space->SetUp()); - - OldSpace* old_space = new OldSpace(heap, OLD_SPACE, NOT_EXECUTABLE); - CHECK(old_space != NULL); - CHECK(old_space->SetUp()); - - // The linear allocation area already counts as used bytes, making - // exact testing impossible. - heap->DisableInlineAllocation(); - - // Test: - // * Allocate a backing store in old_space. - // * Compute the number num_rest_objects of kObjectSize objects that fit into - // of available memory. - // kNumRestObjects. - // * Add the rest of available memory to the compaction space. - // * Allocate kNumRestObjects in the compaction space. - // * Allocate one object more. - // * Merge the compaction space and compare the expected number of pages. - - // Allocate a single object in old_space to initialize a backing page. - old_space->AllocateRawUnaligned(kObjectSize).ToObjectChecked(); - // Compute the number of objects that fit into the rest in old_space. - intptr_t rest = static_cast<int>(old_space->Available()); - CHECK_GT(rest, 0); - intptr_t num_rest_objects = rest / kObjectSize; - // After allocating num_rest_objects in compaction_space we allocate a bit - // more. - const intptr_t kAdditionalCompactionMemory = kObjectSize; - // We expect a single old_space page. - const intptr_t kExpectedInitialOldSpacePages = 1; - // We expect a single additional page in compaction space because we mostly - // use external memory. - const intptr_t kExpectedCompactionPages = 1; - // We expect two pages to be reachable from old_space in the end. - const intptr_t kExpectedOldSpacePagesAfterMerge = 2; - - CHECK_EQ(old_space->CountTotalPages(), kExpectedInitialOldSpacePages); - CHECK_EQ(compaction_space->CountTotalPages(), 0); - CHECK_EQ(compaction_space->Capacity(), 0); - // Make the rest of memory available for compaction. - old_space->DivideUponCompactionSpaces(&collection, 1, rest); - CHECK_EQ(compaction_space->CountTotalPages(), 0); - CHECK_EQ(compaction_space->Capacity(), rest); - while (num_rest_objects-- > 0) { - compaction_space->AllocateRawUnaligned(kObjectSize).ToObjectChecked(); - } - // We only used external memory so far. - CHECK_EQ(compaction_space->CountTotalPages(), 0); - // Additional allocation. - compaction_space->AllocateRawUnaligned(kAdditionalCompactionMemory) - .ToObjectChecked(); - // Now the compaction space shouldve also acquired a page. - CHECK_EQ(compaction_space->CountTotalPages(), kExpectedCompactionPages); - - old_space->MergeCompactionSpace(compaction_space); - CHECK_EQ(old_space->CountTotalPages(), kExpectedOldSpacePagesAfterMerge); - - delete collection; - delete old_space; - - allocator->TearDown(); - delete allocator; -} - - -CompactionSpaceCollection** HeapTester::InitializeCompactionSpaces( - Heap* heap, int num_spaces) { - CompactionSpaceCollection** spaces = - new CompactionSpaceCollection*[num_spaces]; - for (int i = 0; i < num_spaces; i++) { - spaces[i] = new CompactionSpaceCollection(heap); - } - return spaces; -} - - -void HeapTester::DestroyCompactionSpaces(CompactionSpaceCollection** spaces, - int num_spaces) { - for (int i = 0; i < num_spaces; i++) { - delete spaces[i]; - } - delete[] spaces; -} - - -void HeapTester::MergeCompactionSpaces(PagedSpace* space, - CompactionSpaceCollection** spaces, - int num_spaces) { - AllocationSpace id = space->identity(); - for (int i = 0; i < num_spaces; i++) { - space->MergeCompactionSpace(spaces[i]->Get(id)); - CHECK_EQ(spaces[i]->Get(id)->accounting_stats_.Size(), 0); - CHECK_EQ(spaces[i]->Get(id)->accounting_stats_.Capacity(), 0); - CHECK_EQ(spaces[i]->Get(id)->Waste(), 0); - } -} - - -void HeapTester::AllocateInCompactionSpaces(CompactionSpaceCollection** spaces, - AllocationSpace id, int num_spaces, - int num_objects, int object_size) { - for (int i = 0; i < num_spaces; i++) { - for (int j = 0; j < num_objects; j++) { - spaces[i]->Get(id)->AllocateRawUnaligned(object_size).ToObjectChecked(); - } - spaces[i]->Get(id)->EmptyAllocationInfo(); - CHECK_EQ(spaces[i]->Get(id)->accounting_stats_.Size(), - num_objects * object_size); - CHECK_GE(spaces[i]->Get(id)->accounting_stats_.Capacity(), - spaces[i]->Get(id)->accounting_stats_.Size()); - } -} - - -void HeapTester::CompactionStats(CompactionSpaceCollection** spaces, - AllocationSpace id, int num_spaces, - intptr_t* capacity, intptr_t* size) { - *capacity = 0; - *size = 0; - for (int i = 0; i < num_spaces; i++) { - *capacity += spaces[i]->Get(id)->accounting_stats_.Capacity(); - *size += spaces[i]->Get(id)->accounting_stats_.Size(); - } -} - - -void HeapTester::TestCompactionSpaceDivide(int num_additional_objects, - int object_size, - int num_compaction_spaces, - int additional_capacity_in_bytes) { - Isolate* isolate = CcTest::i_isolate(); - Heap* heap = isolate->heap(); - OldSpace* old_space = new OldSpace(heap, OLD_SPACE, NOT_EXECUTABLE); - CHECK(old_space != nullptr); - CHECK(old_space->SetUp()); - old_space->AllocateRawUnaligned(object_size).ToObjectChecked(); - old_space->EmptyAllocationInfo(); - - intptr_t rest_capacity = old_space->accounting_stats_.Capacity() - - old_space->accounting_stats_.Size(); - intptr_t capacity_for_compaction_space = - rest_capacity / num_compaction_spaces; - int num_objects_in_compaction_space = - static_cast<int>(capacity_for_compaction_space) / object_size + - num_additional_objects; - CHECK_GT(num_objects_in_compaction_space, 0); - intptr_t initial_old_space_capacity = old_space->accounting_stats_.Capacity(); - - CompactionSpaceCollection** spaces = - InitializeCompactionSpaces(heap, num_compaction_spaces); - old_space->DivideUponCompactionSpaces(spaces, num_compaction_spaces, - capacity_for_compaction_space); - - intptr_t compaction_capacity = 0; - intptr_t compaction_size = 0; - CompactionStats(spaces, OLD_SPACE, num_compaction_spaces, - &compaction_capacity, &compaction_size); - - intptr_t old_space_capacity = old_space->accounting_stats_.Capacity(); - intptr_t old_space_size = old_space->accounting_stats_.Size(); - // Compaction space memory is subtracted from the original space's capacity. - CHECK_EQ(old_space_capacity, - initial_old_space_capacity - compaction_capacity); - CHECK_EQ(compaction_size, 0); - - AllocateInCompactionSpaces(spaces, OLD_SPACE, num_compaction_spaces, - num_objects_in_compaction_space, object_size); - - // Old space size and capacity should be the same as after dividing. - CHECK_EQ(old_space->accounting_stats_.Size(), old_space_size); - CHECK_EQ(old_space->accounting_stats_.Capacity(), old_space_capacity); - - CompactionStats(spaces, OLD_SPACE, num_compaction_spaces, - &compaction_capacity, &compaction_size); - MergeCompactionSpaces(old_space, spaces, num_compaction_spaces); - - CHECK_EQ(old_space->accounting_stats_.Capacity(), - old_space_capacity + compaction_capacity); - CHECK_EQ(old_space->accounting_stats_.Size(), - old_space_size + compaction_size); - // We check against the expected end capacity. - CHECK_EQ(old_space->accounting_stats_.Capacity(), - initial_old_space_capacity + additional_capacity_in_bytes); - - DestroyCompactionSpaces(spaces, num_compaction_spaces); - delete old_space; -} - - -HEAP_TEST(CompactionSpaceDivideSinglePage) { - const int kObjectSize = KB; - const int kCompactionSpaces = 4; - // Since the bound for objects is tight and the dividing is best effort, we - // subtract some objects to make sure we still fit in the initial page. - // A CHECK makes sure that the overall number of allocated objects stays - // > 0. - const int kAdditionalObjects = -10; - const int kAdditionalCapacityRequired = 0; - TestCompactionSpaceDivide(kAdditionalObjects, kObjectSize, kCompactionSpaces, - kAdditionalCapacityRequired); -} - - -HEAP_TEST(CompactionSpaceDivideMultiplePages) { - const int kObjectSize = KB; - const int kCompactionSpaces = 4; - // Allocate half a page of objects to ensure that we need one more page per - // compaction space. - const int kAdditionalObjects = (Page::kPageSize / kObjectSize / 2); - const int kAdditionalCapacityRequired = - Page::kAllocatableMemory * kCompactionSpaces; - TestCompactionSpaceDivide(kAdditionalObjects, kObjectSize, kCompactionSpaces, - kAdditionalCapacityRequired); -} - - TEST(LargeObjectSpace) { v8::V8::Initialize(); @@ -744,50 +514,6 @@ TEST(SizeOfFirstPageIsLargeEnough) { CHECK(isolate->heap()->lo_space()->IsEmpty()); } - -UNINITIALIZED_TEST(NewSpaceGrowsToTargetCapacity) { - FLAG_target_semi_space_size = 2 * (Page::kPageSize / MB); - if (FLAG_optimize_for_size) return; - - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - { - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); - v8::Context::New(isolate)->Enter(); - - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); - - NewSpace* new_space = i_isolate->heap()->new_space(); - - // This test doesn't work if we start with a non-default new space - // configuration. - if (new_space->InitialTotalCapacity() == Page::kPageSize) { - CHECK_EQ(new_space->CommittedMemory(), new_space->InitialTotalCapacity()); - - // Fill up the first (and only) page of the semi space. - FillCurrentPage(new_space); - - // Try to allocate out of the new space. A new page should be added and - // the - // allocation should succeed. - v8::internal::AllocationResult allocation = - new_space->AllocateRawUnaligned(80); - CHECK(!allocation.IsRetry()); - CHECK_EQ(new_space->CommittedMemory(), 2 * Page::kPageSize); - - // Turn the allocation into a proper object so isolate teardown won't - // crash. - HeapObject* free_space = NULL; - CHECK(allocation.To(&free_space)); - new_space->heap()->CreateFillerObjectAt(free_space->address(), 80); - } - } - isolate->Dispose(); -} - - static HeapObject* AllocateUnaligned(NewSpace* space, int size) { AllocationResult allocation = space->AllocateRawUnaligned(size); CHECK(!allocation.IsRetry()); @@ -797,10 +523,27 @@ static HeapObject* AllocateUnaligned(NewSpace* space, int size) { return filler; } -class Observer : public InlineAllocationObserver { +static HeapObject* AllocateUnaligned(PagedSpace* space, int size) { + AllocationResult allocation = space->AllocateRaw(size, kDoubleUnaligned); + CHECK(!allocation.IsRetry()); + HeapObject* filler = NULL; + CHECK(allocation.To(&filler)); + space->heap()->CreateFillerObjectAt(filler->address(), size); + return filler; +} + +static HeapObject* AllocateUnaligned(LargeObjectSpace* space, int size) { + AllocationResult allocation = space->AllocateRaw(size, EXECUTABLE); + CHECK(!allocation.IsRetry()); + HeapObject* filler = NULL; + CHECK(allocation.To(&filler)); + return filler; +} + +class Observer : public AllocationObserver { public: explicit Observer(intptr_t step_size) - : InlineAllocationObserver(step_size), count_(0) {} + : AllocationObserver(step_size), count_(0) {} void Step(int bytes_allocated, Address, size_t) override { count_++; } @@ -810,85 +553,93 @@ class Observer : public InlineAllocationObserver { int count_; }; +template <typename T> +void testAllocationObserver(Isolate* i_isolate, T* space) { + Observer observer1(128); + space->AddAllocationObserver(&observer1); -UNINITIALIZED_TEST(InlineAllocationObserver) { - v8::Isolate::CreateParams create_params; - create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); - v8::Isolate* isolate = v8::Isolate::New(create_params); - { - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); - v8::Context::New(isolate)->Enter(); + // The observer should not get notified if we have only allocated less than + // 128 bytes. + AllocateUnaligned(space, 64); + CHECK_EQ(observer1.count(), 0); - Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); + // The observer should get called when we have allocated exactly 128 bytes. + AllocateUnaligned(space, 64); + CHECK_EQ(observer1.count(), 1); - NewSpace* new_space = i_isolate->heap()->new_space(); + // Another >128 bytes should get another notification. + AllocateUnaligned(space, 136); + CHECK_EQ(observer1.count(), 2); - Observer observer1(128); - new_space->AddInlineAllocationObserver(&observer1); + // Allocating a large object should get only one notification. + AllocateUnaligned(space, 1024); + CHECK_EQ(observer1.count(), 3); - // The observer should not get notified if we have only allocated less than - // 128 bytes. - AllocateUnaligned(new_space, 64); - CHECK_EQ(observer1.count(), 0); + // Allocating another 2048 bytes in small objects should get 16 + // notifications. + for (int i = 0; i < 64; ++i) { + AllocateUnaligned(space, 32); + } + CHECK_EQ(observer1.count(), 19); - // The observer should get called when we have allocated exactly 128 bytes. - AllocateUnaligned(new_space, 64); - CHECK_EQ(observer1.count(), 1); + // Multiple observers should work. + Observer observer2(96); + space->AddAllocationObserver(&observer2); - // Another >128 bytes should get another notification. - AllocateUnaligned(new_space, 136); - CHECK_EQ(observer1.count(), 2); + AllocateUnaligned(space, 2048); + CHECK_EQ(observer1.count(), 20); + CHECK_EQ(observer2.count(), 1); - // Allocating a large object should get only one notification. - AllocateUnaligned(new_space, 1024); - CHECK_EQ(observer1.count(), 3); + AllocateUnaligned(space, 104); + CHECK_EQ(observer1.count(), 20); + CHECK_EQ(observer2.count(), 2); - // Allocating another 2048 bytes in small objects should get 16 - // notifications. - for (int i = 0; i < 64; ++i) { - AllocateUnaligned(new_space, 32); - } - CHECK_EQ(observer1.count(), 19); + // Callback should stop getting called after an observer is removed. + space->RemoveAllocationObserver(&observer1); - // Multiple observers should work. - Observer observer2(96); - new_space->AddInlineAllocationObserver(&observer2); + AllocateUnaligned(space, 384); + CHECK_EQ(observer1.count(), 20); // no more notifications. + CHECK_EQ(observer2.count(), 3); // this one is still active. - AllocateUnaligned(new_space, 2048); - CHECK_EQ(observer1.count(), 20); - CHECK_EQ(observer2.count(), 1); - - AllocateUnaligned(new_space, 104); - CHECK_EQ(observer1.count(), 20); - CHECK_EQ(observer2.count(), 2); + // Ensure that PauseInlineAllocationObserversScope work correctly. + AllocateUnaligned(space, 48); + CHECK_EQ(observer2.count(), 3); + { + PauseAllocationObserversScope pause_observers(i_isolate->heap()); + CHECK_EQ(observer2.count(), 3); + AllocateUnaligned(space, 384); + CHECK_EQ(observer2.count(), 3); + } + CHECK_EQ(observer2.count(), 3); + // Coupled with the 48 bytes allocated before the pause, another 48 bytes + // allocated here should trigger a notification. + AllocateUnaligned(space, 48); + CHECK_EQ(observer2.count(), 4); + + space->RemoveAllocationObserver(&observer2); + AllocateUnaligned(space, 384); + CHECK_EQ(observer1.count(), 20); + CHECK_EQ(observer2.count(), 4); +} - // Callback should stop getting called after an observer is removed. - new_space->RemoveInlineAllocationObserver(&observer1); +UNINITIALIZED_TEST(AllocationObserver) { + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = CcTest::array_buffer_allocator(); + v8::Isolate* isolate = v8::Isolate::New(create_params); + { + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Context::New(isolate)->Enter(); - AllocateUnaligned(new_space, 384); - CHECK_EQ(observer1.count(), 20); // no more notifications. - CHECK_EQ(observer2.count(), 3); // this one is still active. + Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate); - // Ensure that PauseInlineAllocationObserversScope work correctly. - AllocateUnaligned(new_space, 48); - CHECK_EQ(observer2.count(), 3); - { - PauseInlineAllocationObserversScope pause_observers(new_space); - CHECK_EQ(observer2.count(), 3); - AllocateUnaligned(new_space, 384); - CHECK_EQ(observer2.count(), 3); - } - CHECK_EQ(observer2.count(), 3); - // Coupled with the 48 bytes allocated before the pause, another 48 bytes - // allocated here should trigger a notification. - AllocateUnaligned(new_space, 48); - CHECK_EQ(observer2.count(), 4); - - new_space->RemoveInlineAllocationObserver(&observer2); - AllocateUnaligned(new_space, 384); - CHECK_EQ(observer1.count(), 20); - CHECK_EQ(observer2.count(), 4); + testAllocationObserver<NewSpace>(i_isolate, i_isolate->heap()->new_space()); + // Old space is used but the code path is shared for all + // classes inheriting from PagedSpace. + testAllocationObserver<PagedSpace>(i_isolate, + i_isolate->heap()->old_space()); + testAllocationObserver<LargeObjectSpace>(i_isolate, + i_isolate->heap()->lo_space()); } isolate->Dispose(); } @@ -908,16 +659,16 @@ UNINITIALIZED_TEST(InlineAllocationObserverCadence) { NewSpace* new_space = i_isolate->heap()->new_space(); Observer observer1(512); - new_space->AddInlineAllocationObserver(&observer1); + new_space->AddAllocationObserver(&observer1); Observer observer2(576); - new_space->AddInlineAllocationObserver(&observer2); + new_space->AddAllocationObserver(&observer2); for (int i = 0; i < 512; ++i) { AllocateUnaligned(new_space, 32); } - new_space->RemoveInlineAllocationObserver(&observer1); - new_space->RemoveInlineAllocationObserver(&observer2); + new_space->RemoveAllocationObserver(&observer1); + new_space->RemoveAllocationObserver(&observer2); CHECK_EQ(observer1.count(), 32); CHECK_EQ(observer2.count(), 28); diff --git a/deps/v8/test/cctest/interpreter/bytecode-expectations-printer.cc b/deps/v8/test/cctest/interpreter/bytecode-expectations-printer.cc new file mode 100644 index 0000000000..d5e0456511 --- /dev/null +++ b/deps/v8/test/cctest/interpreter/bytecode-expectations-printer.cc @@ -0,0 +1,301 @@ +// Copyright 2016 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 "test/cctest/interpreter/bytecode-expectations-printer.h" + +#include <iostream> +#include <vector> + +#include "include/libplatform/libplatform.h" +#include "include/v8.h" + +#include "src/base/logging.h" +#include "src/base/smart-pointers.h" +#include "src/compiler.h" + +#include "src/interpreter/bytecode-array-iterator.h" +#include "src/interpreter/bytecode-generator.h" +#include "src/interpreter/bytecodes.h" +#include "src/interpreter/interpreter.h" + +namespace v8 { +namespace internal { +namespace interpreter { + +// static +const char* const BytecodeExpectationsPrinter::kDefaultTopFunctionName = + "__genbckexp_wrapper__"; + +v8::Local<v8::String> BytecodeExpectationsPrinter::V8StringFromUTF8( + const char* data) const { + return v8::String::NewFromUtf8(isolate_, data, v8::NewStringType::kNormal) + .ToLocalChecked(); +} + +std::string BytecodeExpectationsPrinter::WrapCodeInFunction( + const char* function_name, const std::string& function_body) const { + std::ostringstream program_stream; + program_stream << "function " << function_name << "() {" << function_body + << "}\n" + << function_name << "();"; + + return program_stream.str(); +} + +v8::Local<v8::Script> BytecodeExpectationsPrinter::Compile( + const char* program) const { + v8::Local<v8::String> source = V8StringFromUTF8(program); + return v8::Script::Compile(isolate_->GetCurrentContext(), source) + .ToLocalChecked(); +} + +void BytecodeExpectationsPrinter::Run(v8::Local<v8::Script> script) const { + (void)script->Run(isolate_->GetCurrentContext()); +} + +i::Handle<v8::internal::BytecodeArray> +BytecodeExpectationsPrinter::GetBytecodeArrayForGlobal( + const char* global_name) const { + const v8::Local<v8::Context>& context = isolate_->GetCurrentContext(); + v8::Local<v8::String> v8_global_name = V8StringFromUTF8(global_name); + v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( + context->Global()->Get(context, v8_global_name).ToLocalChecked()); + i::Handle<i::JSFunction> js_function = + i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*function)); + + i::Handle<i::BytecodeArray> bytecodes = + i::handle(js_function->shared()->bytecode_array(), i_isolate()); + + return bytecodes; +} + +i::Handle<i::BytecodeArray> +BytecodeExpectationsPrinter::GetBytecodeArrayForScript( + v8::Local<v8::Script> script) const { + i::Handle<i::JSFunction> js_function = v8::Utils::OpenHandle(*script); + return i::handle(js_function->shared()->bytecode_array(), i_isolate()); +} + +void BytecodeExpectationsPrinter::PrintEscapedString( + std::ostream& stream, const std::string& string) const { + for (char c : string) { + switch (c) { + case '"': + stream << "\\\""; + break; + case '\\': + stream << "\\\\"; + break; + default: + stream << c; + break; + } + } +} + +void BytecodeExpectationsPrinter::PrintBytecodeOperand( + std::ostream& stream, const BytecodeArrayIterator& bytecode_iter, + const Bytecode& bytecode, int op_index, int parameter_count) const { + OperandType op_type = Bytecodes::GetOperandType(bytecode, op_index); + OperandSize op_size = Bytecodes::GetOperandSize(bytecode, op_index); + + const char* size_tag; + switch (op_size) { + case OperandSize::kByte: + size_tag = "8"; + break; + case OperandSize::kShort: + size_tag = "16"; + break; + default: + UNREACHABLE(); + return; + } + + if (Bytecodes::IsRegisterOperandType(op_type)) { + Register register_value = bytecode_iter.GetRegisterOperand(op_index); + stream << 'R'; + if (op_size != OperandSize::kByte) stream << size_tag; + if (register_value.is_new_target()) { + stream << "(new_target)"; + } else if (register_value.is_current_context()) { + stream << "(context)"; + } else if (register_value.is_function_closure()) { + stream << "(closure)"; + } else if (register_value.is_parameter()) { + int parameter_index = register_value.ToParameterIndex(parameter_count); + if (parameter_index == 0) { + stream << "(this)"; + } else { + stream << "(arg" << (parameter_index - 1) << ')'; + } + } else { + stream << '(' << register_value.index() << ')'; + } + } else { + stream << 'U' << size_tag << '('; + + if (Bytecodes::IsImmediateOperandType(op_type)) { + // We need a cast, otherwise the result is printed as char. + stream << static_cast<int>(bytecode_iter.GetImmediateOperand(op_index)); + } else if (Bytecodes::IsRegisterCountOperandType(op_type)) { + stream << bytecode_iter.GetRegisterCountOperand(op_index); + } else if (Bytecodes::IsIndexOperandType(op_type)) { + stream << bytecode_iter.GetIndexOperand(op_index); + } else { + UNREACHABLE(); + } + + stream << ')'; + } +} + +void BytecodeExpectationsPrinter::PrintBytecode( + std::ostream& stream, const BytecodeArrayIterator& bytecode_iter, + int parameter_count) const { + Bytecode bytecode = bytecode_iter.current_bytecode(); + + stream << "B(" << Bytecodes::ToString(bytecode) << ')'; + + int operands_count = Bytecodes::NumberOfOperands(bytecode); + for (int op_index = 0; op_index < operands_count; ++op_index) { + stream << ", "; + PrintBytecodeOperand(stream, bytecode_iter, bytecode, op_index, + parameter_count); + } +} + +void BytecodeExpectationsPrinter::PrintV8String(std::ostream& stream, + i::String* string) const { + stream << '"'; + for (int i = 0, length = string->length(); i < length; ++i) { + stream << i::AsEscapedUC16ForJSON(string->Get(i)); + } + stream << '"'; +} + +void BytecodeExpectationsPrinter::PrintConstant( + std::ostream& stream, i::Handle<i::Object> constant) const { + switch (const_pool_type_) { + case ConstantPoolType::kString: + CHECK(constant->IsString()); + PrintV8String(stream, i::String::cast(*constant)); + break; + case ConstantPoolType::kNumber: + if (constant->IsSmi()) { + i::Smi::cast(*constant)->SmiPrint(stream); + } else if (constant->IsHeapNumber()) { + i::HeapNumber::cast(*constant)->HeapNumberPrint(stream); + } else { + UNREACHABLE(); + } + break; + case ConstantPoolType::kMixed: + if (constant->IsSmi()) { + stream << "kInstanceTypeDontCare"; + } else { + stream << "InstanceType::" + << i::HeapObject::cast(*constant)->map()->instance_type(); + } + break; + case ConstantPoolType::kUnknown: + default: + UNREACHABLE(); + return; + } +} + +void BytecodeExpectationsPrinter::PrintFrameSize( + std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const { + const int kPointerSize = sizeof(void*); + int frame_size = bytecode_array->frame_size(); + + DCHECK_EQ(frame_size % kPointerSize, 0); + stream << "frame size: " << frame_size / kPointerSize; + if (frame_size > 0) stream << " # in multiples of sizeof(void*)"; + stream << "\nparameter count: " << bytecode_array->parameter_count() << '\n'; +} + +void BytecodeExpectationsPrinter::PrintBytecodeSequence( + std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const { + stream << "bytecodes: [\n"; + BytecodeArrayIterator bytecode_iter(bytecode_array); + for (; !bytecode_iter.done(); bytecode_iter.Advance()) { + stream << " "; + PrintBytecode(stream, bytecode_iter, bytecode_array->parameter_count()); + stream << ",\n"; + } + stream << "]\n"; +} + +void BytecodeExpectationsPrinter::PrintConstantPool( + std::ostream& stream, i::FixedArray* constant_pool) const { + stream << "constant pool: [\n"; + int num_constants = constant_pool->length(); + if (num_constants > 0) { + for (int i = 0; i < num_constants; ++i) { + stream << " "; + PrintConstant(stream, i::FixedArray::get(constant_pool, i, i_isolate())); + stream << ",\n"; + } + } + stream << "]\n"; +} + +void BytecodeExpectationsPrinter::PrintCodeSnippet( + std::ostream& stream, const std::string& body) const { + stream << "snippet: \"\n"; + std::stringstream body_stream(body); + std::string body_line; + while (std::getline(body_stream, body_line)) { + stream << " "; + PrintEscapedString(stream, body_line); + stream << '\n'; + } + stream << "\"\n"; +} + +void BytecodeExpectationsPrinter::PrintHandlers( + std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const { + stream << "handlers: [\n"; + HandlerTable* table = HandlerTable::cast(bytecode_array->handler_table()); + for (int i = 0, num_entries = table->NumberOfRangeEntries(); i < num_entries; + ++i) { + stream << " [" << table->GetRangeStart(i) << ", " << table->GetRangeEnd(i) + << ", " << table->GetRangeHandler(i) << "],\n"; + } + stream << "]\n"; +} + +void BytecodeExpectationsPrinter::PrintBytecodeArray( + std::ostream& stream, i::Handle<i::BytecodeArray> bytecode_array) const { + PrintFrameSize(stream, bytecode_array); + PrintBytecodeSequence(stream, bytecode_array); + PrintConstantPool(stream, bytecode_array->constant_pool()); + PrintHandlers(stream, bytecode_array); +} + +void BytecodeExpectationsPrinter::PrintExpectation( + std::ostream& stream, const std::string& snippet) const { + std::string source_code = + wrap_ ? WrapCodeInFunction(test_function_name_.c_str(), snippet) + : snippet; + + v8::Local<v8::Script> script = Compile(source_code.c_str()); + + if (execute_) Run(script); + + i::Handle<i::BytecodeArray> bytecode_array = + top_level_ ? GetBytecodeArrayForScript(script) + : GetBytecodeArrayForGlobal(test_function_name_.c_str()); + + stream << "---\n"; + PrintCodeSnippet(stream, snippet); + PrintBytecodeArray(stream, bytecode_array); + stream << '\n'; +} + +} // namespace interpreter +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/cctest/interpreter/bytecode-expectations-printer.h b/deps/v8/test/cctest/interpreter/bytecode-expectations-printer.h new file mode 100644 index 0000000000..236a7d4190 --- /dev/null +++ b/deps/v8/test/cctest/interpreter/bytecode-expectations-printer.h @@ -0,0 +1,119 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TEST_CCTEST_INTERPRETER_BYTECODE_EXPECTATIONS_PRINTER_H_ +#define TEST_CCTEST_INTERPRETER_BYTECODE_EXPECTATIONS_PRINTER_H_ + +#include <iostream> +#include <string> +#include <vector> + +#include "src/interpreter/bytecodes.h" +#include "src/objects.h" + +namespace v8 { + +class Isolate; + +namespace internal { +namespace interpreter { + +class BytecodeArrayIterator; + +class BytecodeExpectationsPrinter final { + public: + enum class ConstantPoolType { + kUnknown, + kString, + kNumber, + kMixed, + }; + + BytecodeExpectationsPrinter(v8::Isolate* i, + ConstantPoolType t = ConstantPoolType::kMixed) + : isolate_(i), + const_pool_type_(t), + execute_(true), + wrap_(true), + test_function_name_(kDefaultTopFunctionName) {} + + void PrintExpectation(std::ostream& stream, // NOLINT + const std::string& snippet) const; + + void set_constant_pool_type(ConstantPoolType const_pool_type) { + const_pool_type_ = const_pool_type; + } + ConstantPoolType const_pool_type() const { return const_pool_type_; } + + void set_execute(bool execute) { execute_ = execute; } + bool execute() const { return execute_; } + + void set_wrap(bool wrap) { wrap_ = wrap; } + bool wrap() const { return wrap_; } + + void set_top_level(bool top_level) { top_level_ = top_level; } + bool top_level() const { return top_level_; } + + void set_test_function_name(const std::string& test_function_name) { + test_function_name_ = test_function_name; + } + std::string test_function_name() const { return test_function_name_; } + + private: + void PrintEscapedString(std::ostream& stream, // NOLINT + const std::string& string) const; + void PrintBytecodeOperand(std::ostream& stream, // NOLINT + const BytecodeArrayIterator& bytecode_iter, + const Bytecode& bytecode, int op_index, + int parameter_count) const; + void PrintBytecode(std::ostream& stream, // NOLINT + const BytecodeArrayIterator& bytecode_iter, + int parameter_count) const; + void PrintV8String(std::ostream& stream, // NOLINT + i::String* string) const; + void PrintConstant(std::ostream& stream, // NOLINT + i::Handle<i::Object> constant) const; + void PrintFrameSize(std::ostream& stream, // NOLINT + i::Handle<i::BytecodeArray> bytecode_array) const; + void PrintBytecodeSequence(std::ostream& stream, // NOLINT + i::Handle<i::BytecodeArray> bytecode_array) const; + void PrintConstantPool(std::ostream& stream, // NOLINT + i::FixedArray* constant_pool) const; + void PrintCodeSnippet(std::ostream& stream, // NOLINT + const std::string& body) const; + void PrintBytecodeArray(std::ostream& stream, // NOLINT + i::Handle<i::BytecodeArray> bytecode_array) const; + void PrintHandlers(std::ostream& stream, // NOLINT + i::Handle<i::BytecodeArray> bytecode_array) const; + + v8::Local<v8::String> V8StringFromUTF8(const char* data) const; + std::string WrapCodeInFunction(const char* function_name, + const std::string& function_body) const; + + v8::Local<v8::Script> Compile(const char* program) const; + void Run(v8::Local<v8::Script> script) const; + i::Handle<i::BytecodeArray> GetBytecodeArrayForGlobal( + const char* global_name) const; + i::Handle<v8::internal::BytecodeArray> GetBytecodeArrayForScript( + v8::Local<v8::Script> script) const; + + i::Isolate* i_isolate() const { + return reinterpret_cast<i::Isolate*>(isolate_); + } + + v8::Isolate* isolate_; + ConstantPoolType const_pool_type_; + bool execute_; + bool wrap_; + bool top_level_; + std::string test_function_name_; + + static const char* const kDefaultTopFunctionName; +}; + +} // namespace interpreter +} // namespace internal +} // namespace v8 + +#endif // TEST_CCTEST_INTERPRETER_BYTECODE_EXPECTATIONS_PRINTER_H_ diff --git a/deps/v8/test/cctest/interpreter/generate-bytecode-expectations.cc b/deps/v8/test/cctest/interpreter/generate-bytecode-expectations.cc new file mode 100644 index 0000000000..567aa41a8e --- /dev/null +++ b/deps/v8/test/cctest/interpreter/generate-bytecode-expectations.cc @@ -0,0 +1,469 @@ +// Copyright 2016 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 <cstring> +#include <fstream> + +#include "test/cctest/interpreter/bytecode-expectations-printer.h" + +#include "include/libplatform/libplatform.h" +#include "include/v8.h" + +#include "src/base/logging.h" +#include "src/base/smart-pointers.h" +#include "src/compiler.h" +#include "src/interpreter/interpreter.h" + +using v8::internal::interpreter::BytecodeExpectationsPrinter; + +namespace { + +class ProgramOptions final { + public: + static ProgramOptions FromCommandLine(int argc, char** argv); + + ProgramOptions() + : parsing_failed_(false), + print_help_(false), + read_raw_js_snippet_(false), + read_from_stdin_(false), + rebaseline_(false), + wrap_(true), + execute_(true), + top_level_(false), + legacy_const_(false), + do_expressions_(false), + const_pool_type_( + BytecodeExpectationsPrinter::ConstantPoolType::kMixed) {} + + bool Validate() const; + void UpdateFromHeader(std::istream& stream); // NOLINT + void PrintHeader(std::ostream& stream) const; // NOLINT + + bool parsing_failed() const { return parsing_failed_; } + bool print_help() const { return print_help_; } + bool read_raw_js_snippet() const { return read_raw_js_snippet_; } + bool read_from_stdin() const { return read_from_stdin_; } + bool write_to_stdout() const { + return output_filename_.empty() && !rebaseline_; + } + bool rebaseline() const { return rebaseline_; } + bool wrap() const { return wrap_; } + bool execute() const { return execute_; } + bool top_level() const { return top_level_; } + bool legacy_const() const { return legacy_const_; } + bool do_expressions() const { return do_expressions_; } + BytecodeExpectationsPrinter::ConstantPoolType const_pool_type() const { + return const_pool_type_; + } + std::string input_filename() const { return input_filename_; } + std::string output_filename() const { return output_filename_; } + std::string test_function_name() const { return test_function_name_; } + + private: + bool parsing_failed_; + bool print_help_; + bool read_raw_js_snippet_; + bool read_from_stdin_; + bool rebaseline_; + bool wrap_; + bool execute_; + bool top_level_; + bool legacy_const_; + bool do_expressions_; + BytecodeExpectationsPrinter::ConstantPoolType const_pool_type_; + std::string input_filename_; + std::string output_filename_; + std::string test_function_name_; +}; + +class ArrayBufferAllocator final : public v8::ArrayBuffer::Allocator { + public: + void* Allocate(size_t length) override { + void* data = AllocateUninitialized(length); + if (data != nullptr) memset(data, 0, length); + return data; + } + void* AllocateUninitialized(size_t length) override { return malloc(length); } + void Free(void* data, size_t) override { free(data); } +}; + +class V8InitializationScope final { + public: + explicit V8InitializationScope(const char* exec_path); + ~V8InitializationScope(); + + v8::Platform* platform() const { return platform_.get(); } + v8::Isolate* isolate() const { return isolate_; } + + private: + v8::base::SmartPointer<v8::Platform> platform_; + v8::Isolate* isolate_; + + DISALLOW_COPY_AND_ASSIGN(V8InitializationScope); +}; + +BytecodeExpectationsPrinter::ConstantPoolType ParseConstantPoolType( + const char* type_string) { + if (strcmp(type_string, "number") == 0) { + return BytecodeExpectationsPrinter::ConstantPoolType::kNumber; + } else if (strcmp(type_string, "string") == 0) { + return BytecodeExpectationsPrinter::ConstantPoolType::kString; + } else if (strcmp(type_string, "mixed") == 0) { + return BytecodeExpectationsPrinter::ConstantPoolType::kMixed; + } + return BytecodeExpectationsPrinter::ConstantPoolType::kUnknown; +} + +const char* ConstantPoolTypeToString( + BytecodeExpectationsPrinter::ConstantPoolType type) { + switch (type) { + case BytecodeExpectationsPrinter::ConstantPoolType::kNumber: + return "number"; + case BytecodeExpectationsPrinter::ConstantPoolType::kMixed: + return "mixed"; + case BytecodeExpectationsPrinter::ConstantPoolType::kString: + return "string"; + default: + UNREACHABLE(); + return nullptr; + } +} + +bool ParseBoolean(const char* string) { + if (strcmp(string, "yes") == 0) { + return true; + } else if (strcmp(string, "no") == 0) { + return false; + } else { + UNREACHABLE(); + return false; + } +} + +const char* BooleanToString(bool value) { return value ? "yes" : "no"; } + +// static +ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) { + ProgramOptions options; + + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "--help") == 0) { + options.print_help_ = true; + } else if (strcmp(argv[i], "--raw-js") == 0) { + options.read_raw_js_snippet_ = true; + } else if (strncmp(argv[i], "--pool-type=", 12) == 0) { + options.const_pool_type_ = ParseConstantPoolType(argv[i] + 12); + } else if (strcmp(argv[i], "--stdin") == 0) { + options.read_from_stdin_ = true; + } else if (strcmp(argv[i], "--rebaseline") == 0) { + options.rebaseline_ = true; + } else if (strcmp(argv[i], "--no-wrap") == 0) { + options.wrap_ = false; + } else if (strcmp(argv[i], "--no-execute") == 0) { + options.execute_ = false; + } else if (strcmp(argv[i], "--top-level") == 0) { + options.top_level_ = true; + } else if (strcmp(argv[i], "--legacy-const") == 0) { + options.legacy_const_ = true; + } else if (strcmp(argv[i], "--do-expressions") == 0) { + options.do_expressions_ = true; + } else if (strncmp(argv[i], "--output=", 9) == 0) { + options.output_filename_ = argv[i] + 9; + } else if (strncmp(argv[i], "--test-function-name=", 21) == 0) { + options.test_function_name_ = argv[i] + 21; + } else if (strncmp(argv[i], "--", 2) != 0) { // It doesn't start with -- + if (!options.input_filename_.empty()) { + std::cerr << "ERROR: More than one input file specified\n"; + options.parsing_failed_ = true; + break; + } + options.input_filename_ = argv[i]; + } else { + std::cerr << "ERROR: Unknonwn option " << argv[i] << "\n"; + options.parsing_failed_ = true; + break; + } + } + + return options; +} + +bool ProgramOptions::Validate() const { + if (parsing_failed_) return false; + if (print_help_) return true; + + if (const_pool_type_ == + BytecodeExpectationsPrinter::ConstantPoolType::kUnknown) { + std::cerr << "ERROR: Unknown constant pool type.\n"; + return false; + } + + if (!read_from_stdin_ && input_filename_.empty()) { + std::cerr << "ERROR: No input file specified.\n"; + return false; + } + + if (read_from_stdin_ && !input_filename_.empty()) { + std::cerr << "ERROR: Reading from stdin, but input files supplied.\n"; + return false; + } + + if (rebaseline_ && read_raw_js_snippet_) { + std::cerr << "ERROR: Cannot use --rebaseline on a raw JS snippet.\n"; + return false; + } + + if (top_level_ && !test_function_name_.empty()) { + std::cerr << "ERROR: test function name specified while processing " + "top level code.\n"; + return false; + } + + return true; +} + +void ProgramOptions::UpdateFromHeader(std::istream& stream) { + std::string line; + + // Skip to the beginning of the options header + while (std::getline(stream, line)) { + if (line == "---") break; + } + + while (std::getline(stream, line)) { + if (line.compare(0, 11, "pool type: ") == 0) { + const_pool_type_ = ParseConstantPoolType(line.c_str() + 11); + } else if (line.compare(0, 9, "execute: ") == 0) { + execute_ = ParseBoolean(line.c_str() + 9); + } else if (line.compare(0, 6, "wrap: ") == 0) { + wrap_ = ParseBoolean(line.c_str() + 6); + } else if (line.compare(0, 20, "test function name: ") == 0) { + test_function_name_ = line.c_str() + 20; + } else if (line.compare(0, 11, "top level: ") == 0) { + top_level_ = ParseBoolean(line.c_str() + 11); + } else if (line.compare(0, 14, "legacy const: ") == 0) { + legacy_const_ = ParseBoolean(line.c_str() + 14); + } else if (line.compare(0, 16, "do expressions: ") == 0) { + do_expressions_ = ParseBoolean(line.c_str() + 16); + } else if (line == "---") { + break; + } else if (line.empty()) { + continue; + } else { + UNREACHABLE(); + return; + } + } +} + +void ProgramOptions::PrintHeader(std::ostream& stream) const { // NOLINT + stream << "---" + "\npool type: " + << ConstantPoolTypeToString(const_pool_type_) + << "\nexecute: " << BooleanToString(execute_) + << "\nwrap: " << BooleanToString(wrap_); + + if (!test_function_name_.empty()) { + stream << "\ntest function name: " << test_function_name_; + } + + if (top_level_) stream << "\ntop level: yes"; + if (legacy_const_) stream << "\nlegacy const: yes"; + if (do_expressions_) stream << "\ndo expressions: yes"; + + stream << "\n\n"; +} + +V8InitializationScope::V8InitializationScope(const char* exec_path) + : platform_(v8::platform::CreateDefaultPlatform()) { + i::FLAG_ignition = true; + i::FLAG_always_opt = false; + i::FLAG_allow_natives_syntax = true; + + v8::V8::InitializeICU(); + v8::V8::InitializeExternalStartupData(exec_path); + v8::V8::InitializePlatform(platform_.get()); + v8::V8::Initialize(); + + ArrayBufferAllocator allocator; + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = &allocator; + + isolate_ = v8::Isolate::New(create_params); +} + +V8InitializationScope::~V8InitializationScope() { + isolate_->Dispose(); + v8::V8::Dispose(); + v8::V8::ShutdownPlatform(); +} + +std::string ReadRawJSSnippet(std::istream& stream) { // NOLINT + std::stringstream body_buffer; + CHECK(body_buffer << stream.rdbuf()); + return body_buffer.str(); +} + +bool ReadNextSnippet(std::istream& stream, std::string* string_out) { // NOLINT + std::string line; + bool found_begin_snippet = false; + string_out->clear(); + while (std::getline(stream, line)) { + if (line == "snippet: \"") { + found_begin_snippet = true; + continue; + } + if (!found_begin_snippet) continue; + if (line == "\"") return true; + CHECK_GE(line.size(), 2u); // We should have the indent + string_out->append(line.begin() + 2, line.end()); + *string_out += '\n'; + } + return false; +} + +std::string UnescapeString(const std::string& escaped_string) { + std::string unescaped_string; + bool previous_was_backslash = false; + for (char c : escaped_string) { + if (previous_was_backslash) { + // If it was not an escape sequence, emit the previous backslash + if (c != '\\' && c != '"') unescaped_string += '\\'; + unescaped_string += c; + previous_was_backslash = false; + } else { + if (c == '\\') { + previous_was_backslash = true; + // Defer emission to the point where we can check if it was an escape. + } else { + unescaped_string += c; + } + } + } + return unescaped_string; +} + +void ExtractSnippets(std::vector<std::string>* snippet_list, + std::istream& body_stream, // NOLINT + bool read_raw_js_snippet) { + if (read_raw_js_snippet) { + snippet_list->push_back(ReadRawJSSnippet(body_stream)); + } else { + std::string snippet; + while (ReadNextSnippet(body_stream, &snippet)) { + snippet_list->push_back(UnescapeString(snippet)); + } + } +} + +void GenerateExpectationsFile(std::ostream& stream, // NOLINT + const std::vector<std::string>& snippet_list, + const ProgramOptions& options, + const char* exec_path) { + V8InitializationScope platform(exec_path); + { + v8::Isolate::Scope isolate_scope(platform.isolate()); + v8::HandleScope handle_scope(platform.isolate()); + v8::Local<v8::Context> context = v8::Context::New(platform.isolate()); + v8::Context::Scope context_scope(context); + + BytecodeExpectationsPrinter printer(platform.isolate(), + options.const_pool_type()); + printer.set_wrap(options.wrap()); + printer.set_execute(options.execute()); + printer.set_top_level(options.top_level()); + if (!options.test_function_name().empty()) { + printer.set_test_function_name(options.test_function_name()); + } + + if (options.legacy_const()) i::FLAG_legacy_const = true; + if (options.do_expressions()) i::FLAG_harmony_do_expressions = true; + + stream << "#\n# Autogenerated by generate-bytecode-expectations\n#\n\n"; + options.PrintHeader(stream); + for (const std::string& snippet : snippet_list) { + printer.PrintExpectation(stream, snippet); + } + } +} + +void PrintUsage(const char* exec_path) { + std::cerr + << "\nUsage: " << exec_path + << " [OPTIONS]... [INPUT FILE]\n\n" + "Options:\n" + " --help Print this help message.\n" + " --raw-js Read raw JavaScript, instead of the output format.\n" + " --stdin Read from standard input instead of file.\n" + " --rebaseline Rebaseline input snippet file.\n" + " --no-wrap Do not wrap the snippet in a function.\n" + " --no-execute Do not execute after compilation.\n" + " --test-function-name=foo " + "Specify the name of the test function.\n" + " --top-level Process top level code, not the top-level function." + " --legacy-const Enable legacy_const flag.\n" + " --do-expressions Enable harmony_do_expressions flag.\n" + " --output=file.name\n" + " Specify the output file. If not specified, output goes to " + "stdout.\n" + " --pool-type=(number|string|mixed)\n" + " Specify the type of the entries in the constant pool " + "(default: mixed).\n" + "\n" + "When using --rebaseline, flags --no-wrap, --no-execute, " + "--test-function-name\nand --pool-type will be overridden by the " + "options specified in the input file\nheader.\n\n" + "Each raw JavaScript file is interpreted as a single snippet.\n\n" + "This tool is intended as a help in writing tests.\n" + "Please, DO NOT blindly copy and paste the output " + "into the test suite.\n"; +} + +} // namespace + +int main(int argc, char** argv) { + ProgramOptions options = ProgramOptions::FromCommandLine(argc, argv); + + if (!options.Validate() || options.print_help()) { + PrintUsage(argv[0]); + return options.print_help() ? 0 : 1; + } + + std::ifstream input_file_handle; + if (!options.read_from_stdin()) { + input_file_handle.open(options.input_filename().c_str()); + if (!input_file_handle.is_open()) { + std::cerr << "ERROR: Could not open '" << options.input_filename() + << "' for reading.\n"; + return 2; + } + } + std::istream& input_stream = + options.read_from_stdin() ? std::cin : input_file_handle; + + if (options.rebaseline()) { + options.UpdateFromHeader(input_stream); + CHECK(options.Validate()); + } + + std::vector<std::string> snippet_list; + ExtractSnippets(&snippet_list, input_stream, options.read_raw_js_snippet()); + + std::ofstream output_file_handle; + if (!options.write_to_stdout()) { + output_file_handle.open(options.rebaseline() + ? options.input_filename().c_str() + : options.output_filename().c_str()); + if (!output_file_handle.is_open()) { + std::cerr << "ERROR: Could not open '" << options.output_filename() + << "' for writing.\n"; + return 3; + } + } + std::ostream& output_stream = + options.write_to_stdout() ? std::cout : output_file_handle; + + GenerateExpectationsFile(output_stream, snippet_list, options, argv[0]); +} diff --git a/deps/v8/test/cctest/interpreter/test-bytecode-generator.cc b/deps/v8/test/cctest/interpreter/test-bytecode-generator.cc index 2c06da26a1..73767eb3c6 100644 --- a/deps/v8/test/cctest/interpreter/test-bytecode-generator.cc +++ b/deps/v8/test/cctest/interpreter/test-bytecode-generator.cc @@ -15,6 +15,8 @@ namespace v8 { namespace internal { namespace interpreter { +static const InstanceType kInstanceTypeDontCare = static_cast<InstanceType>(-1); + class BytecodeGeneratorHelper { public: const char* kFunctionName = "f"; @@ -24,12 +26,9 @@ class BytecodeGeneratorHelper { BytecodeGeneratorHelper() { i::FLAG_ignition = true; - i::FLAG_ignition_fake_try_catch = true; - i::FLAG_ignition_fallback_on_eval_and_catch = false; i::FLAG_ignition_filter = StrDup(kFunctionName); i::FLAG_always_opt = false; i::FLAG_allow_natives_syntax = true; - i::FLAG_legacy_const = true; CcTest::i_isolate()->interpreter()->Initialize(); } @@ -94,6 +93,7 @@ class BytecodeGeneratorHelper { #define B(x) static_cast<uint8_t>(Bytecode::k##x) #define U8(x) static_cast<uint8_t>((x) & 0xff) #define R(x) static_cast<uint8_t>(-(x) & 0xff) +#define R16(x) U16(-(x)) #define A(x, n) R(helper.kLastParamIndex - (n) + 1 + (x)) #define THIS(n) A(0, n) #if defined(V8_TARGET_LITTLE_ENDIAN) @@ -160,6 +160,12 @@ struct ExpectedSnippet { const uint8_t bytecode[2048]; int constant_count; T constants[C]; + int handler_count; + struct { + int start; + int end; + int handler; + } handlers[C]; }; @@ -186,7 +192,9 @@ static void CheckConstant(Handle<Object> expected, Object* actual) { static void CheckConstant(InstanceType expected, Object* actual) { - CHECK_EQ(expected, HeapObject::cast(actual)->map()->instance_type()); + if (expected != kInstanceTypeDontCare) { + CHECK_EQ(expected, HeapObject::cast(actual)->map()->instance_type()); + } } @@ -204,6 +212,17 @@ static void CheckBytecodeArrayEqual(const ExpectedSnippet<T, C>& expected, CheckConstant(expected.constants[i], actual->constant_pool()->get(i)); } } + if (expected.handler_count == 0) { + CHECK_EQ(CcTest::heap()->empty_fixed_array(), actual->handler_table()); + } else { + HandlerTable* table = HandlerTable::cast(actual->handler_table()); + CHECK_EQ(expected.handler_count, table->NumberOfRangeEntries()); + for (int i = 0; i < expected.handler_count; i++) { + CHECK_EQ(expected.handlers[i].start, table->GetRangeStart(i)); + CHECK_EQ(expected.handlers[i].end, table->GetRangeEnd(i)); + CHECK_EQ(expected.handlers[i].handler, table->GetRangeHandler(i)); + } + } BytecodeArrayIterator iterator(actual); int i = 0; @@ -258,18 +277,110 @@ TEST(PrimitiveReturnStatements) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<int> snippets[] = { - {"", 0, 1, 2, {B(LdaUndefined), B(Return)}, 0}, - {"return;", 0, 1, 2, {B(LdaUndefined), B(Return)}, 0}, - {"return null;", 0, 1, 2, {B(LdaNull), B(Return)}, 0}, - {"return true;", 0, 1, 2, {B(LdaTrue), B(Return)}, 0}, - {"return false;", 0, 1, 2, {B(LdaFalse), B(Return)}, 0}, - {"return 0;", 0, 1, 2, {B(LdaZero), B(Return)}, 0}, - {"return +1;", 0, 1, 3, {B(LdaSmi8), U8(1), B(Return)}, 0}, - {"return -1;", 0, 1, 3, {B(LdaSmi8), U8(-1), B(Return)}, 0}, - {"return +127;", 0, 1, 3, {B(LdaSmi8), U8(127), B(Return)}, 0}, - {"return -128;", 0, 1, 3, {B(LdaSmi8), U8(-128), B(Return)}, 0}, + {"", + 0, + 1, + 3, + { + B(StackCheck), // + B(LdaUndefined), // + B(Return) // + }, + 0}, + {"return;", + 0, + 1, + 3, + { + B(StackCheck), // + B(LdaUndefined), // + B(Return) // + }, + 0}, + {"return null;", + 0, + 1, + 3, + { + B(StackCheck), // + B(LdaNull), // + B(Return) // + }, + 0}, + {"return true;", + 0, + 1, + 3, + { + B(StackCheck), // + B(LdaTrue), // + B(Return) // + }, + 0}, + {"return false;", + 0, + 1, + 3, + { + B(StackCheck), // + B(LdaFalse), // + B(Return) // + }, + 0}, + {"return 0;", + 0, + 1, + 3, + { + B(StackCheck), // + B(LdaZero), // + B(Return) // + }, + 0}, + {"return +1;", + 0, + 1, + 4, + { + B(StackCheck), // + B(LdaSmi8), U8(1), // + B(Return) // + }, + 0}, + {"return -1;", + 0, + 1, + 4, + { + B(StackCheck), // + B(LdaSmi8), U8(-1), // + B(Return) // + }, + 0}, + {"return +127;", + 0, + 1, + 4, + { + B(StackCheck), // + B(LdaSmi8), U8(127), // + B(Return) // + }, + 0}, + {"return -128;", + 0, + 1, + 4, + { + B(StackCheck), // + B(LdaSmi8), U8(-128), // + B(Return) // + }, + 0}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -283,20 +394,23 @@ TEST(PrimitiveExpressions) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<int> snippets[] = { {"var x = 0; return x;", kPointerSize, 1, - 4, - {B(LdaZero), // + 5, + {B(StackCheck), // + B(LdaZero), // B(Star), R(0), // B(Return)}, 0}, {"var x = 0; return x + 3;", 2 * kPointerSize, 1, - 10, - {B(LdaZero), // + 11, + {B(StackCheck), // + B(LdaZero), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(3), // @@ -306,8 +420,9 @@ TEST(PrimitiveExpressions) { {"var x = 0; return x - 3;", 2 * kPointerSize, 1, - 10, - {B(LdaZero), // + 11, + {B(StackCheck), // + B(LdaZero), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(3), // @@ -317,8 +432,9 @@ TEST(PrimitiveExpressions) { {"var x = 4; return x * 3;", 2 * kPointerSize, 1, - 11, - {B(LdaSmi8), U8(4), // + 12, + {B(StackCheck), // + B(LdaSmi8), U8(4), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(3), // @@ -328,8 +444,9 @@ TEST(PrimitiveExpressions) { {"var x = 4; return x / 3;", 2 * kPointerSize, 1, - 11, - {B(LdaSmi8), U8(4), // + 12, + {B(StackCheck), // + B(LdaSmi8), U8(4), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(3), // @@ -339,8 +456,9 @@ TEST(PrimitiveExpressions) { {"var x = 4; return x % 3;", 2 * kPointerSize, 1, - 11, - {B(LdaSmi8), U8(4), // + 12, + {B(StackCheck), // + B(LdaSmi8), U8(4), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(3), // @@ -350,8 +468,9 @@ TEST(PrimitiveExpressions) { {"var x = 1; return x | 2;", 2 * kPointerSize, 1, - 11, - {B(LdaSmi8), U8(1), // + 12, + {B(StackCheck), // + B(LdaSmi8), U8(1), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(2), // @@ -361,8 +480,9 @@ TEST(PrimitiveExpressions) { {"var x = 1; return x ^ 2;", 2 * kPointerSize, 1, - 11, - {B(LdaSmi8), U8(1), // + 12, + {B(StackCheck), // + B(LdaSmi8), U8(1), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(2), // @@ -372,8 +492,9 @@ TEST(PrimitiveExpressions) { {"var x = 1; return x & 2;", 2 * kPointerSize, 1, - 11, - {B(LdaSmi8), U8(1), // + 12, + {B(StackCheck), // + B(LdaSmi8), U8(1), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(2), // @@ -383,8 +504,9 @@ TEST(PrimitiveExpressions) { {"var x = 10; return x << 3;", 2 * kPointerSize, 1, - 11, - {B(LdaSmi8), U8(10), // + 12, + {B(StackCheck), // + B(LdaSmi8), U8(10), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(3), // @@ -394,8 +516,9 @@ TEST(PrimitiveExpressions) { {"var x = 10; return x >> 3;", 2 * kPointerSize, 1, - 11, - {B(LdaSmi8), U8(10), // + 12, + {B(StackCheck), // + B(LdaSmi8), U8(10), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(3), // @@ -405,8 +528,9 @@ TEST(PrimitiveExpressions) { {"var x = 10; return x >>> 3;", 2 * kPointerSize, 1, - 11, - {B(LdaSmi8), U8(10), // + 12, + {B(StackCheck), // + B(LdaSmi8), U8(10), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(3), // @@ -416,12 +540,15 @@ TEST(PrimitiveExpressions) { {"var x = 0; return (x, 3);", 1 * kPointerSize, 1, - 6, - {B(LdaZero), // + 7, + {B(StackCheck), // + B(LdaZero), // B(Star), R(0), // B(LdaSmi8), U8(3), // B(Return)}, - 0}}; + 0}, + }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -435,12 +562,14 @@ TEST(LogicalExpressions) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<int> snippets[] = { {"var x = 0; return x || 3;", 1 * kPointerSize, 1, - 8, - {B(LdaZero), // + 9, + {B(StackCheck), // + B(LdaZero), // B(Star), R(0), // B(JumpIfToBooleanTrue), U8(4), // B(LdaSmi8), U8(3), // @@ -449,8 +578,9 @@ TEST(LogicalExpressions) { {"var x = 0; return (x == 1) || 3;", 2 * kPointerSize, 1, - 14, - {B(LdaZero), // + 15, + {B(StackCheck), // + B(LdaZero), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(1), // @@ -462,8 +592,9 @@ TEST(LogicalExpressions) { {"var x = 0; return x && 3;", 1 * kPointerSize, 1, - 8, - {B(LdaZero), // + 9, + {B(StackCheck), // + B(LdaZero), // B(Star), R(0), // B(JumpIfToBooleanFalse), U8(4), // B(LdaSmi8), U8(3), // @@ -472,8 +603,9 @@ TEST(LogicalExpressions) { {"var x = 0; return (x == 0) && 3;", 2 * kPointerSize, 1, - 13, - {B(LdaZero), // + 14, + {B(StackCheck), // + B(LdaZero), // B(Star), R(0), // B(Star), R(1), // B(LdaZero), // @@ -485,8 +617,9 @@ TEST(LogicalExpressions) { {"var x = 0; return x || (1, 2, 3);", 1 * kPointerSize, 1, - 8, - {B(LdaZero), // + 9, + {B(StackCheck), // + B(LdaZero), // B(Star), R(0), // B(JumpIfToBooleanTrue), U8(4), // B(LdaSmi8), U8(3), // @@ -495,8 +628,9 @@ TEST(LogicalExpressions) { {"var a = 2, b = 3, c = 4; return a || (a, b, a, b, c = 5, 3);", 3 * kPointerSize, 1, - 31, - {B(LdaSmi8), U8(2), // + 32, + {B(StackCheck), // + B(LdaSmi8), U8(2), // B(Star), R(0), // B(LdaSmi8), U8(3), // B(Star), R(1), // @@ -518,8 +652,9 @@ TEST(LogicalExpressions) { "3);", 3 * kPointerSize, 1, - 275, - {B(LdaSmi8), U8(1), // + 276, + {B(StackCheck), // + B(LdaSmi8), U8(1), // B(Star), R(0), // B(LdaSmi8), U8(2), // B(Star), R(1), // @@ -541,8 +676,9 @@ TEST(LogicalExpressions) { "3);", 3 * kPointerSize, 1, - 274, - {B(LdaZero), // + 275, + {B(StackCheck), // + B(LdaZero), // B(Star), R(0), // B(LdaSmi8), U8(2), // B(Star), R(1), // @@ -564,8 +700,9 @@ TEST(LogicalExpressions) { "3);", 4 * kPointerSize, 1, - 281, - {B(LdaSmi8), U8(1), // + 282, + {B(StackCheck), // + B(LdaSmi8), U8(1), // B(Star), R(0), // B(LdaSmi8), U8(2), // B(Star), R(1), // @@ -590,8 +727,9 @@ TEST(LogicalExpressions) { "3);", 4 * kPointerSize, 1, - 280, - {B(LdaZero), // + 281, + {B(StackCheck), // + B(LdaZero), // B(Star), R(0), // B(LdaSmi8), U8(2), // B(Star), R(1), // @@ -614,22 +752,25 @@ TEST(LogicalExpressions) { {"return 0 && 3;", 0 * kPointerSize, 1, - 2, - {B(LdaZero), // + 3, + {B(StackCheck), // + B(LdaZero), // B(Return)}, 0}, {"return 1 || 3;", 0 * kPointerSize, 1, - 3, - {B(LdaSmi8), U8(1), // + 4, + {B(StackCheck), // + B(LdaSmi8), U8(1), // B(Return)}, 0}, {"var x = 1; return x && 3 || 0, 1;", 1 * kPointerSize, 1, - 14, - {B(LdaSmi8), U8(1), // + 15, + {B(StackCheck), // + B(LdaSmi8), U8(1), // B(Star), R(0), // B(JumpIfToBooleanFalse), U8(4), // B(LdaSmi8), U8(3), // @@ -637,7 +778,9 @@ TEST(LogicalExpressions) { B(LdaZero), // B(LdaSmi8), U8(1), // B(Return)}, - 0}}; + 0} + }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -651,42 +794,54 @@ TEST(Parameters) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<int> snippets[] = { {"function f() { return this; }", 0, 1, - 3, - {B(Ldar), THIS(1), B(Return)}, + 4, + {B(StackCheck), // + B(Ldar), THIS(1), // + B(Return)}, 0}, {"function f(arg1) { return arg1; }", 0, 2, - 3, - {B(Ldar), A(1, 2), B(Return)}, + 4, + {B(StackCheck), // + B(Ldar), A(1, 2), // + B(Return)}, 0}, {"function f(arg1) { return this; }", 0, 2, - 3, - {B(Ldar), THIS(2), B(Return)}, + 4, + {B(StackCheck), // + B(Ldar), THIS(2), // + B(Return)}, 0}, {"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return arg4; }", 0, 8, - 3, - {B(Ldar), A(4, 8), B(Return)}, + 4, + {B(StackCheck), // + B(Ldar), A(4, 8), // + B(Return)}, 0}, {"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return this; }", 0, 8, - 3, - {B(Ldar), THIS(8), B(Return)}, + 4, + {B(StackCheck), // + B(Ldar), THIS(8), // + B(Return)}, 0}, {"function f(arg1) { arg1 = 1; }", 0, 2, - 6, - {B(LdaSmi8), U8(1), // + 7, + {B(StackCheck), // + B(LdaSmi8), U8(1), // B(Star), A(1, 2), // B(LdaUndefined), // B(Return)}, @@ -694,13 +849,15 @@ TEST(Parameters) { {"function f(arg1, arg2, arg3, arg4) { arg2 = 1; }", 0, 5, - 6, - {B(LdaSmi8), U8(1), // + 7, + {B(StackCheck), // + B(LdaSmi8), U8(1), // B(Star), A(2, 5), // B(LdaUndefined), // B(Return)}, 0}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -714,12 +871,14 @@ TEST(IntegerConstants) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<int> snippets[] = { {"return 12345678;", 0, 1, - 3, + 4, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Return) // }, @@ -728,8 +887,9 @@ TEST(IntegerConstants) { {"var a = 1234; return 5678;", 1 * kPointerSize, 1, - 7, + 8, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(LdaConstant), U8(1), // @@ -740,15 +900,18 @@ TEST(IntegerConstants) { {"var a = 1234; return 1234;", 1 * kPointerSize, 1, - 7, + 8, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(LdaConstant), U8(0), // B(Return) // }, 1, - {1234}}}; + {1234}} + }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -764,12 +927,14 @@ TEST(HeapNumberConstants) { int wide_idx = 0; + // clang-format off ExpectedSnippet<double, 257> snippets[] = { {"return 1.2;", 0, 1, - 3, + 4, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Return) // }, @@ -778,8 +943,9 @@ TEST(HeapNumberConstants) { {"var a = 1.2; return 2.6;", 1 * kPointerSize, 1, - 7, + 8, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(LdaConstant), U8(1), // @@ -790,8 +956,9 @@ TEST(HeapNumberConstants) { {"var a = 3.14; return 3.14;", 1 * kPointerSize, 1, - 7, + 8, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(LdaConstant), U8(1), // @@ -804,8 +971,9 @@ TEST(HeapNumberConstants) { " a = 3.14;", 1 * kPointerSize, 1, - 1031, + 1032, { + B(StackCheck), // REPEAT_256(COMMA, // B(LdaConstant), U8(wide_idx++), // B(Star), R(0)), // @@ -818,6 +986,8 @@ TEST(HeapNumberConstants) { {REPEAT_256(COMMA, 1.414), 3.14}} }; + // clang-format on + for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); @@ -830,12 +1000,14 @@ TEST(StringConstants) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"return \"This is a string\";", 0, 1, - 3, + 4, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Return) // }, @@ -844,8 +1016,9 @@ TEST(StringConstants) { {"var a = \"First string\"; return \"Second string\";", 1 * kPointerSize, 1, - 7, + 8, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(LdaConstant), U8(1), // @@ -856,15 +1029,18 @@ TEST(StringConstants) { {"var a = \"Same string\"; return \"Same string\";", 1 * kPointerSize, 1, - 7, + 8, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(LdaConstant), U8(0), // B(Return) // }, 1, - {"Same string"}}}; + {"Same string"}} + }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -889,18 +1065,18 @@ TEST(PropertyLoads) { // These are a hack used by the LoadICXXXWide tests below. int wide_idx_1 = vector->GetIndex(slot1) - 2; int wide_idx_2 = vector->GetIndex(slot1) - 2; - int wide_idx_3 = vector->GetIndex(slot1) - 2; - int wide_idx_4 = vector->GetIndex(slot1) - 2; + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"function f(a) { return a.name; }\nf({name : \"test\"})", 1 * kPointerSize, 2, - 9, + 10, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // - B(LoadICSloppy), R(0), U8(0), U8(vector->GetIndex(slot1)), // + B(LoadIC), R(0), U8(0), U8(vector->GetIndex(slot1)), // B(Return), // }, 1, @@ -908,11 +1084,12 @@ TEST(PropertyLoads) { {"function f(a) { return a[\"key\"]; }\nf({key : \"test\"})", 1 * kPointerSize, 2, - 9, + 10, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // - B(LoadICSloppy), R(0), U8(0), U8(vector->GetIndex(slot1)), // + B(LoadIC), R(0), U8(0), U8(vector->GetIndex(slot1)), // B(Return) // }, 1, @@ -920,24 +1097,26 @@ TEST(PropertyLoads) { {"function f(a) { return a[100]; }\nf({100 : \"test\"})", 1 * kPointerSize, 2, - 10, + 11, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // B(LdaSmi8), U8(100), // - B(KeyedLoadICSloppy), R(0), U8(vector->GetIndex(slot1)), // + B(KeyedLoadIC), R(0), U8(vector->GetIndex(slot1)), // B(Return) // }, 0}, {"function f(a, b) { return a[b]; }\nf({arg : \"test\"}, \"arg\")", 1 * kPointerSize, 3, - 10, + 11, { + B(StackCheck), // B(Ldar), A(1, 3), // B(Star), R(0), // B(Ldar), A(1, 2), // - B(KeyedLoadICSloppy), R(0), U8(vector->GetIndex(slot1)), // + B(KeyedLoadIC), R(0), U8(vector->GetIndex(slot1)), // B(Return) // }, 0}, @@ -945,45 +1124,21 @@ TEST(PropertyLoads) { "f({\"-124\" : \"test\", name : 123 })", 2 * kPointerSize, 2, - 20, + 21, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(1), // - B(LoadICSloppy), R(1), U8(0), U8(vector->GetIndex(slot1)), // + B(LoadIC), R(1), U8(0), U8(vector->GetIndex(slot1)), // B(Star), R(0), // B(Ldar), A(1, 2), // B(Star), R(1), // B(LdaSmi8), U8(-124), // - B(KeyedLoadICSloppy), R(1), U8(vector->GetIndex(slot2)), // + B(KeyedLoadIC), R(1), U8(vector->GetIndex(slot2)), // B(Return), // }, 1, {"name"}}, - {"function f(a) { \"use strict\"; return a.name; }\nf({name : \"test\"})", - 1 * kPointerSize, - 2, - 9, - { - B(Ldar), A(1, 2), // - B(Star), R(0), // - B(LoadICStrict), R(0), U8(0), U8(vector->GetIndex(slot1)), // - B(Return), // - }, - 1, - {"name"}}, - {"function f(a, b) { \"use strict\"; return a[b]; }\n" - "f({arg : \"test\"}, \"arg\")", - 1 * kPointerSize, - 3, - 10, - { - B(Ldar), A(1, 3), // - B(Star), R(0), // - B(Ldar), A(2, 3), // - B(KeyedLoadICStrict), R(0), U8(vector->GetIndex(slot1)), // - B(Return), // - }, - 0}, {"function f(a) {\n" " var b;\n" "b = a.name;" @@ -992,48 +1147,22 @@ TEST(PropertyLoads) { "f({name : \"test\"})\n", 2 * kPointerSize, 2, - 1291, + 1292, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(1), // - B(LoadICSloppy), R(1), U8(0), U8(wide_idx_1 += 2), // + B(LoadIC), R(1), U8(0), U8(wide_idx_1 += 2), // B(Star), R(0), // REPEAT_127(COMMA, // B(Ldar), A(1, 2), // B(Star), R(1), // - B(LoadICSloppy), R(1), U8(0), // + B(LoadIC), R(1), U8(0), // U8((wide_idx_1 += 2)), // B(Star), R(0)), // B(Ldar), A(1, 2), // B(Star), R(1), // - B(LoadICSloppyWide), R(1), U16(0), U16(wide_idx_1 + 2), // - B(Return), // - }, - 1, - {"name"}}, - {"function f(a) {\n" - " 'use strict'; var b;\n" - " b = a.name;\n" - REPEAT_127(SPACE, " b = a.name; ") - " return a.name; }\n" - "f({name : \"test\"})\n", - 2 * kPointerSize, - 2, - 1291, - { - B(Ldar), A(1, 2), // - B(Star), R(1), // - B(LoadICStrict), R(1), U8(0), U8((wide_idx_2 += 2)), // - B(Star), R(0), // - REPEAT_127(COMMA, // - B(Ldar), A(1, 2), // - B(Star), R(1), // - B(LoadICStrict), R(1), U8(0), // - U8((wide_idx_2 += 2)), // - B(Star), R(0)), // - B(Ldar), A(1, 2), // - B(Star), R(1), // - B(LoadICStrictWide), R(1), U16(0), U16(wide_idx_2 + 2), // + B(LoadICWide), R(1), U16(0), U16(wide_idx_1 + 2), // B(Return), // }, 1, @@ -1046,53 +1175,29 @@ TEST(PropertyLoads) { "f({name : \"test\"}, \"name\")\n", 2 * kPointerSize, 3, - 1419, - { - B(Ldar), A(1, 3), // - B(Star), R(1), // - B(Ldar), A(2, 3), // - B(KeyedLoadICSloppy), R(1), U8((wide_idx_3 += 2)), // - B(Star), R(0), // - REPEAT_127(COMMA, // - B(Ldar), A(1, 3), // - B(Star), R(1), // - B(Ldar), A(2, 3), // - B(KeyedLoadICSloppy), R(1), U8((wide_idx_3 += 2)), // - B(Star), R(0)), // - B(Ldar), A(1, 3), // - B(Star), R(1), // - B(Ldar), A(2, 3), // - B(KeyedLoadICSloppyWide), R(1), U16(wide_idx_3 + 2), // - B(Return), // - }}, - {"function f(a, b) {\n" - " 'use strict'; var c;\n" - " c = a[b];" - REPEAT_127(SPACE, " c = a[b]; ") - " return a[b]; }\n" - "f({name : \"test\"}, \"name\")\n", - 2 * kPointerSize, - 3, - 1419, + 1420, { + B(StackCheck), // B(Ldar), A(1, 3), // B(Star), R(1), // B(Ldar), A(2, 3), // - B(KeyedLoadICStrict), R(1), U8((wide_idx_4 += 2)), // + B(KeyedLoadIC), R(1), U8((wide_idx_2 += 2)), // B(Star), R(0), // REPEAT_127(COMMA, // B(Ldar), A(1, 3), // B(Star), R(1), // B(Ldar), A(2, 3), // - B(KeyedLoadICStrict), R(1), U8((wide_idx_4 += 2)), // + B(KeyedLoadIC), R(1), U8((wide_idx_2 += 2)), // B(Star), R(0)), // B(Ldar), A(1, 3), // B(Star), R(1), // B(Ldar), A(2, 3), // - B(KeyedLoadICStrictWide), R(1), U16(wide_idx_4 + 2), // + B(KeyedLoadICWide), R(1), U16(wide_idx_2 + 2), // B(Return), // }}, }; + // clang-format on + for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName); @@ -1119,12 +1224,14 @@ TEST(PropertyStores) { int wide_idx_3 = vector->GetIndex(slot1) - 2; int wide_idx_4 = vector->GetIndex(slot1) - 2; + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"function f(a) { a.name = \"val\"; }\nf({name : \"test\"})", kPointerSize, 2, - 12, + 13, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // B(LdaConstant), U8(0), // @@ -1137,8 +1244,9 @@ TEST(PropertyStores) { {"function f(a) { a[\"key\"] = \"val\"; }\nf({key : \"test\"})", kPointerSize, 2, - 12, + 13, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // B(LdaConstant), U8(0), // @@ -1151,8 +1259,9 @@ TEST(PropertyStores) { {"function f(a) { a[100] = \"val\"; }\nf({100 : \"test\"})", 2 * kPointerSize, 2, - 16, + 17, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // B(LdaSmi8), U8(100), // @@ -1168,8 +1277,9 @@ TEST(PropertyStores) { {"function f(a, b) { a[b] = \"val\"; }\nf({arg : \"test\"}, \"arg\")", 2 * kPointerSize, 3, - 16, + 17, { + B(StackCheck), // B(Ldar), A(1, 3), // B(Star), R(0), // B(Ldar), A(2, 3), // @@ -1186,14 +1296,15 @@ TEST(PropertyStores) { "f({\"-124\" : \"test\", name : 123 })", 2 * kPointerSize, 2, - 19, + 20, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // B(Ldar), A(1, 2), // B(Star), R(1), // B(LdaSmi8), U8(-124), // - B(KeyedLoadICSloppy), R(1), U8(vector->GetIndex(slot1)), // + B(KeyedLoadIC), R(1), U8(vector->GetIndex(slot1)), // B(StoreICSloppy), R(0), U8(0), U8(vector->GetIndex(slot2)), // B(LdaUndefined), // B(Return), // @@ -1204,8 +1315,9 @@ TEST(PropertyStores) { "f({name : \"test\"})", kPointerSize, 2, - 12, + 13, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // B(LdaConstant), U8(0), // @@ -1219,8 +1331,9 @@ TEST(PropertyStores) { "f({arg : \"test\"}, \"arg\")", 2 * kPointerSize, 3, - 16, + 17, { + B(StackCheck), // B(Ldar), A(1, 3), // B(Star), R(0), // B(Ldar), A(2, 3), // @@ -1239,8 +1352,9 @@ TEST(PropertyStores) { "f({name : \"test\"})\n", kPointerSize, 2, - 1294, + 1295, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // B(LdaSmi8), U8(1), // @@ -1268,8 +1382,9 @@ TEST(PropertyStores) { "f({name : \"test\"})\n", kPointerSize, 2, - 1294, + 1295, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // B(LdaSmi8), U8(1), // @@ -1296,8 +1411,9 @@ TEST(PropertyStores) { "f({name : \"test\"})\n", 2 * kPointerSize, 3, - 1809, + 1810, { + B(StackCheck), // B(Ldar), A(1, 3), // B(Star), R(0), // B(Ldar), A(2, 3), // @@ -1329,8 +1445,9 @@ TEST(PropertyStores) { "f({name : \"test\"})\n", 2 * kPointerSize, 3, - 1809, + 1810, { + B(StackCheck), // B(Ldar), A(1, 3), // B(Star), R(0), // B(Ldar), A(2, 3), // @@ -1353,7 +1470,10 @@ TEST(PropertyStores) { B(KeyedStoreICStrictWide), R(0), R(1), U16(wide_idx_4 + 2), // B(LdaUndefined), // B(Return), // - }}}; + }} + }; + // clang-format on + for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName); @@ -1380,17 +1500,19 @@ TEST(PropertyCall) { // These are a hack used by the CallWide test below. int wide_idx = vector->GetIndex(slot1) - 2; + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"function f(a) { return a.func(); }\nf(" FUNC_ARG ")", 2 * kPointerSize, 2, - 16, + 17, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(1), // - B(LoadICSloppy), R(1), U8(0), U8(vector->GetIndex(slot2)), // + B(LoadIC), R(1), U8(0), U8(vector->GetIndex(slot2)), // B(Star), R(0), // - B(Call), R(0), R(1), U8(0), U8(vector->GetIndex(slot1)), // + B(Call), R(0), R(1), U8(1), U8(vector->GetIndex(slot1)), // B(Return), // }, 1, @@ -1398,17 +1520,18 @@ TEST(PropertyCall) { {"function f(a, b, c) { return a.func(b, c); }\nf(" FUNC_ARG ", 1, 2)", 4 * kPointerSize, 4, - 24, + 25, { + B(StackCheck), // B(Ldar), A(1, 4), // B(Star), R(1), // - B(LoadICSloppy), R(1), U8(0), U8(vector->GetIndex(slot2)), // + B(LoadIC), R(1), U8(0), U8(vector->GetIndex(slot2)), // B(Star), R(0), // B(Ldar), A(2, 4), // B(Star), R(2), // B(Ldar), A(3, 4), // B(Star), R(3), // - B(Call), R(0), R(1), U8(2), U8(vector->GetIndex(slot1)), // + B(Call), R(0), R(1), U8(3), U8(vector->GetIndex(slot1)), // B(Return) // }, 1, @@ -1416,11 +1539,12 @@ TEST(PropertyCall) { {"function f(a, b) { return a.func(b + b, b); }\nf(" FUNC_ARG ", 1)", 4 * kPointerSize, 3, - 30, + 31, { + B(StackCheck), // B(Ldar), A(1, 3), // B(Star), R(1), // - B(LoadICSloppy), R(1), U8(0), U8(vector->GetIndex(slot2)), // + B(LoadIC), R(1), U8(0), U8(vector->GetIndex(slot2)), // B(Star), R(0), // B(Ldar), A(2, 3), // B(Star), R(3), // @@ -1429,36 +1553,38 @@ TEST(PropertyCall) { B(Star), R(2), // B(Ldar), A(2, 3), // B(Star), R(3), // - B(Call), R(0), R(1), U8(2), U8(vector->GetIndex(slot1)), // + B(Call), R(0), R(1), U8(3), U8(vector->GetIndex(slot1)), // B(Return), // }, 1, {"func"}}, {"function f(a) {\n" - " a.func;\n" - REPEAT_127(SPACE, " a.func;\n") - " return a.func(); }\nf(" FUNC_ARG ")", + " a.func;\n" REPEAT_127( + SPACE, " a.func;\n") " return a.func(); }\nf(" FUNC_ARG ")", 2 * kPointerSize, 2, - 1044, + 1047, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // - B(LoadICSloppy), R(0), U8(0), U8(wide_idx += 2), // + B(LoadIC), R(0), U8(0), U8(wide_idx += 2), // REPEAT_127(COMMA, // B(Ldar), A(1, 2), // B(Star), R(0), // - B(LoadICSloppy), R(0), U8(0), U8((wide_idx += 2))), // + B(LoadIC), R(0), U8(0), U8((wide_idx += 2))), // B(Ldar), A(1, 2), // B(Star), R(1), // - B(LoadICSloppyWide), R(1), U16(0), U16(wide_idx + 4), // + B(LoadICWide), R(1), U16(0), U16(wide_idx + 4), // B(Star), R(0), // - B(CallWide), R(0), R(1), U16(0), U16(wide_idx + 2), // + B(CallWide), R16(0), R16(1), U16(1), U16(wide_idx + 2), // B(Return), // }, 1, {"func"}}, }; + // clang-format on + for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName); @@ -1480,15 +1606,16 @@ TEST(LoadGlobal) { // These are a hack used by the LdaGlobalXXXWide tests below. int wide_idx_1 = vector->GetIndex(slot) - 2; - int wide_idx_2 = vector->GetIndex(slot) - 2; + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"var a = 1;\nfunction f() { return a; }\nf()", 0, 1, - 4, + 5, { - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot)), // + B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot)), // B(Return) // }, 1, @@ -1496,29 +1623,21 @@ TEST(LoadGlobal) { {"function t() { }\nfunction f() { return t; }\nf()", 0, 1, - 4, + 5, { - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot)), // + B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot)), // B(Return) // }, 1, {"t"}}, - {"'use strict'; var a = 1;\nfunction f() { return a; }\nf()", - 0, - 1, - 4, - { - B(LdaGlobalStrict), U8(0), U8(vector->GetIndex(slot)), // - B(Return) // - }, - 1, - {"a"}}, {"a = 1;\nfunction f() { return a; }\nf()", 0, 1, - 4, + 5, { - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot)), // + B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot)), // B(Return) // }, 1, @@ -1531,44 +1650,23 @@ TEST(LoadGlobal) { "}\nf({name: 1});", kPointerSize, 2, - 1030, - { - B(Ldar), A(1, 2), // - B(Star), R(0), // - B(LoadICSloppy), R(0), U8(0), U8(wide_idx_1 += 2), // - REPEAT_127(COMMA, // - B(Ldar), A(1, 2), // - B(Star), R(0), // - B(LoadICSloppy), R(0), U8(0), U8(wide_idx_1 += 2)), // - B(LdaGlobalSloppyWide), U16(1), U16(wide_idx_1 + 2), // - B(Return), // - }, - 2, - {"name", "a"}}, - {"a = 1;" - "function f(b) {\n" - " 'use strict';\n" - " b.name\n" - REPEAT_127(SPACE, "b.name; ") - " return a;" - "}\nf({name: 1});", - kPointerSize, - 2, - 1030, + 1031, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // - B(LoadICStrict), R(0), U8(0), U8(wide_idx_2 += 2), // + B(LoadIC), R(0), U8(0), U8(wide_idx_1 += 2), // REPEAT_127(COMMA, // B(Ldar), A(1, 2), // B(Star), R(0), // - B(LoadICStrict), R(0), U8(0), U8(wide_idx_2 += 2)), // - B(LdaGlobalStrictWide), U16(1), U16(wide_idx_2 + 2), // + B(LoadIC), R(0), U8(0), U8(wide_idx_1 += 2)), // + B(LdaGlobalWide), U16(1), U16(wide_idx_1 + 2), // B(Return), // }, 2, {"name", "a"}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -1593,12 +1691,14 @@ TEST(StoreGlobal) { int wide_idx_1 = vector->GetIndex(slot) - 2; int wide_idx_2 = vector->GetIndex(slot) - 2; + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"var a = 1;\nfunction f() { a = 2; }\nf()", 0, 1, - 7, + 8, { + B(StackCheck), // B(LdaSmi8), U8(2), // B(StaGlobalSloppy), U8(0), U8(vector->GetIndex(slot)), // B(LdaUndefined), // @@ -1609,8 +1709,9 @@ TEST(StoreGlobal) { {"var a = \"test\"; function f(b) { a = b; }\nf(\"global\")", 0, 2, - 7, + 8, { + B(StackCheck), // B(Ldar), R(helper.kLastParamIndex), // B(StaGlobalSloppy), U8(0), U8(vector->GetIndex(slot)), // B(LdaUndefined), // @@ -1621,8 +1722,9 @@ TEST(StoreGlobal) { {"'use strict'; var a = 1;\nfunction f() { a = 2; }\nf()", 0, 1, - 7, + 8, { + B(StackCheck), // B(LdaSmi8), U8(2), // B(StaGlobalStrict), U8(0), U8(vector->GetIndex(slot)), // B(LdaUndefined), // @@ -1633,8 +1735,9 @@ TEST(StoreGlobal) { {"a = 1;\nfunction f() { a = 2; }\nf()", 0, 1, - 7, + 8, { + B(StackCheck), // B(LdaSmi8), U8(2), // B(StaGlobalSloppy), U8(0), U8(vector->GetIndex(slot)), // B(LdaUndefined), // @@ -1650,15 +1753,16 @@ TEST(StoreGlobal) { "f({name: 1});", kPointerSize, 2, - 1033, + 1034, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // - B(LoadICSloppy), R(0), U8(0), U8(wide_idx_1 += 2), // + B(LoadIC), R(0), U8(0), U8(wide_idx_1 += 2), // REPEAT_127(COMMA, // B(Ldar), A(1, 2), // B(Star), R(0), // - B(LoadICSloppy), R(0), U8(0), U8(wide_idx_1 += 2)), // + B(LoadIC), R(0), U8(0), U8(wide_idx_1 += 2)), // B(LdaSmi8), U8(2), // B(StaGlobalSloppyWide), U16(1), U16(wide_idx_1 + 2), // B(LdaUndefined), // @@ -1675,15 +1779,16 @@ TEST(StoreGlobal) { "f({name: 1});", kPointerSize, 2, - 1033, + 1034, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // - B(LoadICStrict), R(0), U8(0), U8(wide_idx_2 += 2), // + B(LoadIC), R(0), U8(0), U8(wide_idx_2 += 2), // REPEAT_127(COMMA, // B(Ldar), A(1, 2), // B(Star), R(0), // - B(LoadICStrict), R(0), U8(0), U8(wide_idx_2 += 2)), // + B(LoadIC), R(0), U8(0), U8(wide_idx_2 += 2)), // B(LdaSmi8), U8(2), // B(StaGlobalStrictWide), U16(1), U16(wide_idx_2 + 2), // B(LdaUndefined), // @@ -1692,6 +1797,7 @@ TEST(StoreGlobal) { 2, {"name", "a"}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -1713,17 +1819,19 @@ TEST(CallGlobal) { Handle<i::TypeFeedbackVector> vector = i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"function t() { }\nfunction f() { return t(); }\nf()", 2 * kPointerSize, 1, - 14, + 15, { + B(StackCheck), // B(LdaUndefined), // B(Star), R(1), // - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot2)), // B(Star), R(0), // - B(Call), R(0), R(1), U8(0), U8(vector->GetIndex(slot1)), // + B(Call), R(0), R(1), U8(1), U8(vector->GetIndex(slot1)), // B(Return) // }, 1, @@ -1731,11 +1839,12 @@ TEST(CallGlobal) { {"function t(a, b, c) { }\nfunction f() { return t(1, 2, 3); }\nf()", 5 * kPointerSize, 1, - 26, + 27, { + B(StackCheck), // B(LdaUndefined), // B(Star), R(1), // - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot2)), // B(Star), R(0), // B(LdaSmi8), U8(1), // B(Star), R(2), // @@ -1743,12 +1852,13 @@ TEST(CallGlobal) { B(Star), R(3), // B(LdaSmi8), U8(3), // B(Star), R(4), // - B(Call), R(0), R(1), U8(3), U8(vector->GetIndex(slot1)), // + B(Call), R(0), R(1), U8(4), U8(vector->GetIndex(slot1)), // B(Return) // }, 1, {"t"}}, }; + // clang-format on size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]); for (size_t i = 0; i < num_snippets; i++) { @@ -1763,13 +1873,15 @@ TEST(CallRuntime) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { { "function f() { %TheHole() }\nf()", 0, 1, - 7, + 8, { + B(StackCheck), // B(CallRuntime), U16(Runtime::kTheHole), R(0), U8(0), // B(LdaUndefined), // B(Return) // @@ -1779,8 +1891,9 @@ TEST(CallRuntime) { "function f(a) { return %IsArray(a) }\nf(undefined)", 1 * kPointerSize, 2, - 10, + 11, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // B(CallRuntime), U16(Runtime::kIsArray), R(0), U8(1), // @@ -1791,8 +1904,9 @@ TEST(CallRuntime) { "function f() { return %Add(1, 2) }\nf()", 2 * kPointerSize, 1, - 14, + 15, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(LdaSmi8), U8(2), // @@ -1805,20 +1919,22 @@ TEST(CallRuntime) { "function f() { return %spread_iterable([1]) }\nf()", 2 * kPointerSize, 1, - 15, + 16, { + B(StackCheck), // B(LdaUndefined), // B(Star), R(0), // B(CreateArrayLiteral), U8(0), U8(0), U8(3), // B(Star), R(1), // B(CallJSRuntime), U16(Context::SPREAD_ITERABLE_INDEX), R(0), // - U8(1), // + /* */ U8(2), // B(Return), // }, 1, {InstanceType::FIXED_ARRAY_TYPE}, }, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -1834,12 +1950,14 @@ TEST(IfConditions) { Handle<Object> unused = helper.factory()->undefined_value(); + // clang-format off ExpectedSnippet<Handle<Object>> snippets[] = { {"function f() { if (0) { return 1; } else { return -1; } } f()", 0, 1, - 3, + 4, { + B(StackCheck), // B(LdaSmi8), U8(-1), // B(Return), // }, @@ -1848,8 +1966,9 @@ TEST(IfConditions) { {"function f() { if ('lucky') { return 1; } else { return -1; } } f();", 0, 1, - 3, + 4, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Return), // }, @@ -1858,8 +1977,9 @@ TEST(IfConditions) { {"function f() { if (false) { return 1; } else { return -1; } } f();", 0, 1, - 3, + 4, { + B(StackCheck), // B(LdaSmi8), U8(-1), // B(Return), // }, @@ -1868,8 +1988,9 @@ TEST(IfConditions) { {"function f() { if (false) { return 1; } } f();", 0, 1, - 2, + 3, { + B(StackCheck), // B(LdaUndefined), // B(Return), // }, @@ -1878,8 +1999,9 @@ TEST(IfConditions) { {"function f() { var a = 1; if (a) { a += 1; } else { return 2; } } f();", 2 * kPointerSize, 1, - 23, + 24, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(JumpIfToBooleanFalse), U8(14), // @@ -1900,8 +2022,9 @@ TEST(IfConditions) { "f(99);", kPointerSize, 2, - 17, + 18, { + B(StackCheck), // B(Ldar), A(1, 2), // B(Star), R(0), // B(LdaZero), // @@ -1922,8 +2045,9 @@ TEST(IfConditions) { "f('prop', { prop: 'yes'});", kPointerSize, 3, - 15, + 16, { + B(StackCheck), // B(Ldar), A(1, 3), // B(Star), R(0), // B(Ldar), A(2, 3), // @@ -1942,8 +2066,9 @@ TEST(IfConditions) { " return 200; } else { return -200; } } f(0.001)", 3 * kPointerSize, 2, - 282, + 283, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(LdaZero), // @@ -1973,8 +2098,9 @@ TEST(IfConditions) { " return 200; } else { return -200; } } f()", 2 * kPointerSize, 1, - 276, + 277, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(LdaZero), // @@ -2009,7 +2135,7 @@ TEST(IfConditions) { "} f(1, 1);", kPointerSize, 3, - 106, + 107, { #define IF_CONDITION_RETURN(condition) \ B(Ldar), A(1, 3), \ @@ -2019,6 +2145,7 @@ TEST(IfConditions) { B(JumpIfFalse), U8(5), \ B(LdaSmi8), U8(1), \ B(Return), + B(StackCheck), // IF_CONDITION_RETURN(TestEqual) // IF_CONDITION_RETURN(TestEqualStrict) // IF_CONDITION_RETURN(TestLessThan) // @@ -2042,8 +2169,9 @@ TEST(IfConditions) { "f();", 1 * kPointerSize, 1, - 13, + 14, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(JumpIfToBooleanFalse), U8(5), // @@ -2055,7 +2183,9 @@ TEST(IfConditions) { B(Return) }, 0, - {unused, unused, unused, unused, unused, unused}}}; + {unused, unused, unused, unused, unused, unused}} + }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -2086,17 +2216,19 @@ TEST(DeclareGlobals) { Handle<i::TypeFeedbackVector> load_vector = i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec_loads); + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"var a = 1;", 4 * kPointerSize, 1, - 30, + 31, { B(LdaConstant), U8(0), // B(Star), R(1), // B(LdaZero), // B(Star), R(2), // B(CallRuntime), U16(Runtime::kDeclareGlobals), R(1), U8(2), // + B(StackCheck), // B(LdaConstant), U8(1), // B(Star), R(1), // B(LdaZero), // @@ -2113,13 +2245,14 @@ TEST(DeclareGlobals) { {"function f() {}", 2 * kPointerSize, 1, - 14, + 15, { B(LdaConstant), U8(0), // B(Star), R(0), // B(LdaZero), // B(Star), R(1), // B(CallRuntime), U16(Runtime::kDeclareGlobals), R(0), U8(2), // + B(StackCheck), // B(LdaUndefined), // B(Return) // }, @@ -2128,13 +2261,14 @@ TEST(DeclareGlobals) { {"var a = 1;\na=2;", 4 * kPointerSize, 1, - 36, + 37, { B(LdaConstant), U8(0), // B(Star), R(1), // B(LdaZero), // B(Star), R(2), // B(CallRuntime), U16(Runtime::kDeclareGlobals), R(1), U8(2), // + B(StackCheck), // B(LdaConstant), U8(1), // B(Star), R(1), // B(LdaZero), // @@ -2144,7 +2278,7 @@ TEST(DeclareGlobals) { B(CallRuntime), U16(Runtime::kInitializeVarGlobal), R(1), U8(3), // B(LdaSmi8), U8(2), // B(StaGlobalSloppy), U8(1), // - U8(store_vector->GetIndex(store_slot_2)), // + /* */ U8(store_vector->GetIndex(store_slot_2)), // B(Star), R(0), // B(Return) // }, @@ -2154,20 +2288,20 @@ TEST(DeclareGlobals) { {"function f() {}\nf();", 3 * kPointerSize, 1, - 28, + 29, { B(LdaConstant), U8(0), // B(Star), R(1), // B(LdaZero), // B(Star), R(2), // B(CallRuntime), U16(Runtime::kDeclareGlobals), R(1), U8(2), // + B(StackCheck), // B(LdaUndefined), // B(Star), R(2), // - B(LdaGlobalSloppy), U8(1), // - U8(load_vector->GetIndex(load_slot_1)), // + B(LdaGlobal), U8(1), U8(load_vector->GetIndex(load_slot_1)), // B(Star), R(1), // - B(Call), R(1), R(2), U8(0), // - U8(load_vector->GetIndex(call_slot_1)), // + B(Call), R(1), R(2), U8(1), // + /* */ U8(load_vector->GetIndex(call_slot_1)), // B(Star), R(0), // B(Return) // }, @@ -2175,6 +2309,7 @@ TEST(DeclareGlobals) { {InstanceType::FIXED_ARRAY_TYPE, InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -2188,7 +2323,11 @@ TEST(BreakableBlocks) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; - ExpectedSnippet<int> snippets[] = { + int closure = Register::function_closure().index(); + int context = Register::current_context().index(); + + // clang-format off + ExpectedSnippet<InstanceType> snippets[] = { {"var x = 0;\n" "label: {\n" " x = x + 1;\n" @@ -2198,8 +2337,9 @@ TEST(BreakableBlocks) { "return x;", 2 * kPointerSize, 1, - 16, + 17, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(Star), R(1), // @@ -2222,8 +2362,9 @@ TEST(BreakableBlocks) { "return sum;", 5 * kPointerSize, 1, - 72, + 75, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(LdaZero), // @@ -2232,14 +2373,16 @@ TEST(BreakableBlocks) { B(Star), R(3), // B(LdaSmi8), U8(10), // B(TestLessThan), R(3), // - B(JumpIfFalse), U8(55), // + B(JumpIfFalse), U8(57), // + B(StackCheck), // B(LdaZero), // B(Star), R(2), // B(Ldar), R(2), // B(Star), R(3), // B(LdaSmi8), U8(3), // B(TestLessThan), R(3), // - B(JumpIfFalse), U8(34), // + B(JumpIfFalse), U8(35), // + B(StackCheck), // B(Ldar), R(0), // B(ToNumber), // B(Inc), // @@ -2257,16 +2400,128 @@ TEST(BreakableBlocks) { B(ToNumber), // B(Inc), // B(Star), R(2), // - B(Jump), U8(-40), // + B(Jump), U8(-41), // B(Ldar), R(1), // B(ToNumber), // B(Inc), // B(Star), R(1), // - B(Jump), U8(-61), // + B(Jump), U8(-63), // B(Ldar), R(0), // B(Return), // }}, + {"outer: {\n" + " let y = 10;" + " function f() { return y; }\n" + " break outer;\n" + "}\n", + 5 * kPointerSize, + 1, + 51, + { + B(StackCheck), // + B(LdaConstant), U8(0), // + B(Star), R(3), // + B(Ldar), R(closure), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kPushBlockContext), R(3), U8(2), // + B(PushContext), R(2), // + B(LdaTheHole), // + B(StaContextSlot), R(context), U8(4), // + B(CreateClosure), U8(1), U8(0), // + B(Star), R(0), // + B(LdaSmi8), U8(10), // + B(StaContextSlot), R(context), U8(4), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(2), // + B(Star), R(3), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(3), U8(1), // + B(Star), R(1), // + B(Jump), U8(2), // + B(PopContext), R(2), // + B(LdaUndefined), // + B(Return), // + }, + 3, + {InstanceType::FIXED_ARRAY_TYPE, InstanceType::SHARED_FUNCTION_INFO_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + {"let x = 1;\n" + "outer: {\n" + " inner: {\n" + " let y = 2;\n" + " function f() { return x + y; }\n" + " if (y) break outer;\n" + " y = 3;\n" + " }\n" + "}\n" + "x = 4;", + 6 * kPointerSize, + 1, + 131, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + U8(1), // + B(PushContext), R(2), // + B(LdaTheHole), // + B(StaContextSlot), R(context), U8(4), // + B(StackCheck), // + B(LdaSmi8), U8(1), // + B(StaContextSlot), R(context), U8(4), // + B(LdaConstant), U8(0), // + B(Star), R(4), // + B(Ldar), R(closure), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kPushBlockContext), R(4), U8(2), // + B(PushContext), R(3), // + B(LdaTheHole), // + B(StaContextSlot), R(context), U8(4), // + B(CreateClosure), U8(1), U8(0), // + B(Star), R(0), // + B(LdaSmi8), U8(2), // + B(StaContextSlot), R(context), U8(4), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(2), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1), // + B(Star), R(1), // + B(LdaContextSlot), R(context), U8(4), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(3), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1), // + B(JumpIfToBooleanFalse), U8(6), // + B(PopContext), R(3), // + B(Jump), U8(27), // + B(LdaSmi8), U8(3), // + B(Star), R(4), // + B(LdaContextSlot), R(context), U8(4), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(3), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(5), U8(1), // + B(Ldar), R(4), // + B(StaContextSlot), R(context), U8(4), // + B(PopContext), R(3), // + B(LdaSmi8), U8(4), // + B(Star), R(4), // + B(LdaContextSlot), R(context), U8(4), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(4), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(5), U8(1), // + B(Ldar), R(4), // + B(StaContextSlot), R(context), U8(4), // + B(LdaUndefined), // + B(Return), // + }, + 5, + {InstanceType::FIXED_ARRAY_TYPE, InstanceType::SHARED_FUNCTION_INFO_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -2280,14 +2535,19 @@ TEST(BasicLoops) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; - ExpectedSnippet<int> snippets[] = { + int closure = Register::function_closure().index(); + int context = Register::current_context().index(); + + // clang-format off + ExpectedSnippet<InstanceType> snippets[] = { {"var x = 0;\n" "while (false) { x = 99; break; continue; }\n" "return x;", 1 * kPointerSize, 1, - 4, + 5, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(Return) // @@ -2299,8 +2559,9 @@ TEST(BasicLoops) { "return x;", 1 * kPointerSize, 1, - 4, + 5, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(Return), // @@ -2317,8 +2578,9 @@ TEST(BasicLoops) { "return y;", 3 * kPointerSize, 1, - 64, + 66, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(LdaSmi8), U8(1), // @@ -2327,7 +2589,8 @@ TEST(BasicLoops) { B(Star), R(2), // B(LdaSmi8), U8(10), // B(TestLessThan), R(2), // - B(JumpIfFalse), U8(46), // + B(JumpIfFalse), U8(47), // + B(StackCheck), // B(Ldar), R(1), // B(Star), R(2), // B(LdaSmi8), U8(12), // @@ -2342,14 +2605,14 @@ TEST(BasicLoops) { B(LdaSmi8), U8(3), // B(TestEqual), R(2), // B(JumpIfFalse), U8(4), // - B(Jump), U8(-38), // + B(Jump), U8(-39), // B(Ldar), R(0), // B(Star), R(2), // B(LdaSmi8), U8(4), // B(TestEqual), R(2), // B(JumpIfFalse), U8(4), // B(Jump), U8(4), // - B(Jump), U8(-52), // + B(Jump), U8(-53), // B(Ldar), R(1), // B(Return), // }, @@ -2366,16 +2629,18 @@ TEST(BasicLoops) { "return i;", 2 * kPointerSize, 1, - 77, + 79, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(1), // B(LdaZero), // B(TestLessThan), R(1), // B(JumpIfFalse), U8(4), // - B(Jump), U8(-9), // + B(Jump), U8(-10), // B(Ldar), R(0), // B(Star), R(1), // B(LdaSmi8), U8(3), // @@ -2393,7 +2658,7 @@ TEST(BasicLoops) { B(LdaSmi8), U8(10), // B(TestEqual), R(1), // B(JumpIfFalse), U8(4), // - B(Jump), U8(-45), // + B(Jump), U8(-46), // B(Ldar), R(0), // B(Star), R(1), // B(LdaSmi8), U8(5), // @@ -2405,7 +2670,7 @@ TEST(BasicLoops) { B(LdaSmi8), U8(1), // B(Add), R(1), // B(Star), R(0), // - B(Jump), U8(-69), // + B(Jump), U8(-70), // B(Ldar), R(0), // B(Return), // }, @@ -2422,15 +2687,18 @@ TEST(BasicLoops) { "return i;", 2 * kPointerSize, 1, - 54, + 57, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(1), // B(LdaSmi8), U8(3), // B(TestLessThan), R(1), // - B(JumpIfFalse), U8(26), // + B(JumpIfFalse), U8(27), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(1), // B(LdaSmi8), U8(2), // @@ -2442,14 +2710,14 @@ TEST(BasicLoops) { B(LdaSmi8), U8(1), // B(Add), R(1), // B(Star), R(0), // - B(Jump), U8(-32), // + B(Jump), U8(-33), // B(Ldar), R(0), // B(Star), R(1), // B(LdaSmi8), U8(1), // B(Add), R(1), // B(Star), R(0), // B(Jump), U8(4), // - B(Jump), U8(-46), // + B(Jump), U8(-48), // B(Ldar), R(0), // B(Return), // }, @@ -2463,14 +2731,16 @@ TEST(BasicLoops) { "return y;", 3 * kPointerSize, 1, - 37, + 39, { + B(StackCheck), // B(LdaSmi8), U8(10), // B(Star), R(0), // B(LdaSmi8), U8(1), // B(Star), R(1), // B(Ldar), R(0), // - B(JumpIfToBooleanFalse), U8(24), // + B(JumpIfToBooleanFalse), U8(25), // + B(StackCheck), // B(Ldar), R(1), // B(Star), R(2), // B(LdaSmi8), U8(12), // @@ -2481,7 +2751,7 @@ TEST(BasicLoops) { B(LdaSmi8), U8(1), // B(Sub), R(2), // B(Star), R(0), // - B(Jump), U8(-24), // + B(Jump), U8(-25), // B(Ldar), R(1), // B(Return), // }, @@ -2496,12 +2766,14 @@ TEST(BasicLoops) { "return y;", 3 * kPointerSize, 1, - 64, + 66, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(LdaSmi8), U8(1), // B(Star), R(1), // + B(StackCheck), // B(Ldar), R(1), // B(Star), R(2), // B(LdaSmi8), U8(10), // @@ -2528,7 +2800,7 @@ TEST(BasicLoops) { B(Star), R(2), // B(LdaSmi8), U8(10), // B(TestLessThan), R(2), // - B(JumpIfTrue), U8(-52), // + B(JumpIfTrue), U8(-53), // B(Ldar), R(1), // B(Return), // }, @@ -2542,12 +2814,14 @@ TEST(BasicLoops) { "return y;", 3 * kPointerSize, 1, - 35, + 37, { + B(StackCheck), // B(LdaSmi8), U8(10), // B(Star), R(0), // B(LdaSmi8), U8(1), // B(Star), R(1), // + B(StackCheck), // B(Ldar), R(1), // B(Star), R(2), // B(LdaSmi8), U8(12), // @@ -2559,7 +2833,7 @@ TEST(BasicLoops) { B(Sub), R(2), // B(Star), R(0), // B(Ldar), R(0), // - B(JumpIfToBooleanTrue), U8(-22), // + B(JumpIfToBooleanTrue), U8(-23), // B(Ldar), R(1), // B(Return), // }, @@ -2574,12 +2848,14 @@ TEST(BasicLoops) { "return y;", 3 * kPointerSize, 1, - 52, + 54, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(LdaSmi8), U8(1), // B(Star), R(1), // + B(StackCheck), // B(Ldar), R(1), // B(Star), R(2), // B(LdaSmi8), U8(10), // @@ -2615,12 +2891,14 @@ TEST(BasicLoops) { "return y;", 3 * kPointerSize, 1, - 54, + 56, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(LdaSmi8), U8(1), // B(Star), R(1), // + B(StackCheck), // B(Ldar), R(1), // B(Star), R(2), // B(LdaSmi8), U8(10), // @@ -2641,8 +2919,8 @@ TEST(BasicLoops) { B(LdaSmi8), U8(6), // B(TestEqual), R(2), // B(JumpIfFalse), U8(4), // - B(Jump), U8(-40), // - B(Jump), U8(-42), // + B(Jump), U8(-41), // + B(Jump), U8(-43), // B(Ldar), R(1), // B(Return), // }, @@ -2655,10 +2933,12 @@ TEST(BasicLoops) { "}", 2 * kPointerSize, 1, - 41, + 43, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(1), // B(LdaSmi8), U8(1), // @@ -2670,13 +2950,13 @@ TEST(BasicLoops) { B(LdaSmi8), U8(2), // B(TestEqual), R(1), // B(JumpIfFalse), U8(4), // - B(Jump), U8(-22), // + B(Jump), U8(-23), // B(Ldar), R(0), // B(Star), R(1), // B(LdaSmi8), U8(1), // B(Add), R(1), // B(Star), R(0), // - B(Jump), U8(-34), // + B(Jump), U8(-35), // B(LdaUndefined), // B(Return), // }, @@ -2688,10 +2968,12 @@ TEST(BasicLoops) { "}", 2 * kPointerSize, 1, - 41, + 43, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(1), // B(LdaSmi8), U8(1), // @@ -2703,13 +2985,13 @@ TEST(BasicLoops) { B(LdaSmi8), U8(2), // B(TestEqual), R(1), // B(JumpIfFalse), U8(4), // - B(Jump), U8(-22), // + B(Jump), U8(-23), // B(Ldar), R(0), // B(Star), R(1), // B(LdaSmi8), U8(1), // B(Add), R(1), // B(Star), R(0), // - B(Jump), U8(-34), // + B(Jump), U8(-35), // B(LdaUndefined), // B(Return), // }, @@ -2721,10 +3003,12 @@ TEST(BasicLoops) { "}", 2 * kPointerSize, 1, - 41, + 43, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(1), // B(LdaSmi8), U8(1), // @@ -2742,7 +3026,7 @@ TEST(BasicLoops) { B(LdaSmi8), U8(1), // B(Add), R(1), // B(Star), R(0), // - B(Jump), U8(-34), // + B(Jump), U8(-35), // B(LdaUndefined), // B(Return), // }, @@ -2753,10 +3037,12 @@ TEST(BasicLoops) { "}", 2 * kPointerSize, 1, - 41, + 43, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(1), // B(LdaSmi8), U8(1), // @@ -2774,7 +3060,7 @@ TEST(BasicLoops) { B(LdaSmi8), U8(1), // B(Add), R(1), // B(Star), R(0), // - B(Jump), U8(-34), // + B(Jump), U8(-35), // B(LdaUndefined), // B(Return), // }, @@ -2786,8 +3072,9 @@ TEST(BasicLoops) { "}", 3 * kPointerSize, 1, - 42, + 44, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(LdaZero), // @@ -2796,7 +3083,8 @@ TEST(BasicLoops) { B(Star), R(2), // B(LdaSmi8), U8(100), // B(TestLessThan), R(2), // - B(JumpIfFalse), U8(26), // + B(JumpIfFalse), U8(27), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(2), // B(LdaSmi8), U8(1), // @@ -2808,7 +3096,7 @@ TEST(BasicLoops) { B(LdaSmi8), U8(1), // B(Add), R(2), // B(Star), R(1), // - B(Jump), U8(-32), // + B(Jump), U8(-33), // B(LdaUndefined), // B(Return), // }, @@ -2820,14 +3108,16 @@ TEST(BasicLoops) { "return y;", 3 * kPointerSize, 1, - 33, + 35, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(LdaSmi8), U8(10), // B(Star), R(1), // B(Ldar), R(1), // - B(JumpIfToBooleanFalse), U8(20), // + B(JumpIfToBooleanFalse), U8(21), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(2), // B(LdaSmi8), U8(12), // @@ -2837,7 +3127,7 @@ TEST(BasicLoops) { B(ToNumber), // B(Dec), // B(Star), R(1), // - B(Jump), U8(-20), // + B(Jump), U8(-21), // B(Ldar), R(0), // B(Return), // }, @@ -2849,8 +3139,9 @@ TEST(BasicLoops) { "return x;", 2 * kPointerSize, 1, - 9, + 10, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(LdaZero), // @@ -2867,12 +3158,14 @@ TEST(BasicLoops) { "return x;", 3 * kPointerSize, 1, - 37, + 39, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(LdaZero), // B(Star), R(1), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(2), // B(LdaSmi8), U8(1), // @@ -2887,12 +3180,83 @@ TEST(BasicLoops) { B(ToNumber), // B(Inc), // B(Star), R(1), // - B(Jump), U8(-26), // + B(Jump), U8(-27), // B(Ldar), R(0), // B(Return), // }, 0}, + {"var a = 0;\n" + "while (a) {\n" + " { \n" + " let z = 1;\n" + " function f() { z = 2; }\n" + " if (z) continue;\n" + " z++;\n" + " }\n" + "}\n", + 7 * kPointerSize, + 1, + 118, + { + B(StackCheck), // + B(LdaZero), // + B(Star), R(1), // + B(Ldar), R(1), // + B(JumpIfToBooleanFalse), U8(110), // + B(StackCheck), // + B(LdaConstant), U8(0), // + B(Star), R(4), // + B(Ldar), R(closure), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kPushBlockContext), R(4), U8(2), // + B(PushContext), R(3), // + B(LdaTheHole), // + B(StaContextSlot), R(context), U8(4), // + B(CreateClosure), U8(1), U8(0), // + B(Star), R(0), // + B(LdaSmi8), U8(1), // + B(StaContextSlot), R(context), U8(4), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(2), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1), // + B(Star), R(2), // + B(LdaContextSlot), R(context), U8(4), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(3), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1), // + B(JumpIfToBooleanFalse), U8(6), // + B(PopContext), R(3), // + B(Jump), U8(-67), // + B(LdaContextSlot), R(context), U8(4), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(3), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1), // + B(ToNumber), // + B(Star), R(4), // + B(Inc), // + B(Star), R(5), // + B(LdaContextSlot), R(context), U8(4), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(3), // + B(Star), R(6), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(6), U8(1), // + B(Ldar), R(5), // + B(StaContextSlot), R(context), U8(4), // + B(PopContext), R(3), // + B(Jump), U8(-110), // + B(LdaUndefined), // + B(Return), // + }, + 4, + {InstanceType::FIXED_ARRAY_TYPE, InstanceType::SHARED_FUNCTION_INFO_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -2907,6 +3271,7 @@ TEST(JumpsRequiringConstantWideOperands) { BytecodeGeneratorHelper helper; int constant_count = 0; + // clang-format off ExpectedSnippet<Handle<Object>, 316> snippets[] = { { REPEAT_256(SPACE, "var x = 0.1;") @@ -2920,8 +3285,9 @@ TEST(JumpsRequiringConstantWideOperands) { "return 3;", kPointerSize * 3, 1, - 1359, + 1361, { + B(StackCheck), // #define L(c) B(LdaConstant), U8(c), B(Star), R(0) REPEAT_256(COMMA, L(constant_count++)), #undef L @@ -2937,6 +3303,7 @@ TEST(JumpsRequiringConstantWideOperands) { B(LdaSmi8), U8(3), // B(TestLessThan), R(2), // B(JumpIfFalseConstantWide), U16(313), // + B(StackCheck), // B(Ldar), R(1), // B(Star), R(2), // B(LdaSmi8), U8(1), // @@ -2954,7 +3321,7 @@ TEST(JumpsRequiringConstantWideOperands) { B(Star), R(2), // B(Inc), // B(Star), R(1), // - B(Jump), U8(-47), // + B(Jump), U8(-48), // B(LdaSmi8), U8(3), // B(Return) // }, @@ -2967,9 +3334,11 @@ TEST(JumpsRequiringConstantWideOperands) { REPEAT_8(COMMA, S(0.4)), #undef S #define N(x) CcTest::i_isolate()->factory()->NewNumberFromInt(x) - N(6), N(41), N(13), N(17) + N(6), N(42), N(13), N(17) #undef N - }}}; + }} + }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -2983,6 +3352,7 @@ TEST(UnaryOperators) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<int> snippets[] = { {"var x = 0;" "while (x != 10) {" @@ -2991,8 +3361,9 @@ TEST(UnaryOperators) { "return x;", 2 * kPointerSize, 1, - 29, + 31, { + B(StackCheck), // B(LdaZero), // B(Star), R(0), // B(Ldar), R(0), // @@ -3000,13 +3371,14 @@ TEST(UnaryOperators) { B(LdaSmi8), U8(10), // B(TestEqual), R(1), // B(LogicalNot), // - B(JumpIfFalse), U8(14), // + B(JumpIfFalse), U8(15), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(1), // B(LdaSmi8), U8(10), // B(Add), R(1), // B(Star), R(0), // - B(Jump), U8(-21), // + B(Jump), U8(-22), // B(Ldar), R(0), // B(Return), // }, @@ -3018,28 +3390,31 @@ TEST(UnaryOperators) { "return x;", 2 * kPointerSize, 1, - 20, + 22, { - B(LdaFalse), // - B(Star), R(0), // - B(Ldar), R(0), // - B(LogicalNot), // - B(Star), R(0), // - B(Ldar), R(0), // - B(Star), R(1), // - B(LdaFalse), // - B(TestEqual), R(1), // - B(JumpIfTrue), U8(-12), // - B(Ldar), R(0), // - B(Return), // + B(StackCheck), // + B(LdaFalse), // + B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // + B(LogicalNot), // + B(Star), R(0), // + B(Ldar), R(0), // + B(Star), R(1), // + B(LdaFalse), // + B(TestEqual), R(1), // + B(JumpIfTrue), U8(-13), // + B(Ldar), R(0), // + B(Return), // }, 0}, {"var x = 101;" "return void(x * 3);", 2 * kPointerSize, 1, - 12, + 13, { + B(StackCheck), // B(LdaSmi8), U8(101), // B(Star), R(0), // B(Star), R(1), // @@ -3054,8 +3429,9 @@ TEST(UnaryOperators) { "return y;", 4 * kPointerSize, 1, - 20, + 21, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(Star), R(2), // @@ -3074,8 +3450,9 @@ TEST(UnaryOperators) { "return ~x;", 2 * kPointerSize, 1, - 11, + 12, { + B(StackCheck), // B(LdaSmi8), U8(13), // B(Star), R(0), // B(Star), R(1), // @@ -3088,8 +3465,9 @@ TEST(UnaryOperators) { "return +x;", 2 * kPointerSize, 1, - 11, + 12, { + B(StackCheck), // B(LdaSmi8), U8(13), // B(Star), R(0), // B(Star), R(1), // @@ -3102,8 +3480,9 @@ TEST(UnaryOperators) { "return -x;", 2 * kPointerSize, 1, - 11, + 12, { + B(StackCheck), // B(LdaSmi8), U8(13), // B(Star), R(0), // B(Star), R(1), // @@ -3111,7 +3490,9 @@ TEST(UnaryOperators) { B(Mul), R(1), // B(Return), // }, - 0}}; + 0} + }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -3132,6 +3513,7 @@ TEST(Typeof) { Handle<i::TypeFeedbackVector> vector = i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"function f() {\n" " var x = 13;\n" @@ -3139,8 +3521,9 @@ TEST(Typeof) { "}; f();", kPointerSize, 1, - 6, + 7, { + B(StackCheck), // B(LdaSmi8), U8(13), // B(Star), R(0), // B(TypeOf), // @@ -3152,32 +3535,17 @@ TEST(Typeof) { "}; f();", 0, 1, - 5, - { - B(LdaGlobalInsideTypeofSloppy), U8(0), // - U8(vector->GetIndex(slot)), // - B(TypeOf), // - B(Return), // - }, - 1, - {"x"}}, - {"var x = 13;\n" - "function f() {\n" - " 'use strict';\n" - " return typeof(x);\n" - "}; f();", - 0, - 1, - 5, + 6, { - B(LdaGlobalInsideTypeofStrict), U8(0), // - U8(vector->GetIndex(slot)), // - B(TypeOf), // - B(Return), // + B(StackCheck), // + B(LdaGlobalInsideTypeof), U8(0), U8(vector->GetIndex(slot)), // + B(TypeOf), // + B(Return), // }, 1, {"x"}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -3194,63 +3562,65 @@ TEST(Delete) { int deep_elements_flags = ObjectLiteral::kFastElements | ObjectLiteral::kDisableMementos; int closure = Register::function_closure().index(); + int context = Register::current_context().index(); int first_context_slot = Context::MIN_CONTEXT_SLOTS; + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"var a = {x:13, y:14}; return delete a.x;", 2 * kPointerSize, 1, - 13, + 16, { - B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // - B(Star), R(0), // - B(Star), R(1), // - B(LdaConstant), U8(1), // - B(DeletePropertySloppy), R(1), // - B(Return) - }, + B(StackCheck), // + B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // + B(Star), R(1), // + B(Star), R(0), // + B(Star), R(1), // + B(LdaConstant), U8(1), // + B(DeletePropertySloppy), R(1), // + B(Return)}, 2, {InstanceType::FIXED_ARRAY_TYPE, InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, {"'use strict'; var a = {x:13, y:14}; return delete a.x;", 2 * kPointerSize, 1, - 13, - { - B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // - B(Star), R(0), // - B(Star), R(1), // - B(LdaConstant), U8(1), // - B(DeletePropertyStrict), R(1), // - B(Return) - }, + 16, + {B(StackCheck), // + B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // + B(Star), R(1), // + B(Star), R(0), // + B(Star), R(1), // + B(LdaConstant), U8(1), // + B(DeletePropertyStrict), R(1), // + B(Return)}, 2, {InstanceType::FIXED_ARRAY_TYPE, InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, {"var a = {1:13, 2:14}; return delete a[2];", 2 * kPointerSize, 1, - 13, - { - B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // - B(Star), R(0), // - B(Star), R(1), // - B(LdaSmi8), U8(2), // - B(DeletePropertySloppy), R(1), // - B(Return) - }, + 16, + {B(StackCheck), // + B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // + B(Star), R(1), // + B(Star), R(0), // + B(Star), R(1), // + B(LdaSmi8), U8(2), // + B(DeletePropertySloppy), R(1), // + B(Return)}, 1, {InstanceType::FIXED_ARRAY_TYPE}}, {"var a = 10; return delete a;", 1 * kPointerSize, 1, - 6, - { - B(LdaSmi8), U8(10), // - B(Star), R(0), // - B(LdaFalse), // - B(Return) - }, + 7, + {B(StackCheck), // + B(LdaSmi8), U8(10), // + B(Star), R(0), // + B(LdaFalse), // + B(Return)}, 0}, {"'use strict';" "var a = {1:10};" @@ -3258,33 +3628,33 @@ TEST(Delete) { "return delete a[1];", 2 * kPointerSize, 1, - 27, - { - B(CallRuntime), U16(Runtime::kNewFunctionContext), // - R(closure), U8(1), // - B(PushContext), R(0), // - B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // - B(StaContextSlot), R(0), U8(first_context_slot), // - B(CreateClosure), U8(1), U8(0), // - B(LdaContextSlot), R(0), U8(first_context_slot), // - B(Star), R(1), // - B(LdaSmi8), U8(1), // - B(DeletePropertyStrict), R(1), // - B(Return) - }, + 30, + {B(CallRuntime), U16(Runtime::kNewFunctionContext), // + /* */ R(closure), U8(1), // + B(PushContext), R(0), // + B(StackCheck), // + B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // + B(Star), R(1), // + B(StaContextSlot), R(context), U8(first_context_slot), // + B(CreateClosure), U8(1), U8(0), // + B(LdaContextSlot), R(context), U8(first_context_slot), // + B(Star), R(1), // + B(LdaSmi8), U8(1), // + B(DeletePropertyStrict), R(1), // + B(Return)}, 2, {InstanceType::FIXED_ARRAY_TYPE, InstanceType::SHARED_FUNCTION_INFO_TYPE}}, {"return delete 'test';", 0 * kPointerSize, 1, - 2, - { - B(LdaTrue), // - B(Return) - }, + 3, + {B(StackCheck), // + B(LdaTrue), // + B(Return)}, 0}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -3299,7 +3669,7 @@ TEST(GlobalDelete) { BytecodeGeneratorHelper helper; Zone zone; - int context = Register::function_context().index(); + int context = Register::current_context().index(); int native_context_index = Context::NATIVE_CONTEXT_INDEX; int global_context_index = Context::EXTENSION_INDEX; FeedbackVectorSpec feedback_spec(&zone); @@ -3308,12 +3678,14 @@ TEST(GlobalDelete) { Handle<i::TypeFeedbackVector> vector = i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"var a = {x:13, y:14};\n function f() { return delete a.x; };\n f();", 1 * kPointerSize, 1, - 10, - {B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot)), // + 11, + {B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot)), // B(Star), R(0), // B(LdaConstant), U8(1), // B(DeletePropertySloppy), R(0), // @@ -3325,8 +3697,9 @@ TEST(GlobalDelete) { "function f() {'use strict'; return delete a[1];};\n f();", 1 * kPointerSize, 1, - 10, - {B(LdaGlobalStrict), U8(0), U8(vector->GetIndex(slot)), // + 11, + {B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot)), // B(Star), R(0), // B(LdaSmi8), U8(1), // B(DeletePropertyStrict), R(0), // @@ -3336,8 +3709,9 @@ TEST(GlobalDelete) { {"var a = {x:13, y:14};\n function f() { return delete a; };\n f();", 2 * kPointerSize, 1, - 15, - {B(LdaContextSlot), R(context), U8(native_context_index), // + 16, + {B(StackCheck), // + B(LdaContextSlot), R(context), U8(native_context_index), // B(Star), R(0), // B(LdaContextSlot), R(0), U8(global_context_index), // B(Star), R(1), // @@ -3349,8 +3723,9 @@ TEST(GlobalDelete) { {"b = 30;\n function f() { return delete b; };\n f();", 2 * kPointerSize, 1, - 15, - {B(LdaContextSlot), R(context), U8(native_context_index), // + 16, + {B(StackCheck), // + B(LdaContextSlot), R(context), U8(native_context_index), // B(Star), R(0), // B(LdaContextSlot), R(0), U8(global_context_index), // B(Star), R(1), // @@ -3358,7 +3733,9 @@ TEST(GlobalDelete) { B(DeletePropertySloppy), R(1), // B(Return)}, 1, - {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}}; + {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}} + }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -3379,12 +3756,14 @@ TEST(FunctionLiterals) { Handle<i::TypeFeedbackVector> vector = i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"return function(){ }", 0, 1, - 4, + 5, { + B(StackCheck), // B(CreateClosure), U8(0), U8(0), // B(Return) // }, @@ -3393,13 +3772,14 @@ TEST(FunctionLiterals) { {"return (function(){ })()", 2 * kPointerSize, 1, - 14, + 15, { + B(StackCheck), // B(LdaUndefined), // B(Star), R(1), // B(CreateClosure), U8(0), U8(0), // B(Star), R(0), // - B(Call), R(0), R(1), U8(0), U8(vector->GetIndex(slot)), // + B(Call), R(0), R(1), U8(1), U8(vector->GetIndex(slot)), // B(Return) // }, 1, @@ -3407,20 +3787,22 @@ TEST(FunctionLiterals) { {"return (function(x){ return x; })(1)", 3 * kPointerSize, 1, - 18, + 19, { + B(StackCheck), // B(LdaUndefined), // B(Star), R(1), // B(CreateClosure), U8(0), U8(0), // B(Star), R(0), // B(LdaSmi8), U8(1), // B(Star), R(2), // - B(Call), R(0), R(1), U8(1), U8(vector->GetIndex(slot)), // + B(Call), R(0), R(1), U8(2), U8(vector->GetIndex(slot)), // B(Return) // }, 1, {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -3443,12 +3825,14 @@ TEST(RegExpLiterals) { Handle<i::TypeFeedbackVector> vector = i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"return /ab+d/;", 0 * kPointerSize, 1, - 5, + 6, { + B(StackCheck), // B(CreateRegExpLiteral), U8(0), U8(0), U8(0), // B(Return), // }, @@ -3457,8 +3841,9 @@ TEST(RegExpLiterals) { {"return /(\\w+)\\s(\\w+)/i;", 0 * kPointerSize, 1, - 5, + 6, { + B(StackCheck), // B(CreateRegExpLiteral), U8(0), U8(0), U8(i_flags), // B(Return), // }, @@ -3467,20 +3852,22 @@ TEST(RegExpLiterals) { {"return /ab+d/.exec('abdd');", 3 * kPointerSize, 1, - 22, + 23, { + B(StackCheck), // B(CreateRegExpLiteral), U8(0), U8(0), U8(0), // B(Star), R(1), // - B(LoadICSloppy), R(1), U8(1), U8(vector->GetIndex(slot2)), // + B(LoadIC), R(1), U8(1), U8(vector->GetIndex(slot2)), // B(Star), R(0), // B(LdaConstant), U8(2), // B(Star), R(2), // - B(Call), R(0), R(1), U8(1), U8(vector->GetIndex(slot1)), // + B(Call), R(0), R(1), U8(2), U8(vector->GetIndex(slot1)), // B(Return), // }, 3, {"ab+d", "exec", "abdd"}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -3497,12 +3884,14 @@ TEST(RegExpLiteralsWide) { int wide_idx = 0; + // clang-format off ExpectedSnippet<InstanceType, 257> snippets[] = { {"var a;" REPEAT_256(SPACE, "a = 1.23;") "return /ab+d/;", 1 * kPointerSize, 1, - 1031, + 1032, { + B(StackCheck), // REPEAT_256(COMMA, // B(LdaConstant), U8(wide_idx++), // B(Star), R(0)), // @@ -3513,6 +3902,7 @@ TEST(RegExpLiteralsWide) { {REPEAT_256(COMMA, InstanceType::HEAP_NUMBER_TYPE), InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -3538,12 +3928,14 @@ TEST(ArrayLiterals) { int simple_flags = ArrayLiteral::kDisableMementos | ArrayLiteral::kShallowElements; int deep_elements_flags = ArrayLiteral::kDisableMementos; + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"return [ 1, 2 ];", 0, 1, - 5, + 6, { + B(StackCheck), // B(CreateArrayLiteral), U8(0), U8(0), U8(simple_flags), // B(Return) // }, @@ -3552,8 +3944,9 @@ TEST(ArrayLiterals) { {"var a = 1; return [ a, a + 1 ];", 4 * kPointerSize, 1, - 38, + 39, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(CreateArrayLiteral), U8(0), U8(0), U8(3), // @@ -3577,8 +3970,9 @@ TEST(ArrayLiterals) { {"return [ [ 1, 2 ], [ 3 ] ];", 0, 1, - 5, + 6, { + B(StackCheck), // B(CreateArrayLiteral), U8(0), U8(2), U8(deep_elements_flags), // B(Return) // }, @@ -3587,8 +3981,9 @@ TEST(ArrayLiterals) { {"var a = 1; return [ [ a, 2 ], [ a + 2 ] ];", 6 * kPointerSize, 1, - 68, + 69, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(CreateArrayLiteral), U8(0), U8(2), U8(deep_elements_flags), // @@ -3623,6 +4018,7 @@ TEST(ArrayLiterals) { {InstanceType::FIXED_ARRAY_TYPE, InstanceType::FIXED_ARRAY_TYPE, InstanceType::FIXED_ARRAY_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -3641,12 +4037,14 @@ TEST(ArrayLiteralsWide) { int simple_flags = ArrayLiteral::kDisableMementos | ArrayLiteral::kShallowElements; + // clang-format off ExpectedSnippet<InstanceType, 257> snippets[] = { {"var a;" REPEAT_256(SPACE, "a = 1.23;") "return [ 1 , 2 ];", 1 * kPointerSize, 1, - 1031, + 1032, { + B(StackCheck), // REPEAT_256(COMMA, // B(LdaConstant), U8(wide_idx++), // B(Star), R(0)), // @@ -3657,6 +4055,7 @@ TEST(ArrayLiteralsWide) { {REPEAT_256(COMMA, InstanceType::HEAP_NUMBER_TYPE), InstanceType::FIXED_ARRAY_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -3682,23 +4081,29 @@ TEST(ObjectLiterals) { ObjectLiteral::kDisableMementos; int deep_elements_flags = ObjectLiteral::kFastElements | ObjectLiteral::kDisableMementos; + + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"return { };", - 0, + kPointerSize, 1, - 5, + 8, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(simple_flags), // + B(Star), R(0), // B(Return) // }, 1, {InstanceType::FIXED_ARRAY_TYPE}}, {"return { name: 'string', val: 9.2 };", - 0, + kPointerSize, 1, - 5, + 8, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // + B(Star), R(0), // B(Return) // }, 1, @@ -3706,8 +4111,9 @@ TEST(ObjectLiterals) { {"var a = 1; return { name: 'string', val: a };", 2 * kPointerSize, 1, - 19, + 20, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // @@ -3723,8 +4129,9 @@ TEST(ObjectLiterals) { {"var a = 1; return { val: a, val: a + 1 };", 3 * kPointerSize, 1, - 25, + 26, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // @@ -3743,8 +4150,9 @@ TEST(ObjectLiterals) { {"return { func: function() { } };", 1 * kPointerSize, 1, - 16, + 17, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // B(Star), R(0), // B(CreateClosure), U8(1), U8(0), // @@ -3753,14 +4161,14 @@ TEST(ObjectLiterals) { B(Return), // }, 3, - {InstanceType::FIXED_ARRAY_TYPE, - InstanceType::SHARED_FUNCTION_INFO_TYPE, + {InstanceType::FIXED_ARRAY_TYPE, InstanceType::SHARED_FUNCTION_INFO_TYPE, InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, {"return { func(a) { return a; } };", 1 * kPointerSize, 1, - 16, + 17, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // B(Star), R(0), // B(CreateClosure), U8(1), U8(0), // @@ -3769,26 +4177,27 @@ TEST(ObjectLiterals) { B(Return), // }, 3, - {InstanceType::FIXED_ARRAY_TYPE, - InstanceType::SHARED_FUNCTION_INFO_TYPE, + {InstanceType::FIXED_ARRAY_TYPE, InstanceType::SHARED_FUNCTION_INFO_TYPE, InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, {"return { get a() { return 2; } };", - 5 * kPointerSize, + 6 * kPointerSize, 1, - 29, + 33, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // B(Star), R(0), // + B(Mov), R(0), R(1), // B(LdaConstant), U8(1), // - B(Star), R(1), // - B(CreateClosure), U8(2), U8(0), // B(Star), R(2), // - B(LdaNull), // + B(CreateClosure), U8(2), U8(0), // B(Star), R(3), // - B(LdaZero), // + B(LdaNull), // B(Star), R(4), // + B(LdaZero), // + B(Star), R(5), // B(CallRuntime), U16(Runtime::kDefineAccessorPropertyUnchecked), // - R(0), U8(5), // + /* */ R(1), U8(5), // B(Ldar), R(0), // B(Return), // }, @@ -3797,22 +4206,24 @@ TEST(ObjectLiterals) { InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, InstanceType::SHARED_FUNCTION_INFO_TYPE}}, {"return { get a() { return this.x; }, set a(val) { this.x = val } };", - 5 * kPointerSize, + 6 * kPointerSize, 1, - 31, + 35, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // B(Star), R(0), // + B(Mov), R(0), R(1), // B(LdaConstant), U8(1), // - B(Star), R(1), // - B(CreateClosure), U8(2), U8(0), // B(Star), R(2), // - B(CreateClosure), U8(3), U8(0), // + B(CreateClosure), U8(2), U8(0), // B(Star), R(3), // - B(LdaZero), // + B(CreateClosure), U8(3), U8(0), // B(Star), R(4), // + B(LdaZero), // + B(Star), R(5), // B(CallRuntime), U16(Runtime::kDefineAccessorPropertyUnchecked), // - R(0), U8(5), // + /* */ R(1), U8(5), // B(Ldar), R(0), // B(Return), // }, @@ -3822,22 +4233,24 @@ TEST(ObjectLiterals) { InstanceType::SHARED_FUNCTION_INFO_TYPE, InstanceType::SHARED_FUNCTION_INFO_TYPE}}, {"return { set b(val) { this.y = val } };", - 5 * kPointerSize, + 6 * kPointerSize, 1, - 29, + 33, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // B(Star), R(0), // + B(Mov), R(0), R(1), // B(LdaConstant), U8(1), // - B(Star), R(1), // - B(LdaNull), // B(Star), R(2), // - B(CreateClosure), U8(2), U8(0), // + B(LdaNull), // B(Star), R(3), // - B(LdaZero), // + B(CreateClosure), U8(2), U8(0), // B(Star), R(4), // + B(LdaZero), // + B(Star), R(5), // B(CallRuntime), U16(Runtime::kDefineAccessorPropertyUnchecked), // - R(0), U8(5), // + /* */ R(1), U8(5), // B(Ldar), R(0), // B(Return), // }, @@ -3846,58 +4259,66 @@ TEST(ObjectLiterals) { InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, InstanceType::SHARED_FUNCTION_INFO_TYPE}}, {"var a = 1; return { 1: a };", - 5 * kPointerSize, + 6 * kPointerSize, 1, - 29, + 33, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // B(Star), R(1), // + B(Mov), R(1), R(2), // B(LdaSmi8), U8(1), // - B(Star), R(2), // - B(Ldar), R(0), // B(Star), R(3), // - B(LdaZero), // + B(Ldar), R(0), // B(Star), R(4), // - B(CallRuntime), U16(Runtime::kSetProperty), R(1), U8(4), // + B(LdaZero), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kSetProperty), R(2), U8(4), // B(Ldar), R(1), // B(Return), // }, 1, {InstanceType::FIXED_ARRAY_TYPE}}, {"return { __proto__: null }", - 2 * kPointerSize, + 3 * kPointerSize, 1, - 17, + 21, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(simple_flags), // B(Star), R(0), // - B(LdaNull), B(Star), R(1), // - B(CallRuntime), U16(Runtime::kInternalSetPrototype), R(0), U8(2), // + B(Mov), R(0), R(1), // + B(LdaNull), B(Star), R(2), // + B(CallRuntime), U16(Runtime::kInternalSetPrototype), R(1), U8(2), // B(Ldar), R(0), // B(Return), // }, 1, {InstanceType::FIXED_ARRAY_TYPE}}, {"var a = 'test'; return { [a]: 1 }", - 5 * kPointerSize, + 7 * kPointerSize, 1, - 30, + 37, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(CreateObjectLiteral), U8(1), U8(0), U8(simple_flags), // B(Star), R(1), // + B(Mov), R(1), R(2), // B(Ldar), R(0), // B(ToName), // - B(Star), R(2), // - B(LdaSmi8), U8(1), // B(Star), R(3), // - B(LdaZero), // + B(LdaSmi8), U8(1), // B(Star), R(4), // - B(CallRuntime), U16(Runtime::kDefineDataPropertyUnchecked), R(1), // - U8(4), // + B(LdaZero), // + B(Star), R(5), // + B(LdaZero), // + B(Star), R(6), // + B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), // + /* */ U8(5), // B(Ldar), R(1), // B(Return), // }, @@ -3905,25 +4326,29 @@ TEST(ObjectLiterals) { {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, InstanceType::FIXED_ARRAY_TYPE}}, {"var a = 'test'; return { val: a, [a]: 1 }", - 5 * kPointerSize, + 7 * kPointerSize, 1, - 36, + 43, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(CreateObjectLiteral), U8(1), U8(0), U8(deep_elements_flags), // B(Star), R(1), // B(Ldar), R(0), // B(StoreICSloppy), R(1), U8(2), U8(vector->GetIndex(slot1)), // + B(Mov), R(1), R(2), // B(Ldar), R(0), // B(ToName), // - B(Star), R(2), // - B(LdaSmi8), U8(1), // B(Star), R(3), // - B(LdaZero), // + B(LdaSmi8), U8(1), // B(Star), R(4), // - B(CallRuntime), U16(Runtime::kDefineDataPropertyUnchecked), R(1), // - U8(4), // + B(LdaZero), // + B(Star), R(5), // + B(LdaZero), // + B(Star), R(6), // + B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), // + /* */ U8(5), // B(Ldar), R(1), // B(Return), // }, @@ -3932,26 +4357,32 @@ TEST(ObjectLiterals) { InstanceType::FIXED_ARRAY_TYPE, InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, {"var a = 'test'; return { [a]: 1, __proto__: {} }", - 5 * kPointerSize, + 7 * kPointerSize, 1, - 41, + 53, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(CreateObjectLiteral), U8(1), U8(1), U8(simple_flags), // B(Star), R(1), // + B(Mov), R(1), R(2), // B(Ldar), R(0), // B(ToName), // - B(Star), R(2), // - B(LdaSmi8), U8(1), // B(Star), R(3), // - B(LdaZero), // + B(LdaSmi8), U8(1), // B(Star), R(4), // - B(CallRuntime), U16(Runtime::kDefineDataPropertyUnchecked), R(1), // - U8(4), // + B(LdaZero), // + B(Star), R(5), // + B(LdaZero), // + B(Star), R(6), // + B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), // + /* */ U8(5), // + B(Mov), R(1), R(2), // B(CreateObjectLiteral), U8(1), U8(0), U8(13), // - B(Star), R(2), // - B(CallRuntime), U16(Runtime::kInternalSetPrototype), R(1), U8(2), // + B(Star), R(4), // + B(Star), R(3), // + B(CallRuntime), U16(Runtime::kInternalSetPrototype), R(2), U8(2), // B(Ldar), R(1), // B(Return), // }, @@ -3959,39 +4390,45 @@ TEST(ObjectLiterals) { {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, InstanceType::FIXED_ARRAY_TYPE}}, {"var n = 'name'; return { [n]: 'val', get a() { }, set a(b) {} };", - 5 * kPointerSize, + 7 * kPointerSize, 1, - 64, + 77, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(CreateObjectLiteral), U8(1), U8(0), U8(simple_flags), // B(Star), R(1), // + B(Mov), R(1), R(2), // B(Ldar), R(0), // B(ToName), // - B(Star), R(2), // - B(LdaConstant), U8(2), // B(Star), R(3), // - B(LdaZero), // + B(LdaConstant), U8(2), // B(Star), R(4), // - B(CallRuntime), U16(Runtime::kDefineDataPropertyUnchecked), R(1), // - U8(4), // + B(LdaZero), // + B(Star), R(5), // + B(LdaZero), // + B(Star), R(6), // + B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), // + /* */ U8(5), // + B(Mov), R(1), R(2), // B(LdaConstant), U8(3), // - B(Star), R(2), // - B(CreateClosure), U8(4), U8(0), // B(Star), R(3), // - B(LdaZero), // + B(CreateClosure), U8(4), U8(0), // B(Star), R(4), // + B(LdaZero), // + B(Star), R(5), // B(CallRuntime), U16(Runtime::kDefineGetterPropertyUnchecked), // - R(1), U8(4), // + /* */ R(2), U8(4), // + B(Mov), R(1), R(2), // B(LdaConstant), U8(3), // - B(Star), R(2), // - B(CreateClosure), U8(5), U8(0), // B(Star), R(3), // - B(LdaZero), // + B(CreateClosure), U8(5), U8(0), // B(Star), R(4), // + B(LdaZero), // + B(Star), R(5), // B(CallRuntime), U16(Runtime::kDefineSetterPropertyUnchecked), // - R(1), U8(4), // + /* */ R(2), U8(4), // B(Ldar), R(1), // B(Return), // }, @@ -4003,6 +4440,7 @@ TEST(ObjectLiterals) { InstanceType::SHARED_FUNCTION_INFO_TYPE, InstanceType::SHARED_FUNCTION_INFO_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -4021,24 +4459,28 @@ TEST(ObjectLiteralsWide) { ObjectLiteral::kFastElements | ObjectLiteral::kDisableMementos; int wide_idx = 0; + // clang-format off ExpectedSnippet<InstanceType, 257> snippets[] = { {"var a;" REPEAT_256(SPACE, "a = 1.23;") "return { name: 'string', val: 9.2 };", - 1 * kPointerSize, + 2 * kPointerSize, 1, - 1031, + 1034, { + B(StackCheck), // REPEAT_256(COMMA, // - B(LdaConstant), U8(wide_idx++), // - B(Star), R(0)), // + B(LdaConstant), U8(wide_idx++), // + B(Star), R(0)), // B(CreateObjectLiteralWide), U16(256), U16(0), // - U8(deep_elements_flags), // + /* */ U8(deep_elements_flags), // + B(Star), R(1), // B(Return) // }, 257, {REPEAT_256(COMMA, InstanceType::HEAP_NUMBER_TYPE), InstanceType::FIXED_ARRAY_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -4055,17 +4497,19 @@ TEST(TopLevelObjectLiterals) { int has_function_flags = ObjectLiteral::kFastElements | ObjectLiteral::kHasFunction | ObjectLiteral::kDisableMementos; + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"var a = { func: function() { } };", 5 * kPointerSize, 1, - 48, + 49, { B(LdaConstant), U8(0), // B(Star), R(1), // B(LdaZero), // B(Star), R(2), // B(CallRuntime), U16(Runtime::kDeclareGlobals), R(1), U8(2), // + B(StackCheck), // B(LdaConstant), U8(1), // B(Star), R(1), // B(LdaZero), // @@ -4088,6 +4532,7 @@ TEST(TopLevelObjectLiterals) { InstanceType::SHARED_FUNCTION_INFO_TYPE, InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -4101,18 +4546,91 @@ TEST(TryCatch) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; - // TODO(rmcilroy): modify tests when we have real try catch support. - ExpectedSnippet<int> snippets[] = { + int closure = Register::function_closure().index(); + int context = Register::current_context().index(); + + // clang-format off + ExpectedSnippet<const char*> snippets[] = { {"try { return 1; } catch(e) { return 2; }", - kPointerSize, + 5 * kPointerSize, 1, - 3, + 40, { - B(LdaSmi8), U8(1), // - B(Return), // + B(StackCheck), // + B(Mov), R(context), R(1), // + B(LdaSmi8), U8(1), // + B(Return), // + B(Star), R(3), // + B(LdaConstant), U8(0), // + B(Star), R(2), // + B(Ldar), R(closure), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kPushCatchContext), R(2), U8(3), // + B(Star), R(1), // + B(CallRuntime), U16(Runtime::kInterpreterClearPendingMessage), // + /* */ R(0), U8(0), // + B(Ldar), R(1), // + B(PushContext), R(0), // + B(LdaSmi8), U8(2), // + B(PopContext), R(0), // + B(Return), // + // TODO(mstarzinger): Potential optimization, elide next bytes. + B(LdaUndefined), // + B(Return), // }, - 0}, + 1, + {"e"}, + 1, + {{4, 7, 7}}}, + {"var a; try { a = 1 } catch(e1) {}; try { a = 2 } catch(e2) { a = 3 }", + 6 * kPointerSize, + 1, + 81, + { + B(StackCheck), // + B(Mov), R(context), R(2), // + B(LdaSmi8), U8(1), // + B(Star), R(0), // + B(Jump), U8(30), // + B(Star), R(4), // + B(LdaConstant), U8(0), // + B(Star), R(3), // + B(Ldar), R(closure), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kPushCatchContext), R(3), U8(3), // + B(Star), R(2), // + B(CallRuntime), U16(Runtime::kInterpreterClearPendingMessage), // + /* */ R(0), U8(0), // + B(Ldar), R(2), // + B(PushContext), R(1), // + B(PopContext), R(1), // + B(Mov), R(context), R(2), // + B(LdaSmi8), U8(2), // + B(Star), R(0), // + B(Jump), U8(34), // + B(Star), R(4), // + B(LdaConstant), U8(1), // + B(Star), R(3), // + B(Ldar), R(closure), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kPushCatchContext), R(3), U8(3), // + B(Star), R(2), // + B(CallRuntime), U16(Runtime::kInterpreterClearPendingMessage), // + /* */ R(0), U8(0), // + B(Ldar), R(2), // + B(PushContext), R(1), // + B(LdaSmi8), U8(3), // + B(Star), R(0), // + B(PopContext), R(1), // + B(LdaUndefined), // + B(Return), // + }, + 2, + {"e1", "e2"}, + 2, + {{4, 8, 10}, {41, 45, 47}}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -4126,39 +4644,172 @@ TEST(TryFinally) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; - // TODO(rmcilroy): modify tests when we have real try finally support. - ExpectedSnippet<int> snippets[] = { + int closure = Register::function_closure().index(); + int context = Register::current_context().index(); + + // clang-format off + ExpectedSnippet<const char*> snippets[] = { {"var a = 1; try { a = 2; } finally { a = 3; }", - kPointerSize, + 4 * kPointerSize, 1, - 14, + 51, { - B(LdaSmi8), U8(1), // - B(Star), R(0), // - B(LdaSmi8), U8(2), // - B(Star), R(0), // - B(LdaSmi8), U8(3), // - B(Star), R(0), // - B(LdaUndefined), // - B(Return), // + B(StackCheck), // + B(LdaSmi8), U8(1), // + B(Star), R(0), // + B(Mov), R(context), R(3), // + B(LdaSmi8), U8(2), // + B(Star), R(0), // + B(LdaSmi8), U8(-1), // + B(Star), R(1), // + B(Jump), U8(7), // + B(Star), R(2), // + B(LdaZero), // + B(Star), R(1), // + B(CallRuntime), U16(Runtime::kInterpreterClearPendingMessage), // + /* */ R(0), U8(0), // + B(Star), R(3), // + B(LdaSmi8), U8(3), // + B(Star), R(0), // + B(CallRuntime), U16(Runtime::kInterpreterSetPendingMessage), // + /* */ R(3), U8(1), // + B(LdaZero), // + B(TestEqualStrict), R(1), // + B(JumpIfTrue), U8(4), // + B(Jump), U8(5), // + B(Ldar), R(2), // + B(ReThrow), // + B(LdaUndefined), // + B(Return), // }, - 0}, + 0, + {}, + 1, + {{8, 12, 18}}}, {"var a = 1; try { a = 2; } catch(e) { a = 20 } finally { a = 3; }", - 2 * kPointerSize, + 9 * kPointerSize, 1, - 14, + 88, { - B(LdaSmi8), U8(1), // - B(Star), R(0), // - B(LdaSmi8), U8(2), // - B(Star), R(0), // - B(LdaSmi8), U8(3), // - B(Star), R(0), // - B(LdaUndefined), // - B(Return), // + B(StackCheck), // + B(LdaSmi8), U8(1), // + B(Star), R(0), // + B(Mov), R(context), R(4), // + B(Mov), R(context), R(5), // + B(LdaSmi8), U8(2), // + B(Star), R(0), // + B(Jump), U8(34), // + B(Star), R(7), // + B(LdaConstant), U8(0), // + B(Star), R(6), // + B(Ldar), R(closure), // + B(Star), R(8), // + B(CallRuntime), U16(Runtime::kPushCatchContext), R(6), U8(3), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kInterpreterClearPendingMessage), // + /* */ R(0), U8(0), // + B(Ldar), R(5), // + B(PushContext), R(1), // + B(LdaSmi8), U8(20), // + B(Star), R(0), // + B(PopContext), R(1), // + B(LdaSmi8), U8(-1), // + B(Star), R(2), // + B(Jump), U8(7), // + B(Star), R(3), // + B(LdaZero), // + B(Star), R(2), // + B(CallRuntime), U16(Runtime::kInterpreterClearPendingMessage), // + /* */ R(0), U8(0), // + B(Star), R(4), // + B(LdaSmi8), U8(3), // + B(Star), R(0), // + B(CallRuntime), U16(Runtime::kInterpreterSetPendingMessage), // + /* */ R(4), U8(1), // + B(LdaZero), // + B(TestEqualStrict), R(2), // + B(JumpIfTrue), U8(4), // + B(Jump), U8(5), // + B(Ldar), R(3), // + B(ReThrow), // + B(LdaUndefined), // + B(Return), // }, - 0}, + 1, + {"e"}, + 2, + {{8, 49, 55}, {11, 15, 17}}}, + {"var a; try {" + " try { a = 1 } catch(e) { a = 2 }" + "} catch(e) { a = 20 } finally { a = 3; }", + 10 * kPointerSize, + 1, + 121, + { + B(StackCheck), // + B(Mov), R(context), R(4), // + B(Mov), R(context), R(5), // + B(Mov), R(context), R(6), // + B(LdaSmi8), U8(1), // + B(Star), R(0), // + B(Jump), U8(34), // + B(Star), R(8), // + B(LdaConstant), U8(0), // + B(Star), R(7), // + B(Ldar), R(closure), // + B(Star), R(9), // + B(CallRuntime), U16(Runtime::kPushCatchContext), R(7), U8(3), // + B(Star), R(6), // + B(CallRuntime), U16(Runtime::kInterpreterClearPendingMessage), // + /* */ R(0), U8(0), // + B(Ldar), R(6), // + B(PushContext), R(1), // + B(LdaSmi8), U8(2), // + B(Star), R(0), // + B(PopContext), R(1), // + B(Jump), U8(34), // + B(Star), R(7), // + B(LdaConstant), U8(0), // + B(Star), R(6), // + B(Ldar), R(closure), // + B(Star), R(8), // + B(CallRuntime), U16(Runtime::kPushCatchContext), R(6), U8(3), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kInterpreterClearPendingMessage), // + /* */ R(0), U8(0), // + B(Ldar), R(5), // + B(PushContext), R(1), // + B(LdaSmi8), U8(20), // + B(Star), R(0), // + B(PopContext), R(1), // + B(LdaSmi8), U8(-1), // + B(Star), R(2), // + B(Jump), U8(7), // + B(Star), R(3), // + B(LdaZero), // + B(Star), R(2), // + B(CallRuntime), U16(Runtime::kInterpreterClearPendingMessage), // + /* */ R(0), U8(0), // + B(Star), R(4), // + B(LdaSmi8), U8(3), // + B(Star), R(0), // + B(CallRuntime), U16(Runtime::kInterpreterSetPendingMessage), // + /* */ R(4), U8(1), // + B(LdaZero), // + B(TestEqualStrict), R(2), // + B(JumpIfTrue), U8(4), // + B(Jump), U8(5), // + B(Ldar), R(3), // + B(ReThrow), // + B(LdaUndefined), // + B(Return), // + }, + 1, + {"e"}, + 3, + {{4, 82, 88}, {7, 48, 50}, {10, 14, 16}}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -4172,13 +4823,14 @@ TEST(Throw) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; - // TODO(rmcilroy): modify tests when we have real try catch support. + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"throw 1;", 0, 1, - 3, + 4, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Throw), // }, @@ -4186,8 +4838,9 @@ TEST(Throw) { {"throw 'Error';", 0, 1, - 3, + 4, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Throw), // }, @@ -4196,8 +4849,9 @@ TEST(Throw) { {"var a = 1; if (a) { throw 'Error'; };", 1 * kPointerSize, 1, - 11, + 12, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(JumpIfToBooleanFalse), U8(5), // @@ -4209,6 +4863,7 @@ TEST(Throw) { 1, {"Error"}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -4231,15 +4886,17 @@ TEST(CallNew) { Handle<i::TypeFeedbackVector> vector = i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"function bar() { this.value = 0; }\n" "function f() { return new bar(); }\n" "f()", 1 * kPointerSize, 1, - 10, + 11, { - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), // + B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot2)), // B(Star), R(0), // B(New), R(0), R(0), U8(0), // B(Return), // @@ -4251,12 +4908,14 @@ TEST(CallNew) { "f()", 2 * kPointerSize, 1, - 14, + 17, { - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), // + B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot2)), // B(Star), R(0), // B(LdaSmi8), U8(3), // B(Star), R(1), // + B(Ldar), R(0), // B(New), R(0), R(1), U8(1), // B(Return), // }, @@ -4272,9 +4931,10 @@ TEST(CallNew) { "f()", 4 * kPointerSize, 1, - 22, + 25, { - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), // + B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot2)), // B(Star), R(0), // B(LdaSmi8), U8(3), // B(Star), R(1), // @@ -4282,12 +4942,14 @@ TEST(CallNew) { B(Star), R(2), // B(LdaSmi8), U8(5), // B(Star), R(3), // + B(Ldar), R(0), // B(New), R(0), R(1), U8(3), // B(Return), // }, 1, {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -4309,6 +4971,7 @@ TEST(ContextVariables) { i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); int closure = Register::function_closure().index(); + int context = Register::current_context().index(); int new_target = Register::new_target().index(); int first_context_slot = Context::MIN_CONTEXT_SLOTS; @@ -4318,15 +4981,17 @@ TEST(ContextVariables) { STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS + 3 + 249 == 256); int wide_slot = first_context_slot + 3; + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"var a; return function() { a = 1; };", 1 * kPointerSize, 1, - 11, + 12, { B(CallRuntime), U16(Runtime::kNewFunctionContext), // - R(closure), U8(1), // + /* */ R(closure), U8(1), // B(PushContext), R(0), // + B(StackCheck), // B(CreateClosure), U8(0), U8(0), // B(Return), // }, @@ -4335,49 +5000,52 @@ TEST(ContextVariables) { {"var a = 1; return function() { a = 2; };", 1 * kPointerSize, 1, - 16, + 17, { - B(CallRuntime), U16(Runtime::kNewFunctionContext), // - R(closure), U8(1), // - B(PushContext), R(0), // - B(LdaSmi8), U8(1), // - B(StaContextSlot), R(0), U8(first_context_slot), // - B(CreateClosure), U8(0), U8(0), // - B(Return), // + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + /* */ R(closure), U8(1), // + B(PushContext), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(1), // + B(StaContextSlot), R(context), U8(first_context_slot), // + B(CreateClosure), U8(0), U8(0), // + B(Return), // }, 1, {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, {"var a = 1; var b = 2; return function() { a = 2; b = 3 };", 1 * kPointerSize, 1, - 21, + 22, { - B(CallRuntime), U16(Runtime::kNewFunctionContext), // - R(closure), U8(1), // - B(PushContext), R(0), // - B(LdaSmi8), U8(1), // - B(StaContextSlot), R(0), U8(first_context_slot), // - B(LdaSmi8), U8(2), // - B(StaContextSlot), R(0), U8(first_context_slot + 1), // - B(CreateClosure), U8(0), U8(0), // - B(Return), // + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + /* */ R(closure), U8(1), // + B(PushContext), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(1), // + B(StaContextSlot), R(context), U8(first_context_slot), // + B(LdaSmi8), U8(2), // + B(StaContextSlot), R(context), U8(first_context_slot + 1), // + B(CreateClosure), U8(0), U8(0), // + B(Return), // }, 1, {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, {"var a; (function() { a = 2; })(); return a;", 3 * kPointerSize, 1, - 24, + 25, { B(CallRuntime), U16(Runtime::kNewFunctionContext), // - R(closure), U8(1), // + /* */ R(closure), U8(1), // B(PushContext), R(0), // + B(StackCheck), // B(LdaUndefined), // B(Star), R(2), // B(CreateClosure), U8(0), U8(0), // B(Star), R(1), // - B(Call), R(1), R(2), U8(0), U8(vector->GetIndex(slot)), // - B(LdaContextSlot), R(0), U8(first_context_slot), // + B(Call), R(1), R(2), U8(1), U8(vector->GetIndex(slot)), // + B(LdaContextSlot), R(context), U8(first_context_slot), // B(Return), // }, 1, @@ -4385,15 +5053,16 @@ TEST(ContextVariables) { {"'use strict'; let a = 1; { let b = 2; return function() { a + b; }; }", 4 * kPointerSize, 1, - 44, + 47, { B(CallRuntime), U16(Runtime::kNewFunctionContext), // - R(closure), U8(1), // + /* */ R(closure), U8(1), // B(PushContext), R(0), // B(LdaTheHole), // - B(StaContextSlot), R(0), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // + B(StackCheck), // B(LdaSmi8), U8(1), // - B(StaContextSlot), R(0), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // B(LdaConstant), U8(0), // B(Star), R(2), // B(Ldar), R(closure), // @@ -4401,10 +5070,11 @@ TEST(ContextVariables) { B(CallRuntime), U16(Runtime::kPushBlockContext), R(2), U8(2), // B(PushContext), R(1), // B(LdaTheHole), // - B(StaContextSlot), R(1), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // B(LdaSmi8), U8(2), // - B(StaContextSlot), R(1), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // B(CreateClosure), U8(1), U8(0), // + B(PopContext), R(0), // B(Return), // }, 2, @@ -4417,33 +5087,35 @@ TEST(ContextVariables) { "return b", 3 * kPointerSize, 1, - 1041, + 1042, { B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // - U8(1), // + /* */ U8(1), // B(PushContext), R(0), // B(Ldar), THIS(1), // - B(StaContextSlot), R(0), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // B(CreateUnmappedArguments), // - B(StaContextSlot), R(0), U8(first_context_slot + 1), // + B(StaContextSlot), R(context), U8(first_context_slot + 1), // B(Ldar), R(new_target), // - B(StaContextSlot), R(0), U8(first_context_slot + 2), // + B(StaContextSlot), R(context), U8(first_context_slot + 2), // + B(StackCheck), // REPEAT_249(COMMA, // B(LdaZero), // - B(StaContextSlot), R(0), U8(wide_slot++)), // + B(StaContextSlot), R(context), U8(wide_slot++)), // B(LdaUndefined), // B(Star), R(2), // - B(LdaGlobalStrict), U8(0), U8(1), // + B(LdaGlobal), U8(0), U8(1), // B(Star), R(1), // - B(Call), R(1), R(2), U8(0), U8(0), // + B(Call), R(1), R(2), U8(1), U8(0), // B(LdaSmi8), U8(100), // - B(StaContextSlotWide), R(0), U16(256), // - B(LdaContextSlotWide), R(0), U16(256), // + B(StaContextSlotWide), R(context), U16(256), // + B(LdaContextSlotWide), R(context), U16(256), // B(Return), // }, 1, {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -4458,74 +5130,81 @@ TEST(ContextParameters) { BytecodeGeneratorHelper helper; int closure = Register::function_closure().index(); + int context = Register::current_context().index(); int first_context_slot = Context::MIN_CONTEXT_SLOTS; + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"function f(arg1) { return function() { arg1 = 2; }; }", 1 * kPointerSize, 2, - 16, + 17, { - B(CallRuntime), U16(Runtime::kNewFunctionContext), // - R(closure), U8(1), // - B(PushContext), R(0), // - B(Ldar), R(helper.kLastParamIndex), // - B(StaContextSlot), R(0), U8(first_context_slot), // - B(CreateClosure), U8(0), U8(0), // - B(Return), // + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + /* */ R(closure), U8(1), // + B(PushContext), R(0), // + B(Ldar), R(helper.kLastParamIndex), // + B(StaContextSlot), R(context), U8(first_context_slot), // + B(StackCheck), // + B(CreateClosure), U8(0), U8(0), // + B(Return), // }, 1, {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, {"function f(arg1) { var a = function() { arg1 = 2; }; return arg1; }", 2 * kPointerSize, 2, - 21, + 22, { - B(CallRuntime), U16(Runtime::kNewFunctionContext), // - R(closure), U8(1), // - B(PushContext), R(1), // - B(Ldar), R(helper.kLastParamIndex), // - B(StaContextSlot), R(1), U8(first_context_slot), // - B(CreateClosure), U8(0), U8(0), // - B(Star), R(0), // - B(LdaContextSlot), R(1), U8(first_context_slot), // - B(Return), // + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + /* */ R(closure), U8(1), // + B(PushContext), R(1), // + B(Ldar), R(helper.kLastParamIndex), // + B(StaContextSlot), R(context), U8(first_context_slot), // + B(StackCheck), // + B(CreateClosure), U8(0), U8(0), // + B(Star), R(0), // + B(LdaContextSlot), R(context), U8(first_context_slot), // + B(Return), // }, 1, {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, {"function f(a1, a2, a3, a4) { return function() { a1 = a3; }; }", 1 * kPointerSize, 5, - 21, + 22, { - B(CallRuntime), U16(Runtime::kNewFunctionContext), // - R(closure), U8(1), // - B(PushContext), R(0), // - B(Ldar), R(helper.kLastParamIndex - 3), // - B(StaContextSlot), R(0), U8(first_context_slot + 1), // - B(Ldar), R(helper.kLastParamIndex -1), // - B(StaContextSlot), R(0), U8(first_context_slot), // - B(CreateClosure), U8(0), U8(0), // - B(Return), // + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + /* */ R(closure), U8(1), // + B(PushContext), R(0), // + B(Ldar), R(helper.kLastParamIndex - 3), // + B(StaContextSlot), R(context), U8(first_context_slot + 1), // + B(Ldar), R(helper.kLastParamIndex -1), // + B(StaContextSlot), R(context), U8(first_context_slot), // + B(StackCheck), // + B(CreateClosure), U8(0), U8(0), // + B(Return), // }, 1, {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, {"function f() { var self = this; return function() { self = 2; }; }", 1 * kPointerSize, 1, - 16, + 17, { - B(CallRuntime), U16(Runtime::kNewFunctionContext), // - R(closure), U8(1), // - B(PushContext), R(0), // - B(Ldar), R(helper.kLastParamIndex), // - B(StaContextSlot), R(0), U8(first_context_slot), // - B(CreateClosure), U8(0), U8(0), // - B(Return), // + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + /* */ R(closure), U8(1), // + B(PushContext), R(0), // + B(StackCheck), // + B(Ldar), R(helper.kLastParamIndex), // + B(StaContextSlot), R(context), U8(first_context_slot), // + B(CreateClosure), U8(0), U8(0), // + B(Return), // }, 1, {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -4539,9 +5218,10 @@ TEST(OuterContextVariables) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; - int context = Register::function_context().index(); + int context = Register::current_context().index(); int first_context_slot = Context::MIN_CONTEXT_SLOTS; + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"function Outer() {" " var outerVar = 1;" @@ -4553,8 +5233,9 @@ TEST(OuterContextVariables) { "var f = new Outer().getInnerFunc();", 2 * kPointerSize, 1, - 20, + 21, { + B(StackCheck), // B(Ldar), R(context), // B(Star), R(0), // B(LdaContextSlot), R(0), U8(Context::PREVIOUS_INDEX), // @@ -4575,8 +5256,9 @@ TEST(OuterContextVariables) { "var f = new Outer().getInnerFunc();", 2 * kPointerSize, 1, - 21, + 22, { + B(StackCheck), // B(LdaContextSlot), R(context), U8(first_context_slot), // B(Star), R(0), // B(Ldar), R(context), // @@ -4589,6 +5271,7 @@ TEST(OuterContextVariables) { B(Return), // }}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -4615,6 +5298,7 @@ TEST(CountOperators) { i::NewTypeFeedbackVector(helper.isolate(), &store_feedback_spec); int closure = Register::function_closure().index(); + int context = Register::current_context().index(); int first_context_slot = Context::MIN_CONTEXT_SLOTS; int object_literal_flags = @@ -4622,12 +5306,14 @@ TEST(CountOperators) { int array_literal_flags = ArrayLiteral::kDisableMementos | ArrayLiteral::kShallowElements; + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"var a = 1; return ++a;", 1 * kPointerSize, 1, - 9, + 10, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(ToNumber), // @@ -4638,8 +5324,9 @@ TEST(CountOperators) { {"var a = 1; return a++;", 2 * kPointerSize, 1, - 13, + 14, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(ToNumber), // @@ -4652,8 +5339,9 @@ TEST(CountOperators) { {"var a = 1; return --a;", 1 * kPointerSize, 1, - 9, + 10, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(ToNumber), // @@ -4664,8 +5352,9 @@ TEST(CountOperators) { {"var a = 1; return a--;", 2 * kPointerSize, 1, - 13, + 14, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(ToNumber), // @@ -4678,12 +5367,14 @@ TEST(CountOperators) { {"var a = { val: 1 }; return a.val++;", 3 * kPointerSize, 1, - 23, + 26, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(object_literal_flags), // + B(Star), R(1), // B(Star), R(0), // B(Star), R(1), // - B(LoadICSloppy), R(1), U8(1), U8(vector->GetIndex(slot1)), // + B(LoadIC), R(1), U8(1), U8(vector->GetIndex(slot1)), // B(ToNumber), // B(Star), R(2), // B(Inc), // @@ -4697,12 +5388,14 @@ TEST(CountOperators) { {"var a = { val: 1 }; return --a.val;", 2 * kPointerSize, 1, - 19, + 22, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(object_literal_flags), // + B(Star), R(1), // B(Star), R(0), // B(Star), R(1), // - B(LoadICSloppy), R(1), U8(1), U8(vector->GetIndex(slot1)), // + B(LoadIC), R(1), U8(1), U8(vector->GetIndex(slot1)), // B(ToNumber), // B(Dec), // B(StoreICSloppy), R(1), U8(1), U8(vector->GetIndex(slot2)), // @@ -4714,16 +5407,18 @@ TEST(CountOperators) { {"var name = 'var'; var a = { val: 1 }; return a[name]--;", 5 * kPointerSize, 1, - 30, + 33, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(CreateObjectLiteral), U8(1), U8(0), U8(object_literal_flags), // + B(Star), R(2), // B(Star), R(1), // B(Star), R(2), // B(Ldar), R(0), // B(Star), R(3), // - B(KeyedLoadICSloppy), R(2), U8(vector->GetIndex(slot1)), // + B(KeyedLoadIC), R(2), U8(vector->GetIndex(slot1)), // B(ToNumber), // B(Star), R(4), // B(Dec), // @@ -4737,16 +5432,18 @@ TEST(CountOperators) { {"var name = 'var'; var a = { val: 1 }; return ++a[name];", 4 * kPointerSize, 1, - 26, + 29, { + B(StackCheck), // B(LdaConstant), U8(0), // B(Star), R(0), // B(CreateObjectLiteral), U8(1), U8(0), U8(object_literal_flags), // + B(Star), R(2), // B(Star), R(1), // B(Star), R(2), // B(Ldar), R(0), // B(Star), R(3), // - B(KeyedLoadICSloppy), R(2), U8(vector->GetIndex(slot1)), // + B(KeyedLoadIC), R(2), U8(vector->GetIndex(slot1)), // B(ToNumber), // B(Inc), // B(KeyedStoreICSloppy), R(2), R(3), U8(vector->GetIndex(slot2)), // @@ -4758,19 +5455,20 @@ TEST(CountOperators) { {"var a = 1; var b = function() { return a }; return ++a;", 2 * kPointerSize, 1, - 26, + 27, { B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // - U8(1), // + /* */ U8(1), // B(PushContext), R(1), // + B(StackCheck), // B(LdaSmi8), U8(1), // - B(StaContextSlot), R(1), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // B(CreateClosure), U8(0), U8(0), // B(Star), R(0), // - B(LdaContextSlot), R(1), U8(first_context_slot), // + B(LdaContextSlot), R(context), U8(first_context_slot), // B(ToNumber), // B(Inc), // - B(StaContextSlot), R(1), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // B(Return), // }, 1, @@ -4778,20 +5476,21 @@ TEST(CountOperators) { {"var a = 1; var b = function() { return a }; return a--;", 3 * kPointerSize, 1, - 30, + 31, { B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // - U8(1), // + /* */ U8(1), // B(PushContext), R(1), // + B(StackCheck), // B(LdaSmi8), U8(1), // - B(StaContextSlot), R(1), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // B(CreateClosure), U8(0), U8(0), // B(Star), R(0), // - B(LdaContextSlot), R(1), U8(first_context_slot), // + B(LdaContextSlot), R(context), U8(first_context_slot), // B(ToNumber), // B(Star), R(2), // B(Dec), // - B(StaContextSlot), R(1), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // B(Ldar), R(2), // B(Return), // }, @@ -4800,8 +5499,9 @@ TEST(CountOperators) { {"var idx = 1; var a = [1, 2]; return a[idx++] = 2;", 4 * kPointerSize, 1, - 27, + 28, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(CreateArrayLiteral), U8(0), U8(0), U8(array_literal_flags), // @@ -4814,12 +5514,13 @@ TEST(CountOperators) { B(Star), R(0), // B(LdaSmi8), U8(2), // B(KeyedStoreICSloppy), R(2), R(3), // - U8(store_vector->GetIndex(store_slot)), // + /* */ U8(store_vector->GetIndex(store_slot)), // B(Return), // }, 1, {InstanceType::FIXED_ARRAY_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -4841,13 +5542,15 @@ TEST(GlobalCountOperators) { Handle<i::TypeFeedbackVector> vector = i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"var global = 1;\nfunction f() { return ++global; }\nf()", 0, 1, - 9, + 10, { - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot1)), // + B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot1)), // B(ToNumber), // B(Inc), // B(StaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), // @@ -4858,9 +5561,10 @@ TEST(GlobalCountOperators) { {"var global = 1;\nfunction f() { return global--; }\nf()", 1 * kPointerSize, 1, - 13, + 14, { - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot1)), // + B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot1)), // B(ToNumber), // B(Star), R(0), // B(Dec), // @@ -4874,9 +5578,10 @@ TEST(GlobalCountOperators) { "f()", 0, 1, - 9, + 10, { - B(LdaGlobalStrict), U8(0), U8(vector->GetIndex(slot1)), // + B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot1)), // B(ToNumber), // B(Dec), // B(StaGlobalStrict), U8(0), U8(vector->GetIndex(slot2)), // @@ -4887,9 +5592,10 @@ TEST(GlobalCountOperators) { {"unallocated = 1;\nfunction f() { return unallocated++; }\nf()", 1 * kPointerSize, 1, - 13, + 14, { - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot1)), // + B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot1)), // B(ToNumber), // B(Star), R(0), // B(Inc), // @@ -4900,6 +5606,7 @@ TEST(GlobalCountOperators) { 1, {"unallocated"}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -4915,6 +5622,7 @@ TEST(CompoundExpressions) { Zone zone; int closure = Register::function_closure().index(); + int context = Register::current_context().index(); int first_context_slot = Context::MIN_CONTEXT_SLOTS; FeedbackVectorSpec feedback_spec(&zone); @@ -4926,12 +5634,15 @@ TEST(CompoundExpressions) { int object_literal_flags = ObjectLiteral::kFastElements | ObjectLiteral::kDisableMementos; + + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"var a = 1; a += 2;", 2 * kPointerSize, 1, - 14, + 15, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(Star), R(1), // @@ -4944,8 +5655,9 @@ TEST(CompoundExpressions) { {"var a = 1; a /= 2;", 2 * kPointerSize, 1, - 14, + 15, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(Star), R(1), // @@ -4958,12 +5670,14 @@ TEST(CompoundExpressions) { {"var a = { val: 2 }; a.name *= 2;", 3 * kPointerSize, 1, - 24, + 27, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(object_literal_flags), // + B(Star), R(1), // B(Star), R(0), // B(Star), R(1), // - B(LoadICSloppy), R(1), U8(1), U8(vector->GetIndex(slot1)), // + B(LoadIC), R(1), U8(1), U8(vector->GetIndex(slot1)), // B(Star), R(2), // B(LdaSmi8), U8(2), // B(Mul), R(2), // @@ -4977,14 +5691,16 @@ TEST(CompoundExpressions) { {"var a = { 1: 2 }; a[1] ^= 2;", 4 * kPointerSize, 1, - 27, + 30, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(object_literal_flags), // + B(Star), R(1), // B(Star), R(0), // B(Star), R(1), // B(LdaSmi8), U8(1), // B(Star), R(2), // - B(KeyedLoadICSloppy), R(1), U8(vector->GetIndex(slot1)), // + B(KeyedLoadIC), R(1), U8(vector->GetIndex(slot1)), // B(Star), R(3), // B(LdaSmi8), U8(2), // B(BitwiseXor), R(3), // @@ -4997,25 +5713,27 @@ TEST(CompoundExpressions) { {"var a = 1; (function f() { return a; }); a |= 24;", 2 * kPointerSize, 1, - 29, + 30, { B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // - U8(1), // + /* */ U8(1), // B(PushContext), R(0), // + B(StackCheck), // B(LdaSmi8), U8(1), // - B(StaContextSlot), R(0), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // B(CreateClosure), U8(0), U8(0), // - B(LdaContextSlot), R(0), U8(first_context_slot), // + B(LdaContextSlot), R(context), U8(first_context_slot), // B(Star), R(1), // B(LdaSmi8), U8(24), // B(BitwiseOr), R(1), // - B(StaContextSlot), R(0), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // B(LdaUndefined), // B(Return), // }, 1, {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -5037,13 +5755,15 @@ TEST(GlobalCompoundExpressions) { Handle<i::TypeFeedbackVector> vector = i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"var global = 1;\nfunction f() { return global &= 1; }\nf()", 1 * kPointerSize, 1, - 13, + 14, { - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot1)), // + B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot1)), // B(Star), R(0), // B(LdaSmi8), U8(1), // B(BitwiseAnd), R(0), // @@ -5055,9 +5775,10 @@ TEST(GlobalCompoundExpressions) { {"unallocated = 1;\nfunction f() { return unallocated += 1; }\nf()", 1 * kPointerSize, 1, - 13, + 14, { - B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot1)), // + B(StackCheck), // + B(LdaGlobal), U8(0), U8(vector->GetIndex(slot1)), // B(Star), R(0), // B(LdaSmi8), U8(1), // B(Add), R(0), // @@ -5067,6 +5788,7 @@ TEST(GlobalCompoundExpressions) { 1, {"unallocated"}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -5082,6 +5804,7 @@ TEST(CreateArguments) { Zone zone; int closure = Register::function_closure().index(); + int context = Register::current_context().index(); int first_context_slot = Context::MIN_CONTEXT_SLOTS; FeedbackVectorSpec feedback_spec(&zone); @@ -5090,82 +5813,96 @@ TEST(CreateArguments) { Handle<i::TypeFeedbackVector> vector = i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"function f() { return arguments; }", 1 * kPointerSize, 1, - 4, + 7, { B(CreateMappedArguments), // B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // B(Return), // }}, {"function f() { return arguments[0]; }", 2 * kPointerSize, 1, - 10, + 13, { B(CreateMappedArguments), // B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // B(Star), R(1), // B(LdaZero), // - B(KeyedLoadICSloppy), R(1), U8(vector->GetIndex(slot)), // + B(KeyedLoadIC), R(1), U8(vector->GetIndex(slot)), // B(Return), // }}, {"function f() { 'use strict'; return arguments; }", 1 * kPointerSize, 1, - 4, + 7, { B(CreateUnmappedArguments), // B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // B(Return), // }}, {"function f(a) { return arguments[0]; }", 3 * kPointerSize, 2, - 22, + 25, { B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // - U8(1), // + /* */ U8(1), // B(PushContext), R(1), // B(Ldar), R(BytecodeGeneratorHelper::kLastParamIndex), // - B(StaContextSlot), R(1), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // B(CreateMappedArguments), // B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // B(Star), R(2), // B(LdaZero), // - B(KeyedLoadICSloppy), R(2), U8(vector->GetIndex(slot)), // + B(KeyedLoadIC), R(2), U8(vector->GetIndex(slot)), // B(Return), // }}, {"function f(a, b, c) { return arguments; }", 2 * kPointerSize, 4, - 26, + 29, { B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // - U8(1), // + /* */ U8(1), // B(PushContext), R(1), // B(Ldar), R(BytecodeGeneratorHelper::kLastParamIndex - 2), // - B(StaContextSlot), R(1), U8(first_context_slot + 2), // + B(StaContextSlot), R(context), U8(first_context_slot + 2), // B(Ldar), R(BytecodeGeneratorHelper::kLastParamIndex - 1), // - B(StaContextSlot), R(1), U8(first_context_slot + 1), // + B(StaContextSlot), R(context), U8(first_context_slot + 1), // B(Ldar), R(BytecodeGeneratorHelper::kLastParamIndex), // - B(StaContextSlot), R(1), U8(first_context_slot), // + B(StaContextSlot), R(context), U8(first_context_slot), // B(CreateMappedArguments), // B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // B(Return), // }}, {"function f(a, b, c) { 'use strict'; return arguments; }", 1 * kPointerSize, 4, - 4, + 7, { B(CreateUnmappedArguments), // B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // B(Return), // }}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -5174,14 +5911,119 @@ TEST(CreateArguments) { } } +TEST(CreateRestParameter) { + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + Zone zone; + + FeedbackVectorSpec feedback_spec(&zone); + FeedbackVectorSlot slot = feedback_spec.AddKeyedLoadICSlot(); + FeedbackVectorSlot slot1 = feedback_spec.AddKeyedLoadICSlot(); + + Handle<i::TypeFeedbackVector> vector = + i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); + + // clang-format off + ExpectedSnippet<int> snippets[] = { + {"function f(...restArgs) { return restArgs; }", + 1 * kPointerSize, + 1, + 7, + { + B(CreateRestParameter), // + B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // + B(Return), // + }, + 0, + {}}, + {"function f(a, ...restArgs) { return restArgs; }", + 2 * kPointerSize, + 2, + 14, + { + B(CreateRestParameter), // + B(Star), R(0), // + B(LdaTheHole), // + B(Star), R(1), // + B(StackCheck), // + B(Ldar), A(1, 2), // + B(Star), R(1), // + B(Ldar), R(0), // + B(Return), // + }, + 0, + {}}, + {"function f(a, ...restArgs) { return restArgs[0]; }", + 3 * kPointerSize, + 2, + 20, + { + B(CreateRestParameter), // + B(Star), R(0), // + B(LdaTheHole), // + B(Star), R(1), // + B(StackCheck), // + B(Ldar), A(1, 2), // + B(Star), R(1), // + B(Ldar), R(0), // + B(Star), R(2), // + B(LdaZero), // + B(KeyedLoadIC), R(2), U8(vector->GetIndex(slot)), // + B(Return), // + }, + 0, + {}}, + {"function f(a, ...restArgs) { return restArgs[0] + arguments[0]; }", + 5 * kPointerSize, + 2, + 35, + { + B(CreateUnmappedArguments), // + B(Star), R(0), // + B(CreateRestParameter), // + B(Star), R(1), // + B(LdaTheHole), // + B(Star), R(2), // + B(StackCheck), // + B(Ldar), A(1, 2), // + B(Star), R(2), // + B(Ldar), R(1), // + B(Star), R(3), // + B(LdaZero), // + B(KeyedLoadIC), R(3), U8(vector->GetIndex(slot)), // + B(Star), R(4), // + B(Ldar), R(0), // + B(Star), R(3), // + B(LdaZero), // + B(KeyedLoadIC), R(3), U8(vector->GetIndex(slot1)), // + B(Add), R(4), // + B(Return), // + }, + 0, + {}}, + }; + // clang-format on + + for (size_t i = 0; i < arraysize(snippets); i++) { + Handle<BytecodeArray> bytecode_array = + helper.MakeBytecodeForFunction(snippets[i].code_snippet); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } +} TEST(IllegalRedeclaration) { + bool old_legacy_const_flag = FLAG_legacy_const; + FLAG_legacy_const = true; + InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; CHECK_GE(MessageTemplate::kVarRedeclaration, 128); // Must adapt bytecode if this changes. + // clang-format off ExpectedSnippet<Handle<Object>, 2> snippets[] = { {"const a = 1; { var a = 2; }", 3 * kPointerSize, @@ -5199,12 +6041,15 @@ TEST(IllegalRedeclaration) { {helper.factory()->NewNumberFromInt(MessageTemplate::kVarRedeclaration), helper.factory()->NewStringFromAsciiChecked("a")}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); CheckBytecodeArrayEqual(snippets[i], bytecode_array); } + + FLAG_legacy_const = old_legacy_const_flag; } @@ -5226,53 +6071,69 @@ TEST(ForIn) { Handle<i::TypeFeedbackVector> vector = i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"for (var p in null) {}", 2 * kPointerSize, 1, - 2, - {B(LdaUndefined), B(Return)}, + 3, + { + B(StackCheck), // + B(LdaUndefined), // + B(Return) // + }, 0}, {"for (var p in undefined) {}", 2 * kPointerSize, 1, - 2, - {B(LdaUndefined), B(Return)}, + 3, + { + B(StackCheck), // + B(LdaUndefined), // + B(Return) // + }, 0}, {"for (var p in undefined) {}", 2 * kPointerSize, 1, - 2, - {B(LdaUndefined), B(Return)}, + 3, + { + B(StackCheck), // + B(LdaUndefined), // + B(Return) // + }, 0}, {"var x = 'potatoes';\n" "for (var p in x) { return p; }", 8 * kPointerSize, 1, - 45, + 46, { - B(LdaConstant), U8(0), // - B(Star), R(1), // - B(JumpIfUndefined), U8(39), // - B(JumpIfNull), U8(37), // - B(ToObject), // - B(JumpIfNull), U8(34), // - B(Star), R(3), // - B(ForInPrepare), R(4), R(5), R(6), // - B(LdaZero), // - B(Star), R(7), // - B(ForInDone), R(7), R(6), // - B(JumpIfTrue), U8(20), // - B(ForInNext), R(3), R(4), R(5), R(7), // - B(JumpIfUndefined), U8(7), // - B(Star), R(0), // - B(Star), R(2), // - B(Return), // - B(ForInStep), R(7), // - B(Star), R(7), // - B(Jump), U8(-21), // - B(LdaUndefined), // - B(Return), // + B(StackCheck), // + B(LdaConstant), U8(0), // + B(Star), R(1), // + B(JumpIfUndefined), U8(39), // + B(JumpIfNull), U8(37), // + B(ToObject), // + B(JumpIfNull), U8(34), // + B(Star), R(3), // + B(ForInPrepare), R(4), // + B(LdaZero), // + B(Star), R(7), // + B(ForInDone), R(7), R(6), // + B(JumpIfTrue), U8(22), // + B(ForInNext), R(3), R(7), R(4), // + B(JumpIfUndefined), U8(10), // + B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // + B(Star), R(2), // + B(Return), // + B(ForInStep), R(7), // + B(Star), R(7), // + B(Jump), U8(-23), // + B(LdaUndefined), // + B(Return), // }, 1, {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, @@ -5280,8 +6141,9 @@ TEST(ForIn) { "for (var p in [1,2,3]) { x += p; }", 9 * kPointerSize, 1, - 57, + 58, { + B(StackCheck), // B(LdaZero), // B(Star), R(1), // B(CreateArrayLiteral), U8(0), U8(0), U8(3), // @@ -5290,14 +6152,16 @@ TEST(ForIn) { B(ToObject), // B(JumpIfNull), U8(43), // B(Star), R(3), // - B(ForInPrepare), R(4), R(5), R(6), // + B(ForInPrepare), R(4), // B(LdaZero), // B(Star), R(7), // B(ForInDone), R(7), R(6), // - B(JumpIfTrue), U8(29), // - B(ForInNext), R(3), R(4), R(5), R(7), // - B(JumpIfUndefined), U8(16), // + B(JumpIfTrue), U8(31), // + B(ForInNext), R(3), R(7), R(4), // + B(JumpIfUndefined), U8(19), // B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // B(Star), R(2), // B(Ldar), R(1), // B(Star), R(8), // @@ -5306,7 +6170,7 @@ TEST(ForIn) { B(Star), R(1), // B(ForInStep), R(7), // B(Star), R(7), // - B(Jump), U8(-30), // + B(Jump), U8(-32), // B(LdaUndefined), // B(Return), // }, @@ -5319,31 +6183,34 @@ TEST(ForIn) { "}", 8 * kPointerSize, 1, - 94, + 95, { + B(StackCheck), // B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // + B(Star), R(1), // B(Star), R(0), // B(CreateArrayLiteral), U8(1), U8(1), U8(simple_flags), // - B(JumpIfUndefined), U8(82), // - B(JumpIfNull), U8(80), // + B(JumpIfUndefined), U8(80), // + B(JumpIfNull), U8(78), // B(ToObject), // - B(JumpIfNull), U8(77), // + B(JumpIfNull), U8(75), // B(Star), R(1), // - B(ForInPrepare), R(2), R(3), R(4), // + B(ForInPrepare), R(2), // B(LdaZero), // B(Star), R(5), // B(ForInDone), R(5), R(4), // B(JumpIfTrue), U8(63), // - B(ForInNext), R(1), R(2), R(3), R(5), // - B(JumpIfUndefined), U8(50), // + B(ForInNext), R(1), R(5), R(2), // + B(JumpIfUndefined), U8(51), // B(Star), R(6), // B(Ldar), R(0), // B(Star), R(7), // B(Ldar), R(6), // B(StoreICSloppy), R(7), U8(2), U8(vector->GetIndex(slot4)), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(6), // - B(LoadICSloppy), R(6), U8(2), U8(vector->GetIndex(slot2)), // + B(LoadIC), R(6), U8(2), U8(vector->GetIndex(slot2)), // B(Star), R(7), // B(LdaSmi8), U8(10), // B(TestEqual), R(7), // @@ -5351,7 +6218,7 @@ TEST(ForIn) { B(Jump), U8(20), // B(Ldar), R(0), // B(Star), R(6), // - B(LoadICSloppy), R(6), U8(2), U8(vector->GetIndex(slot3)), // + B(LoadIC), R(6), U8(2), U8(vector->GetIndex(slot3)), // B(Star), R(7), // B(LdaSmi8), U8(20), // B(TestEqual), R(7), // @@ -5370,23 +6237,24 @@ TEST(ForIn) { "for (x[0] in [1,2,3]) { return x[3]; }", 9 * kPointerSize, 1, - 71, + 70, { + B(StackCheck), // B(CreateArrayLiteral), U8(0), U8(0), U8(simple_flags), // B(Star), R(0), // B(CreateArrayLiteral), U8(1), U8(1), U8(simple_flags), // - B(JumpIfUndefined), U8(59), // - B(JumpIfNull), U8(57), // + B(JumpIfUndefined), U8(57), // + B(JumpIfNull), U8(55), // B(ToObject), // - B(JumpIfNull), U8(54), // + B(JumpIfNull), U8(52), // B(Star), R(1), // - B(ForInPrepare), R(2), R(3), R(4), // + B(ForInPrepare), R(2), // B(LdaZero), // B(Star), R(5), // B(ForInDone), R(5), R(4), // B(JumpIfTrue), U8(40), // - B(ForInNext), R(1), R(2), R(3), R(5), // - B(JumpIfUndefined), U8(27), // + B(ForInNext), R(1), R(5), R(2), // + B(JumpIfUndefined), U8(28), // B(Star), R(6), // B(Ldar), R(0), // B(Star), R(7), // @@ -5394,10 +6262,11 @@ TEST(ForIn) { B(Star), R(8), // B(Ldar), R(6), // B(KeyedStoreICSloppy), R(7), R(8), U8(vector->GetIndex(slot3)), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(6), // B(LdaSmi8), U8(3), // - B(KeyedLoadICSloppy), R(6), U8(vector->GetIndex(slot2)), // + B(KeyedLoadIC), R(6), U8(vector->GetIndex(slot2)), // B(Return), // B(ForInStep), R(5), // B(Star), R(5), // @@ -5408,6 +6277,259 @@ TEST(ForIn) { 2, {InstanceType::FIXED_ARRAY_TYPE, InstanceType::FIXED_ARRAY_TYPE}}, }; + // clang-format on + + for (size_t i = 0; i < arraysize(snippets); i++) { + Handle<BytecodeArray> bytecode_array = + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } +} + + +// TODO(rmcilroy): Do something about this; new bytecode is too large +// (150+ instructions) to adapt manually. +DISABLED_TEST(ForOf) { + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + Zone zone; + + int array_literal_flags = + ArrayLiteral::kDisableMementos | ArrayLiteral::kShallowElements; + int object_literal_flags = + ObjectLiteral::kFastElements | ObjectLiteral::kDisableMementos; + + FeedbackVectorSpec feedback_spec(&zone); + FeedbackVectorSlot slot1 = feedback_spec.AddCallICSlot(); + FeedbackVectorSlot slot2 = feedback_spec.AddKeyedLoadICSlot(); + FeedbackVectorSlot slot3 = feedback_spec.AddCallICSlot(); + FeedbackVectorSlot slot4 = feedback_spec.AddLoadICSlot(); + FeedbackVectorSlot slot5 = feedback_spec.AddLoadICSlot(); + FeedbackVectorSlot slot6 = feedback_spec.AddLoadICSlot(); + FeedbackVectorSlot slot7 = feedback_spec.AddStoreICSlot(); + FeedbackVectorSlot slot8 = feedback_spec.AddLoadICSlot(); + Handle<i::TypeFeedbackVector> vector = + i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); + + // clang-format off + ExpectedSnippet<InstanceType, 8> snippets[] = { + {"for (var p of [0, 1, 2]) {}", + 7 * kPointerSize, + 1, + 86, + { + B(StackCheck), // + B(CreateArrayLiteral), U8(0), U8(0), U8(array_literal_flags), // + B(Star), R(5), // + B(LdaConstant), U8(1), // + B(KeyedLoadIC), R(5), U8(vector->GetIndex(slot2)), // + B(Star), R(4), // + B(Call), R(4), R(5), U8(1), U8(vector->GetIndex(slot1)), // + B(Star), R(1), // + B(Ldar), R(1), // + B(Star), R(6), // + B(LoadIC), R(6), U8(2), U8(vector->GetIndex(slot4)), // + B(Star), R(5), // + B(Call), R(5), R(6), U8(1), U8(vector->GetIndex(slot3)), // + B(Star), R(2), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kInlineIsJSReceiver), R(4), U8(1), // + B(LogicalNot), // + B(JumpIfFalse), U8(11), // + B(Ldar), R(2), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), // + /* */ R(4), U8(1), // + B(Ldar), R(2), // + B(Star), R(4), // + B(LoadIC), R(4), U8(3), U8(vector->GetIndex(slot5)), // + B(JumpIfToBooleanTrue), U8(19), // + B(Ldar), R(2), // + B(Star), R(4), // + B(LoadIC), R(4), U8(4), U8(vector->GetIndex(slot6)), // + B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // + B(Star), R(3), // + B(Jump), U8(-61), // + B(LdaUndefined), // + B(Return), // + }, + 5, + {InstanceType::FIXED_ARRAY_TYPE, InstanceType::SYMBOL_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + {"var x = 'potatoes';\n" + "for (var p of x) { return p; }", + 8 * kPointerSize, + 1, + 85, + { + B(StackCheck), // + B(LdaConstant), U8(0), // + B(Star), R(3), // + B(Star), R(6), // + B(LdaConstant), U8(1), // + B(KeyedLoadIC), R(6), U8(vector->GetIndex(slot2)), // + B(Star), R(5), // + B(Call), R(5), R(6), U8(1), U8(vector->GetIndex(slot1)), // + B(Star), R(1), // + B(Ldar), R(1), // + B(Star), R(7), // + B(LoadIC), R(7), U8(2), U8(vector->GetIndex(slot4)), // + B(Star), R(6), // + B(Call), R(6), R(7), U8(1), U8(vector->GetIndex(slot3)), // + B(Star), R(2), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kInlineIsJSReceiver), R(5), U8(1), // + B(LogicalNot), // + B(JumpIfFalse), U8(11), // + B(Ldar), R(2), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), // + /* */ R(5), U8(1), // + B(Ldar), R(2), // + B(Star), R(5), // + B(LoadIC), R(5), U8(3), U8(vector->GetIndex(slot5)), // + B(JumpIfToBooleanTrue), U8(18), // + B(Ldar), R(2), // + B(Star), R(5), // + B(LoadIC), R(5), U8(4), U8(vector->GetIndex(slot6)), // + B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // + B(Star), R(4), // + B(Return), // + B(LdaUndefined), // + B(Return), // + }, + 5, + {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::SYMBOL_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + {"for (var x of [10, 20, 30]) {\n" + " if (x == 10) continue;\n" + " if (x == 20) break;\n" + "}", + 7 * kPointerSize, + 1, + 108, + { + B(StackCheck), // + B(CreateArrayLiteral), U8(0), U8(0), U8(array_literal_flags), // + B(Star), R(5), // + B(LdaConstant), U8(1), // + B(KeyedLoadIC), R(5), U8(vector->GetIndex(slot2)), // + B(Star), R(4), // + B(Call), R(4), R(5), U8(1), U8(vector->GetIndex(slot1)), // + B(Star), R(1), // + B(Ldar), R(1), // + B(Star), R(6), // + B(LoadIC), R(6), U8(2), U8(vector->GetIndex(slot4)), // + B(Star), R(5), // + B(Call), R(5), R(6), U8(1), U8(vector->GetIndex(slot3)), // + B(Star), R(2), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kInlineIsJSReceiver), R(4), U8(1), // + B(LogicalNot), // + B(JumpIfFalse), U8(11), // + B(Ldar), R(2), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), // + /* */ R(4), U8(1), // + B(Ldar), R(2), // + B(Star), R(4), // + B(LoadIC), R(4), U8(3), U8(vector->GetIndex(slot5)), // + B(JumpIfToBooleanTrue), U8(41), // + B(Ldar), R(2), // + B(Star), R(4), // + B(LoadIC), R(4), U8(4), U8(vector->GetIndex(slot6)), // + B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // + B(Star), R(3), // + B(Star), R(4), // + B(LdaSmi8), U8(10), // + B(TestEqual), R(4), // + B(JumpIfFalse), U8(4), // + B(Jump), U8(-69), // + B(Ldar), R(3), // + B(Star), R(4), // + B(LdaSmi8), U8(20), // + B(TestEqual), R(4), // + B(JumpIfFalse), U8(4), // + B(Jump), U8(4), // + B(Jump), U8(-83), // + B(LdaUndefined), // + B(Return), // + }, + 5, + {InstanceType::FIXED_ARRAY_TYPE, InstanceType::SYMBOL_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + {"var x = { 'a': 1, 'b': 2 };\n" + "for (x['a'] of [1,2,3]) { return x['a']; }", + 6 * kPointerSize, + 1, + 103, + { + B(StackCheck), // + B(CreateObjectLiteral), U8(0), U8(0), U8(object_literal_flags), // + B(Star), R(3), // + B(Star), R(2), // + B(CreateArrayLiteral), U8(1), U8(1), U8(array_literal_flags), // + B(Star), R(4), // + B(LdaConstant), U8(2), // + B(KeyedLoadIC), R(4), U8(vector->GetIndex(slot2)), // + B(Star), R(3), // + B(Call), R(3), R(4), U8(1), U8(vector->GetIndex(slot1)), // + B(Star), R(0), // + B(Ldar), R(0), // + B(Star), R(5), // + B(LoadIC), R(5), U8(3), U8(vector->GetIndex(slot4)), // + B(Star), R(4), // + B(Call), R(4), R(5), U8(1), U8(vector->GetIndex(slot3)), // + B(Star), R(1), // + B(Star), R(3), // + B(CallRuntime), U16(Runtime::kInlineIsJSReceiver), R(3), U8(1), // + B(LogicalNot), // + B(JumpIfFalse), U8(11), // + B(Ldar), R(1), // + B(Star), R(3), // + B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), // + /* */ R(3), U8(1), // + B(Ldar), R(1), // + B(Star), R(3), // + B(LoadIC), R(3), U8(4), U8(vector->GetIndex(slot5)), // + B(JumpIfToBooleanTrue), U8(28), // + B(Ldar), R(2), // + B(Star), R(3), // + B(Ldar), R(1), // + B(Star), R(4), // + B(LoadIC), R(4), U8(5), U8(vector->GetIndex(slot6)), // + B(StoreICSloppy), R(3), U8(6), U8(vector->GetIndex(slot7)), // + B(StackCheck), // + B(Ldar), R(2), // + B(Star), R(3), // + B(LoadIC), R(3), U8(6), U8(vector->GetIndex(slot8)), // + B(Return), // + B(LdaUndefined), // + B(Return), // + }, + 7, + {InstanceType::FIXED_ARRAY_TYPE, + InstanceType::FIXED_ARRAY_TYPE, + InstanceType::SYMBOL_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -5421,12 +6543,14 @@ TEST(Conditional) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<int> snippets[] = { {"return 1 ? 2 : 3;", 0, 1, - 11, + 12, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(JumpIfToBooleanFalse), U8(6), // B(LdaSmi8), U8(2), // @@ -5437,8 +6561,9 @@ TEST(Conditional) { {"return 1 ? 2 ? 3 : 4 : 5;", 0, 1, - 19, + 20, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(JumpIfToBooleanFalse), U8(14), // B(LdaSmi8), U8(2), // @@ -5451,6 +6576,7 @@ TEST(Conditional) { B(Return), // }}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -5464,6 +6590,7 @@ TEST(Switch) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<int> snippets[] = { {"var a = 1;\n" "switch(a) {\n" @@ -5472,8 +6599,9 @@ TEST(Switch) { "}\n", 3 * kPointerSize, 1, - 30, + 31, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(1), // The tag variable is allocated as a B(Star), R(0), // local by the parser, hence the store @@ -5499,8 +6627,9 @@ TEST(Switch) { "}\n", 3 * kPointerSize, 1, - 36, + 37, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(1), // B(Star), R(0), // @@ -5528,8 +6657,9 @@ TEST(Switch) { "}\n", 3 * kPointerSize, 1, - 34, + 35, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(1), // B(Star), R(0), // @@ -5557,8 +6687,9 @@ TEST(Switch) { "}\n", 3 * kPointerSize, 1, - 34, + 35, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(1), // B(Star), R(0), // @@ -5586,8 +6717,9 @@ TEST(Switch) { "}\n", 3 * kPointerSize, 1, - 43, + 44, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(1), // B(TypeOf), // @@ -5619,8 +6751,9 @@ TEST(Switch) { "}\n", 3 * kPointerSize, 1, - 31, + 32, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(1), // B(Star), R(0), // @@ -5647,8 +6780,9 @@ TEST(Switch) { "}\n", 3 * kPointerSize, 1, - 288, + 289, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(1), // B(Star), R(0), // @@ -5683,8 +6817,9 @@ TEST(Switch) { "}\n", 5 * kPointerSize, 1, - 60, + 61, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(2), // B(Star), R(0), // @@ -5718,6 +6853,7 @@ TEST(Switch) { B(Return), // }}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -5733,12 +6869,14 @@ TEST(BasicBlockToBoolean) { // Check that we generate JumpIfToBoolean if they are at the start of basic // blocks. + // clang-format off ExpectedSnippet<int> snippets[] = { {"var a = 1; if (a || a < 0) { return 1; }", 2 * kPointerSize, 1, - 20, + 21, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(JumpIfToBooleanTrue), U8(9), // @@ -5755,8 +6893,9 @@ TEST(BasicBlockToBoolean) { {"var a = 1; if (a && a < 0) { return 1; }", 2 * kPointerSize, 1, - 20, + 21, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(JumpIfToBooleanFalse), U8(9), // @@ -5773,8 +6912,9 @@ TEST(BasicBlockToBoolean) { {"var a = 1; a = (a || a < 0) ? 2 : 3;", 2 * kPointerSize, 1, - 25, + 26, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(JumpIfToBooleanTrue), U8(9), // @@ -5791,6 +6931,7 @@ TEST(BasicBlockToBoolean) { B(Return), // }}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -5804,20 +6945,23 @@ TEST(DeadCodeRemoval) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<int> snippets[] = { {"return; var a = 1; a();", 1 * kPointerSize, 1, - 2, + 3, { + B(StackCheck), // B(LdaUndefined), // B(Return), // }}, {"if (false) { return; }; var a = 1;", 1 * kPointerSize, 1, - 6, + 7, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(LdaUndefined), // @@ -5826,16 +6970,18 @@ TEST(DeadCodeRemoval) { {"if (true) { return 1; } else { return 2; };", 0, 1, - 3, + 4, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Return), // }}, {"var a = 1; if (a) { return 1; }; return 2;", 1 * kPointerSize, 1, - 12, + 13, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(JumpIfToBooleanFalse), U8(5), // @@ -5845,6 +6991,7 @@ TEST(DeadCodeRemoval) { B(Return), // }}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -5860,31 +7007,46 @@ TEST(ThisFunction) { int closure = Register::function_closure().index(); + // clang-format off ExpectedSnippet<int> snippets[] = { {"var f;\n f = function f() { }", - 1 * kPointerSize, + 2 * kPointerSize, 1, - 9, + 19, { - B(LdaTheHole), // - B(Star), R(0), // - B(Ldar), R(closure), // - B(Star), R(0), // - B(LdaUndefined), // - B(Return), // + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(closure), // + B(Star), R(1), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(5), // + B(Mov), R(1), R(0), // + B(Ldar), R(1), // + B(LdaUndefined), // + B(Return), // }}, {"var f;\n f = function f() { return f; }", - 1 * kPointerSize, + 2 * kPointerSize, 1, - 8, + 23, { - B(LdaTheHole), // - B(Star), R(0), // - B(Ldar), R(closure), // - B(Star), R(0), // - B(Return), // + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(closure), // + B(Star), R(1), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(5), // + B(Mov), R(1), R(0), // + B(Ldar), R(1), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(3), // + B(LdaUndefined), // + B(Return), // }}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -5900,27 +7062,44 @@ TEST(NewTarget) { int new_target = Register::new_target().index(); - ExpectedSnippet<int> snippets[] = { + // clang-format off + ExpectedSnippet<InstanceType> snippets[] = { {"return new.target;", - 1 * kPointerSize, + 2 * kPointerSize, 1, - 5, + 19, { - B(Ldar), R(new_target), // - B(Star), R(0), // - B(Return), // - }}, + B(Ldar), R(new_target), // + B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(0), // + B(Star), R(1), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(1), U8(1), // + B(Return), // + }, + 1, + {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, {"new.target;", - 1 * kPointerSize, + 2 * kPointerSize, 1, - 6, + 20, { - B(Ldar), R(new_target), // - B(Star), R(0), // - B(LdaUndefined), // - B(Return), // - }}, - }; + B(Ldar), R(new_target), // + B(Star), R(0), // + B(StackCheck), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(0), // + B(Star), R(1), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(1), U8(1), // + B(LdaUndefined), // + B(Return), // + }, + 1, + {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}}; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -5934,6 +7113,7 @@ TEST(RemoveRedundantLdar) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<int> snippets[] = { {"var ld_a = 1;\n" // This test is to check Ldar does not "while(true) {\n" // get removed if the preceding Star is @@ -5943,9 +7123,11 @@ TEST(RemoveRedundantLdar) { "return ld_a;", 2 * kPointerSize, 1, - 29, - {B(LdaSmi8), U8(1), // + 31, + {B(StackCheck), // + B(LdaSmi8), U8(1), // B(Star), R(0), // + B(StackCheck), // B(Ldar), R(0), // This load should not be removed as it B(Star), R(1), // is the target of the branch. B(Ldar), R(0), // @@ -5956,7 +7138,7 @@ TEST(RemoveRedundantLdar) { B(TestGreaterThan), R(1), // B(JumpIfFalse), U8(4), // B(Jump), U8(4), // - B(Jump), U8(-20), // + B(Jump), U8(-21), // B(Ldar), R(0), // B(Return)}}, {"var ld_a = 1;\n" @@ -5967,9 +7149,11 @@ TEST(RemoveRedundantLdar) { "return ld_a;", 2 * kPointerSize, 1, - 27, - {B(LdaSmi8), U8(1), // + 29, + {B(StackCheck), // + B(LdaSmi8), U8(1), // B(Star), R(0), // + B(StackCheck), // B(Ldar), R(0), // B(Star), R(1), // B(Ldar), R(0), // @@ -5987,8 +7171,9 @@ TEST(RemoveRedundantLdar) { " return ld_a;", 2 * kPointerSize, 1, - 13, + 14, { + B(StackCheck), // B(LdaSmi8), U8(1), // B(Star), R(0), // B(Star), R(1), // @@ -5998,6 +7183,7 @@ TEST(RemoveRedundantLdar) { B(Return) // }}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -6011,13 +7197,15 @@ TEST(AssignmentsInBinaryExpression) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"var x = 0, y = 1;\n" "return (x = 2, y = 3, x = 4, y = 5)", 2 * kPointerSize, 1, - 24, + 25, { + B(StackCheck), // B(LdaZero), B(Star), R(0), // B(LdaSmi8), U8(1), // B(Star), R(1), // @@ -6037,8 +7225,9 @@ TEST(AssignmentsInBinaryExpression) { "return y", 2 * kPointerSize, 1, - 11, + 12, { + B(StackCheck), // B(LdaSmi8), U8(55), // B(Star), R(0), // B(LdaSmi8), U8(100), // @@ -6052,8 +7241,9 @@ TEST(AssignmentsInBinaryExpression) { "return x;", 3 * kPointerSize, 1, - 23, + 24, { + B(StackCheck), // B(LdaSmi8), U8(55), // B(Star), R(0), // B(Star), R(1), // @@ -6074,8 +7264,9 @@ TEST(AssignmentsInBinaryExpression) { "return x;", 3 * kPointerSize, 1, - 31, + 32, { + B(StackCheck), // B(LdaSmi8), U8(55), // B(Star), R(0), // B(LdaSmi8), U8(56), // @@ -6100,8 +7291,9 @@ TEST(AssignmentsInBinaryExpression) { "return y;", 4 * kPointerSize, 1, - 31, + 32, { + B(StackCheck), // B(LdaSmi8), U8(55), // B(Star), R(0), // B(Star), R(2), // @@ -6125,8 +7317,9 @@ TEST(AssignmentsInBinaryExpression) { "return x;", 3 * kPointerSize, 1, - 31, + 32, { + B(StackCheck), // B(LdaSmi8), U8(55), // B(Star), R(0), // B(Star), R(1), // @@ -6150,8 +7343,9 @@ TEST(AssignmentsInBinaryExpression) { "y;\n", 5 * kPointerSize, 1, - 69, + 70, { + B(StackCheck), // B(LdaSmi8), U8(10), // B(Star), R(0), // B(LdaSmi8), U8(20), // @@ -6193,8 +7387,9 @@ TEST(AssignmentsInBinaryExpression) { "return 1 + x + (x++) + (++x);\n", 4 * kPointerSize, 1, - 37, + 38, { + B(StackCheck), // B(LdaSmi8), U8(17), // B(Star), R(0), // B(LdaSmi8), U8(1), // @@ -6217,7 +7412,9 @@ TEST(AssignmentsInBinaryExpression) { B(Add), R(3), // B(Return), // }, - 0}}; + 0} + }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -6233,49 +7430,51 @@ TEST(Eval) { Zone zone; int closure = Register::function_closure().index(); - int context = Register::function_context().index(); + int context = Register::current_context().index(); int new_target = Register::new_target().index(); int first_context_slot = Context::MIN_CONTEXT_SLOTS; + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"return eval('1;');", 9 * kPointerSize, 1, - 67, + 65, { - B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // - U8(1), // - B(PushContext), R(0), // - B(Ldar), THIS(1), // - B(StaContextSlot), R(0), U8(first_context_slot), // - B(CreateMappedArguments), // - B(StaContextSlot), R(0), U8(first_context_slot + 1), // - B(Ldar), R(new_target), // - B(StaContextSlot), R(0), U8(first_context_slot + 2), // - B(Mov), R(context), R(3), // - B(LdaConstant), U8(0), // - B(Star), R(4), // - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlot), // - R(3), U8(2), R(1), // - B(LdaConstant), U8(1), // - B(Star), R(3), // - B(Mov), R(1), R(4), // - B(Mov), R(3), R(5), // - B(Mov), R(closure), R(6), // - B(LdaZero), // - B(Star), R(7), // - B(LdaSmi8), U8(10), // - B(Star), R(8), // - B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), // - U8(5), // - B(Star), R(1), // - B(Call), R(1), R(2), U8(1), U8(0), // - B(Return), // + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + /* */ U8(1), // + B(PushContext), R(0), // + B(Ldar), THIS(1), // + B(StaContextSlot), R(context), U8(first_context_slot), // + B(CreateMappedArguments), // + B(StaContextSlot), R(context), U8(first_context_slot + 1), // + B(Ldar), R(new_target), // + B(StaContextSlot), R(context), U8(first_context_slot + 2), // + B(StackCheck), // + B(LdaConstant), U8(0), // + B(Star), R(3), // + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), // + /* */ R(3), U8(1), R(1), // + B(LdaConstant), U8(1), // + B(Star), R(3), // + B(Mov), R(1), R(4), // + B(Mov), R(3), R(5), // + B(Mov), R(closure), R(6), // + B(LdaZero), // + B(Star), R(7), // + B(LdaSmi8), U8(10), // + B(Star), R(8), // + B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), // + /* */ U8(5), // + B(Star), R(1), // + B(Call), R(1), R(2), U8(2), U8(0), // + B(Return), // }, 2, {"eval", "1;"}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -6290,125 +7489,127 @@ TEST(LookupSlot) { BytecodeGeneratorHelper helper; int closure = Register::function_closure().index(); + int context = Register::current_context().index(); int first_context_slot = Context::MIN_CONTEXT_SLOTS; - int context = Register::function_context().index(); int new_target = Register::new_target().index(); + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"eval('var x = 10;'); return x;", 9 * kPointerSize, 1, - 69, + 67, { - B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // - U8(1), // - B(PushContext), R(0), // - B(Ldar), THIS(1), // - B(StaContextSlot), R(0), U8(first_context_slot), // - B(CreateMappedArguments), // - B(StaContextSlot), R(0), U8(first_context_slot + 1), // - B(Ldar), R(new_target), // - B(StaContextSlot), R(0), U8(first_context_slot + 2), // - B(Mov), R(context), R(3), // - B(LdaConstant), U8(0), // - B(Star), R(4), // - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlot), // - R(3), U8(2), R(1), // - B(LdaConstant), U8(1), // - B(Star), R(3), // - B(Mov), R(1), R(4), // - B(Mov), R(3), R(5), // - B(Mov), R(closure), R(6), // - B(LdaZero), // - B(Star), R(7), // - B(LdaSmi8), U8(10), // - B(Star), R(8), // - B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), // - U8(5), // - B(Star), R(1), // - B(Call), R(1), R(2), U8(1), U8(0), // - B(LdaLookupSlot), U8(2), // - B(Return), // + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + /* */ U8(1), // + B(PushContext), R(0), // + B(Ldar), THIS(1), // + B(StaContextSlot), R(context), U8(first_context_slot), // + B(CreateMappedArguments), // + B(StaContextSlot), R(context), U8(first_context_slot + 1), // + B(Ldar), R(new_target), // + B(StaContextSlot), R(context), U8(first_context_slot + 2), // + B(StackCheck), // + B(LdaConstant), U8(0), // + B(Star), R(3), // + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), // + R(3), U8(1), R(1), // + B(LdaConstant), U8(1), // + B(Star), R(3), // + B(Mov), R(1), R(4), // + B(Mov), R(3), R(5), // + B(Mov), R(closure), R(6), // + B(LdaZero), // + B(Star), R(7), // + B(LdaSmi8), U8(10), // + B(Star), R(8), // + B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), // + U8(5), // + B(Star), R(1), // + B(Call), R(1), R(2), U8(2), U8(0), // + B(LdaLookupSlot), U8(2), // + B(Return), // }, 3, {"eval", "var x = 10;", "x"}}, {"eval('var x = 10;'); return typeof x;", - 9 * kPointerSize, - 1, - 70, - { - B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // - U8(1), // - B(PushContext), R(0), // - B(Ldar), THIS(1), // - B(StaContextSlot), R(0), U8(first_context_slot), // - B(CreateMappedArguments), // - B(StaContextSlot), R(0), U8(first_context_slot + 1), // - B(Ldar), R(new_target), // - B(StaContextSlot), R(0), U8(first_context_slot + 2), // - B(Mov), R(context), R(3), // - B(LdaConstant), U8(0), // - B(Star), R(4), // - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlot), // - R(3), U8(2), R(1), // - B(LdaConstant), U8(1), // - B(Star), R(3), // - B(Mov), R(1), R(4), // - B(Mov), R(3), R(5), // - B(Mov), R(closure), R(6), // - B(LdaZero), // - B(Star), R(7), // - B(LdaSmi8), U8(10), // - B(Star), R(8), // - B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), // - U8(5), // - B(Star), R(1), // - B(Call), R(1), R(2), U8(1), U8(0), // - B(LdaLookupSlotInsideTypeof), U8(2), // - B(TypeOf), // - B(Return), // + 9 * kPointerSize, + 1, + 68, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + /* */ U8(1), // + B(PushContext), R(0), // + B(Ldar), THIS(1), // + B(StaContextSlot), R(context), U8(first_context_slot), // + B(CreateMappedArguments), // + B(StaContextSlot), R(context), U8(first_context_slot + 1), // + B(Ldar), R(new_target), // + B(StaContextSlot), R(context), U8(first_context_slot + 2), // + B(StackCheck), // + B(LdaConstant), U8(0), // + B(Star), R(3), // + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), // + /* */ R(3), U8(1), R(1), // + B(LdaConstant), U8(1), // + B(Star), R(3), // + B(Mov), R(1), R(4), // + B(Mov), R(3), R(5), // + B(Mov), R(closure), R(6), // + B(LdaZero), // + B(Star), R(7), // + B(LdaSmi8), U8(10), // + B(Star), R(8), // + B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), // + /* */ U8(5), // + B(Star), R(1), // + B(Call), R(1), R(2), U8(2), U8(0), // + B(LdaLookupSlotInsideTypeof), U8(2), // + B(TypeOf), // + B(Return), // }, 3, {"eval", "var x = 10;", "x"}}, {"x = 20; return eval('');", 9 * kPointerSize, 1, - 71, - { - B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // - U8(1), // - B(PushContext), R(0), // - B(Ldar), THIS(1), // - B(StaContextSlot), R(0), U8(first_context_slot), // - B(CreateMappedArguments), // - B(StaContextSlot), R(0), U8(first_context_slot + 1), // - B(Ldar), R(new_target), // - B(StaContextSlot), R(0), U8(first_context_slot + 2), // - B(LdaSmi8), U8(20), // - B(StaLookupSlotSloppy), U8(0), // - B(Mov), R(context), R(3), // - B(LdaConstant), U8(1), // - B(Star), R(4), // - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlot), // - R(3), U8(2), R(1), // - B(LdaConstant), U8(2), // - B(Star), R(3), // - B(Mov), R(1), R(4), // - B(Mov), R(3), R(5), // - B(Mov), R(closure), R(6), // - B(LdaZero), // - B(Star), R(7), // - B(LdaSmi8), U8(10), // - B(Star), R(8), // - B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), // - U8(5), // - B(Star), R(1), // - B(Call), R(1), R(2), U8(1), U8(0), // - B(Return), // + 69, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + U8(1), // + B(PushContext), R(0), // + B(Ldar), THIS(1), // + B(StaContextSlot), R(context), U8(first_context_slot), // + B(CreateMappedArguments), // + B(StaContextSlot), R(context), U8(first_context_slot + 1), // + B(Ldar), R(new_target), // + B(StaContextSlot), R(context), U8(first_context_slot + 2), // + B(StackCheck), // + B(LdaSmi8), U8(20), // + B(StaLookupSlotSloppy), U8(0), // + B(LdaConstant), U8(1), // + B(Star), R(3), // + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), // + /* */ R(3), U8(1), R(1), // + B(LdaConstant), U8(2), // + B(Star), R(3), // + B(Mov), R(1), R(4), // + B(Mov), R(3), R(5), // + B(Mov), R(closure), R(6), // + B(LdaZero), // + B(Star), R(7), // + B(LdaSmi8), U8(10), // + B(Star), R(8), // + B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), // + /* */ U8(5), // + B(Star), R(1), // + B(Call), R(1), R(2), U8(2), U8(0), // + B(Return), // }, 3, {"x", "eval", ""}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -6432,31 +7633,32 @@ TEST(CallLookupSlot) { i::NewTypeFeedbackVector(helper.isolate(), &feedback_spec); int closure = Register::function_closure().index(); - int context = Register::function_context().index(); + int context = Register::current_context().index(); int new_target = Register::new_target().index(); + // clang-format off ExpectedSnippet<InstanceType> snippets[] = { {"g = function(){}; eval(''); return g();", 9 * kPointerSize, 1, - 90, + 85, { B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // - U8(1), // + /* */ U8(1), // B(PushContext), R(0), // B(Ldar), THIS(1), // - B(StaContextSlot), R(0), U8(4), // + B(StaContextSlot), R(context), U8(4), // B(CreateMappedArguments), // - B(StaContextSlot), R(0), U8(5), // + B(StaContextSlot), R(context), U8(5), // B(Ldar), R(new_target), // - B(StaContextSlot), R(0), U8(6), // + B(StaContextSlot), R(context), U8(6), // + B(StackCheck), // B(CreateClosure), U8(0), U8(0), // B(StaLookupSlotSloppy), U8(1), // - B(Mov), R(context), R(3), // B(LdaConstant), U8(2), // - B(Star), R(4), // - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlot), // - R(3), U8(2), R(1), // + B(Star), R(3), // + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), // + R(3), U8(1), R(1), // B(LdaConstant), U8(3), // B(Star), R(3), // B(Mov), R(1), R(4), // @@ -6469,13 +7671,12 @@ TEST(CallLookupSlot) { B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), // U8(5), // B(Star), R(1), // - B(Call), R(1), R(2), U8(1), U8(0), // - B(Mov), R(context), R(3), // + B(Call), R(1), R(2), U8(2), U8(0), // B(LdaConstant), U8(1), // - B(Star), R(4), // - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlot), // - R(3), U8(2), R(1), // - B(Call), R(1), R(2), U8(0), U8(vector->GetIndex(slot2)), // + B(Star), R(3), // + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), // + R(3), U8(1), R(1), // + B(Call), R(1), R(2), U8(1), U8(vector->GetIndex(slot2)), // B(Return), // }, 4, @@ -6484,6 +7685,7 @@ TEST(CallLookupSlot) { InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { Handle<BytecodeArray> bytecode_array = @@ -6493,6 +7695,8 @@ TEST(CallLookupSlot) { } +// TODO(mythria): tests for variable/function declaration in lookup slots. + TEST(LookupSlotInEval) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; @@ -6505,12 +7709,14 @@ TEST(LookupSlotInEval) { "}" "f1();"; + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"return x;", 0 * kPointerSize, 1, - 3, + 4, { + B(StackCheck), // B(LdaLookupSlot), U8(0), // B(Return) // }, @@ -6519,8 +7725,9 @@ TEST(LookupSlotInEval) { {"x = 10;", 0 * kPointerSize, 1, - 6, + 7, { + B(StackCheck), // B(LdaSmi8), U8(10), // B(StaLookupSlotSloppy), U8(0), // B(LdaUndefined), // @@ -6531,8 +7738,9 @@ TEST(LookupSlotInEval) { {"'use strict'; x = 10;", 0 * kPointerSize, 1, - 6, + 7, { + B(StackCheck), // B(LdaSmi8), U8(10), // B(StaLookupSlotStrict), U8(0), // B(LdaUndefined), // @@ -6543,8 +7751,9 @@ TEST(LookupSlotInEval) { {"return typeof x;", 0 * kPointerSize, 1, - 4, + 5, { + B(StackCheck), // B(LdaLookupSlotInsideTypeof), U8(0), // B(TypeOf), // B(Return), // @@ -6552,15 +7761,14 @@ TEST(LookupSlotInEval) { 1, {"x"}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { std::string script = std::string(function_prologue) + std::string(snippets[i].code_snippet) + std::string(function_epilogue); - // TODO(mythria): use * as filter when function declarations are supported - // inside eval. Handle<BytecodeArray> bytecode_array = - helper.MakeBytecode(script.c_str(), "t", "f"); + helper.MakeBytecode(script.c_str(), "*", "f"); CheckBytecodeArrayEqual(snippets[i], bytecode_array); } } @@ -6581,13 +7789,15 @@ TEST(LookupSlotWideInEval) { "f1();"; int const_count[] = {0, 0, 0, 0}; + // clang-format off ExpectedSnippet<InstanceType, 257> snippets[] = { {REPEAT_256(SPACE, "var y = 2.3;") "return x;", 1 * kPointerSize, 1, - 1028, + 1029, { + B(StackCheck), // REPEAT_256(SPACE, // B(LdaConstant), U8(const_count[0]++), // B(Star), R(0), ) // @@ -6601,8 +7811,9 @@ TEST(LookupSlotWideInEval) { "return typeof x;", 1 * kPointerSize, 1, - 1029, + 1030, { + B(StackCheck), // REPEAT_256(SPACE, // B(LdaConstant), U8(const_count[1]++), // B(Star), R(0), ) // @@ -6617,8 +7828,9 @@ TEST(LookupSlotWideInEval) { "x = 10;", 1 * kPointerSize, 1, - 1031, + 1032, { + B(StackCheck), // REPEAT_256(SPACE, // B(LdaConstant), U8(const_count[2]++), // B(Star), R(0), ) // @@ -6635,9 +7847,10 @@ TEST(LookupSlotWideInEval) { "x = 10;", 1 * kPointerSize, 1, - 1031, + 1032, { - REPEAT_256(SPACE, + B(StackCheck), // + REPEAT_256(SPACE, // B(LdaConstant), U8(const_count[3]++), // B(Star), R(0), ) // B(LdaSmi8), U8(10), // @@ -6649,15 +7862,14 @@ TEST(LookupSlotWideInEval) { {REPEAT_256(COMMA, InstanceType::HEAP_NUMBER_TYPE), InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { std::string script = std::string(function_prologue) + std::string(snippets[i].code_snippet) + std::string(function_epilogue); - // TODO(mythria): use * as filter when function declarations are supported - // inside eval. Handle<BytecodeArray> bytecode_array = - helper.MakeBytecode(script.c_str(), "t", "f"); + helper.MakeBytecode(script.c_str(), "*", "f"); CheckBytecodeArrayEqual(snippets[i], bytecode_array); } } @@ -6677,51 +7889,1215 @@ TEST(DeleteLookupSlotInEval) { "}" "f1();"; + // clang-format off ExpectedSnippet<const char*> snippets[] = { {"delete x;", - 0 * kPointerSize, + 1 * kPointerSize, 1, - 5, + 12, { - B(LdaConstant), U8(0), // - B(DeleteLookupSlot), // - B(LdaUndefined), // - B(Return) // + B(StackCheck), // + B(LdaConstant), U8(0), // + B(Star), R(0), // + B(CallRuntime), U16(Runtime::kDeleteLookupSlot), R(0), U8(1), // + B(LdaUndefined), // + B(Return) // }, 1, {"x"}}, {"return delete y;", 0 * kPointerSize, 1, - 2, + 3, { + B(StackCheck), // B(LdaFalse), // B(Return) // }, 0}, {"return delete z;", - 0 * kPointerSize, + 1 * kPointerSize, 1, - 4, + 11, { - B(LdaConstant), U8(0), // - B(DeleteLookupSlot), // - B(Return) // + B(StackCheck), // + B(LdaConstant), U8(0), // + B(Star), R(0), // + B(CallRuntime), U16(Runtime::kDeleteLookupSlot), R(0), U8(1), // + B(Return) // }, 1, {"z"}}, }; + // clang-format on for (size_t i = 0; i < arraysize(snippets); i++) { std::string script = std::string(function_prologue) + std::string(snippets[i].code_snippet) + std::string(function_epilogue); Handle<BytecodeArray> bytecode_array = - helper.MakeBytecode(script.c_str(), "t", "f"); + helper.MakeBytecode(script.c_str(), "*", "f"); CheckBytecodeArrayEqual(snippets[i], bytecode_array); } } +TEST(WideRegisters) { + // Prepare prologue that creates frame for lots of registers. + std::ostringstream os; + for (size_t i = 0; i < 157; ++i) { + os << "var x" << i << ";\n"; + } + std::string prologue(os.str()); + + // clang-format off + ExpectedSnippet<int> snippets[] = { + {"x0 = x127;\n" + "return x0;\n", + 161 * kPointerSize, + 1, + 11, + { + B(StackCheck), // + B(MovWide), R16(131), R16(125), // + B(Ldar), R(125), // + B(Star), R(0), // + B(Return), // + }}, + {"x127 = x126;\n" + "return x127;\n", + 161 * kPointerSize, + 1, + 23, + { + B(StackCheck), // + B(MovWide), R16(130), R16(125), // + B(Ldar), R(125), // + B(Star), R(125), // + B(MovWide), R16(125), R16(131), // + B(MovWide), R16(131), R16(125), // + B(Ldar), R(125), // + B(Return), // + }}, + {"if (x2 > 3) { return x129; }\n" + "return x128;\n", + 162 * kPointerSize, + 1, + 37, + { + B(StackCheck), // + B(Ldar), R(2), // + B(Star), R(125), // + B(MovWide), R16(125), R16(161), // + B(LdaSmi8), U8(3), // + B(MovWide), R16(161), R16(125), // + B(TestGreaterThan), R(125), // + B(JumpIfFalse), U8(10), // + B(MovWide), R16(133), R16(125), // + B(Ldar), R(125), // + B(Return), // + B(MovWide), R16(132), R16(125), // + B(Ldar), R(125), // + B(Return), // + }}, + {"var x0 = 0;\n" + "if (x129 == 3) { var x129 = x0; }\n" + "if (x2 > 3) { return x0; }\n" + "return x129;\n", + 162 * kPointerSize, + 1, + 69, + { + B(StackCheck), // + B(LdaZero), // + B(Star), R(0), // + B(MovWide), R16(133), R16(125), // + B(Ldar), R(125), // + B(Star), R(125), // + B(MovWide), R16(125), R16(161), // + B(LdaSmi8), U8(3), // + B(MovWide), R16(161), R16(125), // + B(TestEqual), R(125), // + B(JumpIfFalse), U8(11), // + B(Ldar), R(0), // + B(Star), R(125), // + B(MovWide), R16(125), R16(133), // + B(Ldar), R(2), // + B(Star), R(125), // + B(MovWide), R16(125), R16(161), // + B(LdaSmi8), U8(3), // + B(MovWide), R16(161), R16(125), // + B(TestGreaterThan), R(125), // + B(JumpIfFalse), U8(5), // + B(Ldar), R(0), // + B(Return), // + B(MovWide), R16(133), R16(125), // + B(Ldar), R(125), // + B(Return), // + }}, + {"var x0 = 0;\n" + "var x1 = 0;\n" + "for (x128 = 0; x128 < 64; x128++) {" + " x1 += x128;" + "}" + "return x128;\n", + 162 * kPointerSize, + 1, + 99, + { + B(StackCheck), // + B(LdaZero), // + B(Star), R(0), // + B(LdaZero), // + B(Star), R(1), // + B(LdaZero), // + B(Star), R(125), // + B(MovWide), R16(125), R16(132), // + B(MovWide), R16(132), R16(125), // + B(Ldar), R(125), // + B(Star), R(125), // + B(MovWide), R16(125), R16(161), // + B(LdaSmi8), U8(64), // + B(MovWide), R16(161), R16(125), // + B(TestLessThan), R(125), // + B(JumpIfFalse), U8(53), // + B(StackCheck), // + B(Ldar), R(1), // + B(Star), R(125), // + B(MovWide), R16(125), R16(161), // + B(MovWide), R16(132), R16(125), // + B(Ldar), R(125), // + B(MovWide), R16(161), R16(125), // + B(Add), R(125), // + B(Star), R(1), // + B(MovWide), R16(132), R16(125), // + B(Ldar), R(125), // + B(ToNumber), // + B(Star), R(125), // + B(MovWide), R16(125), R16(161), // + B(Inc), // + B(Star), R(125), // + B(MovWide), R16(125), R16(132), // + B(Jump), U8(-74), // + B(MovWide), R16(132), R16(125), // + B(Ldar), R(125), // + B(Return), // + }}, + {"var x0 = 1234;\n" + "var x1 = 0;\n" + "for (x128 in x0) {" + " x1 += x128;" + "}" + "return x1;\n", + 167 * kPointerSize, + 1, + 111, + { + B(StackCheck), // + B(LdaConstant), U8(0), // + B(Star), R(0), // + B(LdaZero), // + B(Star), R(1), // + B(Ldar), R(0), // + B(JumpIfUndefined), U8(98), // + B(JumpIfNull), U8(96), // + B(ToObject), // + B(JumpIfNull), U8(93), // + B(Star), R(125), // + B(MovWide), R16(125), R16(161), // + B(ForInPrepareWide), R16(162), // + B(LdaZero), // + B(Star), R(125), // + B(MovWide), R16(125), R16(165), // + B(MovWide), R16(165), R16(125), // + B(MovWide), R16(164), R16(126), // + B(ForInDone), R(125), R(126), // + B(JumpIfTrue), U8(60), // + B(ForInNextWide), R16(161), R16(165), R16(162), // + B(JumpIfUndefined), U8(35), // + B(Star), R(125), // + B(MovWide), R16(125), R16(132), // + B(StackCheck), // + B(Ldar), R(1), // + B(Star), R(125), // + B(MovWide), R16(125), R16(166), // + B(MovWide), R16(132), R16(125), // + B(Ldar), R(125), // + B(MovWide), R16(166), R16(125), // + B(Add), R(125), // + B(Star), R(1), // + B(MovWide), R16(165), R16(125), // + B(ForInStep), R(125), // + B(Star), R(125), // + B(MovWide), R16(125), R16(165), // + B(Jump), U8(-71), // + B(Ldar), R(1), // + B(Return), // + }, + 1, + {1234}}, + {"x0 = %Add(x64, x63);\n" + "x1 = %Add(x27, x143);\n" + "%TheHole();\n" + "return x1;\n", + 163 * kPointerSize, + 1, + 66, + { + B(StackCheck), // + B(Ldar), R(64), // + B(Star), R(125), // + B(MovWide), R16(125), R16(161), // + B(Ldar), R(63), // + B(Star), R(125), // + B(MovWide), R16(125), R16(162), // + B(CallRuntimeWide), U16(Runtime::kAdd), R16(161), U8(2), // + B(Star), R(0), // + B(Ldar), R(27), // + B(Star), R(125), // + B(MovWide), R16(125), R16(161), // + B(MovWide), R16(147), R16(125), // + B(Ldar), R(125), // + B(Star), R(125), // + B(MovWide), R16(125), R16(162), // + B(CallRuntimeWide), U16(Runtime::kAdd), R16(161), U8(2), // + B(Star), R(1), // + B(CallRuntime), U16(Runtime::kTheHole), R(0), U8(0), // + B(Ldar), R(1), // + B(Return), // + }} + }; + // clang-format on + + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + + for (size_t i = 0; i < arraysize(snippets); ++i) { + std::string body = prologue + snippets[i].code_snippet; + Handle<BytecodeArray> bytecode_array = + helper.MakeBytecodeForFunctionBody(body.c_str()); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } +} + +TEST(ConstVariable) { + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + // clang-format off + ExpectedSnippet<const char*> snippets[] = { + {"const x = 10;", + 1 * kPointerSize, + 1, + 10, + { + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(Star), R(0), // + B(LdaUndefined), // + B(Return) // + }, + 0}, + {"const x = 10; return x;", + 2 * kPointerSize, + 1, + 20, + { + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(Star), R(0), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(0), // + B(Star), R(1), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(1), U8(1), // + B(Return) // + }, + 1, + {"x"}}, + {"const x = ( x = 20);", + 3 * kPointerSize, + 1, + 32, + { + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(20), // + B(Star), R(1), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(0), // + B(Star), R(2), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1), // + B(CallRuntime), U16(Runtime::kThrowConstAssignError), R(0), // + /* */ U8(0), // + B(Ldar), R(1), // + B(Star), R(0), // + B(LdaUndefined), // + B(Return) // + }, + 1, + {"x"}}, + {"const x = 10; x = 20;", + 3 * kPointerSize, + 1, + 36, + { + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(Star), R(0), // + B(LdaSmi8), U8(20), // + B(Star), R(1), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(0), // + B(Star), R(2), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1), // + B(CallRuntime), U16(Runtime::kThrowConstAssignError), R(0), // + /* */ U8(0), // + B(Ldar), R(1), // + B(Star), R(0), // + B(LdaUndefined), // + B(Return) // + }, + 1, + {"x"}}, + }; + // clang-format on + + for (size_t i = 0; i < arraysize(snippets); i++) { + Handle<BytecodeArray> bytecode_array = + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } +} + +TEST(LetVariable) { + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + + // clang-format off + ExpectedSnippet<const char*> snippets[] = { + {"let x = 10;", + 1 * kPointerSize, + 1, + 10, + { + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(Star), R(0), // + B(LdaUndefined), // + B(Return) // + }, + 0}, + {"let x = 10; return x;", + 2 * kPointerSize, + 1, + 20, + { + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(Star), R(0), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(0), // + B(Star), R(1), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(1), U8(1), // + B(Return) // + }, + 1, + {"x"}}, + {"let x = (x = 20);", + 3 * kPointerSize, + 1, + 27, + { + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(20), // + B(Star), R(1), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(0), // + B(Star), R(2), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1), // + B(Ldar), R(1), // + B(Star), R(0), // + B(LdaUndefined), // + B(Return) // + }, + 1, + {"x"}}, + {"let x = 10; x = 20;", + 3 * kPointerSize, + 1, + 31, + { + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(Star), R(0), // + B(LdaSmi8), U8(20), // + B(Star), R(1), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(0), // + B(Star), R(2), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1), // + B(Ldar), R(1), // + B(Star), R(0), // + B(LdaUndefined), // + B(Return) // + }, + 1, + {"x"}}, + }; + // clang-format on + + for (size_t i = 0; i < arraysize(snippets); i++) { + Handle<BytecodeArray> bytecode_array = + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } +} + +TEST(LegacyConstVariable) { + bool old_legacy_const_flag = FLAG_legacy_const; + FLAG_legacy_const = true; + + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + + // clang-format off + ExpectedSnippet<const char*> snippets[] = { + {"const x = 10;", + 2 * kPointerSize, + 1, + 19, + { + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(Star), R(1), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(5), // + B(Mov), R(1), R(0), // + B(Ldar), R(1), // + B(LdaUndefined), // + B(Return) // + }, + 0}, + {"const x = 10; return x;", + 2 * kPointerSize, + 1, + 23, + { + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(Star), R(1), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(5), // + B(Mov), R(1), R(0), // + B(Ldar), R(1), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(3), // + B(LdaUndefined), // + B(Return) // + }, + 0}, + {"const x = ( x = 20);", + 2 * kPointerSize, + 1, + 23, + { + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(20), // + B(Star), R(1), // + B(Ldar), R(0), // + B(Ldar), R(1), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(5), // + B(Mov), R(1), R(0), // + B(Ldar), R(1), // + B(LdaUndefined), // + B(Return) // + }, + 0}, + {"const x = 10; x = 20;", + 2 * kPointerSize, + 1, + 27, + { + B(LdaTheHole), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(Star), R(1), // + B(Ldar), R(0), // + B(JumpIfNotHole), U8(5), // + B(Mov), R(1), R(0), // + B(Ldar), R(1), // + B(LdaSmi8), U8(20), // + B(Star), R(1), // + B(Ldar), R(0), // + B(Ldar), R(1), // + B(LdaUndefined), // + B(Return) // + }, + 0}, + }; + // clang-format on + + for (size_t i = 0; i < arraysize(snippets); i++) { + Handle<BytecodeArray> bytecode_array = + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } + + FLAG_legacy_const = old_legacy_const_flag; +} + +TEST(ConstVariableContextSlot) { + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + + int closure = Register::function_closure().index(); + int context = Register::current_context().index(); + + // TODO(mythria): Add tests for initialization of this via super calls. + // TODO(mythria): Add tests that walk the context chain. + // clang-format off + ExpectedSnippet<InstanceType> snippets[] = { + {"const x = 10; function f1() {return x;}", + 2 * kPointerSize, + 1, + 24, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + U8(1), // + B(PushContext), R(1), // + B(LdaTheHole), // + B(StaContextSlot), R(context), U8(4), // + B(CreateClosure), U8(0), U8(0), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(StaContextSlot), R(context), U8(4), // + B(LdaUndefined), // + B(Return) // + }, + 1, + {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + {"const x = 10; function f1() {return x;} return x;", + 3 * kPointerSize, + 1, + 37, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + U8(1), // + B(PushContext), R(1), // + B(LdaTheHole), // + B(StaContextSlot), R(context), U8(4), // + B(CreateClosure), U8(0), U8(0), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(StaContextSlot), R(context), U8(4), // + B(LdaContextSlot), R(context), U8(4), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(1), // + B(Star), R(2), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1), // + B(Return) // + }, + 2, + {InstanceType::SHARED_FUNCTION_INFO_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + {"const x = (x = 20); function f1() {return x;}", + 4 * kPointerSize, + 1, + 50, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + /* */ U8(1), // + B(PushContext), R(1), // + B(LdaTheHole), // + B(StaContextSlot), R(context), U8(4), // + B(CreateClosure), U8(0), U8(0), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(20), // + B(Star), R(2), // + B(LdaContextSlot), R(context), U8(4), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(1), // + B(Star), R(3), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(3), U8(1), // + B(CallRuntime), U16(Runtime::kThrowConstAssignError), R(0), // + U8(0), // + B(Ldar), R(2), // + B(StaContextSlot), R(context), U8(4), // + B(StaContextSlot), R(context), U8(4), // + B(LdaUndefined), // + B(Return) // + }, + 2, + {InstanceType::SHARED_FUNCTION_INFO_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + {"const x = 10; x = 20; function f1() {return x;}", + 4 * kPointerSize, + 1, + 52, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + /* */ U8(1), // + B(PushContext), R(1), // + B(LdaTheHole), // + B(StaContextSlot), R(context), U8(4), // + B(CreateClosure), U8(0), U8(0), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(StaContextSlot), R(context), U8(4), // + B(LdaSmi8), U8(20), // + B(Star), R(2), // + B(LdaContextSlot), R(context), U8(4), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(1), // + B(Star), R(3), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(3), U8(1), // + B(CallRuntime), U16(Runtime::kThrowConstAssignError), R(0), // + U8(0), // + B(Ldar), R(2), // + B(StaContextSlot), R(context), U8(4), // + B(LdaUndefined), // + B(Return) // + }, + 2, + {InstanceType::SHARED_FUNCTION_INFO_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + }; + // clang-format on + + for (size_t i = 0; i < arraysize(snippets); i++) { + Handle<BytecodeArray> bytecode_array = + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } +} + +TEST(LetVariableContextSlot) { + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + + int closure = Register::function_closure().index(); + int context = Register::current_context().index(); + + // clang-format off + ExpectedSnippet<InstanceType> snippets[] = { + {"let x = 10; function f1() {return x;}", + 2 * kPointerSize, + 1, + 24, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + /* */ U8(1), // + B(PushContext), R(1), // + B(LdaTheHole), // + B(StaContextSlot), R(context), U8(4), // + B(CreateClosure), U8(0), U8(0), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(StaContextSlot), R(context), U8(4), // + B(LdaUndefined), // + B(Return) // + }, + 1, + {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + {"let x = 10; function f1() {return x;} return x;", + 3 * kPointerSize, + 1, + 37, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + /* */ U8(1), // + B(PushContext), R(1), // + B(LdaTheHole), // + B(StaContextSlot), R(context), U8(4), // + B(CreateClosure), U8(0), U8(0), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(StaContextSlot), R(context), U8(4), // + B(LdaContextSlot), R(context), U8(4), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(1), // + B(Star), R(2), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1), // + B(Return) // + }, + 2, + {InstanceType::SHARED_FUNCTION_INFO_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + {"let x = (x = 20); function f1() {return x;}", + 4 * kPointerSize, + 1, + 45, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + /* */ U8(1), // + B(PushContext), R(1), // + B(LdaTheHole), // + B(StaContextSlot), R(context), U8(4), // + B(CreateClosure), U8(0), U8(0), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(20), // + B(Star), R(2), // + B(LdaContextSlot), R(context), U8(4), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(1), // + B(Star), R(3), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(3), U8(1), // + B(Ldar), R(2), // + B(StaContextSlot), R(context), U8(4), // + B(StaContextSlot), R(context), U8(4), // + B(LdaUndefined), // + B(Return) // + }, + 2, + {InstanceType::SHARED_FUNCTION_INFO_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + {"let x = 10; x = 20; function f1() {return x;}", + 4 * kPointerSize, + 1, + 47, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + /* */ U8(1), // + B(PushContext), R(1), // + B(LdaTheHole), // + B(StaContextSlot), R(context), U8(4), // + B(CreateClosure), U8(0), U8(0), // + B(Star), R(0), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(StaContextSlot), R(context), U8(4), // + B(LdaSmi8), U8(20), // + B(Star), R(2), // + B(LdaContextSlot), R(context), U8(4), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(1), // + B(Star), R(3), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(3), U8(1), // + B(Ldar), R(2), // + B(StaContextSlot), R(context), U8(4), // + B(LdaUndefined), // + B(Return) // + }, + 2, + {InstanceType::SHARED_FUNCTION_INFO_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + }; + // clang-format on + + for (size_t i = 0; i < arraysize(snippets); i++) { + Handle<BytecodeArray> bytecode_array = + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } +} + +TEST(DoExpression) { + bool old_flag = FLAG_harmony_do_expressions; + FLAG_harmony_do_expressions = true; + + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + + // clang-format off + ExpectedSnippet<const char*> snippets[] = { + {"var a = do { }; return a;", + 2 * kPointerSize, + 1, + 6, + { + B(StackCheck), // + B(Ldar), R(0), // + B(Star), R(1), // + B(Return) // + }, + 0}, + {"var a = do { var x = 100; }; return a;", + 3 * kPointerSize, + 1, + 11, + { + B(StackCheck), // + B(LdaSmi8), U8(100), // + B(Star), R(1), // + B(LdaUndefined), // + B(Star), R(0), // + B(Star), R(2), // + B(Return) // + }, + 0}, + {"while(true) { var a = 10; a = do { ++a; break; }; a = 20; }", + 2 * kPointerSize, + 1, + 26, + { + B(StackCheck), // + B(StackCheck), // + B(LdaSmi8), U8(10), // + B(Star), R(1), // + B(ToNumber), // + B(Inc), // + B(Star), R(1), // + B(Star), R(0), // + B(Jump), U8(12), // + B(Ldar), R(0), // + B(Star), R(1), // + B(LdaSmi8), U8(20), // + B(Star), R(1), // + B(Jump), U8(-21), // + B(LdaUndefined), // + B(Return), // + }, + 0}, + }; + // clang-format on + + for (size_t i = 0; i < arraysize(snippets); i++) { + Handle<BytecodeArray> bytecode_array = + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } + FLAG_harmony_do_expressions = old_flag; +} + +TEST(WithStatement) { + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + + int deep_elements_flags = + ObjectLiteral::kFastElements | ObjectLiteral::kDisableMementos; + int context = Register::current_context().index(); + int closure = Register::function_closure().index(); + int new_target = Register::new_target().index(); + + // clang-format off + ExpectedSnippet<InstanceType> snippets[] = { + {"with ({x:42}) { return x; }", + 5 * kPointerSize, + 1, + 47, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + /* */ U8(1), // + B(PushContext), R(0), // + B(Ldar), THIS(1), // + B(StaContextSlot), R(context), U8(4), // + B(CreateMappedArguments), // + B(StaContextSlot), R(context), U8(5), // + B(Ldar), R(new_target), // + B(StaContextSlot), R(context), U8(6), // + B(StackCheck), // + B(CreateObjectLiteral), U8(0), U8(0), U8(deep_elements_flags), // + B(Star), R(2), // + B(ToObject), // + B(Star), R(3), // + B(Ldar), R(closure), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kPushWithContext), R(3), U8(2), // + B(PushContext), R(1), // + B(LdaLookupSlot), U8(1), // + B(PopContext), R(0), // + B(Return), // + }, + 2, + {InstanceType::FIXED_ARRAY_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + }; + // clang-format on + + for (size_t i = 0; i < arraysize(snippets); i++) { + Handle<BytecodeArray> bytecode_array = + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } +} + +TEST(DoDebugger) { + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + + // clang-format off + ExpectedSnippet<const char*> snippet = { + "debugger;", + 0, + 1, + 4, + { + B(StackCheck), // + B(Debugger), // + B(LdaUndefined), // + B(Return) // + }, + 0 + }; + // clang-format on + + Handle<BytecodeArray> bytecode_array = + helper.MakeBytecodeForFunctionBody(snippet.code_snippet); + CheckBytecodeArrayEqual(snippet, bytecode_array); +} + +// TODO(rmcilroy): Update expectations after switch to +// Runtime::kDefineDataPropertyInLiteral. +TEST(ClassDeclarations) { + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + + int closure = Register::function_closure().index(); + int context = Register::current_context().index(); + + // clang-format off + ExpectedSnippet<InstanceType, 12> snippets[] = { + {"class Person {\n" + " constructor(name) { this.name = name; }\n" + " speak() { console.log(this.name + ' is speaking.'); }\n" + "}\n", + 9 * kPointerSize, + 1, + 71, + { + B(LdaTheHole), // + B(Star), R(1), // + B(StackCheck), // + B(LdaTheHole), // + B(Star), R(0), // + B(LdaTheHole), // + B(Star), R(2), // + B(CreateClosure), U8(0), U8(0), // + B(Star), R(3), // + B(LdaSmi8), U8(15), // + B(Star), R(4), // + B(LdaConstant), U8(1), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kDefineClass), R(2), U8(4), // + B(Star), R(2), // + B(LoadIC), R(2), U8(2), U8(1), // + B(Star), R(3), // + B(Mov), R(3), R(4), // + B(LdaConstant), U8(3), // + B(Star), R(5), // + B(CreateClosure), U8(4), U8(0), // + B(Star), R(6), // + B(LdaSmi8), U8(2), // + B(Star), R(7), // + B(LdaZero), // + B(Star), R(8), // + B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(4), U8(5), + B(CallRuntime), U16(Runtime::kFinalizeClassDefinition), R(2), U8(2), // + B(Star), R(0), // + B(Star), R(1), // + B(LdaUndefined), // + B(Return) // + }, + 5, + { InstanceType::SHARED_FUNCTION_INFO_TYPE, kInstanceTypeDontCare, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + {"class person {\n" + " constructor(name) { this.name = name; }\n" + " speak() { console.log(this.name + ' is speaking.'); }\n" + "}\n", + 9 * kPointerSize, + 1, + 71, + { + B(LdaTheHole), // + B(Star), R(1), // + B(StackCheck), // + B(LdaTheHole), // + B(Star), R(0), // + B(LdaTheHole), // + B(Star), R(2), // + B(CreateClosure), U8(0), U8(0), // + B(Star), R(3), // + B(LdaSmi8), U8(15), // + B(Star), R(4), // + B(LdaConstant), U8(1), // + B(Star), R(5), // + B(CallRuntime), U16(Runtime::kDefineClass), R(2), U8(4), // + B(Star), R(2), // + B(LoadIC), R(2), U8(2), U8(1), // + B(Star), R(3), // + B(Mov), R(3), R(4), // + B(LdaConstant), U8(3), // + B(Star), R(5), // + B(CreateClosure), U8(4), U8(0), // + B(Star), R(6), // + B(LdaSmi8), U8(2), // + B(Star), R(7), // + B(LdaZero), // + B(Star), R(8), // + B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(4), U8(5), + B(CallRuntime), U16(Runtime::kFinalizeClassDefinition), R(2), U8(2), // + B(Star), R(0), // + B(Star), R(1), // + B(LdaUndefined), // + B(Return) // + }, + 5, + { InstanceType::SHARED_FUNCTION_INFO_TYPE, kInstanceTypeDontCare, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + {"var n0 = 'a';" + "var n1 = 'b';" + "class N {\n" + " [n0]() { return n0; }\n" + " static [n1]() { return n1; }\n" + "}\n", + 10 * kPointerSize, + 1, + 125, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), // + /* */ U8(1), // + B(PushContext), R(2), // + B(LdaTheHole), // + B(Star), R(1), // + B(StackCheck), // + B(LdaConstant), U8(0), // + B(StaContextSlot), R(context), U8(4), // + B(LdaConstant), U8(1), // + B(StaContextSlot), R(context), U8(5), // + B(LdaTheHole), // + B(Star), R(0), // + B(LdaTheHole), // + B(Star), R(3), // + B(CreateClosure), U8(2), U8(0), // + B(Star), R(4), // + B(LdaSmi8), U8(41), // + B(Star), R(5), // + B(LdaSmi8), U8(107), // + B(Star), R(6), // + B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4), // + B(Star), R(3), // + B(LoadIC), R(3), U8(3), U8(1), // + B(Star), R(4), // + B(Mov), R(4), R(5), // + B(LdaContextSlot), R(context), U8(4), // + B(ToName), // + B(Star), R(6), // + B(CreateClosure), U8(4), U8(0), // + B(Star), R(7), // + B(LdaSmi8), U8(2), // + B(Star), R(8), // + B(LdaSmi8), U8(1), // + B(Star), R(9), // + B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(5), U8(5), + B(Mov), R(3), R(5), // + B(LdaContextSlot), R(context), U8(5), // + B(ToName), // + B(Star), R(6), // + B(LdaConstant), U8(3), // + B(TestEqualStrict), R(6), // + B(JumpIfFalse), U8(7), // + B(CallRuntime), U16(Runtime::kThrowStaticPrototypeError), // + /* */ R(0), U8(0), // + B(CreateClosure), U8(5), U8(0), // + B(Star), R(7), // + B(LdaSmi8), U8(1), // + B(Star), R(9), // + B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(5), U8(5), + B(CallRuntime), U16(Runtime::kFinalizeClassDefinition), R(3), U8(2), // + B(Star), R(0), // + B(Star), R(1), // + B(LdaUndefined), // + B(Return), // + }, + 6, + { InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::SHARED_FUNCTION_INFO_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::SHARED_FUNCTION_INFO_TYPE, + InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + {"var count = 0;\n" + "class C { constructor() { count++; }}\n" + "return new C();\n", + 10 * kPointerSize, + 1, + 74, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), R(closure), U8(1), // + B(PushContext), R(2), // + B(LdaTheHole), // + B(Star), R(1), // + B(StackCheck), // + B(LdaZero), // + B(StaContextSlot), R(context), U8(4), // + B(LdaTheHole), // + B(Star), R(0), // + B(LdaTheHole), // + B(Star), R(3), // + B(CreateClosure), U8(0), U8(0), // + B(Star), R(4), // + B(LdaSmi8), U8(30), // + B(Star), R(5), // + B(LdaSmi8), U8(67), // + B(Star), R(6), // + B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4), // + B(Star), R(3), // + B(LoadIC), R(3), U8(1), U8(1), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kFinalizeClassDefinition), R(3), U8(2), // + B(Star), R(0), // + B(Star), R(1), // + B(JumpIfNotHole), U8(11), // + B(LdaConstant), U8(2), // + B(Star), R(4), // + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1), // + B(Star), R(3), // + B(New), R(3), R(0), U8(0), // + B(Return), // + }, + 3, + { InstanceType::SHARED_FUNCTION_INFO_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, + }; + // clang-format on + + for (size_t i = 0; i < arraysize(snippets); i++) { + Handle<BytecodeArray> bytecode_array = + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } +} + +// TODO(oth): Add tests for super keyword. + } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/interpreter/test-interpreter.cc b/deps/v8/test/cctest/interpreter/test-interpreter.cc index 506cf00cd0..69cf0e18bd 100644 --- a/deps/v8/test/cctest/interpreter/test-interpreter.cc +++ b/deps/v8/test/cctest/interpreter/test-interpreter.cc @@ -65,8 +65,6 @@ class InterpreterTester { bytecode_(bytecode), feedback_vector_(feedback_vector) { i::FLAG_ignition = true; - i::FLAG_ignition_fake_try_catch = true; - i::FLAG_ignition_fallback_on_eval_and_catch = false; i::FLAG_always_opt = false; // Set ignition filter flag via SetFlagsFromString to avoid double-free // (or potential leak with StrDup() based on ownership confusion). @@ -98,6 +96,18 @@ class InterpreterTester { return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>()); } + Local<Message> CheckThrowsReturnMessage() { + TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate_)); + auto callable = GetCallable<>(); + MaybeHandle<Object> no_result = callable(); + CHECK(isolate_->has_pending_exception()); + CHECK(try_catch.HasCaught()); + CHECK(no_result.is_null()); + isolate_->OptionalRescheduleException(true); + CHECK(!try_catch.Message().IsEmpty()); + return try_catch.Message(); + } + static Handle<Object> NewObject(const char* script) { return v8::Utils::OpenHandle(*CompileRun(script)); } @@ -165,10 +175,8 @@ TEST(InterpreterReturn) { Handle<Object> undefined_value = handles.main_isolate()->factory()->undefined_value(); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); builder.Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -184,10 +192,8 @@ TEST(InterpreterLoadUndefined) { Handle<Object> undefined_value = handles.main_isolate()->factory()->undefined_value(); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); builder.LoadUndefined().Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -202,10 +208,8 @@ TEST(InterpreterLoadNull) { HandleAndZoneScope handles; Handle<Object> null_value = handles.main_isolate()->factory()->null_value(); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); builder.LoadNull().Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -221,10 +225,8 @@ TEST(InterpreterLoadTheHole) { Handle<Object> the_hole_value = handles.main_isolate()->factory()->the_hole_value(); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); builder.LoadTheHole().Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -239,10 +241,8 @@ TEST(InterpreterLoadTrue) { HandleAndZoneScope handles; Handle<Object> true_value = handles.main_isolate()->factory()->true_value(); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); builder.LoadTrue().Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -257,10 +257,8 @@ TEST(InterpreterLoadFalse) { HandleAndZoneScope handles; Handle<Object> false_value = handles.main_isolate()->factory()->false_value(); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); builder.LoadFalse().Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -277,10 +275,8 @@ TEST(InterpreterLoadLiteral) { // Small Smis. for (int i = -128; i < 128; i++) { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); builder.LoadLiteral(Smi::FromInt(i)).Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -292,10 +288,8 @@ TEST(InterpreterLoadLiteral) { // Large Smis. { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); builder.LoadLiteral(Smi::FromInt(0x12345678)).Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -307,10 +301,8 @@ TEST(InterpreterLoadLiteral) { // Heap numbers. { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); builder.LoadLiteral(factory->NewHeapNumber(-2.1e19)).Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -322,10 +314,8 @@ TEST(InterpreterLoadLiteral) { // Strings. { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); Handle<i::String> string = factory->NewStringFromAsciiChecked("String"); builder.LoadLiteral(string).Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -342,10 +332,8 @@ TEST(InterpreterLoadStoreRegisters) { HandleAndZoneScope handles; Handle<Object> true_value = handles.main_isolate()->factory()->true_value(); for (int i = 0; i <= kMaxInt8; i++) { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(i + 1); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, i + 1); Register reg(i); builder.LoadTrue() .StoreAccumulatorInRegister(reg) @@ -362,117 +350,6 @@ TEST(InterpreterLoadStoreRegisters) { } -TEST(InterpreterExchangeRegisters) { - for (int locals_count = 2; locals_count < 300; locals_count += 126) { - HandleAndZoneScope handles; - for (int exchanges = 1; exchanges < 4; exchanges++) { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(locals_count); - builder.set_context_count(0); - builder.set_parameter_count(0); - - Register r0(0); - Register r1(locals_count - 1); - builder.LoadTrue(); - builder.StoreAccumulatorInRegister(r0); - builder.ExchangeRegisters(r0, r1); - builder.LoadFalse(); - builder.StoreAccumulatorInRegister(r0); - - bool expected = false; - for (int i = 0; i < exchanges; i++) { - builder.ExchangeRegisters(r0, r1); - expected = !expected; - } - builder.LoadAccumulatorWithRegister(r0); - builder.Return(); - Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); - InterpreterTester tester(handles.main_isolate(), bytecode_array); - auto callable = tester.GetCallable<>(); - Handle<Object> return_val = callable().ToHandleChecked(); - Handle<Object> expected_val = - handles.main_isolate()->factory()->ToBoolean(expected); - CHECK(return_val.is_identical_to(expected_val)); - } - } -} - - -TEST(InterpreterExchangeRegistersWithParameter) { - for (int locals_count = 2; locals_count < 300; locals_count += 126) { - HandleAndZoneScope handles; - for (int exchanges = 1; exchanges < 4; exchanges++) { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(locals_count); - builder.set_context_count(0); - builder.set_parameter_count(3); - - Register r0 = Register::FromParameterIndex(2, 3); - Register r1(locals_count - 1); - builder.LoadTrue(); - builder.StoreAccumulatorInRegister(r0); - builder.ExchangeRegisters(r0, r1); - builder.LoadFalse(); - builder.StoreAccumulatorInRegister(r0); - - bool expected = false; - for (int i = 0; i < exchanges; i++) { - builder.ExchangeRegisters(r0, r1); - expected = !expected; - } - builder.LoadAccumulatorWithRegister(r0); - builder.Return(); - Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); - InterpreterTester tester(handles.main_isolate(), bytecode_array); - auto callable = tester.GetCallable<>(); - Handle<Object> return_val = callable().ToHandleChecked(); - Handle<Object> expected_val = - handles.main_isolate()->factory()->ToBoolean(expected); - CHECK(return_val.is_identical_to(expected_val)); - } - } -} - - -TEST(InterpreterExchangeWideRegisters) { - for (int locals_count = 3; locals_count < 300; locals_count += 126) { - HandleAndZoneScope handles; - for (int exchanges = 0; exchanges < 7; exchanges++) { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(locals_count); - builder.set_context_count(0); - builder.set_parameter_count(0); - - Register r0(0); - Register r1(locals_count - 1); - Register r2(locals_count - 2); - builder.LoadLiteral(Smi::FromInt(200)); - builder.StoreAccumulatorInRegister(r0); - builder.ExchangeRegisters(r0, r1); - builder.LoadLiteral(Smi::FromInt(100)); - builder.StoreAccumulatorInRegister(r0); - builder.ExchangeRegisters(r0, r2); - builder.LoadLiteral(Smi::FromInt(0)); - builder.StoreAccumulatorInRegister(r0); - for (int i = 0; i < exchanges; i++) { - builder.ExchangeRegisters(r1, r2); - builder.ExchangeRegisters(r0, r1); - } - builder.LoadAccumulatorWithRegister(r0); - builder.Return(); - Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); - InterpreterTester tester(handles.main_isolate(), bytecode_array); - auto callable = tester.GetCallable<>(); - Handle<Object> return_val = callable().ToHandleChecked(); - Handle<Object> expected_val = - handles.main_isolate()->factory()->NewNumberFromInt(100 * - (exchanges % 3)); - CHECK(return_val.is_identical_to(expected_val)); - } - } -} - - static const Token::Value kShiftOperators[] = { Token::Value::SHL, Token::Value::SAR, Token::Value::SHR}; @@ -539,17 +416,14 @@ TEST(InterpreterShiftOpsSmi) { HandleAndZoneScope handles; i::Factory* factory = handles.main_isolate()->factory(); BytecodeArrayBuilder builder(handles.main_isolate(), - handles.main_zone()); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(1); + handles.main_zone(), 1, 0, 1); Register reg(0); int lhs = lhs_inputs[l]; int rhs = rhs_inputs[r]; builder.LoadLiteral(Smi::FromInt(lhs)) .StoreAccumulatorInRegister(reg) .LoadLiteral(Smi::FromInt(rhs)) - .BinaryOperation(kShiftOperators[o], reg, Strength::WEAK) + .BinaryOperation(kShiftOperators[o], reg) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -574,17 +448,14 @@ TEST(InterpreterBinaryOpsSmi) { HandleAndZoneScope handles; i::Factory* factory = handles.main_isolate()->factory(); BytecodeArrayBuilder builder(handles.main_isolate(), - handles.main_zone()); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(1); + handles.main_zone(), 1, 0, 1); Register reg(0); int lhs = lhs_inputs[l]; int rhs = rhs_inputs[r]; builder.LoadLiteral(Smi::FromInt(lhs)) .StoreAccumulatorInRegister(reg) .LoadLiteral(Smi::FromInt(rhs)) - .BinaryOperation(kArithmeticOperators[o], reg, Strength::WEAK) + .BinaryOperation(kArithmeticOperators[o], reg) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -610,17 +481,14 @@ TEST(InterpreterBinaryOpsHeapNumber) { HandleAndZoneScope handles; i::Factory* factory = handles.main_isolate()->factory(); BytecodeArrayBuilder builder(handles.main_isolate(), - handles.main_zone()); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(1); + handles.main_zone(), 1, 0, 1); Register reg(0); double lhs = lhs_inputs[l]; double rhs = rhs_inputs[r]; builder.LoadLiteral(factory->NewNumber(lhs)) .StoreAccumulatorInRegister(reg) .LoadLiteral(factory->NewNumber(rhs)) - .BinaryOperation(kArithmeticOperators[o], reg, Strength::WEAK) + .BinaryOperation(kArithmeticOperators[o], reg) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -669,15 +537,13 @@ TEST(InterpreterStringAdd) { }; for (size_t i = 0; i < arraysize(test_cases); i++) { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 1); Register reg(0); builder.LoadLiteral(test_cases[i].lhs) .StoreAccumulatorInRegister(reg) .LoadLiteral(test_cases[i].rhs) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -691,10 +557,8 @@ TEST(InterpreterStringAdd) { TEST(InterpreterParameter1) { HandleAndZoneScope handles; - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); builder.LoadAccumulatorWithRegister(builder.Parameter(0)).Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -715,18 +579,16 @@ TEST(InterpreterParameter1) { TEST(InterpreterParameter8) { HandleAndZoneScope handles; - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(8); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 8, + 0, 0); builder.LoadAccumulatorWithRegister(builder.Parameter(0)) - .BinaryOperation(Token::Value::ADD, builder.Parameter(1), Strength::WEAK) - .BinaryOperation(Token::Value::ADD, builder.Parameter(2), Strength::WEAK) - .BinaryOperation(Token::Value::ADD, builder.Parameter(3), Strength::WEAK) - .BinaryOperation(Token::Value::ADD, builder.Parameter(4), Strength::WEAK) - .BinaryOperation(Token::Value::ADD, builder.Parameter(5), Strength::WEAK) - .BinaryOperation(Token::Value::ADD, builder.Parameter(6), Strength::WEAK) - .BinaryOperation(Token::Value::ADD, builder.Parameter(7), Strength::WEAK) + .BinaryOperation(Token::Value::ADD, builder.Parameter(1)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(2)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(3)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(4)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(5)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(6)) + .BinaryOperation(Token::Value::ADD, builder.Parameter(7)) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -752,10 +614,8 @@ TEST(InterpreterParameter8) { TEST(InterpreterParameter1Assign) { HandleAndZoneScope handles; - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); builder.LoadLiteral(Smi::FromInt(5)) .StoreAccumulatorInRegister(builder.Parameter(0)) .LoadAccumulatorWithRegister(builder.Parameter(0)) @@ -882,12 +742,9 @@ TEST(InterpreterLoadNamedProperty) { Handle<i::String> name = factory->NewStringFromAsciiChecked("val"); name = factory->string_table()->LookupString(isolate, name); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); - builder.LoadNamedProperty(builder.Parameter(0), name, vector->GetIndex(slot), - i::SLOPPY) + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); + builder.LoadNamedProperty(builder.Parameter(0), name, vector->GetIndex(slot)) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -938,13 +795,10 @@ TEST(InterpreterLoadKeyedProperty) { Handle<i::String> key = factory->NewStringFromAsciiChecked("key"); key = factory->string_table()->LookupString(isolate, key); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 1); builder.LoadLiteral(key) - .LoadKeyedProperty(builder.Parameter(0), vector->GetIndex(slot), - i::STRICT) + .LoadKeyedProperty(builder.Parameter(0), vector->GetIndex(slot)) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -983,10 +837,8 @@ TEST(InterpreterStoreNamedProperty) { Handle<i::String> name = factory->NewStringFromAsciiChecked("val"); name = factory->string_table()->LookupString(isolate, name); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 0); builder.LoadLiteral(Smi::FromInt(999)) .StoreNamedProperty(builder.Parameter(0), name, vector->GetIndex(slot), i::STRICT) @@ -1044,10 +896,8 @@ TEST(InterpreterStoreKeyedProperty) { Handle<i::String> name = factory->NewStringFromAsciiChecked("val"); name = factory->string_table()->LookupString(isolate, name); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 1); builder.LoadLiteral(name) .StoreAccumulatorInRegister(Register(0)) .LoadLiteral(Smi::FromInt(999)) @@ -1078,8 +928,7 @@ TEST(InterpreterStoreKeyedProperty) { CHECK_EQ(Smi::cast(*result), Smi::FromInt(999)); } - -TEST(InterpreterCall) { +static void TestInterpreterCall(TailCallMode tail_call_mode) { HandleAndZoneScope handles; i::Isolate* isolate = handles.main_isolate(); i::Factory* factory = isolate->factory(); @@ -1097,13 +946,11 @@ TEST(InterpreterCall) { // Check with no args. { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(1); - builder.LoadNamedProperty(builder.Parameter(0), name, slot_index, i::SLOPPY) + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 1); + builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) .StoreAccumulatorInRegister(Register(0)) - .Call(Register(0), builder.Parameter(0), 0, 0) + .Call(Register(0), builder.Parameter(0), 1, 0, tail_call_mode) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1118,13 +965,11 @@ TEST(InterpreterCall) { // Check that receiver is passed properly. { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(1); - builder.LoadNamedProperty(builder.Parameter(0), name, slot_index, i::SLOPPY) + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 1); + builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) .StoreAccumulatorInRegister(Register(0)) - .Call(Register(0), builder.Parameter(0), 0, 0) + .Call(Register(0), builder.Parameter(0), 1, 0, tail_call_mode) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1142,11 +987,9 @@ TEST(InterpreterCall) { // Check with two parameters (+ receiver). { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(4); - builder.set_context_count(0); - builder.set_parameter_count(1); - builder.LoadNamedProperty(builder.Parameter(0), name, slot_index, i::SLOPPY) + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 4); + builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) .StoreAccumulatorInRegister(Register(0)) .LoadAccumulatorWithRegister(builder.Parameter(0)) .StoreAccumulatorInRegister(Register(1)) @@ -1154,7 +997,7 @@ TEST(InterpreterCall) { .StoreAccumulatorInRegister(Register(2)) .LoadLiteral(Smi::FromInt(11)) .StoreAccumulatorInRegister(Register(3)) - .Call(Register(0), Register(1), 2, 0) + .Call(Register(0), Register(1), 3, 0, tail_call_mode) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1171,11 +1014,9 @@ TEST(InterpreterCall) { // Check with 10 parameters (+ receiver). { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(12); - builder.set_context_count(0); - builder.set_parameter_count(1); - builder.LoadNamedProperty(builder.Parameter(0), name, slot_index, i::SLOPPY) + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 12); + builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) .StoreAccumulatorInRegister(Register(0)) .LoadAccumulatorWithRegister(builder.Parameter(0)) .StoreAccumulatorInRegister(Register(1)) @@ -1199,7 +1040,7 @@ TEST(InterpreterCall) { .StoreAccumulatorInRegister(Register(10)) .LoadLiteral(factory->NewStringFromAsciiChecked("j")) .StoreAccumulatorInRegister(Register(11)) - .Call(Register(0), Register(1), 10, 0) + .Call(Register(0), Register(1), 11, 0, tail_call_mode) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1220,6 +1061,9 @@ TEST(InterpreterCall) { } } +TEST(InterpreterCall) { TestInterpreterCall(TailCallMode::kDisallow); } + +TEST(InterpreterTailCall) { TestInterpreterCall(TailCallMode::kAllow); } static BytecodeArrayBuilder& SetRegister(BytecodeArrayBuilder& builder, Register reg, int value, @@ -1236,7 +1080,7 @@ static BytecodeArrayBuilder& IncrementRegister(BytecodeArrayBuilder& builder, Register scratch) { return builder.StoreAccumulatorInRegister(scratch) .LoadLiteral(Smi::FromInt(value)) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .StoreAccumulatorInRegister(reg) .LoadAccumulatorWithRegister(scratch); } @@ -1244,10 +1088,8 @@ static BytecodeArrayBuilder& IncrementRegister(BytecodeArrayBuilder& builder, TEST(InterpreterJumps) { HandleAndZoneScope handles; - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(2); - builder.set_context_count(0); - builder.set_parameter_count(0); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0, + 0, 2); Register reg(0), scratch(1); BytecodeLabel label[3]; @@ -1273,10 +1115,8 @@ TEST(InterpreterJumps) { TEST(InterpreterConditionalJumps) { HandleAndZoneScope handles; - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(2); - builder.set_context_count(0); - builder.set_parameter_count(0); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0, + 0, 2); Register reg(0), scratch(1); BytecodeLabel label[2]; BytecodeLabel done, done1; @@ -1309,10 +1149,8 @@ TEST(InterpreterConditionalJumps) { TEST(InterpreterConditionalJumps2) { // TODO(oth): Add tests for all conditional jumps near and far. HandleAndZoneScope handles; - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(2); - builder.set_context_count(0); - builder.set_parameter_count(0); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0, + 0, 2); Register reg(0), scratch(1); BytecodeLabel label[2]; BytecodeLabel done, done1; @@ -1397,15 +1235,12 @@ TEST(InterpreterSmiComparisons) { for (size_t j = 0; j < arraysize(inputs); j++) { HandleAndZoneScope handles; BytecodeArrayBuilder builder(handles.main_isolate(), - handles.main_zone()); + handles.main_zone(), 0, 0, 1); Register r0(0); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(0); builder.LoadLiteral(Smi::FromInt(inputs[i])) .StoreAccumulatorInRegister(r0) .LoadLiteral(Smi::FromInt(inputs[j])) - .CompareOperation(comparison, r0, Strength::WEAK) + .CompareOperation(comparison, r0) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1436,15 +1271,12 @@ TEST(InterpreterHeapNumberComparisons) { HandleAndZoneScope handles; i::Factory* factory = handles.main_isolate()->factory(); BytecodeArrayBuilder builder(handles.main_isolate(), - handles.main_zone()); + handles.main_zone(), 0, 0, 1); Register r0(0); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(0); builder.LoadLiteral(factory->NewHeapNumber(inputs[i])) .StoreAccumulatorInRegister(r0) .LoadLiteral(factory->NewHeapNumber(inputs[j])) - .CompareOperation(comparison, r0, Strength::WEAK) + .CompareOperation(comparison, r0) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1472,15 +1304,12 @@ TEST(InterpreterStringComparisons) { HandleAndZoneScope handles; i::Factory* factory = handles.main_isolate()->factory(); BytecodeArrayBuilder builder(handles.main_isolate(), - handles.main_zone()); + handles.main_zone(), 0, 0, 1); Register r0(0); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(0); builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs)) .StoreAccumulatorInRegister(r0) .LoadLiteral(factory->NewStringFromAsciiChecked(rhs)) - .CompareOperation(comparison, r0, Strength::WEAK) + .CompareOperation(comparison, r0) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1519,24 +1348,21 @@ TEST(InterpreterMixedComparisons) { HandleAndZoneScope handles; i::Factory* factory = handles.main_isolate()->factory(); BytecodeArrayBuilder builder(handles.main_isolate(), - handles.main_zone()); + handles.main_zone(), 0, 0, 1); Register r0(0); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(0); if (pass == 0) { // Comparison with HeapNumber on the lhs and String on the rhs builder.LoadLiteral(factory->NewNumber(lhs)) .StoreAccumulatorInRegister(r0) .LoadLiteral(factory->NewStringFromAsciiChecked(rhs_cstr)) - .CompareOperation(comparison, r0, Strength::WEAK) + .CompareOperation(comparison, r0) .Return(); } else { // Comparison with HeapNumber on the rhs and String on the lhs builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs_cstr)) .StoreAccumulatorInRegister(r0) .LoadLiteral(factory->NewNumber(rhs)) - .CompareOperation(comparison, r0, Strength::WEAK) + .CompareOperation(comparison, r0) .Return(); } @@ -1564,15 +1390,13 @@ TEST(InterpreterInstanceOf) { Handle<i::Object> cases[] = {Handle<i::Object>::cast(instance), other}; for (size_t i = 0; i < arraysize(cases); i++) { bool expected_value = (i == 0); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0, + 0, 1); Register r0(0); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(0); builder.LoadLiteral(cases[i]); builder.StoreAccumulatorInRegister(r0) .LoadLiteral(func) - .CompareOperation(Token::Value::INSTANCEOF, r0, Strength::WEAK) + .CompareOperation(Token::Value::INSTANCEOF, r0) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1590,20 +1414,18 @@ TEST(InterpreterTestIn) { i::Factory* factory = handles.main_isolate()->factory(); // Allocate an array Handle<i::JSArray> array = - factory->NewJSArray(i::ElementsKind::FAST_SMI_ELEMENTS); + factory->NewJSArray(0, i::ElementsKind::FAST_SMI_ELEMENTS); // Check for these properties on the array object const char* properties[] = {"length", "fuzzle", "x", "0"}; for (size_t i = 0; i < arraysize(properties); i++) { bool expected_value = (i == 0); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0, + 0, 1); Register r0(0); - builder.set_locals_count(1); - builder.set_context_count(0); - builder.set_parameter_count(0); builder.LoadLiteral(factory->NewStringFromAsciiChecked(properties[i])) .StoreAccumulatorInRegister(r0) .LoadLiteral(Handle<Object>::cast(array)) - .CompareOperation(Token::Value::IN, r0, Strength::WEAK) + .CompareOperation(Token::Value::IN, r0) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1620,11 +1442,9 @@ TEST(InterpreterUnaryNot) { HandleAndZoneScope handles; for (size_t i = 1; i < 10; i++) { bool expected_value = ((i & 1) == 1); - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0, + 0, 0); Register r0(0); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(0); builder.LoadFalse(); for (size_t j = 0; j < i; j++) { builder.LogicalNot(); @@ -1683,11 +1503,9 @@ TEST(InterpreterUnaryNotNonBoolean) { }; for (size_t i = 0; i < arraysize(object_type_tuples); i++) { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0, + 0, 0); Register r0(0); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(0); LoadAny(&builder, factory, object_type_tuples[i].first); builder.LogicalNot(); builder.Return(); @@ -1731,10 +1549,8 @@ TEST(InterpreterTypeof) { TEST(InterpreterCallRuntime) { HandleAndZoneScope handles; - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - builder.set_locals_count(2); - builder.set_context_count(0); - builder.set_parameter_count(1); + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1, + 0, 2); builder.LoadLiteral(Smi::FromInt(15)) .StoreAccumulatorInRegister(Register(0)) .LoadLiteral(Smi::FromInt(40)) @@ -2133,29 +1949,76 @@ TEST(InterpreterLogicalAnd) { TEST(InterpreterTryCatch) { HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); - // TODO(rmcilroy): modify tests when we have real try catch support. - std::string source(InterpreterTester::SourceForBody( - "var a = 1; try { a = a + 1; } catch(e) { a = a + 2; }; return a;")); - InterpreterTester tester(handles.main_isolate(), source.c_str()); - auto callable = tester.GetCallable<>(); + std::pair<const char*, Handle<Object>> catches[] = { + std::make_pair("var a = 1; try { a = 2 } catch(e) { a = 3 }; return a;", + handle(Smi::FromInt(2), isolate)), + std::make_pair("var a; try { undef.x } catch(e) { a = 2 }; return a;", + handle(Smi::FromInt(2), isolate)), + std::make_pair("var a; try { throw 1 } catch(e) { a = e + 2 }; return a;", + handle(Smi::FromInt(3), isolate)), + std::make_pair("var a; try { throw 1 } catch(e) { a = e + 2 };" + " try { throw a } catch(e) { a = e + 3 }; return a;", + handle(Smi::FromInt(6), isolate)), + }; - Handle<Object> return_val = callable().ToHandleChecked(); - CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(2)); + for (size_t i = 0; i < arraysize(catches); i++) { + std::string source(InterpreterTester::SourceForBody(catches[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*catches[i].second)); + } } TEST(InterpreterTryFinally) { HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + i::Factory* factory = isolate->factory(); - // TODO(rmcilroy): modify tests when we have real try finally support. - std::string source(InterpreterTester::SourceForBody( - "var a = 1; try { a = a + 1; } finally { a = a + 2; }; return a;")); - InterpreterTester tester(handles.main_isolate(), source.c_str()); - auto callable = tester.GetCallable<>(); + std::pair<const char*, Handle<Object>> finallies[] = { + std::make_pair( + "var a = 1; try { a = a + 1; } finally { a = a + 2; }; return a;", + factory->NewStringFromStaticChars("R4")), + std::make_pair( + "var a = 1; try { a = 2; return 23; } finally { a = 3 }; return a;", + factory->NewStringFromStaticChars("R23")), + std::make_pair( + "var a = 1; try { a = 2; throw 23; } finally { a = 3 }; return a;", + factory->NewStringFromStaticChars("E23")), + std::make_pair( + "var a = 1; try { a = 2; throw 23; } finally { return a; };", + factory->NewStringFromStaticChars("R2")), + std::make_pair( + "var a = 1; try { a = 2; throw 23; } finally { throw 42; };", + factory->NewStringFromStaticChars("E42")), + std::make_pair("var a = 1; for (var i = 10; i < 20; i += 5) {" + " try { a = 2; break; } finally { a = 3; }" + "} return a + i;", + factory->NewStringFromStaticChars("R13")), + std::make_pair("var a = 1; for (var i = 10; i < 20; i += 5) {" + " try { a = 2; continue; } finally { a = 3; }" + "} return a + i;", + factory->NewStringFromStaticChars("R23")), + std::make_pair("var a = 1; try { a = 2;" + " try { a = 3; throw 23; } finally { a = 4; }" + "} catch(e) { a = a + e; } return a;", + factory->NewStringFromStaticChars("R27")), + }; - Handle<Object> return_val = callable().ToHandleChecked(); - CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(4)); + const char* try_wrapper = + "(function() { try { return 'R' + f() } catch(e) { return 'E' + e }})()"; + + for (size_t i = 0; i < arraysize(finallies); i++) { + std::string source(InterpreterTester::SourceForBody(finallies[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + tester.GetCallable<>(); + Handle<Object> wrapped = v8::Utils::OpenHandle(*CompileRun(try_wrapper)); + CHECK(wrapped->SameValue(*finallies[i].second)); + } } @@ -2164,7 +2027,6 @@ TEST(InterpreterThrow) { i::Isolate* isolate = handles.main_isolate(); i::Factory* factory = isolate->factory(); - // TODO(rmcilroy): modify tests when we have real try catch support. std::pair<const char*, Handle<Object>> throws[] = { std::make_pair("throw undefined;\n", factory->undefined_value()), @@ -2364,6 +2226,15 @@ TEST(InterpreterCreateArguments) { std::make_pair("function f(a, b, c, d) {" " 'use strict'; c = b; return arguments[2]; }", 2), + // check rest parameters + std::make_pair("function f(...restArray) { return restArray[0]; }", 0), + std::make_pair("function f(a, ...restArray) { return restArray[0]; }", 1), + std::make_pair("function f(a, ...restArray) { return arguments[0]; }", 0), + std::make_pair("function f(a, ...restArray) { return arguments[1]; }", 1), + std::make_pair("function f(a, ...restArray) { return restArray[1]; }", 2), + std::make_pair("function f(a, ...arguments) { return arguments[0]; }", 1), + std::make_pair("function f(a, b, ...restArray) { return restArray[0]; }", + 2), }; // Test passing no arguments. @@ -2698,211 +2569,301 @@ TEST(InterpreterBasicLoops) { TEST(InterpreterForIn) { - HandleAndZoneScope handles; - std::pair<const char*, int> for_in_samples[] = { - {"function f() {\n" - " var r = -1;\n" - " for (var a in null) { r = a; }\n" - " return r;\n" - "}", + {"var r = -1;\n" + "for (var a in null) { r = a; }\n" + "return r;\n", -1}, - {"function f() {\n" - " var r = -1;\n" - " for (var a in undefined) { r = a; }\n" - " return r;\n" - "}", + {"var r = -1;\n" + "for (var a in undefined) { r = a; }\n" + "return r;\n", -1}, - {"function f() {\n" - " var r = 0;\n" - " for (var a in [0,6,7,9]) { r = r + (1 << a); }\n" - " return r;\n" - "}", + {"var r = 0;\n" + "for (var a in [0,6,7,9]) { r = r + (1 << a); }\n" + "return r;\n", 0xf}, + {"var r = 0;\n" + "for (var a in [0,6,7,9]) { r = r + (1 << a); }\n" + "var r = 0;\n" + "for (var a in [0,6,7,9]) { r = r + (1 << a); }\n" + "return r;\n", + 0xf}, + {"var r = 0;\n" + "for (var a in 'foobar') { r = r + (1 << a); }\n" + "return r;\n", + 0x3f}, + {"var r = 0;\n" + "for (var a in {1:0, 10:1, 100:2, 1000:3}) {\n" + " r = r + Number(a);\n" + " }\n" + " return r;\n", + 1111}, + {"var r = 0;\n" + "var data = {1:0, 10:1, 100:2, 1000:3};\n" + "for (var a in data) {\n" + " if (a == 1) delete data[1];\n" + " r = r + Number(a);\n" + " }\n" + " return r;\n", + 1111}, + {"var r = 0;\n" + "var data = {1:0, 10:1, 100:2, 1000:3};\n" + "for (var a in data) {\n" + " if (a == 10) delete data[100];\n" + " r = r + Number(a);\n" + " }\n" + " return r;\n", + 1011}, + {"var r = 0;\n" + "var data = {1:0, 10:1, 100:2, 1000:3};\n" + "for (var a in data) {\n" + " if (a == 10) data[10000] = 4;\n" + " r = r + Number(a);\n" + " }\n" + " return r;\n", + 1111}, + {"var r = 0;\n" + "var input = 'foobar';\n" + "for (var a in input) {\n" + " if (input[a] == 'b') break;\n" + " r = r + (1 << a);\n" + "}\n" + "return r;\n", + 0x7}, + {"var r = 0;\n" + "var input = 'foobar';\n" + "for (var a in input) {\n" + " if (input[a] == 'b') continue;\n" + " r = r + (1 << a);\n" + "}\n" + "return r;\n", + 0x37}, + {"var r = 0;\n" + "var data = {1:0, 10:1, 100:2, 1000:3};\n" + "for (var a in data) {\n" + " if (a == 10) {\n" + " data[10000] = 4;\n" + " }\n" + " r = r + Number(a);\n" + "}\n" + "return r;\n", + 1111}, + {"var r = [ 3 ];\n" + "var data = {1:0, 10:1, 100:2, 1000:3};\n" + "for (r[10] in data) {\n" + "}\n" + "return Number(r[10]);\n", + 1000}, + {"var r = [ 3 ];\n" + "var data = {1:0, 10:1, 100:2, 1000:3};\n" + "for (r['100'] in data) {\n" + "}\n" + "return Number(r['100']);\n", + 1000}, + {"var obj = {}\n" + "var descObj = new Boolean(false);\n" + "var accessed = 0;\n" + "descObj.enumerable = true;\n" + "Object.defineProperties(obj, { prop:descObj });\n" + "for (var p in obj) {\n" + " if (p === 'prop') { accessed = 1; }\n" + "}\n" + "return accessed;", + 1}, + {"var appointment = {};\n" + "Object.defineProperty(appointment, 'startTime', {\n" + " value: 1001,\n" + " writable: false,\n" + " enumerable: false,\n" + " configurable: true\n" + "});\n" + "Object.defineProperty(appointment, 'name', {\n" + " value: 'NAME',\n" + " writable: false,\n" + " enumerable: false,\n" + " configurable: true\n" + "});\n" + "var meeting = Object.create(appointment);\n" + "Object.defineProperty(meeting, 'conferenceCall', {\n" + " value: 'In-person meeting',\n" + " writable: false,\n" + " enumerable: false,\n" + " configurable: true\n" + "});\n" + "\n" + "var teamMeeting = Object.create(meeting);\n" + "\n" + "var flags = 0;\n" + "for (var p in teamMeeting) {\n" + " if (p === 'startTime') {\n" + " flags |= 1;\n" + " }\n" + " if (p === 'name') {\n" + " flags |= 2;\n" + " }\n" + " if (p === 'conferenceCall') {\n" + " flags |= 4;\n" + " }\n" + "}\n" + "\n" + "var hasOwnProperty = !teamMeeting.hasOwnProperty('name') &&\n" + " !teamMeeting.hasOwnProperty('startTime') &&\n" + " !teamMeeting.hasOwnProperty('conferenceCall');\n" + "if (!hasOwnProperty) {\n" + " flags |= 8;\n" + "}\n" + "return flags;\n", + 0}, + {"var data = {x:23, y:34};\n" + " var result = 0;\n" + "var o = {};\n" + "var arr = [o];\n" + "for (arr[0].p in data)\n" // This is to test if value is loaded + " result += data[arr[0].p];\n" // back from accumulator before storing + "return result;\n", // named properties. + 57}, + {"var data = {x:23, y:34};\n" + "var result = 0;\n" + "var o = {};\n" + "var i = 0;\n" + "for (o[i++] in data)\n" // This is to test if value is loaded + " result += data[o[i-1]];\n" // back from accumulator before + "return result;\n", // storing keyed properties. + 57}}; + + // Two passes are made for this test. On the first, 8-bit register + // operands are employed, and on the 16-bit register operands are + // used. + for (int pass = 0; pass < 2; pass++) { + HandleAndZoneScope handles; + std::ostringstream wide_os; + if (pass == 1) { + for (int i = 0; i < 200; i++) { + wide_os << "var local" << i << " = 0;\n"; + } + } + + for (size_t i = 0; i < arraysize(for_in_samples); i++) { + std::ostringstream body_os; + body_os << wide_os.str() << for_in_samples[i].first; + std::string body(body_os.str()); + std::string function = InterpreterTester::SourceForBody(body.c_str()); + InterpreterTester tester(handles.main_isolate(), function.c_str()); + auto callable = tester.GetCallable<>(); + Handle<Object> return_val = callable().ToHandleChecked(); + CHECK_EQ(Handle<Smi>::cast(return_val)->value(), + for_in_samples[i].second); + } + } +} + + +TEST(InterpreterForOf) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + i::Factory* factory = isolate->factory(); + + std::pair<const char*, Handle<Object>> for_of[] = { {"function f() {\n" " var r = 0;\n" - " for (var a in [0,6,7,9]) { r = r + (1 << a); }\n" - " var r = 0;\n" - " for (var a in [0,6,7,9]) { r = r + (1 << a); }\n" + " for (var a of [0,6,7,9]) { r += a; }\n" " return r;\n" "}", - 0xf}, + handle(Smi::FromInt(22), isolate)}, {"function f() {\n" - " var r = 0;\n" - " for (var a in 'foobar') { r = r + (1 << a); }\n" + " var r = '';\n" + " for (var a of 'foobar') { r = a + r; }\n" " return r;\n" "}", - 0x3f}, + factory->NewStringFromStaticChars("raboof")}, {"function f() {\n" + " var a = [1, 2, 3];\n" + " a.name = 4;\n" " var r = 0;\n" - " for (var a in {1:0, 10:1, 100:2, 1000:3}) {\n" - " r = r + Number(a);\n" - " }\n" - " return r;\n" + " for (var x of a) { r += x; }\n" + " return r;\n" "}", - 1111}, + handle(Smi::FromInt(6), isolate)}, {"function f() {\n" - " var r = 0;\n" - " var data = {1:0, 10:1, 100:2, 1000:3};\n" - " for (var a in data) {\n" - " if (a == 1) delete data[1];\n" - " r = r + Number(a);\n" - " }\n" - " return r;\n" - "}", - 1111}, + " var r = '';\n" + " var data = [1, 2, 3]; \n" + " for (a of data) { delete data[0]; r += a; } return r; }", + factory->NewStringFromStaticChars("123")}, {"function f() {\n" - " var r = 0;\n" - " var data = {1:0, 10:1, 100:2, 1000:3};\n" - " for (var a in data) {\n" - " if (a == 10) delete data[100];\n" - " r = r + Number(a);\n" - " }\n" - " return r;\n" - "}", - 1011}, + " var r = '';\n" + " var data = [1, 2, 3]; \n" + " for (a of data) { delete data[2]; r += a; } return r; }", + factory->NewStringFromStaticChars("12undefined")}, {"function f() {\n" - " var r = 0;\n" - " var data = {1:0, 10:1, 100:2, 1000:3};\n" - " for (var a in data) {\n" - " if (a == 10) data[10000] = 4;\n" - " r = r + Number(a);\n" - " }\n" - " return r;\n" - "}", - 1111}, + " var r = '';\n" + " var data = [1, 2, 3]; \n" + " for (a of data) { delete data; r += a; } return r; }", + factory->NewStringFromStaticChars("123")}, {"function f() {\n" - " var r = 0;\n" + " var r = '';\n" " var input = 'foobar';\n" - " for (var a in input) {\n" - " if (input[a] == 'b') break;\n" - " r = r + (1 << a);\n" + " for (var a of input) {\n" + " if (a == 'b') break;\n" + " r += a;\n" " }\n" " return r;\n" "}", - 0x7}, + factory->NewStringFromStaticChars("foo")}, {"function f() {\n" - "var r = 0;\n" - "var input = 'foobar';\n" - "for (var a in input) {\n" - " if (input[a] == 'b') continue;\n" - " r = r + (1 << a);\n" - "}\n" - "return r;\n" - "}", - 0x37}, - {"function f() {\n" - " var r = 0;\n" - " var data = {1:0, 10:1, 100:2, 1000:3};\n" - " for (var a in data) {\n" - " if (a == 10) {\n" - " data[10000] = 4;\n" - " }\n" - " r = r + Number(a);\n" + " var r = '';\n" + " var input = 'foobar';\n" + " for (var a of input) {\n" + " if (a == 'b') continue;\n" + " r += a;\n" " }\n" " return r;\n" "}", - 1111}, + factory->NewStringFromStaticChars("fooar")}, {"function f() {\n" - " var r = [ 3 ];\n" - " var data = {1:0, 10:1, 100:2, 1000:3};\n" - " for (r[10] in data) {\n" - " }\n" - " return Number(r[10]);\n" + " var r = '';\n" + " var data = [1, 2, 3, 4]; \n" + " for (a of data) { data[2] = 567; r += a; }\n" + " return r;\n" "}", - 1000}, + factory->NewStringFromStaticChars("125674")}, {"function f() {\n" - " var r = [ 3 ];\n" - " var data = {1:0, 10:1, 100:2, 1000:3};\n" - " for (r['100'] in data) {\n" - " }\n" - " return Number(r['100']);\n" + " var r = '';\n" + " var data = [1, 2, 3, 4]; \n" + " for (a of data) { data[4] = 567; r += a; }\n" + " return r;\n" "}", - 1000}, + factory->NewStringFromStaticChars("1234567")}, {"function f() {\n" - " var obj = {}\n" - " var descObj = new Boolean(false);\n" - " var accessed = 0;\n" - " descObj.enumerable = true;\n" - " Object.defineProperties(obj, { prop:descObj });\n" - " for (var p in obj) {\n" - " if (p === 'prop') { accessed = 1; }\n" - " }\n" - " return accessed;" + " var r = '';\n" + " var data = [1, 2, 3, 4]; \n" + " for (a of data) { data[5] = 567; r += a; }\n" + " return r;\n" "}", - 1}, + factory->NewStringFromStaticChars("1234undefined567")}, {"function f() {\n" - " var appointment = {};\n" - " Object.defineProperty(appointment, 'startTime', {\n" - " value: 1001,\n" - " writable: false,\n" - " enumerable: false,\n" - " configurable: true\n" - " });\n" - " Object.defineProperty(appointment, 'name', {\n" - " value: 'NAME',\n" - " writable: false,\n" - " enumerable: false,\n" - " configurable: true\n" - " });\n" - " var meeting = Object.create(appointment);\n" - " Object.defineProperty(meeting, 'conferenceCall', {\n" - " value: 'In-person meeting',\n" - " writable: false,\n" - " enumerable: false,\n" - " configurable: true\n" - " });\n" - "\n" - " var teamMeeting = Object.create(meeting);\n" - "\n" - " var flags = 0;\n" - " for (var p in teamMeeting) {\n" - " if (p === 'startTime') {\n" - " flags |= 1;\n" - " }\n" - " if (p === 'name') {\n" - " flags |= 2;\n" - " }\n" - " if (p === 'conferenceCall') {\n" - " flags |= 4;\n" + " var r = '';\n" + " var obj = new Object();\n" + " obj[Symbol.iterator] = function() { return {\n" + " index: 3,\n" + " data: ['a', 'b', 'c', 'd']," + " next: function() {" + " return {" + " done: this.index == -1,\n" + " value: this.index < 0 ? undefined : this.data[this.index--]\n" " }\n" - " }\n" - "\n" - " var hasOwnProperty = !teamMeeting.hasOwnProperty('name') &&\n" - " !teamMeeting.hasOwnProperty('startTime') &&\n" - " !teamMeeting.hasOwnProperty('conferenceCall');\n" - " if (!hasOwnProperty) {\n" - " flags |= 8;\n" - " }\n" - " return flags;\n" - " }", - 0}, - {"function f() {\n" - " var data = {x:23, y:34};\n" - " var result = 0;\n" - " var o = {};\n" - " var arr = [o];\n" - " for (arr[0].p in data)\n" // This is to test if value is loaded - " result += data[arr[0].p];\n" // back from accumulator before storing - " return result;\n" // named properties. - "}", - 57}, - {"function f() {\n" - " var data = {x:23, y:34};\n" - " var result = 0;\n" - " var o = {};\n" - " var i = 0;\n" - " for (o[i++] in data)\n" // This is to test if value is loaded - " result += data[o[i-1]];\n" // back from accumulator before - " return result;\n" // storing keyed properties. + " }\n" + " }}\n" + " for (a of obj) { r += a }\n" + " return r;\n" "}", - 57}}; + factory->NewStringFromStaticChars("dcba")}, + }; - for (size_t i = 0; i < arraysize(for_in_samples); i++) { - InterpreterTester tester(handles.main_isolate(), for_in_samples[i].first); + for (size_t i = 0; i < arraysize(for_of); i++) { + InterpreterTester tester(handles.main_isolate(), for_of[i].first); auto callable = tester.GetCallable<>(); Handle<Object> return_val = callable().ToHandleChecked(); - CHECK_EQ(Handle<Smi>::cast(return_val)->value(), for_in_samples[i].second); + CHECK(return_val->SameValue(*for_of[i].second)); } } @@ -3422,10 +3383,10 @@ TEST(InterpreterDeleteLookupSlot) { TEST(JumpWithConstantsAndWideConstants) { HandleAndZoneScope handles; - auto isolate = handles.main_isolate(); - auto factory = isolate->factory(); const int kStep = 13; - for (int constants = 3; constants < 256 + 3 * kStep; constants += kStep) { + for (int constants = 11; constants < 256 + 3 * kStep; constants += kStep) { + auto isolate = handles.main_isolate(); + auto factory = isolate->factory(); std::ostringstream filler_os; // Generate a string that consumes constant pool entries and // spread out branch distances in script below. @@ -3448,8 +3409,8 @@ TEST(JumpWithConstantsAndWideConstants) { for (int a = 0; a < 3; a++) { InterpreterTester tester(handles.main_isolate(), script.c_str()); auto callable = tester.GetCallable<Handle<Object>>(); - Handle<Object> return_val = - callable(factory->NewNumberFromInt(a)).ToHandleChecked(); + Handle<Object> argument = factory->NewNumberFromInt(a); + Handle<Object> return_val = callable(argument).ToHandleChecked(); static const int results[] = {11, 12, 2}; CHECK_EQ(Handle<Smi>::cast(return_val)->value(), results[a]); } @@ -3500,7 +3461,6 @@ TEST(InterpreterEval) { std::string source(InterpreterTester::SourceForBody(eval[i].first)); InterpreterTester tester(handles.main_isolate(), source.c_str()); auto callable = tester.GetCallable<>(); - Handle<i::Object> return_value = callable().ToHandleChecked(); CHECK(return_value->SameValue(*eval[i].second)); } @@ -3562,6 +3522,646 @@ TEST(InterpreterEvalGlobal) { } } + +TEST(InterpreterEvalVariableDecl) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + i::Factory* factory = isolate->factory(); + + std::pair<const char*, Handle<Object>> eval_global[] = { + {"function f() { eval('var x = 10; x++;'); return x; }", + handle(Smi::FromInt(11), isolate)}, + {"function f() { var x = 20; eval('var x = 10; x++;'); return x; }", + handle(Smi::FromInt(11), isolate)}, + {"function f() {" + " var x = 20;" + " eval('\"use strict\"; var x = 10; x++;');" + " return x; }", + handle(Smi::FromInt(20), isolate)}, + {"function f() {" + " var y = 30;" + " eval('var x = {1:20}; x[2]=y;');" + " return x[2]; }", + handle(Smi::FromInt(30), isolate)}, + {"function f() {" + " eval('var x = {name:\"test\"};');" + " return x.name; }", + factory->NewStringFromStaticChars("test")}, + {"function f() {" + " eval('var x = [{name:\"test\"}, {type:\"cc\"}];');" + " return x[1].type+x[0].name; }", + factory->NewStringFromStaticChars("cctest")}, + {"function f() {\n" + " var x = 3;\n" + " var get_eval_x;\n" + " eval('\"use strict\"; " + " var x = 20; " + " get_eval_x = function func() {return x;};');\n" + " return get_eval_x() + x;\n" + "}", + handle(Smi::FromInt(23), isolate)}, + // TODO(mythria): Add tests with const declarations. + }; + + for (size_t i = 0; i < arraysize(eval_global); i++) { + InterpreterTester tester(handles.main_isolate(), eval_global[i].first, "*"); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*eval_global[i].second)); + } +} + + +TEST(InterpreterEvalFunctionDecl) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + + std::pair<const char*, Handle<Object>> eval_func_decl[] = { + {"function f() {\n" + " var x = 3;\n" + " eval('var x = 20;" + " function get_x() {return x;};');\n" + " return get_x() + x;\n" + "}", + handle(Smi::FromInt(40), isolate)}, + }; + + for (size_t i = 0; i < arraysize(eval_func_decl); i++) { + InterpreterTester tester(handles.main_isolate(), eval_func_decl[i].first, + "*"); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*eval_func_decl[i].second)); + } +} + +TEST(InterpreterWideRegisterArithmetic) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + + static const size_t kMaxRegisterForTest = 150; + std::ostringstream os; + os << "function " << InterpreterTester::function_name() << "(arg) {\n"; + os << " var retval = -77;\n"; + for (size_t i = 0; i < kMaxRegisterForTest; i++) { + os << " var x" << i << " = " << i << ";\n"; + } + for (size_t i = 0; i < kMaxRegisterForTest / 2; i++) { + size_t j = kMaxRegisterForTest - i - 1; + os << " var tmp = x" << j << ";\n"; + os << " var x" << j << " = x" << i << ";\n"; + os << " var x" << i << " = tmp;\n"; + } + for (size_t i = 0; i < kMaxRegisterForTest / 2; i++) { + size_t j = kMaxRegisterForTest - i - 1; + os << " var tmp = x" << j << ";\n"; + os << " var x" << j << " = x" << i << ";\n"; + os << " var x" << i << " = tmp;\n"; + } + for (size_t i = 0; i < kMaxRegisterForTest; i++) { + os << " if (arg == " << i << ") {\n" // + << " retval = x" << i << ";\n" // + << " }\n"; // + } + os << " return retval;\n"; + os << "}\n"; + + std::string source = os.str(); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<Handle<Object>>(); + for (size_t i = 0; i < kMaxRegisterForTest; i++) { + Handle<Object> arg = handle(Smi::FromInt(static_cast<int>(i)), isolate); + Handle<Object> return_value = callable(arg).ToHandleChecked(); + CHECK(return_value->SameValue(*arg)); + } +} + +TEST(InterpreterCallWideRegisters) { + static const int kPeriod = 25; + static const int kLength = 512; + static const int kStartChar = 65; + + for (int pass = 0; pass < 3; pass += 1) { + std::ostringstream os; + for (int i = 0; i < pass * 97; i += 1) { + os << "var x" << i << " = " << i << "\n"; + } + os << "return String.fromCharCode("; + os << kStartChar; + for (int i = 1; i < kLength; i += 1) { + os << "," << kStartChar + (i % kPeriod); + } + os << ");"; + std::string source = InterpreterTester::SourceForBody(os.str().c_str()); + HandleAndZoneScope handles; + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable(); + Handle<Object> return_val = callable().ToHandleChecked(); + Handle<String> return_string = Handle<String>::cast(return_val); + CHECK_EQ(return_string->length(), kLength); + for (int i = 0; i < kLength; i += 1) { + CHECK_EQ(return_string->Get(i), 65 + (i % kPeriod)); + } + } +} + +TEST(InterpreterWideParametersPickOne) { + static const int kParameterCount = 130; + for (int parameter = 0; parameter < 10; parameter++) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + std::ostringstream os; + os << "function " << InterpreterTester::function_name() << "(arg) {\n"; + os << " function selector(i"; + for (int i = 0; i < kParameterCount; i++) { + os << "," + << "a" << i; + } + os << ") {\n"; + os << " return a" << parameter << ";\n"; + os << " };\n"; + os << " return selector(arg"; + for (int i = 0; i < kParameterCount; i++) { + os << "," << i; + } + os << ");"; + os << "}\n"; + + std::string source = os.str(); + InterpreterTester tester(handles.main_isolate(), source.c_str(), "*"); + auto callable = tester.GetCallable<Handle<Object>>(); + Handle<Object> arg = handle(Smi::FromInt(0xaa55), isolate); + Handle<Object> return_value = callable(arg).ToHandleChecked(); + Handle<Smi> actual = Handle<Smi>::cast(return_value); + CHECK_EQ(actual->value(), parameter); + } +} + +TEST(InterpreterWideParametersSummation) { + static int kParameterCount = 200; + static int kBaseValue = 17000; + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + std::ostringstream os; + os << "function " << InterpreterTester::function_name() << "(arg) {\n"; + os << " function summation(i"; + for (int i = 0; i < kParameterCount; i++) { + os << "," + << "a" << i; + } + os << ") {\n"; + os << " var sum = " << kBaseValue << ";\n"; + os << " switch(i) {\n"; + for (int i = 0; i < kParameterCount; i++) { + int j = kParameterCount - i - 1; + os << " case " << j << ": sum += a" << j << ";\n"; + } + os << " }\n"; + os << " return sum;\n"; + os << " };\n"; + os << " return summation(arg"; + for (int i = 0; i < kParameterCount; i++) { + os << "," << i; + } + os << ");"; + os << "}\n"; + + std::string source = os.str(); + InterpreterTester tester(handles.main_isolate(), source.c_str(), "*"); + auto callable = tester.GetCallable<Handle<Object>>(); + for (int i = 0; i < kParameterCount; i++) { + Handle<Object> arg = handle(Smi::FromInt(i), isolate); + Handle<Object> return_value = callable(arg).ToHandleChecked(); + int expected = kBaseValue + i * (i + 1) / 2; + Handle<Smi> actual = Handle<Smi>::cast(return_value); + CHECK_EQ(actual->value(), expected); + } +} + +TEST(InterpreterDoExpression) { + bool old_flag = FLAG_harmony_do_expressions; + FLAG_harmony_do_expressions = true; + + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + Factory* factory = isolate->factory(); + + std::pair<const char*, Handle<Object>> do_expr[] = { + {"var a = do {}; return a;", factory->undefined_value()}, + {"var a = do { var x = 100; }; return a;", factory->undefined_value()}, + {"var a = do { var x = 100; }; return a;", factory->undefined_value()}, + {"var a = do { var x = 100; x++; }; return a;", + handle(Smi::FromInt(100), isolate)}, + {"var i = 0; for (; i < 5;) { i = do { if (i == 3) { break; }; i + 1; }};" + "return i;", + handle(Smi::FromInt(3), isolate)}, + }; + + for (size_t i = 0; i < arraysize(do_expr); i++) { + std::string source(InterpreterTester::SourceForBody(do_expr[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*do_expr[i].second)); + } + + FLAG_harmony_do_expressions = old_flag; +} + +TEST(InterpreterWithStatement) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + + std::pair<const char*, Handle<Object>> with_stmt[] = { + {"with({x:42}) return x;", handle(Smi::FromInt(42), isolate)}, + {"with({}) { var y = 10; return y;}", handle(Smi::FromInt(10), isolate)}, + {"var y = {x:42};" + " function inner() {" + " var x = 20;" + " with(y) return x;" + "}" + "return inner();", + handle(Smi::FromInt(42), isolate)}, + {"var y = {x:42};" + " function inner(o) {" + " var x = 20;" + " with(o) return x;" + "}" + "return inner(y);", + handle(Smi::FromInt(42), isolate)}, + }; + + for (size_t i = 0; i < arraysize(with_stmt); i++) { + std::string source(InterpreterTester::SourceForBody(with_stmt[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*with_stmt[i].second)); + } +} + +TEST(InterpreterClassLiterals) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + std::pair<const char*, Handle<Object>> examples[] = { + {"class C {\n" + " constructor(x) { this.x_ = x; }\n" + " method() { return this.x_; }\n" + "}\n" + "return new C(99).method();", + handle(Smi::FromInt(99), isolate)}, + {"class C {\n" + " constructor(x) { this.x_ = x; }\n" + " static static_method(x) { return x; }\n" + "}\n" + "return C.static_method(101);", + handle(Smi::FromInt(101), isolate)}, + {"class C {\n" + " get x() { return 102; }\n" + "}\n" + "return new C().x", + handle(Smi::FromInt(102), isolate)}, + {"class C {\n" + " static get x() { return 103; }\n" + "}\n" + "return C.x", + handle(Smi::FromInt(103), isolate)}, + {"class C {\n" + " constructor() { this.x_ = 0; }" + " set x(value) { this.x_ = value; }\n" + " get x() { return this.x_; }\n" + "}\n" + "var c = new C();" + "c.x = 104;" + "return c.x;", + handle(Smi::FromInt(104), isolate)}, + {"var x = 0;" + "class C {\n" + " static set x(value) { x = value; }\n" + " static get x() { return x; }\n" + "}\n" + "C.x = 105;" + "return C.x;", + handle(Smi::FromInt(105), isolate)}, + {"var method = 'f';" + "class C {\n" + " [method]() { return 106; }\n" + "}\n" + "return new C().f();", + handle(Smi::FromInt(106), isolate)}, + }; + + for (size_t i = 0; i < arraysize(examples); ++i) { + std::string source(InterpreterTester::SourceForBody(examples[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*examples[i].second)); + } +} + +TEST(InterpreterClassAndSuperClass) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + std::pair<const char*, Handle<Object>> examples[] = { + {"class A {\n" + " constructor(x) { this.x_ = x; }\n" + " method() { return this.x_; }\n" + "}\n" + "class B extends A {\n" + " constructor(x, y) { super(x); this.y_ = y; }\n" + " method() { return super.method() + 1; }\n" + "}\n" + "return new B(998, 0).method();\n", + handle(Smi::FromInt(999), isolate)}, + {"class A {\n" + " constructor() { this.x_ = 2; this.y_ = 3; }\n" + "}\n" + "class B extends A {\n" + " constructor() { super(); }" + " method() { this.x_++; this.y_++; return this.x_ + this.y_; }\n" + "}\n" + "return new B().method();\n", + handle(Smi::FromInt(7), isolate)}, + {"var calls = 0;\n" + "class B {}\n" + "B.prototype.x = 42;\n" + "class C extends B {\n" + " constructor() {\n" + " super();\n" + " calls++;\n" + " }\n" + "}\n" + "new C;\n" + "return calls;\n", + handle(Smi::FromInt(1), isolate)}, + {"class A {\n" + " method() { return 1; }\n" + " get x() { return 2; }\n" + "}\n" + "class B extends A {\n" + " method() { return super.x === 2 ? super.method() : -1; }\n" + "}\n" + "return new B().method();\n", + handle(Smi::FromInt(1), isolate)}, + {"var object = { setY(v) { super.y = v; }};\n" + "object.setY(10);\n" + "return object.y;\n", + handle(Smi::FromInt(10), isolate)}, + }; + + for (size_t i = 0; i < arraysize(examples); ++i) { + std::string source(InterpreterTester::SourceForBody(examples[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*examples[i].second)); + } +} + +TEST(InterpreterConstDeclaration) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + i::Factory* factory = isolate->factory(); + + std::pair<const char*, Handle<Object>> const_decl[] = { + {"const x = 3; return x;", handle(Smi::FromInt(3), isolate)}, + {"let x = 10; x = x + 20; return x;", handle(Smi::FromInt(30), isolate)}, + {"let x = 10; x = 20; return x;", handle(Smi::FromInt(20), isolate)}, + {"let x; x = 20; return x;", handle(Smi::FromInt(20), isolate)}, + {"let x; return x;", factory->undefined_value()}, + {"var x = 10; { let x = 30; } return x;", + handle(Smi::FromInt(10), isolate)}, + {"let x = 10; { let x = 20; } return x;", + handle(Smi::FromInt(10), isolate)}, + {"var x = 10; eval('let x = 20;'); return x;", + handle(Smi::FromInt(10), isolate)}, + {"var x = 10; eval('const x = 20;'); return x;", + handle(Smi::FromInt(10), isolate)}, + {"var x = 10; { const x = 20; } return x;", + handle(Smi::FromInt(10), isolate)}, + {"var x = 10; { const x = 20; return x;} return -1;", + handle(Smi::FromInt(20), isolate)}, + {"var a = 10;\n" + "for (var i = 0; i < 10; ++i) {\n" + " const x = i;\n" // const declarations are block scoped. + " a = a + x;\n" + "}\n" + "return a;\n", + handle(Smi::FromInt(55), isolate)}, + }; + + // Tests for sloppy mode. + for (size_t i = 0; i < arraysize(const_decl); i++) { + std::string source(InterpreterTester::SourceForBody(const_decl[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*const_decl[i].second)); + } + + // Tests for strict mode. + for (size_t i = 0; i < arraysize(const_decl); i++) { + std::string strict_body = + "'use strict'; " + std::string(const_decl[i].first); + std::string source(InterpreterTester::SourceForBody(strict_body.c_str())); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*const_decl[i].second)); + } +} + +TEST(InterpreterConstDeclarationLookupSlots) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + i::Factory* factory = isolate->factory(); + + std::pair<const char*, Handle<Object>> const_decl[] = { + {"const x = 3; function f1() {return x;}; return x;", + handle(Smi::FromInt(3), isolate)}, + {"let x = 10; x = x + 20; function f1() {return x;}; return x;", + handle(Smi::FromInt(30), isolate)}, + {"let x; x = 20; function f1() {return x;}; return x;", + handle(Smi::FromInt(20), isolate)}, + {"let x; function f1() {return x;}; return x;", + factory->undefined_value()}, + }; + + // Tests for sloppy mode. + for (size_t i = 0; i < arraysize(const_decl); i++) { + std::string source(InterpreterTester::SourceForBody(const_decl[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*const_decl[i].second)); + } + + // Tests for strict mode. + for (size_t i = 0; i < arraysize(const_decl); i++) { + std::string strict_body = + "'use strict'; " + std::string(const_decl[i].first); + std::string source(InterpreterTester::SourceForBody(strict_body.c_str())); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*const_decl[i].second)); + } +} + +TEST(InterpreterConstInLookupContextChain) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + + const char* prologue = + "function OuterMost() {\n" + " const outerConst = 10;\n" + " let outerLet = 20;\n" + " function Outer() {\n" + " function Inner() {\n" + " this.innerFunc = function() { "; + const char* epilogue = + " }\n" + " }\n" + " this.getInnerFunc =" + " function() {return new Inner().innerFunc;}\n" + " }\n" + " this.getOuterFunc =" + " function() {return new Outer().getInnerFunc();}" + "}\n" + "var f = new OuterMost().getOuterFunc();\n" + "f();\n"; + std::pair<const char*, Handle<Object>> const_decl[] = { + {"return outerConst;", handle(Smi::FromInt(10), isolate)}, + {"return outerLet;", handle(Smi::FromInt(20), isolate)}, + {"outerLet = 30; return outerLet;", handle(Smi::FromInt(30), isolate)}, + {"var outerLet = 40; return outerLet;", + handle(Smi::FromInt(40), isolate)}, + {"var outerConst = 50; return outerConst;", + handle(Smi::FromInt(50), isolate)}, + {"try { outerConst = 30 } catch(e) { return -1; }", + handle(Smi::FromInt(-1), isolate)}}; + + for (size_t i = 0; i < arraysize(const_decl); i++) { + std::string script = std::string(prologue) + + std::string(const_decl[i].first) + + std::string(epilogue); + InterpreterTester tester(handles.main_isolate(), script.c_str(), "*"); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*const_decl[i].second)); + } + + // Tests for Legacy constant. + bool old_flag_legacy_const = FLAG_legacy_const; + FLAG_legacy_const = true; + + std::pair<const char*, Handle<Object>> legacy_const_decl[] = { + {"return outerConst = 23;", handle(Smi::FromInt(23), isolate)}, + {"outerConst = 30; return outerConst;", + handle(Smi::FromInt(10), isolate)}, + }; + + for (size_t i = 0; i < arraysize(legacy_const_decl); i++) { + std::string script = std::string(prologue) + + std::string(legacy_const_decl[i].first) + + std::string(epilogue); + InterpreterTester tester(handles.main_isolate(), script.c_str(), "*"); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*legacy_const_decl[i].second)); + } + + FLAG_legacy_const = old_flag_legacy_const; +} + +TEST(InterpreterIllegalConstDeclaration) { + HandleAndZoneScope handles; + + std::pair<const char*, const char*> const_decl[] = { + {"const x = x = 10 + 3; return x;", + "Uncaught ReferenceError: x is not defined"}, + {"const x = 10; x = 20; return x;", + "Uncaught TypeError: Assignment to constant variable."}, + {"const x = 10; { x = 20; } return x;", + "Uncaught TypeError: Assignment to constant variable."}, + {"const x = 10; eval('x = 20;'); return x;", + "Uncaught TypeError: Assignment to constant variable."}, + {"let x = x + 10; return x;", + "Uncaught ReferenceError: x is not defined"}, + {"'use strict'; (function f1() { f1 = 123; })() ", + "Uncaught TypeError: Assignment to constant variable."}, + }; + + // Tests for sloppy mode. + for (size_t i = 0; i < arraysize(const_decl); i++) { + std::string source(InterpreterTester::SourceForBody(const_decl[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); + v8::Local<v8::String> expected_string = v8_str(const_decl[i].second); + CHECK( + message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) + .FromJust()); + } + + // Tests for strict mode. + for (size_t i = 0; i < arraysize(const_decl); i++) { + std::string strict_body = + "'use strict'; " + std::string(const_decl[i].first); + std::string source(InterpreterTester::SourceForBody(strict_body.c_str())); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get(); + v8::Local<v8::String> expected_string = v8_str(const_decl[i].second); + CHECK( + message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string) + .FromJust()); + } +} + +TEST(InterpreterLegacyConstDeclaration) { + bool old_flag_legacy_const = FLAG_legacy_const; + FLAG_legacy_const = true; + + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + + std::pair<const char*, Handle<Object>> const_decl[] = { + {"const x = (x = 10) + 3; return x;", handle(Smi::FromInt(13), isolate)}, + {"const x = 10; x = 20; return x;", handle(Smi::FromInt(10), isolate)}, + {"var a = 10;\n" + "for (var i = 0; i < 10; ++i) {\n" + " const x = i;\n" // Legacy constants are not block scoped. + " a = a + x;\n" + "}\n" + "return a;\n", + handle(Smi::FromInt(10), isolate)}, + {"const x = 20; eval('x = 10;'); return x;", + handle(Smi::FromInt(20), isolate)}, + }; + + for (size_t i = 0; i < arraysize(const_decl); i++) { + std::string source(InterpreterTester::SourceForBody(const_decl[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*const_decl[i].second)); + } + + FLAG_legacy_const = old_flag_legacy_const; +} + } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/profiler-extension.cc b/deps/v8/test/cctest/profiler-extension.cc index a917932978..024cc9c635 100644 --- a/deps/v8/test/cctest/profiler-extension.cc +++ b/deps/v8/test/cctest/profiler-extension.cc @@ -27,41 +27,35 @@ // // Tests of profiles generator and utilities. -#include "src/base/logging.h" #include "test/cctest/profiler-extension.h" +#include "test/cctest/cctest.h" namespace v8 { namespace internal { - v8::CpuProfile* ProfilerExtension::last_profile = NULL; const char* ProfilerExtension::kSource = "native function startProfiling();" - "native function stopProfiling();"; + "native function stopProfiling();" + "native function collectSample();"; v8::Local<v8::FunctionTemplate> ProfilerExtension::GetNativeFunctionTemplate( v8::Isolate* isolate, v8::Local<v8::String> name) { v8::Local<v8::Context> context = isolate->GetCurrentContext(); - if (name->Equals(context, v8::String::NewFromUtf8(isolate, "startProfiling", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { + if (name->Equals(context, v8_str(isolate, "startProfiling")).FromJust()) { return v8::FunctionTemplate::New(isolate, ProfilerExtension::StartProfiling); - } else if (name->Equals(context, - v8::String::NewFromUtf8(isolate, "stopProfiling", - v8::NewStringType::kNormal) - .ToLocalChecked()) - .FromJust()) { - return v8::FunctionTemplate::New(isolate, - ProfilerExtension::StopProfiling); - } else { - CHECK(false); - return v8::Local<v8::FunctionTemplate>(); } + if (name->Equals(context, v8_str(isolate, "stopProfiling")).FromJust()) { + return v8::FunctionTemplate::New(isolate, ProfilerExtension::StopProfiling); + } + if (name->Equals(context, v8_str(isolate, "collectSample")).FromJust()) { + return v8::FunctionTemplate::New(isolate, ProfilerExtension::CollectSample); + } + CHECK(false); + return v8::Local<v8::FunctionTemplate>(); } - void ProfilerExtension::StartProfiling( const v8::FunctionCallbackInfo<v8::Value>& args) { last_profile = NULL; @@ -71,7 +65,6 @@ void ProfilerExtension::StartProfiling( : v8::String::Empty(args.GetIsolate())); } - void ProfilerExtension::StopProfiling( const v8::FunctionCallbackInfo<v8::Value>& args) { v8::CpuProfiler* cpu_profiler = args.GetIsolate()->GetCpuProfiler(); @@ -80,5 +73,10 @@ void ProfilerExtension::StopProfiling( : v8::String::Empty(args.GetIsolate())); } +void ProfilerExtension::CollectSample( + const v8::FunctionCallbackInfo<v8::Value>& args) { + args.GetIsolate()->GetCpuProfiler()->CollectSample(); +} + } // namespace internal } // namespace v8 diff --git a/deps/v8/test/cctest/profiler-extension.h b/deps/v8/test/cctest/profiler-extension.h index e63d374fb5..00f9a5a808 100644 --- a/deps/v8/test/cctest/profiler-extension.h +++ b/deps/v8/test/cctest/profiler-extension.h @@ -40,10 +40,13 @@ class ProfilerExtension : public v8::Extension { ProfilerExtension() : v8::Extension("v8/profiler", kSource) { } virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate( v8::Isolate* isolate, v8::Local<v8::String> name); - static void StartProfiling(const v8::FunctionCallbackInfo<v8::Value>& args); - static void StopProfiling(const v8::FunctionCallbackInfo<v8::Value>& args); static v8::CpuProfile* last_profile; + private: + static void StartProfiling(const v8::FunctionCallbackInfo<v8::Value>& args); + static void StopProfiling(const v8::FunctionCallbackInfo<v8::Value>& args); + static void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args); + static const char* kSource; }; diff --git a/deps/v8/test/cctest/test-accessors.cc b/deps/v8/test/cctest/test-accessors.cc index 0687c33500..90ea08144d 100644 --- a/deps/v8/test/cctest/test-accessors.cc +++ b/deps/v8/test/cctest/test-accessors.cc @@ -686,9 +686,9 @@ THREADED_TEST(Regress433458) { static bool security_check_value = false; - static bool SecurityTestCallback(Local<v8::Context> accessing_context, - Local<v8::Object> accessed_object) { + Local<v8::Object> accessed_object, + Local<v8::Value> data) { return security_check_value; } diff --git a/deps/v8/test/cctest/test-api-fast-accessor-builder.cc b/deps/v8/test/cctest/test-api-fast-accessor-builder.cc index 1e1c972694..eeb6b96fbc 100644 --- a/deps/v8/test/cctest/test-api-fast-accessor-builder.cc +++ b/deps/v8/test/cctest/test-api-fast-accessor-builder.cc @@ -51,9 +51,9 @@ namespace { "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \ "*/ " // 16 lines * 64 'X' =~ 1024 character comment. -#define FN_WARMUP(name, src) \ - "function " name "() { " src INLINE_SPOILER \ - " }; for(i = 0; i < 2; i++) { " name "() } " +#define FN(name, src) "function " name "() { " src INLINE_SPOILER " }" +#define WARMUP(name, count) "for(i = 0; i < " count "; i++) { " name "() } " +#define FN_WARMUP(name, src) FN(name, src) "; " WARMUP(name, "2") static void NativePropertyAccessor( const v8::FunctionCallbackInfo<v8::Value>& info) { @@ -112,6 +112,9 @@ void AddInternalFieldAccessor(v8::Isolate* isolate, // "Fast" accessor that accesses an internal field. TEST(FastAccessorWithInternalField) { + // Crankshaft support for fast accessors is not implemented; crankshafted + // code uses the slow accessor which breaks this test's expectations. + v8::internal::FLAG_always_opt = false; LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); @@ -142,6 +145,9 @@ TEST(FastAccessorWithInternalField) { // "Fast" accessor with control flow via ...OrReturnNull methods. TEST(FastAccessorOrReturnNull) { + // Crankshaft support for fast accessors is not implemented; crankshafted + // code uses the slow accessor which breaks this test's expectations. + v8::internal::FLAG_always_opt = false; LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); @@ -191,6 +197,9 @@ TEST(FastAccessorOrReturnNull) { // "Fast" accessor with simple control flow via explicit labels. TEST(FastAccessorControlFlowWithLabels) { + // Crankshaft support for fast accessors is not implemented; crankshafted + // code uses the slow accessor which breaks this test's expectations. + v8::internal::FLAG_always_opt = false; LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); @@ -226,6 +235,9 @@ TEST(FastAccessorControlFlowWithLabels) { // "Fast" accessor, loading things. TEST(FastAccessorLoad) { + // Crankshaft support for fast accessors is not implemented; crankshafted + // code uses the slow accessor which breaks this test's expectations. + v8::internal::FLAG_always_opt = false; LocalContext env; v8::Isolate* isolate = env->GetIsolate(); v8::HandleScope scope(isolate); @@ -286,3 +298,67 @@ TEST(FastAccessorLoad) { CompileRun(FN_WARMUP("loadval", "return obj.loadval")); ExpectString("loadval()", "Hello"); } + +void ApiCallbackInt(const v8::FunctionCallbackInfo<v8::Value>& info) { + info.GetReturnValue().Set(12345); +} + +const char* kApiCallbackStringValue = + "Hello World! Bizarro C++ world, actually."; +void ApiCallbackString(const v8::FunctionCallbackInfo<v8::Value>& info) { + info.GetReturnValue().Set(v8_str(kApiCallbackStringValue)); +} + +void ApiCallbackParam(const v8::FunctionCallbackInfo<v8::Value>& info) { + CHECK_EQ(1, info.Length()); + CHECK(info[0]->IsNumber()); + info.GetReturnValue().Set(info[0]); +} + +// "Fast" accessor, callback to embedder +TEST(FastAccessorCallback) { + // Crankshaft support for fast accessors is not implemented; crankshafted + // code uses the slow accessor which breaks this test's expectations. + v8::internal::FLAG_always_opt = false; + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope scope(isolate); + + v8::Local<v8::ObjectTemplate> foo = v8::ObjectTemplate::New(isolate); + { + auto builder = v8::experimental::FastAccessorBuilder::New(isolate); + builder->ReturnValue( + builder->Call(&ApiCallbackInt, builder->IntegerConstant(999))); + foo->SetAccessorProperty(v8_str("int"), + v8::FunctionTemplate::NewWithFastHandler( + isolate, NativePropertyAccessor, builder)); + + builder = v8::experimental::FastAccessorBuilder::New(isolate); + builder->ReturnValue( + builder->Call(&ApiCallbackString, builder->IntegerConstant(0))); + foo->SetAccessorProperty(v8_str("str"), + v8::FunctionTemplate::NewWithFastHandler( + isolate, NativePropertyAccessor, builder)); + + builder = v8::experimental::FastAccessorBuilder::New(isolate); + builder->ReturnValue( + builder->Call(&ApiCallbackParam, builder->IntegerConstant(1000))); + foo->SetAccessorProperty(v8_str("param"), + v8::FunctionTemplate::NewWithFastHandler( + isolate, NativePropertyAccessor, builder)); + } + + // Create an instance. + v8::Local<v8::Object> obj = foo->NewInstance(env.local()).ToLocalChecked(); + CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust()); + + // Callbacks: + CompileRun(FN_WARMUP("callbackint", "return obj.int")); + ExpectInt32("callbackint()", 12345); + + CompileRun(FN_WARMUP("callbackstr", "return obj.str")); + ExpectString("callbackstr()", kApiCallbackStringValue); + + CompileRun(FN_WARMUP("callbackparam", "return obj.param")); + ExpectInt32("callbackparam()", 1000); +} diff --git a/deps/v8/test/cctest/test-api-interceptors.cc b/deps/v8/test/cctest/test-api-interceptors.cc index 9f5eb21954..ac54ededca 100644 --- a/deps/v8/test/cctest/test-api-interceptors.cc +++ b/deps/v8/test/cctest/test-api-interceptors.cc @@ -1879,9 +1879,9 @@ THREADED_TEST(IndexedInterceptorWithNoSetter) { ExpectString(code, "PASSED"); } - static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context, - Local<v8::Object> accessed_object) { + Local<v8::Object> accessed_object, + Local<v8::Value> data) { return false; } @@ -3475,9 +3475,9 @@ struct AccessCheckData { AccessCheckData* g_access_check_data = nullptr; - bool SimpleAccessChecker(Local<v8::Context> accessing_context, - Local<v8::Object> access_object) { + Local<v8::Object> access_object, + Local<v8::Value> data) { g_access_check_data->count++; return g_access_check_data->result; } diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index b78d450fcb..f4e8fe8e4b 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -1889,59 +1889,258 @@ THREADED_TEST(GlobalPrototype) { THREADED_TEST(ObjectTemplate) { + LocalContext env; v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); + Local<v8::FunctionTemplate> acc = + v8::FunctionTemplate::New(isolate, Returns42); + CHECK(env->Global() + ->Set(env.local(), v8_str("acc"), + acc->GetFunction(env.local()).ToLocalChecked()) + .FromJust()); + Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate); v8::Local<v8::String> class_name = v8_str("the_class_name"); fun->SetClassName(class_name); Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun); templ1->Set(isolate, "x", v8_num(10)); templ1->Set(isolate, "y", v8_num(13)); - LocalContext env; + templ1->Set(v8_str("foo"), acc); Local<v8::Object> instance1 = templ1->NewInstance(env.local()).ToLocalChecked(); CHECK(class_name->StrictEquals(instance1->GetConstructorName())); CHECK(env->Global()->Set(env.local(), v8_str("p"), instance1).FromJust()); - CHECK(v8_compile("(p.x == 10)") - ->Run(env.local()) - .ToLocalChecked() - ->BooleanValue(env.local()) - .FromJust()); - CHECK(v8_compile("(p.y == 13)") - ->Run(env.local()) - .ToLocalChecked() - ->BooleanValue(env.local()) - .FromJust()); + CHECK(CompileRun("(p.x == 10)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(p.y == 13)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(p.foo() == 42)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(p.foo == acc)")->BooleanValue(env.local()).FromJust()); + // Ensure that foo become a data field. + CompileRun("p.foo = function() {}"); Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate); fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123)); Local<ObjectTemplate> templ2 = fun2->InstanceTemplate(); templ2->Set(isolate, "a", v8_num(12)); templ2->Set(isolate, "b", templ1); + templ2->Set(v8_str("bar"), acc); + templ2->SetAccessorProperty(v8_str("acc"), acc); Local<v8::Object> instance2 = templ2->NewInstance(env.local()).ToLocalChecked(); CHECK(env->Global()->Set(env.local(), v8_str("q"), instance2).FromJust()); - CHECK(v8_compile("(q.nirk == 123)") - ->Run(env.local()) - .ToLocalChecked() + CHECK(CompileRun("(q.nirk == 123)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q.a == 12)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q.b.x == 10)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q.b.y == 13)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q.b.foo() == 42)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q.b.foo === acc)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q.b !== p)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q.acc == 42)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q.bar() == 42)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q.bar == acc)")->BooleanValue(env.local()).FromJust()); + + instance2 = templ2->NewInstance(env.local()).ToLocalChecked(); + CHECK(env->Global()->Set(env.local(), v8_str("q2"), instance2).FromJust()); + CHECK(CompileRun("(q2.nirk == 123)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q2.a == 12)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q2.b.x == 10)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q2.b.y == 13)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q2.b.foo() == 42)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q2.b.foo === acc)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q2.acc == 42)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q2.bar() == 42)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("(q2.bar === acc)")->BooleanValue(env.local()).FromJust()); + + CHECK(CompileRun("(q.b !== q2.b)")->BooleanValue(env.local()).FromJust()); + CHECK(CompileRun("q.b.x = 17; (q2.b.x == 10)") ->BooleanValue(env.local()) .FromJust()); - CHECK(v8_compile("(q.a == 12)") - ->Run(env.local()) - .ToLocalChecked() + CHECK(CompileRun("desc1 = Object.getOwnPropertyDescriptor(q, 'acc');" + "(desc1.get === acc)") ->BooleanValue(env.local()) .FromJust()); - CHECK(v8_compile("(q.b.x == 10)") - ->Run(env.local()) - .ToLocalChecked() - ->BooleanValue(env.local()) - .FromJust()); - CHECK(v8_compile("(q.b.y == 13)") - ->Run(env.local()) - .ToLocalChecked() + CHECK(CompileRun("desc2 = Object.getOwnPropertyDescriptor(q2, 'acc');" + "(desc2.get === acc)") ->BooleanValue(env.local()) .FromJust()); } +THREADED_TEST(IntegerValue) { + LocalContext env; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + + CHECK_EQ(0, CompileRun("undefined")->IntegerValue(env.local()).FromJust()); +} + +static void GetNirk(Local<String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + ApiTestFuzzer::Fuzz(); + info.GetReturnValue().Set(v8_num(900)); +} + +static void GetRino(Local<String> name, + const v8::PropertyCallbackInfo<v8::Value>& info) { + ApiTestFuzzer::Fuzz(); + info.GetReturnValue().Set(v8_num(560)); +} + +enum ObjectInstantiationMode { + // Create object using ObjectTemplate::NewInstance. + ObjectTemplate_NewInstance, + // Create object using FunctionTemplate::NewInstance on constructor. + Constructor_GetFunction_NewInstance, + // Create object using new operator on constructor. + Constructor_GetFunction_New +}; + +// Test object instance creation using a function template with an instance +// template inherited from another function template with accessors and data +// properties in prototype template. +static void TestObjectTemplateInheritedWithPrototype( + ObjectInstantiationMode mode) { + LocalContext env; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + + Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate); + fun_A->SetClassName(v8_str("A")); + v8::Local<v8::ObjectTemplate> prototype_templ = fun_A->PrototypeTemplate(); + prototype_templ->Set(isolate, "a", v8_num(113)); + prototype_templ->SetNativeDataProperty(v8_str("nirk"), GetNirk); + prototype_templ->Set(isolate, "b", v8_num(153)); + + Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate); + v8::Local<v8::String> class_name = v8_str("B"); + fun_B->SetClassName(class_name); + fun_B->Inherit(fun_A); + prototype_templ = fun_B->PrototypeTemplate(); + prototype_templ->Set(isolate, "c", v8_num(713)); + prototype_templ->SetNativeDataProperty(v8_str("rino"), GetRino); + prototype_templ->Set(isolate, "d", v8_num(753)); + + Local<ObjectTemplate> templ = fun_B->InstanceTemplate(); + templ->Set(isolate, "x", v8_num(10)); + templ->Set(isolate, "y", v8_num(13)); + + // Perform several iterations to trigger creation from cached boilerplate. + for (int i = 0; i < 3; i++) { + Local<v8::Object> instance; + switch (mode) { + case ObjectTemplate_NewInstance: + instance = templ->NewInstance(env.local()).ToLocalChecked(); + break; + + case Constructor_GetFunction_NewInstance: { + Local<v8::Function> function_B = + fun_B->GetFunction(env.local()).ToLocalChecked(); + instance = function_B->NewInstance(env.local()).ToLocalChecked(); + break; + } + case Constructor_GetFunction_New: { + Local<v8::Function> function_B = + fun_B->GetFunction(env.local()).ToLocalChecked(); + if (i == 0) { + CHECK(env->Global() + ->Set(env.local(), class_name, function_B) + .FromJust()); + } + instance = + CompileRun("new B()")->ToObject(env.local()).ToLocalChecked(); + break; + } + default: + UNREACHABLE(); + } + + CHECK(class_name->StrictEquals(instance->GetConstructorName())); + CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust()); + + CHECK_EQ(10, CompileRun("o.x")->IntegerValue(env.local()).FromJust()); + CHECK_EQ(13, CompileRun("o.y")->IntegerValue(env.local()).FromJust()); + + CHECK_EQ(113, CompileRun("o.a")->IntegerValue(env.local()).FromJust()); + CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust()); + CHECK_EQ(153, CompileRun("o.b")->IntegerValue(env.local()).FromJust()); + CHECK_EQ(713, CompileRun("o.c")->IntegerValue(env.local()).FromJust()); + CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust()); + CHECK_EQ(753, CompileRun("o.d")->IntegerValue(env.local()).FromJust()); + } +} + +THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype1) { + TestObjectTemplateInheritedWithPrototype(ObjectTemplate_NewInstance); +} + +THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype2) { + TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_NewInstance); +} + +THREADED_TEST(TestObjectTemplateInheritedWithAccessorsInPrototype3) { + TestObjectTemplateInheritedWithPrototype(Constructor_GetFunction_New); +} + +// Test object instance creation using a function template without an instance +// template inherited from another function template. +static void TestObjectTemplateInheritedWithoutInstanceTemplate( + ObjectInstantiationMode mode) { + LocalContext env; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + + Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate); + fun_A->SetClassName(v8_str("A")); + + Local<ObjectTemplate> templ_A = fun_A->InstanceTemplate(); + templ_A->SetNativeDataProperty(v8_str("nirk"), GetNirk); + templ_A->SetNativeDataProperty(v8_str("rino"), GetRino); + + Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate); + v8::Local<v8::String> class_name = v8_str("B"); + fun_B->SetClassName(class_name); + fun_B->Inherit(fun_A); + + // Perform several iterations to trigger creation from cached boilerplate. + for (int i = 0; i < 3; i++) { + Local<v8::Object> instance; + switch (mode) { + case Constructor_GetFunction_NewInstance: { + Local<v8::Function> function_B = + fun_B->GetFunction(env.local()).ToLocalChecked(); + instance = function_B->NewInstance(env.local()).ToLocalChecked(); + break; + } + case Constructor_GetFunction_New: { + Local<v8::Function> function_B = + fun_B->GetFunction(env.local()).ToLocalChecked(); + if (i == 0) { + CHECK(env->Global() + ->Set(env.local(), class_name, function_B) + .FromJust()); + } + instance = + CompileRun("new B()")->ToObject(env.local()).ToLocalChecked(); + break; + } + default: + UNREACHABLE(); + } + + CHECK(class_name->StrictEquals(instance->GetConstructorName())); + CHECK(env->Global()->Set(env.local(), v8_str("o"), instance).FromJust()); + + CHECK_EQ(900, CompileRun("o.nirk")->IntegerValue(env.local()).FromJust()); + CHECK_EQ(560, CompileRun("o.rino")->IntegerValue(env.local()).FromJust()); + } +} + +THREADED_TEST(TestObjectTemplateInheritedWithPrototype1) { + TestObjectTemplateInheritedWithoutInstanceTemplate( + Constructor_GetFunction_NewInstance); +} + +THREADED_TEST(TestObjectTemplateInheritedWithPrototype2) { + TestObjectTemplateInheritedWithoutInstanceTemplate( + Constructor_GetFunction_New); +} static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) { ApiTestFuzzer::Fuzz(); @@ -2020,31 +2219,12 @@ THREADED_TEST(DescriptorInheritance) { ->NewInstance(env.local()) .ToLocalChecked()) .FromJust()); - CHECK_EQ(17.2, v8_compile("obj.flabby()") - ->Run(env.local()) - .ToLocalChecked() - ->NumberValue(env.local()) - .FromJust()); - CHECK(v8_compile("'flabby' in obj") - ->Run(env.local()) - .ToLocalChecked() - ->BooleanValue(env.local()) - .FromJust()); - CHECK_EQ(15.2, v8_compile("obj.knurd") - ->Run(env.local()) - .ToLocalChecked() - ->NumberValue(env.local()) - .FromJust()); - CHECK(v8_compile("'knurd' in obj") - ->Run(env.local()) - .ToLocalChecked() - ->BooleanValue(env.local()) - .FromJust()); - CHECK_EQ(20.1, v8_compile("obj.v1") - ->Run(env.local()) - .ToLocalChecked() - ->NumberValue(env.local()) - .FromJust()); + CHECK_EQ(17.2, + CompileRun("obj.flabby()")->NumberValue(env.local()).FromJust()); + CHECK(CompileRun("'flabby' in obj")->BooleanValue(env.local()).FromJust()); + CHECK_EQ(15.2, CompileRun("obj.knurd")->NumberValue(env.local()).FromJust()); + CHECK(CompileRun("'knurd' in obj")->BooleanValue(env.local()).FromJust()); + CHECK_EQ(20.1, CompileRun("obj.v1")->NumberValue(env.local()).FromJust()); CHECK(env->Global() ->Set(env.local(), v8_str("obj2"), base2->GetFunction(env.local()) @@ -2052,36 +2232,106 @@ THREADED_TEST(DescriptorInheritance) { ->NewInstance(env.local()) .ToLocalChecked()) .FromJust()); - CHECK_EQ(17.2, v8_compile("obj2.flabby()") - ->Run(env.local()) - .ToLocalChecked() - ->NumberValue(env.local()) - .FromJust()); - CHECK(v8_compile("'flabby' in obj2") - ->Run(env.local()) - .ToLocalChecked() - ->BooleanValue(env.local()) - .FromJust()); - CHECK_EQ(15.2, v8_compile("obj2.knurd") - ->Run(env.local()) - .ToLocalChecked() - ->NumberValue(env.local()) - .FromJust()); - CHECK(v8_compile("'knurd' in obj2") - ->Run(env.local()) - .ToLocalChecked() - ->BooleanValue(env.local()) - .FromJust()); - CHECK_EQ(10.1, v8_compile("obj2.v2") - ->Run(env.local()) - .ToLocalChecked() - ->NumberValue(env.local()) - .FromJust()); + CHECK_EQ(17.2, + CompileRun("obj2.flabby()")->NumberValue(env.local()).FromJust()); + CHECK(CompileRun("'flabby' in obj2")->BooleanValue(env.local()).FromJust()); + CHECK_EQ(15.2, CompileRun("obj2.knurd")->NumberValue(env.local()).FromJust()); + CHECK(CompileRun("'knurd' in obj2")->BooleanValue(env.local()).FromJust()); + CHECK_EQ(10.1, CompileRun("obj2.v2")->NumberValue(env.local()).FromJust()); // base1 and base2 cannot cross reference to each's prototype - CHECK(v8_compile("obj.v2")->Run(env.local()).ToLocalChecked()->IsUndefined()); - CHECK( - v8_compile("obj2.v1")->Run(env.local()).ToLocalChecked()->IsUndefined()); + CHECK(CompileRun("obj.v2")->IsUndefined()); + CHECK(CompileRun("obj2.v1")->IsUndefined()); +} + +THREADED_TEST(DescriptorInheritance2) { + LocalContext env; + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + v8::Local<v8::FunctionTemplate> fun_A = v8::FunctionTemplate::New(isolate); + fun_A->SetClassName(v8_str("A")); + fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd1"), GetKnurd); + fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk1"), GetNirk); + fun_A->InstanceTemplate()->SetNativeDataProperty(v8_str("rino1"), GetRino); + + v8::Local<v8::FunctionTemplate> fun_B = v8::FunctionTemplate::New(isolate); + fun_B->SetClassName(v8_str("B")); + fun_B->Inherit(fun_A); + + v8::Local<v8::FunctionTemplate> fun_C = v8::FunctionTemplate::New(isolate); + fun_C->SetClassName(v8_str("C")); + fun_C->Inherit(fun_B); + fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd2"), GetKnurd); + fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk2"), GetNirk); + fun_C->InstanceTemplate()->SetNativeDataProperty(v8_str("rino2"), GetRino); + + v8::Local<v8::FunctionTemplate> fun_D = v8::FunctionTemplate::New(isolate); + fun_D->SetClassName(v8_str("D")); + fun_D->Inherit(fun_C); + + v8::Local<v8::FunctionTemplate> fun_E = v8::FunctionTemplate::New(isolate); + fun_E->SetClassName(v8_str("E")); + fun_E->Inherit(fun_D); + fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("knurd3"), GetKnurd); + fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("nirk3"), GetNirk); + fun_E->InstanceTemplate()->SetNativeDataProperty(v8_str("rino3"), GetRino); + + v8::Local<v8::FunctionTemplate> fun_F = v8::FunctionTemplate::New(isolate); + fun_F->SetClassName(v8_str("F")); + fun_F->Inherit(fun_E); + v8::Local<v8::ObjectTemplate> templ = fun_F->InstanceTemplate(); + const int kDataPropertiesNumber = 100; + for (int i = 0; i < kDataPropertiesNumber; i++) { + v8::Local<v8::Value> val = v8_num(i); + v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked(); + v8::Local<v8::String> name = String::Concat(v8_str("p"), val_str); + + templ->Set(name, val); + templ->Set(val_str, val); + } + + CHECK(env->Global() + ->Set(env.local(), v8_str("F"), + fun_F->GetFunction(env.local()).ToLocalChecked()) + .FromJust()); + + v8::Local<v8::Script> script = v8_compile("o = new F()"); + + for (int i = 0; i < 100; i++) { + v8::HandleScope scope(isolate); + script->Run(env.local()).ToLocalChecked(); + } + v8::Local<v8::Object> object = script->Run(env.local()) + .ToLocalChecked() + ->ToObject(env.local()) + .ToLocalChecked(); + + CHECK_EQ(15.2, CompileRun("o.knurd1")->NumberValue(env.local()).FromJust()); + CHECK_EQ(15.2, CompileRun("o.knurd2")->NumberValue(env.local()).FromJust()); + CHECK_EQ(15.2, CompileRun("o.knurd3")->NumberValue(env.local()).FromJust()); + + CHECK_EQ(900, CompileRun("o.nirk1")->IntegerValue(env.local()).FromJust()); + CHECK_EQ(900, CompileRun("o.nirk2")->IntegerValue(env.local()).FromJust()); + CHECK_EQ(900, CompileRun("o.nirk3")->IntegerValue(env.local()).FromJust()); + + CHECK_EQ(560, CompileRun("o.rino1")->IntegerValue(env.local()).FromJust()); + CHECK_EQ(560, CompileRun("o.rino2")->IntegerValue(env.local()).FromJust()); + CHECK_EQ(560, CompileRun("o.rino3")->IntegerValue(env.local()).FromJust()); + + for (int i = 0; i < kDataPropertiesNumber; i++) { + v8::Local<v8::Value> val = v8_num(i); + v8::Local<v8::String> val_str = val->ToString(env.local()).ToLocalChecked(); + v8::Local<v8::String> name = String::Concat(v8_str("p"), val_str); + + CHECK_EQ(i, object->Get(env.local(), name) + .ToLocalChecked() + ->IntegerValue(env.local()) + .FromJust()); + CHECK_EQ(i, object->Get(env.local(), val) + .ToLocalChecked() + ->IntegerValue(env.local()) + .FromJust()); + } } @@ -2135,7 +2385,7 @@ static void ThrowingSymbolAccessorGetter( } -THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) { +THREADED_TEST(AccessorIsPreservedOnAttributeChange) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate); LocalContext env; @@ -2145,11 +2395,11 @@ THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) { CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); CompileRun("Object.defineProperty(a, 'length', { writable: false });"); CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0); - // But we should still have an ExecutableAccessorInfo. + // But we should still have an AccessorInfo. i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length"))); i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR); CHECK_EQ(i::LookupIterator::ACCESSOR, it.state()); - CHECK(it.GetAccessors()->IsExecutableAccessorInfo()); + CHECK(it.GetAccessors()->IsAccessorInfo()); } @@ -7779,7 +8029,6 @@ static void ArgumentsTestCallback( ApiTestFuzzer::Fuzz(); v8::Isolate* isolate = args.GetIsolate(); Local<Context> context = isolate->GetCurrentContext(); - CHECK(args_fun->Equals(context, args.Callee()).FromJust()); CHECK_EQ(3, args.Length()); CHECK(v8::Integer::New(isolate, 1)->Equals(context, args[0]).FromJust()); CHECK(v8::Integer::New(isolate, 2)->Equals(context, args[1]).FromJust()); @@ -8940,8 +9189,11 @@ TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) { // For use within the TestSecurityHandler() test. static bool g_security_callback_result = false; static bool SecurityTestCallback(Local<v8::Context> accessing_context, - Local<v8::Object> accessed_object) { + Local<v8::Object> accessed_object, + Local<v8::Value> data) { printf("a\n"); + CHECK(!data.IsEmpty() && data->IsInt32()); + CHECK_EQ(42, data->Int32Value(accessing_context).FromJust()); return g_security_callback_result; } @@ -8952,7 +9204,7 @@ TEST(SecurityHandler) { v8::HandleScope scope0(isolate); v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate); - global_template->SetAccessCheckCallback(SecurityTestCallback); + global_template->SetAccessCheckCallback(SecurityTestCallback, v8_num(42)); // Create an environment v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); context0->Enter(); @@ -9138,7 +9390,8 @@ THREADED_TEST(SecurityChecksForPrototypeChain) { static bool security_check_with_gc_called; static bool SecurityTestCallbackWithGC(Local<v8::Context> accessing_context, - Local<v8::Object> accessed_object) { + Local<v8::Object> accessed_object, + Local<v8::Value> data) { CcTest::heap()->CollectAllGarbage(); security_check_with_gc_called = true; return true; @@ -9625,7 +9878,8 @@ TEST(DetachedAccesses) { static bool allowed_access = false; static bool AccessBlocker(Local<v8::Context> accessing_context, - Local<v8::Object> accessed_object) { + Local<v8::Object> accessed_object, + Local<v8::Value> data) { v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext(); return context->Global()->Equals(context, accessed_object).FromJust() || allowed_access; @@ -9919,9 +10173,9 @@ TEST(AccessControlES5) { CHECK_EQ(42, g_echo_value); // Make sure we didn't call the setter. } - static bool AccessAlwaysBlocked(Local<v8::Context> accessing_context, - Local<v8::Object> global) { + Local<v8::Object> global, + Local<v8::Value> data) { i::PrintF("Access blocked.\n"); return false; } @@ -10065,7 +10319,8 @@ THREADED_TEST(CrossDomainAccessors) { static int access_count = 0; static bool AccessCounter(Local<v8::Context> accessing_context, - Local<v8::Object> accessed_object) { + Local<v8::Object> accessed_object, + Local<v8::Value> data) { access_count++; return true; } @@ -10724,7 +10979,8 @@ THREADED_TEST(Regress91517) { Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate); t2->SetHiddenPrototype(true); t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2)); - t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate)); + t2->InstanceTemplate()->Set(v8_str("objects"), + v8::ObjectTemplate::New(isolate)); t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2)); Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate); t3->SetHiddenPrototype(true); @@ -10772,6 +11028,7 @@ THREADED_TEST(Regress91517) { ExpectTrue("names.indexOf(\"boo\") >= 0"); ExpectTrue("names.indexOf(\"foo\") >= 0"); ExpectTrue("names.indexOf(\"fuz1\") >= 0"); + ExpectTrue("names.indexOf(\"objects\") >= 0"); ExpectTrue("names.indexOf(\"fuz2\") >= 0"); ExpectFalse("names[1005] == undefined"); } @@ -12793,6 +13050,203 @@ THREADED_TEST(Overriding) { } +static void ShouldThrowOnErrorGetter( + Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { + ApiTestFuzzer::Fuzz(); + v8::Isolate* isolate = info.GetIsolate(); + Local<Boolean> should_throw_on_error = + Boolean::New(isolate, info.ShouldThrowOnError()); + info.GetReturnValue().Set(should_throw_on_error); +} + + +template <typename T> +static void ShouldThrowOnErrorSetter(Local<Name> name, Local<v8::Value> value, + const v8::PropertyCallbackInfo<T>& info) { + ApiTestFuzzer::Fuzz(); + v8::Isolate* isolate = info.GetIsolate(); + auto context = isolate->GetCurrentContext(); + Local<Boolean> should_throw_on_error_value = + Boolean::New(isolate, info.ShouldThrowOnError()); + CHECK(context->Global() + ->Set(isolate->GetCurrentContext(), v8_str("should_throw_setter"), + should_throw_on_error_value) + .FromJust()); +} + + +THREADED_TEST(AccessorShouldThrowOnError) { + i::FLAG_strong_mode = true; + LocalContext context; + v8::Isolate* isolate = context->GetIsolate(); + v8::HandleScope scope(isolate); + Local<Object> global = context->Global(); + + Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate); + Local<ObjectTemplate> instance_templ = templ->InstanceTemplate(); + instance_templ->SetAccessor(v8_str("f"), ShouldThrowOnErrorGetter, + ShouldThrowOnErrorSetter<void>); + + Local<v8::Object> instance = templ->GetFunction(context.local()) + .ToLocalChecked() + ->NewInstance(context.local()) + .ToLocalChecked(); + + CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust()); + + // SLOPPY mode + Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked(); + CHECK(value->IsFalse()); + v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked(); + value = global->Get(context.local(), v8_str("should_throw_setter")) + .ToLocalChecked(); + CHECK(value->IsFalse()); + + // STRICT mode + value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked(); + CHECK(value->IsFalse()); + v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked(); + value = global->Get(context.local(), v8_str("should_throw_setter")) + .ToLocalChecked(); + CHECK(value->IsTrue()); + + // STRONG mode + value = v8_compile("'use strong';o.f")->Run(context.local()).ToLocalChecked(); + CHECK(value->IsFalse()); + v8_compile("'use strong'; o.f = 153")->Run(context.local()).ToLocalChecked(); + value = global->Get(context.local(), v8_str("should_throw_setter")) + .ToLocalChecked(); + CHECK(value->IsTrue()); +} + + +static void ShouldThrowOnErrorQuery( + Local<Name> name, const v8::PropertyCallbackInfo<v8::Integer>& info) { + ApiTestFuzzer::Fuzz(); + v8::Isolate* isolate = info.GetIsolate(); + info.GetReturnValue().Set(v8::None); + + auto context = isolate->GetCurrentContext(); + Local<Boolean> should_throw_on_error_value = + Boolean::New(isolate, info.ShouldThrowOnError()); + CHECK(context->Global() + ->Set(isolate->GetCurrentContext(), v8_str("should_throw_query"), + should_throw_on_error_value) + .FromJust()); +} + + +static void ShouldThrowOnErrorDeleter( + Local<Name> name, const v8::PropertyCallbackInfo<v8::Boolean>& info) { + ApiTestFuzzer::Fuzz(); + v8::Isolate* isolate = info.GetIsolate(); + info.GetReturnValue().Set(v8::True(isolate)); + + auto context = isolate->GetCurrentContext(); + Local<Boolean> should_throw_on_error_value = + Boolean::New(isolate, info.ShouldThrowOnError()); + CHECK(context->Global() + ->Set(isolate->GetCurrentContext(), v8_str("should_throw_deleter"), + should_throw_on_error_value) + .FromJust()); +} + + +static void ShouldThrowOnErrorPropertyEnumerator( + const v8::PropertyCallbackInfo<v8::Array>& info) { + ApiTestFuzzer::Fuzz(); + v8::Isolate* isolate = info.GetIsolate(); + Local<v8::Array> names = v8::Array::New(isolate, 1); + CHECK(names->Set(isolate->GetCurrentContext(), names, v8_num(1)).FromJust()); + info.GetReturnValue().Set(names); + + auto context = isolate->GetCurrentContext(); + Local<Boolean> should_throw_on_error_value = + Boolean::New(isolate, info.ShouldThrowOnError()); + CHECK(context->Global() + ->Set(isolate->GetCurrentContext(), + v8_str("should_throw_enumerator"), + should_throw_on_error_value) + .FromJust()); +} + + +THREADED_TEST(InterceptorShouldThrowOnError) { + i::FLAG_strong_mode = true; + LocalContext context; + v8::Isolate* isolate = context->GetIsolate(); + v8::HandleScope scope(isolate); + Local<Object> global = context->Global(); + + auto interceptor_templ = v8::ObjectTemplate::New(isolate); + v8::NamedPropertyHandlerConfiguration handler( + ShouldThrowOnErrorGetter, ShouldThrowOnErrorSetter<Value>, + ShouldThrowOnErrorQuery, ShouldThrowOnErrorDeleter, + ShouldThrowOnErrorPropertyEnumerator); + interceptor_templ->SetHandler(handler); + + Local<v8::Object> instance = + interceptor_templ->NewInstance(context.local()).ToLocalChecked(); + + CHECK(global->Set(context.local(), v8_str("o"), instance).FromJust()); + + // SLOPPY mode + Local<Value> value = v8_compile("o.f")->Run(context.local()).ToLocalChecked(); + CHECK(value->IsFalse()); + v8_compile("o.f = 153")->Run(context.local()).ToLocalChecked(); + value = global->Get(context.local(), v8_str("should_throw_setter")) + .ToLocalChecked(); + CHECK(value->IsFalse()); + + v8_compile("delete o.f")->Run(context.local()).ToLocalChecked(); + value = global->Get(context.local(), v8_str("should_throw_deleter")) + .ToLocalChecked(); + CHECK(value->IsFalse()); + + v8_compile("Object.getOwnPropertyNames(o)") + ->Run(context.local()) + .ToLocalChecked(); + value = global->Get(context.local(), v8_str("should_throw_enumerator")) + .ToLocalChecked(); + CHECK(value->IsFalse()); + + // STRICT mode + value = v8_compile("'use strict';o.f")->Run(context.local()).ToLocalChecked(); + CHECK(value->IsFalse()); + v8_compile("'use strict'; o.f = 153")->Run(context.local()).ToLocalChecked(); + value = global->Get(context.local(), v8_str("should_throw_setter")) + .ToLocalChecked(); + CHECK(value->IsTrue()); + + v8_compile("'use strict'; delete o.f")->Run(context.local()).ToLocalChecked(); + value = global->Get(context.local(), v8_str("should_throw_deleter")) + .ToLocalChecked(); + CHECK(value->IsTrue()); + + v8_compile("'use strict'; Object.getOwnPropertyNames(o)") + ->Run(context.local()) + .ToLocalChecked(); + value = global->Get(context.local(), v8_str("should_throw_enumerator")) + .ToLocalChecked(); + CHECK(value->IsFalse()); + + // STRONG mode + value = v8_compile("'use strong';o.f")->Run(context.local()).ToLocalChecked(); + CHECK(value->IsFalse()); + v8_compile("'use strong'; o.f = 153")->Run(context.local()).ToLocalChecked(); + value = global->Get(context.local(), v8_str("should_throw_setter")) + .ToLocalChecked(); + CHECK(value->IsTrue()); + + v8_compile("'use strong'; Object.getOwnPropertyNames(o)") + ->Run(context.local()) + .ToLocalChecked(); + value = global->Get(context.local(), v8_str("should_throw_enumerator")) + .ToLocalChecked(); + CHECK(value->IsFalse()); +} + + static void IsConstructHandler( const v8::FunctionCallbackInfo<v8::Value>& args) { ApiTestFuzzer::Fuzz(); @@ -19780,7 +20234,7 @@ THREADED_TEST(CreationContextOfJsBoundFunction) { Context::Scope scope(other_context); CHECK(bound_function1->CreationContext() == context1); CheckContextId(bound_function1, 1); - CHECK(bound_function2->CreationContext() == context2); + CHECK(bound_function2->CreationContext() == context1); CheckContextId(bound_function2, 1); } @@ -20171,16 +20625,20 @@ THREADED_TEST(Regress93759) { context->Exit(); - // Template for object for second context. Values to test are put on it as - // properties. - Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate); - global_template->Set(v8_str("simple"), simple_object); - global_template->Set(v8_str("protected"), protected_object); - global_template->Set(v8_str("global"), global_object); - global_template->Set(v8_str("proxy"), proxy_object); - global_template->Set(v8_str("hidden"), object_with_hidden); + LocalContext context2; + v8::Local<v8::Object> global = context2->Global(); - LocalContext context2(NULL, global_template); + // Setup global variables. + CHECK(global->Set(context2.local(), v8_str("simple"), simple_object) + .FromJust()); + CHECK(global->Set(context2.local(), v8_str("protected"), protected_object) + .FromJust()); + CHECK(global->Set(context2.local(), v8_str("global"), global_object) + .FromJust()); + CHECK( + global->Set(context2.local(), v8_str("proxy"), proxy_object).FromJust()); + CHECK(global->Set(context2.local(), v8_str("hidden"), object_with_hidden) + .FromJust()); Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)"); CHECK(result1->Equals(context2.local(), simple_object->GetPrototype()) @@ -20332,20 +20790,34 @@ THREADED_TEST(ForeignFunctionReceiver) { uint8_t callback_fired = 0; +uint8_t before_call_entered_callback_count1 = 0; +uint8_t before_call_entered_callback_count2 = 0; -void CallCompletedCallback1() { +void CallCompletedCallback1(v8::Isolate*) { v8::base::OS::Print("Firing callback 1.\n"); callback_fired ^= 1; // Toggle first bit. } -void CallCompletedCallback2() { +void CallCompletedCallback2(v8::Isolate*) { v8::base::OS::Print("Firing callback 2.\n"); callback_fired ^= 2; // Toggle second bit. } +void BeforeCallEnteredCallback1(v8::Isolate*) { + v8::base::OS::Print("Firing before call entered callback 1.\n"); + before_call_entered_callback_count1++; +} + + +void BeforeCallEnteredCallback2(v8::Isolate*) { + v8::base::OS::Print("Firing before call entered callback 2.\n"); + before_call_entered_callback_count2++; +} + + void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) { int32_t level = args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust(); @@ -20378,36 +20850,54 @@ TEST(CallCompletedCallback) { env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1); env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1); env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2); + env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1); + env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback2); + env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1); v8::base::OS::Print("--- Script (1) ---\n"); + callback_fired = 0; + before_call_entered_callback_count1 = 0; + before_call_entered_callback_count2 = 0; Local<Script> script = v8::Script::Compile(env.local(), v8_str("recursion(0)")).ToLocalChecked(); script->Run(env.local()).ToLocalChecked(); CHECK_EQ(3, callback_fired); + CHECK_EQ(4, before_call_entered_callback_count1); + CHECK_EQ(4, before_call_entered_callback_count2); v8::base::OS::Print("\n--- Script (2) ---\n"); callback_fired = 0; + before_call_entered_callback_count1 = 0; + before_call_entered_callback_count2 = 0; env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1); + env->GetIsolate()->RemoveBeforeCallEnteredCallback( + BeforeCallEnteredCallback1); script->Run(env.local()).ToLocalChecked(); CHECK_EQ(2, callback_fired); + CHECK_EQ(0, before_call_entered_callback_count1); + CHECK_EQ(4, before_call_entered_callback_count2); v8::base::OS::Print("\n--- Function ---\n"); callback_fired = 0; + before_call_entered_callback_count1 = 0; + before_call_entered_callback_count2 = 0; Local<Function> recursive_function = Local<Function>::Cast( env->Global()->Get(env.local(), v8_str("recursion")).ToLocalChecked()); v8::Local<Value> args[] = {v8_num(0)}; recursive_function->Call(env.local(), env->Global(), 1, args) .ToLocalChecked(); CHECK_EQ(2, callback_fired); + CHECK_EQ(0, before_call_entered_callback_count1); + CHECK_EQ(4, before_call_entered_callback_count2); } -void CallCompletedCallbackNoException() { +void CallCompletedCallbackNoException(v8::Isolate*) { v8::HandleScope scope(CcTest::isolate()); CompileRun("1+1;"); } -void CallCompletedCallbackException() { +void CallCompletedCallbackException(v8::Isolate*) { v8::HandleScope scope(CcTest::isolate()); CompileRun("throw 'second exception';"); } @@ -21676,9 +22166,8 @@ class RequestInterruptTestWithMethodCall v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); v8::Local<v8::Template> proto = t->PrototypeTemplate(); proto->Set(v8_str("shouldContinue"), - Function::New(env_.local(), ShouldContinueCallback, - v8::External::New(isolate_, this)) - .ToLocalChecked()); + FunctionTemplate::New(isolate_, ShouldContinueCallback, + v8::External::New(isolate_, this))); CHECK(env_->Global() ->Set(env_.local(), v8_str("Klass"), t->GetFunction(env_.local()).ToLocalChecked()) @@ -21744,9 +22233,8 @@ class RequestInterruptTestWithMethodCallAndInterceptor v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_); v8::Local<v8::Template> proto = t->PrototypeTemplate(); proto->Set(v8_str("shouldContinue"), - Function::New(env_.local(), ShouldContinueCallback, - v8::External::New(isolate_, this)) - .ToLocalChecked()); + FunctionTemplate::New(isolate_, ShouldContinueCallback, + v8::External::New(isolate_, this))); v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate(); instance_template->SetHandler( v8::NamedPropertyHandlerConfiguration(EmptyInterceptor)); @@ -21958,7 +22446,7 @@ THREADED_TEST(FunctionNew) { ->get_api_func_data() ->serial_number()), i_isolate); - auto cache = i_isolate->function_cache(); + auto cache = i_isolate->template_instantiations_cache(); CHECK(cache->Lookup(serial_number)->IsTheHole()); // Verify that each Function::New creates a new function instance Local<Object> data2 = v8::Object::New(isolate); @@ -22034,7 +22522,6 @@ class ApiCallOptimizationChecker { static void OptimizationCallback( const v8::FunctionCallbackInfo<v8::Value>& info) { - CHECK(callee == info.Callee()); CHECK(data == info.Data()); CHECK(receiver == info.This()); if (info.Length() == 1) { @@ -23699,16 +24186,16 @@ TEST(SealHandleScopeNested) { static bool access_was_called = false; - static bool AccessAlwaysAllowedWithFlag(Local<v8::Context> accessing_context, - Local<v8::Object> accessed_object) { + Local<v8::Object> accessed_object, + Local<v8::Value> data) { access_was_called = true; return true; } - static bool AccessAlwaysBlockedWithFlag(Local<v8::Context> accessing_context, - Local<v8::Object> accessed_object) { + Local<v8::Object> accessed_object, + Local<v8::Value> data) { access_was_called = true; return false; } @@ -23970,6 +24457,37 @@ static void ExtrasBindingTestRuntimeFunction( args.GetReturnValue().Set(v8_num(7)); } +TEST(ExtrasFunctionSource) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + LocalContext env; + + v8::Local<v8::Object> binding = env->GetExtrasBindingObject(); + + // Functions defined in extras do not expose source code. + auto func = binding->Get(env.local(), v8_str("testFunctionToString")) + .ToLocalChecked() + .As<v8::Function>(); + auto undefined = v8::Undefined(isolate); + auto result = func->Call(env.local(), undefined, 0, {}) + .ToLocalChecked() + .As<v8::String>(); + CHECK(result->StrictEquals(v8_str("function foo() { [native code] }"))); + + // Functions defined in extras do not show up in the stack trace. + auto wrapper = binding->Get(env.local(), v8_str("testStackTrace")) + .ToLocalChecked() + .As<v8::Function>(); + CHECK(env->Global()->Set(env.local(), v8_str("wrapper"), wrapper).FromJust()); + ExpectString( + "function f(x) { return wrapper(x) }" + "function g() { return new Error().stack; }" + "f(g)", + "Error\n" + " at g (<anonymous>:1:58)\n" + " at f (<anonymous>:1:24)\n" + " at <anonymous>:1:78"); +} TEST(ExtrasBindingObject) { v8::Isolate* isolate = CcTest::isolate(); @@ -24318,7 +24836,6 @@ TEST(AbortOnUncaughtExceptionNoAbort) { TEST(AccessCheckedIsConcatSpreadable) { - i::FLAG_harmony_concat_spreadable = true; v8::Isolate* isolate = CcTest::isolate(); HandleScope scope(isolate); LocalContext env; diff --git a/deps/v8/test/cctest/test-asm-validator.cc b/deps/v8/test/cctest/test-asm-validator.cc index fae75008c7..207b915378 100644 --- a/deps/v8/test/cctest/test-asm-validator.cc +++ b/deps/v8/test/cctest/test-asm-validator.cc @@ -16,14 +16,15 @@ #include "test/cctest/expression-type-collector-macros.h" // Macros for function types. -#define FUNC_V_TYPE Bounds(Type::Function(Type::Undefined(zone), zone)) +#define FUNC_FOREIGN_TYPE Bounds(Type::Function(Type::Any(), zone)) +#define FUNC_V_TYPE Bounds(Type::Function(Type::Undefined(), zone)) #define FUNC_I_TYPE Bounds(Type::Function(cache.kAsmSigned, zone)) #define FUNC_F_TYPE Bounds(Type::Function(cache.kAsmFloat, zone)) #define FUNC_D_TYPE Bounds(Type::Function(cache.kAsmDouble, zone)) #define FUNC_D2D_TYPE \ Bounds(Type::Function(cache.kAsmDouble, cache.kAsmDouble, zone)) #define FUNC_N2F_TYPE \ - Bounds(Type::Function(cache.kAsmFloat, Type::Number(zone), zone)) + Bounds(Type::Function(cache.kAsmFloat, Type::Number(), zone)) #define FUNC_I2I_TYPE \ Bounds(Type::Function(cache.kAsmSigned, cache.kAsmInt, zone)) #define FUNC_II2D_TYPE \ @@ -33,11 +34,10 @@ #define FUNC_DD2D_TYPE \ Bounds(Type::Function(cache.kAsmDouble, cache.kAsmDouble, cache.kAsmDouble, \ zone)) -#define FUNC_NN2N_TYPE \ - Bounds(Type::Function(Type::Number(zone), Type::Number(zone), \ - Type::Number(zone), zone)) +#define FUNC_NN2N_TYPE \ + Bounds(Type::Function(Type::Number(), Type::Number(), Type::Number(), zone)) #define FUNC_N2N_TYPE \ - Bounds(Type::Function(Type::Number(zone), Type::Number(zone), zone)) + Bounds(Type::Function(Type::Number(), Type::Number(), zone)) // Macros for array types. #define FLOAT64_ARRAY_TYPE Bounds(Type::Array(cache.kAsmDouble, zone)) @@ -265,7 +265,7 @@ TEST(ValidateMinimum) { } } // "use asm"; - CHECK_EXPR(Literal, Bounds(Type::String(zone))); + CHECK_EXPR(Literal, Bounds(Type::String())); // var exp = stdlib.Math.exp; CHECK_EXPR(Assignment, FUNC_D2D_TYPE) { CHECK_VAR(exp, FUNC_D2D_TYPE); @@ -518,12 +518,11 @@ void CheckStdlibShortcuts2(Zone* zone, ZoneVector<ExpressionTypeEntry>& types, CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) { #define CHECK_FUNC_TYPES_END_1() \ /* "use asm"; */ \ - CHECK_EXPR(Literal, Bounds(Type::String(zone))); \ + CHECK_EXPR(Literal, Bounds(Type::String())); \ /* stdlib shortcuts. */ \ CheckStdlibShortcuts1(zone, types, index, depth, cache); \ CheckStdlibShortcuts2(zone, types, index, depth, cache); - #define CHECK_FUNC_TYPES_END_2() \ /* return { foo: foo }; */ \ CHECK_EXPR(ObjectLiteral, Bounds::Unbounded()) { \ @@ -564,10 +563,10 @@ TEST(ReturnVoid) { "function foo() { bar(); }") { CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) { // return undefined; - CHECK_EXPR(Literal, Bounds(Type::Undefined(zone))); + CHECK_EXPR(Literal, Bounds(Type::Undefined())); } CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) { - CHECK_EXPR(Call, Bounds(Type::Undefined(zone))) { + CHECK_EXPR(Call, Bounds(Type::Undefined())) { CHECK_VAR(bar, FUNC_V_TYPE); } } @@ -582,7 +581,7 @@ TEST(EmptyBody) { "function foo() { bar(); }") { CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE); CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) { - CHECK_EXPR(Call, Bounds(Type::Undefined(zone))) { + CHECK_EXPR(Call, Bounds(Type::Undefined())) { CHECK_VAR(bar, FUNC_V_TYPE); } } @@ -602,7 +601,7 @@ TEST(DoesNothing) { } } CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) { - CHECK_EXPR(Call, Bounds(Type::Undefined(zone))) { + CHECK_EXPR(Call, Bounds(Type::Undefined())) { CHECK_VAR(bar, FUNC_V_TYPE); } } @@ -1066,7 +1065,7 @@ TEST(UnsignedDivide) { CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); } CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmSigned)) { - CHECK_EXPR(BinaryOperation, Bounds(Type::None(zone), Type::Any(zone))) { + CHECK_EXPR(BinaryOperation, Bounds(Type::None(), Type::Any())) { CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmUnsigned)) { CHECK_VAR(x, Bounds(cache.kAsmInt)); CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); @@ -1327,7 +1326,7 @@ TEST(Load1) { CHECK_EXPR(Property, Bounds(cache.kAsmInt)) { CHECK_VAR(i8, Bounds(cache.kInt8Array)); CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmSigned)) { - CHECK_VAR(x, Bounds(cache.kAsmSigned)); + CHECK_VAR(x, Bounds(cache.kAsmInt)); CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); } } @@ -1387,7 +1386,7 @@ TEST(Store1) { CHECK_EXPR(Property, Bounds::Unbounded()) { CHECK_VAR(i8, Bounds(cache.kInt8Array)); CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmSigned)) { - CHECK_VAR(x, Bounds(cache.kAsmSigned)); + CHECK_VAR(x, Bounds(cache.kAsmInt)); CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); } } @@ -1435,6 +1434,71 @@ TEST(StoreFloat) { CHECK_FUNC_TYPES_END } +TEST(StoreIntish) { + CHECK_FUNC_TYPES_BEGIN( + "function bar() { var x = 1; var y = 1; i32[0] = x + y; }\n" + "function foo() { bar(); }") { + CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) { + CHECK_EXPR(Assignment, Bounds(cache.kAsmInt)) { + CHECK_VAR(x, Bounds(cache.kAsmInt)); + CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); + } + CHECK_EXPR(Assignment, Bounds(cache.kAsmInt)) { + CHECK_VAR(y, Bounds(cache.kAsmInt)); + CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); + } + CHECK_EXPR(Assignment, Bounds(cache.kAsmInt)) { + CHECK_EXPR(Property, Bounds::Unbounded()) { + CHECK_VAR(i32, Bounds(cache.kInt32Array)); + CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); + } + CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmInt)) { + CHECK_VAR(x, Bounds(cache.kAsmInt)); + CHECK_VAR(y, Bounds(cache.kAsmInt)); + } + } + } + CHECK_SKIP(); + } + CHECK_FUNC_TYPES_END +} + +TEST(StoreFloatish) { + CHECK_FUNC_TYPES_BEGIN( + "function bar() { " + "var x = fround(1.0); " + "var y = fround(1.0); f32[0] = x + y; }\n" + "function foo() { bar(); }") { + CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) { + CHECK_EXPR(Assignment, Bounds(cache.kAsmFloat)) { + CHECK_VAR(x, Bounds(cache.kAsmFloat)); + CHECK_EXPR(Call, Bounds(cache.kAsmFloat)) { + CHECK_VAR(fround, FUNC_N2F_TYPE); + CHECK_EXPR(Literal, Bounds(cache.kAsmDouble)); + } + } + CHECK_EXPR(Assignment, Bounds(cache.kAsmFloat)) { + CHECK_VAR(y, Bounds(cache.kAsmFloat)); + CHECK_EXPR(Call, Bounds(cache.kAsmFloat)) { + CHECK_VAR(fround, FUNC_N2F_TYPE); + CHECK_EXPR(Literal, Bounds(cache.kAsmDouble)); + } + } + CHECK_EXPR(Assignment, Bounds(cache.kAsmFloat)) { + CHECK_EXPR(Property, Bounds::Unbounded()) { + CHECK_VAR(f32, Bounds(cache.kFloat32Array)); + CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); + } + CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmFloat)) { + CHECK_VAR(x, Bounds(cache.kAsmFloat)); + CHECK_VAR(y, Bounds(cache.kAsmFloat)); + } + } + } + CHECK_SKIP(); + } + CHECK_FUNC_TYPES_END +} TEST(Load1Constant) { CHECK_FUNC_TYPES_BEGIN( @@ -1522,7 +1586,9 @@ TEST(FunctionTables) { CHECK_EXPR(Property, FUNC_I2I_TYPE) { CHECK_VAR(table1, FUNC_I2I_ARRAY_TYPE); CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmSigned)) { - CHECK_VAR(x, Bounds(cache.kAsmSigned)); + // TODO(bradnelson): revert this + // CHECK_VAR(x, Bounds(cache.kAsmSigned)); + CHECK_VAR(x, Bounds(cache.kAsmInt)); CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); } } @@ -1711,9 +1777,9 @@ TEST(MismatchedReturnTypeExpression) { TEST(AssignToFloatishToF64) { CHECK_FUNC_ERROR( - "function bar() { var v = fround(1.0); f32[0] = v + fround(1.0); }\n" + "function bar() { var v = fround(1.0); f64[0] = v + fround(1.0); }\n" "function foo() { bar(); }", - "asm: line 39: intish or floatish assignment\n"); + "asm: line 39: floatish assignment to double array\n"); } @@ -1724,8 +1790,8 @@ TEST(ForeignFunction) { "function foo() { bar(); }") { CHECK_EXPR(FunctionLiteral, FUNC_I_TYPE) { CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmSigned)) { - CHECK_EXPR(Call, Bounds(Type::Number(zone))) { - CHECK_VAR(baz, Bounds(Type::Any(zone))); + CHECK_EXPR(Call, Bounds(cache.kAsmSigned)) { + CHECK_VAR(baz, FUNC_FOREIGN_TYPE); CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); } @@ -1739,9 +1805,9 @@ TEST(ForeignFunction) { } } CHECK_FUNC_TYPES_END_1() - CHECK_EXPR(Assignment, Bounds(Type::Any(zone))) { - CHECK_VAR(baz, Bounds(Type::Any(zone))); - CHECK_EXPR(Property, Bounds(Type::Any(zone))) { + CHECK_EXPR(Assignment, Bounds(FUNC_FOREIGN_TYPE)) { + CHECK_VAR(baz, Bounds(FUNC_FOREIGN_TYPE)); + CHECK_EXPR(Property, Bounds(FUNC_FOREIGN_TYPE)) { CHECK_VAR(foreign, Bounds::Unbounded()); CHECK_EXPR(Literal, Bounds::Unbounded()); } @@ -1749,6 +1815,28 @@ TEST(ForeignFunction) { CHECK_FUNC_TYPES_END_2() } +TEST(ByteArray) { + // Forbidden by asm.js spec, present in embenchen. + CHECK_FUNC_TYPES_BEGIN( + "function bar() { var x = 0; i8[x] = 2; }\n" + "function foo() { bar(); }") { + CHECK_EXPR(FunctionLiteral, FUNC_V_TYPE) { + CHECK_EXPR(Assignment, Bounds(cache.kAsmInt)) { + CHECK_VAR(x, Bounds(cache.kAsmInt)); + CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); + } + CHECK_EXPR(Assignment, Bounds(cache.kAsmInt)) { + CHECK_EXPR(Property, Bounds::Unbounded()) { + CHECK_VAR(i8, Bounds(cache.kInt8Array)); + CHECK_VAR(x, Bounds(cache.kAsmSigned)); + } + CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); + } + } + CHECK_SKIP(); + } + CHECK_FUNC_TYPES_END +} TEST(BadExports) { HARNESS_PREAMBLE() @@ -1767,7 +1855,14 @@ TEST(BadExports) { TEST(NestedHeapAssignment) { CHECK_FUNC_ERROR( - "function bar() { var x = 0; i8[x = 1] = 2; }\n" + "function bar() { var x = 0; i16[x = 1] = 2; }\n" + "function foo() { bar(); }", + "asm: line 39: expected >> in heap access\n"); +} + +TEST(BadOperatorHeapAssignment) { + CHECK_FUNC_ERROR( + "function bar() { var x = 0; i16[x & 1] = 2; }\n" "function foo() { bar(); }", "asm: line 39: expected >> in heap access\n"); } @@ -1786,7 +1881,7 @@ TEST(BadStandardFunctionCallOutside) { "var s0 = sin(0);\n" "function bar() { }\n" "function foo() { bar(); }", - "asm: line 39: calls forbidden outside function bodies\n"); + "asm: line 39: illegal variable reference in module body\n"); } @@ -1795,7 +1890,7 @@ TEST(BadFunctionCallOutside) { "function bar() { return 0.0; }\n" "var s0 = bar(0);\n" "function foo() { bar(); }", - "asm: line 40: calls forbidden outside function bodies\n"); + "asm: line 40: illegal variable reference in module body\n"); } @@ -1835,7 +1930,7 @@ TEST(NestedAssignmentInHeap) { CHECK_EXPR(Property, Bounds::Unbounded()) { CHECK_VAR(i8, Bounds(cache.kInt8Array)); CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmSigned)) { - CHECK_EXPR(Assignment, Bounds(cache.kAsmSigned)) { + CHECK_EXPR(Assignment, Bounds(cache.kAsmInt)) { CHECK_VAR(x, Bounds(cache.kAsmInt)); CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); } @@ -2007,7 +2102,7 @@ TEST(SwitchTest) { CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); } } - CHECK_EXPR(Literal, Bounds(Type::Undefined(zone))); + CHECK_EXPR(Literal, Bounds(Type::Undefined())); CHECK_VAR(.switch_tag, Bounds(cache.kAsmSigned)); // case 1: return 23; CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); @@ -2048,3 +2143,202 @@ TEST(BadSwitchOrder) { "function foo() { bar(); }", "asm: line 39: default case out of order\n"); } + +TEST(BadForeignCall) { + const char test_function[] = + "function TestModule(stdlib, foreign, buffer) {\n" + " \"use asm\";\n" + " var ffunc = foreign.foo;\n" + " function test1() { var x = 0; ffunc(x); }\n" + " return { testFunc1: test1 };\n" + "}\n"; + v8::V8::Initialize(); + HandleAndZoneScope handles; + Zone* zone = handles.main_zone(); + ZoneVector<ExpressionTypeEntry> types(zone); + CHECK_EQ( + "asm: line 4: foreign call argument expected to be int, double, or " + "fixnum\n", + Validate(zone, test_function, &types)); +} + +TEST(BadImports) { + const char test_function[] = + "function TestModule(stdlib, foreign, buffer) {\n" + " \"use asm\";\n" + " var fint = (foreign.bar | 0) | 0;\n" + " function test1() {}\n" + " return { testFunc1: test1 };\n" + "}\n"; + v8::V8::Initialize(); + HandleAndZoneScope handles; + Zone* zone = handles.main_zone(); + ZoneVector<ExpressionTypeEntry> types(zone); + CHECK_EQ("asm: line 3: illegal computation inside module body\n", + Validate(zone, test_function, &types)); +} + +TEST(BadVariableReference) { + const char test_function[] = + "function TestModule(stdlib, foreign, buffer) {\n" + " \"use asm\";\n" + " var x = 0;\n" + " var y = x;\n" + " function test1() {}\n" + " return { testFunc1: test1 };\n" + "}\n"; + v8::V8::Initialize(); + HandleAndZoneScope handles; + Zone* zone = handles.main_zone(); + ZoneVector<ExpressionTypeEntry> types(zone); + CHECK_EQ("asm: line 4: illegal variable reference in module body\n", + Validate(zone, test_function, &types)); +} + +TEST(BadForeignVariableReferenceValueOr) { + const char test_function[] = + "function TestModule(stdlib, foreign, buffer) {\n" + " \"use asm\";\n" + " var fint = foreign.bar | 1;\n" + "}\n"; + v8::V8::Initialize(); + HandleAndZoneScope handles; + Zone* zone = handles.main_zone(); + ZoneVector<ExpressionTypeEntry> types(zone); + CHECK_EQ("asm: line 3: illegal integer annotation value\n", + Validate(zone, test_function, &types)); +} + +TEST(BadForeignVariableReferenceValueOrDot) { + const char test_function[] = + "function TestModule(stdlib, foreign, buffer) {\n" + " \"use asm\";\n" + " var fint = foreign.bar | 1.0;\n" + "}\n"; + v8::V8::Initialize(); + HandleAndZoneScope handles; + Zone* zone = handles.main_zone(); + ZoneVector<ExpressionTypeEntry> types(zone); + CHECK_EQ("asm: line 3: illegal integer annotation value\n", + Validate(zone, test_function, &types)); +} + +TEST(BadForeignVariableReferenceValueMul) { + const char test_function[] = + "function TestModule(stdlib, foreign, buffer) {\n" + " \"use asm\";\n" + " var fint = foreign.bar * 2.0;\n" + "}\n"; + v8::V8::Initialize(); + HandleAndZoneScope handles; + Zone* zone = handles.main_zone(); + ZoneVector<ExpressionTypeEntry> types(zone); + CHECK_EQ("asm: line 3: illegal double annotation value\n", + Validate(zone, test_function, &types)); +} + +TEST(BadForeignVariableReferenceValueMulNoDot) { + const char test_function[] = + "function TestModule(stdlib, foreign, buffer) {\n" + " \"use asm\";\n" + " var fint = foreign.bar * 1;\n" + "}\n"; + v8::V8::Initialize(); + HandleAndZoneScope handles; + Zone* zone = handles.main_zone(); + ZoneVector<ExpressionTypeEntry> types(zone); + CHECK_EQ("asm: line 3: ill-typed arithmetic operation\n", + Validate(zone, test_function, &types)); +} + +TEST(Imports) { + const char test_function[] = + "function TestModule(stdlib, foreign, buffer) {\n" + " \"use asm\";\n" + " var ffunc = foreign.foo;\n" + " var fint = foreign.bar | 0;\n" + " var fdouble = +foreign.baz;\n" + " function test1() { return ffunc(fint|0, fdouble) | 0; }\n" + " function test2() { return +ffunc(fdouble, fint|0); }\n" + " return { testFunc1: test1, testFunc2: test2 };\n" + "}\n"; + + v8::V8::Initialize(); + HandleAndZoneScope handles; + Zone* zone = handles.main_zone(); + ZoneVector<ExpressionTypeEntry> types(zone); + CHECK_EQ("", Validate(zone, test_function, &types)); + TypeCache cache; + + CHECK_TYPES_BEGIN { + // Module. + CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) { + // function test1 + CHECK_EXPR(FunctionLiteral, FUNC_I_TYPE) { + CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmSigned)) { + CHECK_EXPR(Call, Bounds(cache.kAsmSigned)) { + CHECK_VAR(ffunc, FUNC_FOREIGN_TYPE); + CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmSigned)) { + CHECK_VAR(fint, Bounds(cache.kAsmInt)); + CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); + } + CHECK_VAR(fdouble, Bounds(cache.kAsmDouble)); + } + CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); + } + } + // function test2 + CHECK_EXPR(FunctionLiteral, FUNC_D_TYPE) { + CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmDouble)) { + CHECK_EXPR(Call, Bounds(cache.kAsmDouble)) { + CHECK_VAR(ffunc, FUNC_FOREIGN_TYPE); + CHECK_VAR(fdouble, Bounds(cache.kAsmDouble)); + CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmSigned)) { + CHECK_VAR(fint, Bounds(cache.kAsmInt)); + CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); + } + } + CHECK_EXPR(Literal, Bounds(cache.kAsmDouble)); + } + } + // "use asm"; + CHECK_EXPR(Literal, Bounds(Type::String())); + // var func = foreign.foo; + CHECK_EXPR(Assignment, Bounds(FUNC_FOREIGN_TYPE)) { + CHECK_VAR(ffunc, Bounds(FUNC_FOREIGN_TYPE)); + CHECK_EXPR(Property, Bounds(FUNC_FOREIGN_TYPE)) { + CHECK_VAR(foreign, Bounds::Unbounded()); + CHECK_EXPR(Literal, Bounds::Unbounded()); + } + } + // var fint = foreign.bar | 0; + CHECK_EXPR(Assignment, Bounds(cache.kAsmInt)) { + CHECK_VAR(fint, Bounds(cache.kAsmInt)); + CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmSigned)) { + CHECK_EXPR(Property, Bounds(Type::Number())) { + CHECK_VAR(foreign, Bounds::Unbounded()); + CHECK_EXPR(Literal, Bounds::Unbounded()); + } + CHECK_EXPR(Literal, Bounds(cache.kAsmFixnum)); + } + } + // var fdouble = +foreign.baz; + CHECK_EXPR(Assignment, Bounds(cache.kAsmDouble)) { + CHECK_VAR(fdouble, Bounds(cache.kAsmDouble)); + CHECK_EXPR(BinaryOperation, Bounds(cache.kAsmDouble)) { + CHECK_EXPR(Property, Bounds(Type::Number())) { + CHECK_VAR(foreign, Bounds::Unbounded()); + CHECK_EXPR(Literal, Bounds::Unbounded()); + } + CHECK_EXPR(Literal, Bounds(cache.kAsmDouble)); + } + } + // return { testFunc1: test1, testFunc2: test2 }; + CHECK_EXPR(ObjectLiteral, Bounds::Unbounded()) { + CHECK_VAR(test1, FUNC_I_TYPE); + CHECK_VAR(test2, FUNC_D_TYPE); + } + } + } + CHECK_TYPES_END +} diff --git a/deps/v8/test/cctest/test-assembler-arm.cc b/deps/v8/test/cctest/test-assembler-arm.cc index 563b050c48..68eaab16f6 100644 --- a/deps/v8/test/cctest/test-assembler-arm.cc +++ b/deps/v8/test/cctest/test-assembler-arm.cc @@ -1819,6 +1819,55 @@ TEST(uxtah) { } +#define TEST_RBIT(expected_, input_) \ + t.input = input_; \ + t.result = 0; \ + dummy = CALL_GENERATED_CODE(isolate, f, &t, 0, 0, 0, 0); \ + CHECK_EQ(expected_, t.result); + + +TEST(rbit) { + CcTest::InitializeVM(); + Isolate* const isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + Assembler assm(isolate, nullptr, 0); + + if (CpuFeatures::IsSupported(ARMv7)) { + CpuFeatureScope scope(&assm, ARMv7); + + typedef struct { + uint32_t input; + uint32_t result; + } T; + T t; + + __ ldr(r1, MemOperand(r0, offsetof(T, input))); + __ rbit(r1, r1); + __ str(r1, MemOperand(r0, offsetof(T, result))); + __ bx(lr); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + + F3 f = FUNCTION_CAST<F3>(code->entry()); + Object* dummy = NULL; + TEST_RBIT(0xffffffff, 0xffffffff); + TEST_RBIT(0x00000000, 0x00000000); + TEST_RBIT(0xffff0000, 0x0000ffff); + TEST_RBIT(0xff00ff00, 0x00ff00ff); + TEST_RBIT(0xf0f0f0f0, 0x0f0f0f0f); + TEST_RBIT(0x1e6a2c48, 0x12345678); + USE(dummy); + } +} + + TEST(code_relative_offset) { // Test extracting the offset of a label from the beginning of the code // in a register. diff --git a/deps/v8/test/cctest/test-assembler-mips.cc b/deps/v8/test/cctest/test-assembler-mips.cc index 4f986cea9b..1928a753fd 100644 --- a/deps/v8/test/cctest/test-assembler-mips.cc +++ b/deps/v8/test/cctest/test-assembler-mips.cc @@ -384,6 +384,14 @@ TEST(MIPS3) { TEST(MIPS4) { + // Exchange between GP anf FP registers is done through memory + // on FPXX compiled binaries and architectures that do not support + // MTHC1 and MTFC1. If this is the case, skipping this test. + if (IsFpxxMode() && + (IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kLoongson))) { + return; + } + // Test moves between floating point and integer registers. CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); @@ -403,7 +411,7 @@ TEST(MIPS4) { __ ldc1(f6, MemOperand(a0, offsetof(T, b)) ); // Swap f4 and f6, by using four integer registers, t0-t3. - if (!IsFp64Mode()) { + if (IsFp32Mode()) { __ mfc1(t0, f4); __ mfc1(t1, f5); __ mfc1(t2, f6); @@ -415,6 +423,7 @@ TEST(MIPS4) { __ mtc1(t3, f5); } else { CHECK(!IsMipsArchVariant(kMips32r1) && !IsMipsArchVariant(kLoongson)); + DCHECK(IsFp64Mode() || IsFpxxMode()); __ mfc1(t0, f4); __ mfhc1(t1, f4); __ mfc1(t2, f6); @@ -425,6 +434,7 @@ TEST(MIPS4) { __ mtc1(t2, f4); __ mthc1(t3, f4); } + // Store the swapped f4 and f5 back to memory. __ sdc1(f4, MemOperand(a0, offsetof(T, a)) ); __ sdc1(f6, MemOperand(a0, offsetof(T, c)) ); @@ -811,8 +821,6 @@ TEST(MIPS9) { TEST(MIPS10) { // Test conversions between doubles and words. - // Test maps double to FP reg pairs in fp32 mode - // and into FP reg in fp64 mode. CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); @@ -830,24 +838,16 @@ TEST(MIPS10) { Assembler assm(isolate, NULL, 0); Label L, C; - if (!IsMipsArchVariant(kMips32r2)) return; + if (IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kLoongson)) return; // Load all structure elements to registers. // (f0, f1) = a (fp32), f0 = a (fp64) __ ldc1(f0, MemOperand(a0, offsetof(T, a))); - if (IsFp64Mode()) { - __ mfc1(t0, f0); // t0 = f0(31..0) - __ mfhc1(t1, f0); // t1 = sign_extend(f0(63..32)) - __ sw(t0, MemOperand(a0, offsetof(T, dbl_mant))); // dbl_mant = t0 - __ sw(t1, MemOperand(a0, offsetof(T, dbl_exp))); // dbl_exp = t1 - } else { - // Save the raw bits of the double. - __ mfc1(t0, f0); // t0 = a1 - __ mfc1(t1, f1); // t1 = a2 - __ sw(t0, MemOperand(a0, offsetof(T, dbl_mant))); // dbl_mant = t0 - __ sw(t1, MemOperand(a0, offsetof(T, dbl_exp))); // dbl_exp = t1 - } + __ mfc1(t0, f0); // t0 = f0(31..0) + __ mfhc1(t1, f0); // t1 = sign_extend(f0(63..32)) + __ sw(t0, MemOperand(a0, offsetof(T, dbl_mant))); // dbl_mant = t0 + __ sw(t1, MemOperand(a0, offsetof(T, dbl_exp))); // dbl_exp = t1 // Convert double in f0 to word, save hi/lo parts. __ cvt_w_d(f0, f0); // a_word = (word)a @@ -1456,10 +1456,10 @@ TEST(min_max) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); - MacroAssembler assm(isolate, NULL, 0, + MacroAssembler assm(isolate, nullptr, 0, v8::internal::CodeObjectRequired::kYes); - typedef struct test_float { + struct TestFloat { double a; double b; double c; @@ -1468,21 +1468,35 @@ TEST(min_max) { float f; float g; float h; - } TestFloat; + }; TestFloat test; - const double double_nan = std::numeric_limits<double>::quiet_NaN(); - const float float_nan = std::numeric_limits<float>::quiet_NaN(); - const int kTableLength = 5; - double inputsa[kTableLength] = {2.0, 3.0, double_nan, 3.0, double_nan}; - double inputsb[kTableLength] = {3.0, 2.0, 3.0, double_nan, double_nan}; - double outputsdmin[kTableLength] = {2.0, 2.0, 3.0, 3.0, double_nan}; - double outputsdmax[kTableLength] = {3.0, 3.0, 3.0, 3.0, double_nan}; - - float inputse[kTableLength] = {2.0, 3.0, float_nan, 3.0, float_nan}; - float inputsf[kTableLength] = {3.0, 2.0, 3.0, float_nan, float_nan}; - float outputsfmin[kTableLength] = {2.0, 2.0, 3.0, 3.0, float_nan}; - float outputsfmax[kTableLength] = {3.0, 3.0, 3.0, 3.0, float_nan}; + const double dnan = std::numeric_limits<double>::quiet_NaN(); + const double dinf = std::numeric_limits<double>::infinity(); + const double dminf = -std::numeric_limits<double>::infinity(); + const float fnan = std::numeric_limits<float>::quiet_NaN(); + const float finf = std::numeric_limits<float>::infinity(); + const float fminf = std::numeric_limits<float>::infinity(); + const int kTableLength = 13; + double inputsa[kTableLength] = {2.0, 3.0, dnan, 3.0, -0.0, 0.0, dinf, + dnan, 42.0, dinf, dminf, dinf, dnan}; + double inputsb[kTableLength] = {3.0, 2.0, 3.0, dnan, 0.0, -0.0, dnan, + dinf, dinf, 42.0, dinf, dminf, dnan}; + double outputsdmin[kTableLength] = {2.0, 2.0, 3.0, 3.0, -0.0, + -0.0, dinf, dinf, 42.0, 42.0, + dminf, dminf, dnan}; + double outputsdmax[kTableLength] = {3.0, 3.0, 3.0, 3.0, 0.0, 0.0, dinf, + dinf, dinf, dinf, dinf, dinf, dnan}; + + float inputse[kTableLength] = {2.0, 3.0, fnan, 3.0, -0.0, 0.0, finf, + fnan, 42.0, finf, fminf, finf, fnan}; + float inputsf[kTableLength] = {3.0, 2.0, 3.0, fnan, -0.0, 0.0, fnan, + finf, finf, 42.0, finf, fminf, fnan}; + float outputsfmin[kTableLength] = {2.0, 2.0, 3.0, 3.0, -0.0, + -0.0, finf, finf, 42.0, 42.0, + fminf, fminf, fnan}; + float outputsfmax[kTableLength] = {3.0, 3.0, 3.0, 3.0, 0.0, 0.0, finf, + finf, finf, finf, finf, finf, fnan}; __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, a))); __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, b))); @@ -1863,16 +1877,20 @@ TEST(Cvt_d_uw) { TEST(mina_maxa) { if (IsMipsArchVariant(kMips32r6)) { - const int kTableLength = 15; + const int kTableLength = 23; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); - MacroAssembler assm(isolate, NULL, 0, + MacroAssembler assm(isolate, nullptr, 0, v8::internal::CodeObjectRequired::kYes); - const double double_nan = std::numeric_limits<double>::quiet_NaN(); - const float float_nan = std::numeric_limits<float>::quiet_NaN(); - - typedef struct test_float { + const double dnan = std::numeric_limits<double>::quiet_NaN(); + const double dinf = std::numeric_limits<double>::infinity(); + const double dminf = -std::numeric_limits<double>::infinity(); + const float fnan = std::numeric_limits<float>::quiet_NaN(); + const float finf = std::numeric_limits<float>::infinity(); + const float fminf = std::numeric_limits<float>::infinity(); + + struct TestFloat { double a; double b; double resd; @@ -1881,41 +1899,34 @@ TEST(mina_maxa) { float d; float resf; float resf1; - }TestFloat; + }; TestFloat test; double inputsa[kTableLength] = { - 5.3, 4.8, 6.1, 9.8, 9.8, 9.8, -10.0, -8.9, - -9.8, -10.0, -8.9, -9.8, double_nan, 3.0, double_nan - }; + 5.3, 4.8, 6.1, 9.8, 9.8, 9.8, -10.0, -8.9, -9.8, -10.0, -8.9, -9.8, + dnan, 3.0, -0.0, 0.0, dinf, dnan, 42.0, dinf, dminf, dinf, dnan}; double inputsb[kTableLength] = { - 4.8, 5.3, 6.1, -10.0, -8.9, -9.8, 9.8, 9.8, - 9.8, -9.8, -11.2, -9.8, 3.0, double_nan, double_nan - }; + 4.8, 5.3, 6.1, -10.0, -8.9, -9.8, 9.8, 9.8, 9.8, -9.8, -11.2, -9.8, + 3.0, dnan, 0.0, -0.0, dnan, dinf, dinf, 42.0, dinf, dminf, dnan}; double resd[kTableLength] = { - 4.8, 4.8, 6.1, 9.8, -8.9, -9.8, 9.8, -8.9, - -9.8, -9.8, -8.9, -9.8, 3.0, 3.0, double_nan - }; + 4.8, 4.8, 6.1, 9.8, -8.9, -9.8, 9.8, -8.9, -9.8, -9.8, -8.9, -9.8, + 3.0, 3.0, -0.0, -0.0, dinf, dinf, 42.0, 42.0, dminf, dminf, dnan}; double resd1[kTableLength] = { - 5.3, 5.3, 6.1, -10.0, 9.8, 9.8, -10.0, 9.8, - 9.8, -10.0, -11.2, -9.8, 3.0, 3.0, double_nan - }; + 5.3, 5.3, 6.1, -10.0, 9.8, 9.8, -10.0, 9.8, 9.8, -10.0, -11.2, -9.8, + 3.0, 3.0, 0.0, 0.0, dinf, dinf, dinf, dinf, dinf, dinf, dnan}; float inputsc[kTableLength] = { - 5.3, 4.8, 6.1, 9.8, 9.8, 9.8, -10.0, -8.9, - -9.8, -10.0, -8.9, -9.8, float_nan, 3.0, float_nan - }; - float inputsd[kTableLength] = { - 4.8, 5.3, 6.1, -10.0, -8.9, -9.8, 9.8, 9.8, - 9.8, -9.8, -11.2, -9.8, 3.0, float_nan, float_nan - }; + 5.3, 4.8, 6.1, 9.8, 9.8, 9.8, -10.0, -8.9, -9.8, -10.0, -8.9, -9.8, + fnan, 3.0, -0.0, 0.0, finf, fnan, 42.0, finf, fminf, finf, fnan}; + float inputsd[kTableLength] = {4.8, 5.3, 6.1, -10.0, -8.9, -9.8, + 9.8, 9.8, 9.8, -9.8, -11.2, -9.8, + 3.0, fnan, -0.0, 0.0, fnan, finf, + finf, 42.0, finf, fminf, fnan}; float resf[kTableLength] = { - 4.8, 4.8, 6.1, 9.8, -8.9, -9.8, 9.8, -8.9, - -9.8, -9.8, -8.9, -9.8, 3.0, 3.0, float_nan - }; + 4.8, 4.8, 6.1, 9.8, -8.9, -9.8, 9.8, -8.9, -9.8, -9.8, -8.9, -9.8, + 3.0, 3.0, -0.0, -0.0, finf, finf, 42.0, 42.0, fminf, fminf, fnan}; float resf1[kTableLength] = { - 5.3, 5.3, 6.1, -10.0, 9.8, 9.8, -10.0, 9.8, - 9.8, -10.0, -11.2, -9.8, 3.0, 3.0, float_nan - }; + 5.3, 5.3, 6.1, -10.0, 9.8, 9.8, -10.0, 9.8, 9.8, -10.0, -11.2, -9.8, + 3.0, 3.0, 0.0, 0.0, finf, finf, finf, finf, finf, finf, fnan}; __ ldc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, b)) ); @@ -5024,8 +5035,7 @@ TEST(r6_jialc) { } } - -uint64_t run_addiupc(int32_t imm19) { +static uint32_t run_addiupc(int32_t imm19) { Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); @@ -5058,13 +5068,13 @@ TEST(r6_addiupc) { int32_t imm19; }; - struct TestCaseAddiupc tc[] = { - // imm19 - { -262144 }, // 0x40000 - { -1 }, // 0x7FFFF - { 0 }, - { 1 }, // 0x00001 - { 262143 } // 0x3FFFF + TestCaseAddiupc tc[] = { + // imm19 + {-262144}, // 0x40000 + {-1}, // 0x7FFFF + {0}, + {1}, // 0x00001 + {262143} // 0x3FFFF }; size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAddiupc); diff --git a/deps/v8/test/cctest/test-assembler-mips64.cc b/deps/v8/test/cctest/test-assembler-mips64.cc index 988083cadc..b979db29bb 100644 --- a/deps/v8/test/cctest/test-assembler-mips64.cc +++ b/deps/v8/test/cctest/test-assembler-mips64.cc @@ -1586,10 +1586,10 @@ TEST(min_max) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); - MacroAssembler assm(isolate, NULL, 0, + MacroAssembler assm(isolate, nullptr, 0, v8::internal::CodeObjectRequired::kYes); - typedef struct test_float { + struct TestFloat { double a; double b; double c; @@ -1598,21 +1598,35 @@ TEST(min_max) { float f; float g; float h; - } TestFloat; + }; TestFloat test; - const double double_nan = std::numeric_limits<double>::quiet_NaN(); - const float float_nan = std::numeric_limits<float>::quiet_NaN(); - const int kTableLength = 5; - double inputsa[kTableLength] = {2.0, 3.0, double_nan, 3.0, double_nan}; - double inputsb[kTableLength] = {3.0, 2.0, 3.0, double_nan, double_nan}; - double outputsdmin[kTableLength] = {2.0, 2.0, 3.0, 3.0, double_nan}; - double outputsdmax[kTableLength] = {3.0, 3.0, 3.0, 3.0, double_nan}; - - float inputse[kTableLength] = {2.0, 3.0, float_nan, 3.0, float_nan}; - float inputsf[kTableLength] = {3.0, 2.0, 3.0, float_nan, float_nan}; - float outputsfmin[kTableLength] = {2.0, 2.0, 3.0, 3.0, float_nan}; - float outputsfmax[kTableLength] = {3.0, 3.0, 3.0, 3.0, float_nan}; + const double dnan = std::numeric_limits<double>::quiet_NaN(); + const double dinf = std::numeric_limits<double>::infinity(); + const double dminf = -std::numeric_limits<double>::infinity(); + const float fnan = std::numeric_limits<float>::quiet_NaN(); + const float finf = std::numeric_limits<float>::infinity(); + const float fminf = std::numeric_limits<float>::infinity(); + const int kTableLength = 13; + double inputsa[kTableLength] = {2.0, 3.0, dnan, 3.0, -0.0, 0.0, dinf, + dnan, 42.0, dinf, dminf, dinf, dnan}; + double inputsb[kTableLength] = {3.0, 2.0, 3.0, dnan, 0.0, -0.0, dnan, + dinf, dinf, 42.0, dinf, dminf, dnan}; + double outputsdmin[kTableLength] = {2.0, 2.0, 3.0, 3.0, -0.0, + -0.0, dinf, dinf, 42.0, 42.0, + dminf, dminf, dnan}; + double outputsdmax[kTableLength] = {3.0, 3.0, 3.0, 3.0, 0.0, 0.0, dinf, + dinf, dinf, dinf, dinf, dinf, dnan}; + + float inputse[kTableLength] = {2.0, 3.0, fnan, 3.0, -0.0, 0.0, finf, + fnan, 42.0, finf, fminf, finf, fnan}; + float inputsf[kTableLength] = {3.0, 2.0, 3.0, fnan, -0.0, 0.0, fnan, + finf, finf, 42.0, finf, fminf, fnan}; + float outputsfmin[kTableLength] = {2.0, 2.0, 3.0, 3.0, -0.0, + -0.0, finf, finf, 42.0, 42.0, + fminf, fminf, fnan}; + float outputsfmax[kTableLength] = {3.0, 3.0, 3.0, 3.0, 0.0, 0.0, finf, + finf, finf, finf, finf, finf, fnan}; __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, a))); __ ldc1(f8, MemOperand(a0, offsetof(TestFloat, b))); @@ -1946,16 +1960,20 @@ TEST(rint_s) { TEST(mina_maxa) { if (kArchVariant == kMips64r6) { - const int kTableLength = 15; + const int kTableLength = 23; CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); - MacroAssembler assm(isolate, NULL, 0, + MacroAssembler assm(isolate, nullptr, 0, v8::internal::CodeObjectRequired::kYes); - const double double_nan = std::numeric_limits<double>::quiet_NaN(); - const float float_nan = std::numeric_limits<float>::quiet_NaN(); - - typedef struct test_float { + const double dnan = std::numeric_limits<double>::quiet_NaN(); + const double dinf = std::numeric_limits<double>::infinity(); + const double dminf = -std::numeric_limits<double>::infinity(); + const float fnan = std::numeric_limits<float>::quiet_NaN(); + const float finf = std::numeric_limits<float>::infinity(); + const float fminf = std::numeric_limits<float>::infinity(); + + struct TestFloat { double a; double b; double resd; @@ -1964,41 +1982,34 @@ TEST(mina_maxa) { float d; float resf; float resf1; - }TestFloat; + }; TestFloat test; double inputsa[kTableLength] = { - 5.3, 4.8, 6.1, 9.8, 9.8, 9.8, -10.0, -8.9, - -9.8, -10.0, -8.9, -9.8, double_nan, 3.0, double_nan - }; + 5.3, 4.8, 6.1, 9.8, 9.8, 9.8, -10.0, -8.9, -9.8, -10.0, -8.9, -9.8, + dnan, 3.0, -0.0, 0.0, dinf, dnan, 42.0, dinf, dminf, dinf, dnan}; double inputsb[kTableLength] = { - 4.8, 5.3, 6.1, -10.0, -8.9, -9.8, 9.8, 9.8, - 9.8, -9.8, -11.2, -9.8, 3.0, double_nan, double_nan - }; + 4.8, 5.3, 6.1, -10.0, -8.9, -9.8, 9.8, 9.8, 9.8, -9.8, -11.2, -9.8, + 3.0, dnan, 0.0, -0.0, dnan, dinf, dinf, 42.0, dinf, dminf, dnan}; double resd[kTableLength] = { - 4.8, 4.8, 6.1, 9.8, -8.9, -9.8, 9.8, -8.9, - -9.8, -9.8, -8.9, -9.8, 3.0, 3.0, double_nan - }; + 4.8, 4.8, 6.1, 9.8, -8.9, -9.8, 9.8, -8.9, -9.8, -9.8, -8.9, -9.8, + 3.0, 3.0, -0.0, -0.0, dinf, dinf, 42.0, 42.0, dminf, dminf, dnan}; double resd1[kTableLength] = { - 5.3, 5.3, 6.1, -10.0, 9.8, 9.8, -10.0, 9.8, - 9.8, -10.0, -11.2, -9.8, 3.0, 3.0, double_nan - }; + 5.3, 5.3, 6.1, -10.0, 9.8, 9.8, -10.0, 9.8, 9.8, -10.0, -11.2, -9.8, + 3.0, 3.0, 0.0, 0.0, dinf, dinf, dinf, dinf, dinf, dinf, dnan}; float inputsc[kTableLength] = { - 5.3, 4.8, 6.1, 9.8, 9.8, 9.8, -10.0, -8.9, - -9.8, -10.0, -8.9, -9.8, float_nan, 3.0, float_nan - }; - float inputsd[kTableLength] = { - 4.8, 5.3, 6.1, -10.0, -8.9, -9.8, 9.8, 9.8, - 9.8, -9.8, -11.2, -9.8, 3.0, float_nan, float_nan - }; + 5.3, 4.8, 6.1, 9.8, 9.8, 9.8, -10.0, -8.9, -9.8, -10.0, -8.9, -9.8, + fnan, 3.0, -0.0, 0.0, finf, fnan, 42.0, finf, fminf, finf, fnan}; + float inputsd[kTableLength] = {4.8, 5.3, 6.1, -10.0, -8.9, -9.8, + 9.8, 9.8, 9.8, -9.8, -11.2, -9.8, + 3.0, fnan, -0.0, 0.0, fnan, finf, + finf, 42.0, finf, fminf, fnan}; float resf[kTableLength] = { - 4.8, 4.8, 6.1, 9.8, -8.9, -9.8, 9.8, -8.9, - -9.8, -9.8, -8.9, -9.8, 3.0, 3.0, float_nan - }; + 4.8, 4.8, 6.1, 9.8, -8.9, -9.8, 9.8, -8.9, -9.8, -9.8, -8.9, -9.8, + 3.0, 3.0, -0.0, -0.0, finf, finf, 42.0, 42.0, fminf, fminf, fnan}; float resf1[kTableLength] = { - 5.3, 5.3, 6.1, -10.0, 9.8, 9.8, -10.0, 9.8, - 9.8, -10.0, -11.2, -9.8, 3.0, 3.0, float_nan - }; + 5.3, 5.3, 6.1, -10.0, 9.8, 9.8, -10.0, 9.8, 9.8, -10.0, -11.2, -9.8, + 3.0, 3.0, 0.0, 0.0, finf, finf, finf, finf, finf, finf, fnan}; __ ldc1(f2, MemOperand(a0, offsetof(TestFloat, a)) ); __ ldc1(f4, MemOperand(a0, offsetof(TestFloat, b)) ); @@ -4997,6 +5008,55 @@ TEST(r6_aui_family) { } +uint64_t run_li_macro(uint64_t rs, LiFlags mode) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + + __ li(a0, rs, mode); + __ mov(v0, a0); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(&desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint64_t res = reinterpret_cast<uint64_t>( + CALL_GENERATED_CODE(isolate, f, 0, 0, 0, 0, 0)); + + return res; +} + + +TEST(li_macro) { + CcTest::InitializeVM(); + + uint64_t inputs[] = { + 0x0000000000000000, 0x000000000000ffff, 0x00000000ffffffff, + 0x0000ffffffffffff, 0xffffffffffffffff, 0xffff000000000000, + 0xffffffff00000000, 0xffffffffffff0000, 0xffff0000ffff0000, + 0x0000ffffffff0000, 0x0000ffff0000ffff, 0x00007fffffffffff, + 0x7fffffffffffffff, 0x000000007fffffff, 0x00007fff7fffffff, + }; + + size_t nr_test_cases = sizeof(inputs) / sizeof(inputs[0]); + for (size_t i = 0; i < nr_test_cases; ++i) { + uint64_t res = run_li_macro(inputs[i], OPTIMIZE_SIZE); + CHECK_EQ(inputs[i], res); + res = run_li_macro(inputs[i], CONSTANT_SIZE); + CHECK_EQ(inputs[i], res); + if (is_int48(inputs[i])) { + res = run_li_macro(inputs[i], ADDRESS_LOAD); + CHECK_EQ(inputs[i], res); + } + } +} + + uint64_t run_lwpc(int offset) { Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); diff --git a/deps/v8/test/cctest/test-ast-expression-visitor.cc b/deps/v8/test/cctest/test-ast-expression-visitor.cc index b6cca6ac38..a40f87ccfe 100644 --- a/deps/v8/test/cctest/test-ast-expression-visitor.cc +++ b/deps/v8/test/cctest/test-ast-expression-visitor.cc @@ -343,7 +343,6 @@ TEST(VisitThrow) { v8::V8::Initialize(); HandleAndZoneScope handles; ZoneVector<ExpressionTypeEntry> types(handles.main_zone()); - // Check that traversing an empty for statement works. const char test_function[] = "function foo() {\n" " throw 123;\n" @@ -364,7 +363,6 @@ TEST(VisitYield) { v8::V8::Initialize(); HandleAndZoneScope handles; ZoneVector<ExpressionTypeEntry> types(handles.main_zone()); - // Check that traversing an empty for statement works. const char test_function[] = "function* foo() {\n" " yield 123;\n" @@ -372,7 +370,7 @@ TEST(VisitYield) { CollectTypes(&handles, test_function, &types); CHECK_TYPES_BEGIN { CHECK_EXPR(FunctionLiteral, Bounds::Unbounded()) { - // Generator function yields generator on entry. + // Implicit initial yield CHECK_EXPR(Yield, Bounds::Unbounded()) { CHECK_VAR(.generator_object, Bounds::Unbounded()); CHECK_EXPR(Assignment, Bounds::Unbounded()) { @@ -380,16 +378,20 @@ TEST(VisitYield) { CHECK_EXPR(CallRuntime, Bounds::Unbounded()); } } - // Then yields undefined. + // Explicit yield CHECK_EXPR(Yield, Bounds::Unbounded()) { CHECK_VAR(.generator_object, Bounds::Unbounded()); CHECK_EXPR(Literal, Bounds::Unbounded()); } - // Then yields 123. + // Implicit final yield CHECK_EXPR(Yield, Bounds::Unbounded()) { CHECK_VAR(.generator_object, Bounds::Unbounded()); CHECK_EXPR(Literal, Bounds::Unbounded()); } + // Implicit finally clause + CHECK_EXPR(CallRuntime, Bounds::Unbounded()) { + CHECK_VAR(.generator_object, Bounds::Unbounded()); + } } } CHECK_TYPES_END @@ -400,7 +402,6 @@ TEST(VisitSkipping) { v8::V8::Initialize(); HandleAndZoneScope handles; ZoneVector<ExpressionTypeEntry> types(handles.main_zone()); - // Check that traversing an empty for statement works. const char test_function[] = "function foo(x) {\n" " return (x + x) + 1;\n" diff --git a/deps/v8/test/cctest/test-cpu-profiler.cc b/deps/v8/test/cctest/test-cpu-profiler.cc index 29a24e62df..361c879af3 100644 --- a/deps/v8/test/cctest/test-cpu-profiler.cc +++ b/deps/v8/test/cctest/test-cpu-profiler.cc @@ -75,7 +75,7 @@ TEST(StartStop) { CpuProfilesCollection profiles(isolate->heap()); ProfileGenerator generator(&profiles); SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor( - &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100))); + &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100))); processor->Start(); processor->StopSynchronously(); } @@ -417,15 +417,16 @@ TEST(ProfileStartEndTime) { CHECK(profile->GetStartTime() <= profile->GetEndTime()); } - static v8::CpuProfile* RunProfiler(v8::Local<v8::Context> env, v8::Local<v8::Function> function, v8::Local<v8::Value> argv[], int argc, - unsigned min_js_samples, + unsigned min_js_samples = 0, + unsigned min_external_samples = 0, bool collect_samples = false) { v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler(); v8::Local<v8::String> profile_name = v8_str("my_profile"); + cpu_profiler->SetSamplingInterval(100); cpu_profiler->StartProfiling(profile_name, collect_samples); i::Sampler* sampler = @@ -433,7 +434,8 @@ static v8::CpuProfile* RunProfiler(v8::Local<v8::Context> env, sampler->StartCountingSamples(); do { function->Call(env, env->Global(), argc, argv).ToLocalChecked(); - } while (sampler->js_and_external_sample_count() < min_js_samples); + } while (sampler->js_sample_count() < min_js_samples || + sampler->external_sample_count() < min_external_samples); v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name); @@ -445,55 +447,14 @@ static v8::CpuProfile* RunProfiler(v8::Local<v8::Context> env, } -static bool ContainsString(v8::Local<v8::Context> context, - v8::Local<v8::String> string, - const Vector<v8::Local<v8::String> >& vector) { - for (int i = 0; i < vector.length(); i++) { - if (string->Equals(context, vector[i]).FromJust()) return true; - } - return false; -} - - -static void CheckChildrenNames(v8::Local<v8::Context> context, - const v8::CpuProfileNode* node, - const Vector<v8::Local<v8::String> >& names) { - int count = node->GetChildrenCount(); - for (int i = 0; i < count; i++) { - v8::Local<v8::String> name = node->GetChild(i)->GetFunctionName(); - if (!ContainsString(context, 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; - if (name->Equals(context, node->GetChild(j)->GetFunctionName()) - .FromJust()) { - 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::Local<v8::Context> context, const v8::CpuProfileNode* node, const char* name) { int count = node->GetChildrenCount(); - v8::Local<v8::String> nameHandle = v8_str(name); + v8::Local<v8::String> name_handle = v8_str(name); for (int i = 0; i < count; i++) { const v8::CpuProfileNode* child = node->GetChild(i); - if (nameHandle->Equals(context, child->GetFunctionName()).FromJust()) { + if (name_handle->Equals(context, child->GetFunctionName()).FromJust()) { return child; } } @@ -521,8 +482,6 @@ static void CheckSimpleBranch(v8::Local<v8::Context> context, for (int i = 0; i < length; i++) { const char* name = names[i]; node = GetChild(context, node, name); - int expectedChildrenCount = (i == length - 1) ? 0 : 1; - CHECK_EQ(expectedChildrenCount, node->GetChildrenCount()); } } @@ -537,38 +496,43 @@ static const ProfileNode* GetSimpleBranch(v8::Local<v8::Context> context, return reinterpret_cast<const ProfileNode*>(node); } +static void CallCollectSample(const v8::FunctionCallbackInfo<v8::Value>& info) { + info.GetIsolate()->GetCpuProfiler()->CollectSample(); +} -static const char* cpu_profiler_test_source = "function loop(timeout) {\n" -" this.mmm = 0;\n" -" var start = Date.now();\n" -" while (Date.now() - start < timeout) {\n" -" var n = 100*1000;\n" -" while(n > 1) {\n" -" n--;\n" -" this.mmm += n * n * n;\n" -" }\n" -" }\n" -"}\n" -"function delay() { try { loop(10); } catch(e) { } }\n" -"function bar() { delay(); }\n" -"function baz() { delay(); }\n" -"function foo() {\n" -" try {\n" -" delay();\n" -" bar();\n" -" delay();\n" -" baz();\n" -" } catch (e) { }\n" -"}\n" -"function start(timeout) {\n" -" var start = Date.now();\n" -" do {\n" -" foo();\n" -" var duration = Date.now() - start;\n" -" } while (duration < timeout);\n" -" return duration;\n" -"}\n"; - +static const char* cpu_profiler_test_source = + "%NeverOptimizeFunction(loop);\n" + "%NeverOptimizeFunction(delay);\n" + "%NeverOptimizeFunction(bar);\n" + "%NeverOptimizeFunction(baz);\n" + "%NeverOptimizeFunction(foo);\n" + "%NeverOptimizeFunction(start);\n" + "function loop(timeout) {\n" + " this.mmm = 0;\n" + " var start = Date.now();\n" + " do {\n" + " var n = 1000;\n" + " while(n > 1) {\n" + " n--;\n" + " this.mmm += n * n * n;\n" + " }\n" + " } while (Date.now() - start < timeout);\n" + "}\n" + "function delay() { loop(10); }\n" + "function bar() { delay(); }\n" + "function baz() { delay(); }\n" + "function foo() {\n" + " delay();\n" + " bar();\n" + " delay();\n" + " baz();\n" + "}\n" + "function start(duration) {\n" + " var start = Date.now();\n" + " do {\n" + " foo();\n" + " } while (Date.now() - start < duration);\n" + "}\n"; // Check that the profile tree for the script above will look like the // following: @@ -588,6 +552,7 @@ static const char* cpu_profiler_test_source = "function loop(timeout) {\n" // 2 2 (program) [-1] // 6 6 (garbage collector) [-1] TEST(CollectCpuProfile) { + i::FLAG_allow_natives_syntax = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -598,49 +563,37 @@ TEST(CollectCpuProfile) { v8::Local<v8::Value> args[] = { v8::Integer::New(env->GetIsolate(), profiling_interval_ms)}; v8::CpuProfile* profile = - RunProfiler(env.local(), function, args, arraysize(args), 200); - function->Call(env.local(), env->Global(), arraysize(args), args) - .ToLocalChecked(); + RunProfiler(env.local(), function, args, arraysize(args), 1000); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); + const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start"); + const v8::CpuProfileNode* foo_node = GetChild(env.local(), start_node, "foo"); - ScopedVector<v8::Local<v8::String> > names(3); - names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName); - names[1] = v8_str(ProfileGenerator::kProgramEntryName); - names[2] = v8_str("start"); - CheckChildrenNames(env.local(), root, names); - - const v8::CpuProfileNode* startNode = GetChild(env.local(), root, "start"); - CHECK_EQ(1, startNode->GetChildrenCount()); - - const v8::CpuProfileNode* fooNode = GetChild(env.local(), startNode, "foo"); - CHECK_EQ(3, fooNode->GetChildrenCount()); - - const char* barBranch[] = { "bar", "delay", "loop" }; - CheckSimpleBranch(env.local(), fooNode, barBranch, arraysize(barBranch)); - const char* bazBranch[] = { "baz", "delay", "loop" }; - CheckSimpleBranch(env.local(), fooNode, bazBranch, arraysize(bazBranch)); - const char* delayBranch[] = { "delay", "loop" }; - CheckSimpleBranch(env.local(), fooNode, delayBranch, arraysize(delayBranch)); + const char* bar_branch[] = {"bar", "delay", "loop"}; + CheckSimpleBranch(env.local(), foo_node, bar_branch, arraysize(bar_branch)); + const char* baz_branch[] = {"baz", "delay", "loop"}; + CheckSimpleBranch(env.local(), foo_node, baz_branch, arraysize(baz_branch)); + const char* delay_branch[] = {"delay", "loop"}; + CheckSimpleBranch(env.local(), foo_node, delay_branch, + arraysize(delay_branch)); profile->Delete(); } - static const char* hot_deopt_no_frame_entry_test_source = -"function foo(a, b) {\n" -" try {\n" -" return a + b;\n" -" } catch (e) { }\n" -"}\n" -"function start(timeout) {\n" -" var start = Date.now();\n" -" do {\n" -" for (var i = 1; i < 1000; ++i) foo(1, i);\n" -" var duration = Date.now() - start;\n" -" } while (duration < timeout);\n" -" return duration;\n" -"}\n"; + "%NeverOptimizeFunction(foo);\n" + "%NeverOptimizeFunction(start);\n" + "function foo(a, b) {\n" + " return a + b;\n" + "}\n" + "function start(timeout) {\n" + " var start = Date.now();\n" + " do {\n" + " for (var i = 1; i < 1000; ++i) foo(1, i);\n" + " var duration = Date.now() - start;\n" + " } while (duration < timeout);\n" + " return duration;\n" + "}\n"; // Check that the profile tree for the script above will look like the // following: @@ -652,10 +605,11 @@ static const char* hot_deopt_no_frame_entry_test_source = // 2 2 (program) [-1] // 6 6 (garbage collector) [-1] // -// The test checks no FP ranges are present in a deoptimized funcion. +// The test checks no FP ranges are present in a deoptimized function. // If 'foo' has no ranges the samples falling into the prologue will miss the // 'start' function on the stack, so 'foo' will be attached to the (root). TEST(HotDeoptNoFrameEntry) { + i::FLAG_allow_natives_syntax = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -666,28 +620,19 @@ TEST(HotDeoptNoFrameEntry) { v8::Local<v8::Value> args[] = { v8::Integer::New(env->GetIsolate(), profiling_interval_ms)}; v8::CpuProfile* profile = - RunProfiler(env.local(), function, args, arraysize(args), 200); + RunProfiler(env.local(), function, args, arraysize(args), 1000); function->Call(env.local(), env->Global(), arraysize(args), args) .ToLocalChecked(); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - - ScopedVector<v8::Local<v8::String> > names(3); - names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName); - names[1] = v8_str(ProfileGenerator::kProgramEntryName); - names[2] = v8_str("start"); - CheckChildrenNames(env.local(), root, names); - - const v8::CpuProfileNode* startNode = GetChild(env.local(), root, "start"); - CHECK_EQ(1, startNode->GetChildrenCount()); - - GetChild(env.local(), startNode, "foo"); + const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start"); + GetChild(env.local(), start_node, "foo"); profile->Delete(); } - TEST(CollectCpuProfileSamples) { + i::FLAG_allow_natives_syntax = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -698,7 +643,7 @@ TEST(CollectCpuProfileSamples) { v8::Local<v8::Value> args[] = { v8::Integer::New(env->GetIsolate(), profiling_interval_ms)}; v8::CpuProfile* profile = - RunProfiler(env.local(), function, args, arraysize(args), 200, true); + RunProfiler(env.local(), function, args, arraysize(args), 1000, 0, true); CHECK_LE(200, profile->GetSamplesCount()); uint64_t end_time = profile->GetEndTime(); @@ -715,15 +660,18 @@ TEST(CollectCpuProfileSamples) { profile->Delete(); } - -static const char* cpu_profiler_test_source2 = "function loop() {}\n" -"function delay() { loop(); }\n" -"function start(count) {\n" -" var k = 0;\n" -" do {\n" -" delay();\n" -" } while (++k < count*100*1000);\n" -"}\n"; +static const char* cpu_profiler_test_source2 = + "%NeverOptimizeFunction(loop);\n" + "%NeverOptimizeFunction(delay);\n" + "%NeverOptimizeFunction(start);\n" + "function loop() {}\n" + "function delay() { loop(); }\n" + "function start(duration) {\n" + " var start = Date.now();\n" + " do {\n" + " for (var i = 0; i < 10000; ++i) delay();\n" + " } while (Date.now() - start < duration);\n" + "}"; // Check that the profile tree doesn't contain unexpected traces: // - 'loop' can be called only by 'delay' @@ -737,47 +685,28 @@ static const char* cpu_profiler_test_source2 = "function loop() {}\n" // 16 16 loop [-1] #5 // 14 14 (program) [-1] #2 TEST(SampleWhenFrameIsNotSetup) { + i::FLAG_allow_natives_syntax = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); CompileRun(cpu_profiler_test_source2); v8::Local<v8::Function> function = GetFunction(env.local(), "start"); - int32_t repeat_count = 100; -#if defined(USE_SIMULATOR) - // Simulators are much slower. - repeat_count = 1; -#endif + int32_t duration_ms = 100; v8::Local<v8::Value> args[] = { - v8::Integer::New(env->GetIsolate(), repeat_count)}; + v8::Integer::New(env->GetIsolate(), duration_ms)}; v8::CpuProfile* profile = - RunProfiler(env.local(), function, args, arraysize(args), 100); + RunProfiler(env.local(), function, args, arraysize(args), 1000); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - - ScopedVector<v8::Local<v8::String> > names(3); - names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName); - names[1] = v8_str(ProfileGenerator::kProgramEntryName); - names[2] = v8_str("start"); - CheckChildrenNames(env.local(), root, names); - - const v8::CpuProfileNode* startNode = FindChild(env.local(), 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.local(), startNode, "delay"); - if (delayNode->GetChildrenCount() > 0) { - CHECK_EQ(1, delayNode->GetChildrenCount()); - GetChild(env.local(), delayNode, "loop"); - } - } + const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start"); + const v8::CpuProfileNode* delay_node = + GetChild(env.local(), start_node, "delay"); + GetChild(env.local(), delay_node, "loop"); profile->Delete(); } - static const char* native_accessor_test_source = "function start(count) {\n" " for (var i = 0; i < count; i++) {\n" " var o = instance.foo;\n" @@ -785,7 +714,6 @@ static const char* native_accessor_test_source = "function start(count) {\n" " }\n" "}\n"; - class TestApiCallbacks { public: explicit TestApiCallbacks(int min_duration_ms) @@ -794,19 +722,19 @@ class TestApiCallbacks { static void Getter(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { - TestApiCallbacks* data = fromInfo(info); + TestApiCallbacks* data = FromInfo(info); data->Wait(); } static void Setter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info) { - TestApiCallbacks* data = fromInfo(info); + TestApiCallbacks* data = FromInfo(info); data->Wait(); } static void Callback(const v8::FunctionCallbackInfo<v8::Value>& info) { - TestApiCallbacks* data = fromInfo(info); + TestApiCallbacks* data = FromInfo(info); data->Wait(); } @@ -823,8 +751,8 @@ class TestApiCallbacks { } } - template<typename T> - static TestApiCallbacks* fromInfo(const T& info) { + template <typename T> + static TestApiCallbacks* FromInfo(const T& info) { void* data = v8::External::Cast(*info.Data())->Value(); return reinterpret_cast<TestApiCallbacks*>(data); } @@ -865,12 +793,12 @@ TEST(NativeAccessorUninitializedIC) { int32_t repeat_count = 1; v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)}; v8::CpuProfile* profile = - RunProfiler(env.local(), function, args, arraysize(args), 180); + RunProfiler(env.local(), function, args, arraysize(args), 0, 100); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - const v8::CpuProfileNode* startNode = GetChild(env.local(), root, "start"); - GetChild(env.local(), startNode, "get foo"); - GetChild(env.local(), startNode, "set foo"); + const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start"); + GetChild(env.local(), start_node, "get foo"); + GetChild(env.local(), start_node, "set foo"); profile->Delete(); } @@ -918,12 +846,12 @@ TEST(NativeAccessorMonomorphicIC) { int32_t repeat_count = 100; v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)}; v8::CpuProfile* profile = - RunProfiler(env.local(), function, args, arraysize(args), 200); + RunProfiler(env.local(), function, args, arraysize(args), 0, 100); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - const v8::CpuProfileNode* startNode = GetChild(env.local(), root, "start"); - GetChild(env.local(), startNode, "get foo"); - GetChild(env.local(), startNode, "set foo"); + const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start"); + GetChild(env.local(), start_node, "get foo"); + GetChild(env.local(), start_node, "set foo"); profile->Delete(); } @@ -969,11 +897,11 @@ TEST(NativeMethodUninitializedIC) { int32_t repeat_count = 1; v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)}; v8::CpuProfile* profile = - RunProfiler(env.local(), function, args, arraysize(args), 100); + RunProfiler(env.local(), function, args, arraysize(args), 0, 100); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - const v8::CpuProfileNode* startNode = GetChild(env.local(), root, "start"); - GetChild(env.local(), startNode, "fooMethod"); + const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start"); + GetChild(env.local(), start_node, "fooMethod"); profile->Delete(); } @@ -1023,12 +951,12 @@ TEST(NativeMethodMonomorphicIC) { int32_t repeat_count = 100; v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)}; v8::CpuProfile* profile = - RunProfiler(env.local(), function, args, arraysize(args), 100); + RunProfiler(env.local(), function, args, arraysize(args), 0, 200); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); GetChild(env.local(), root, "start"); - const v8::CpuProfileNode* startNode = GetChild(env.local(), root, "start"); - GetChild(env.local(), startNode, "fooMethod"); + const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start"); + GetChild(env.local(), start_node, "fooMethod"); profile->Delete(); } @@ -1052,18 +980,12 @@ TEST(BoundFunctionCall) { CompileRun(bound_function_test_source); v8::Local<v8::Function> function = GetFunction(env, "start"); - v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0); + v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - ScopedVector<v8::Local<v8::String> > names(3); - names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName); - names[1] = v8_str(ProfileGenerator::kProgramEntryName); - names[2] = v8_str("start"); - // Don't allow |foo| node to be at the top level. - CheckChildrenNames(env, root, names); - const v8::CpuProfileNode* startNode = GetChild(env, root, "start"); - GetChild(env, startNode, "foo"); + const v8::CpuProfileNode* start_node = GetChild(env, root, "start"); + GetChild(env, start_node, "foo"); profile->Delete(); } @@ -1166,18 +1088,21 @@ TEST(TickLines) { CHECK_EQ(hit_count, value); } - -static const char* call_function_test_source = "function bar(iterations) {\n" -"}\n" -"function start(duration) {\n" -" var start = Date.now();\n" -" while (Date.now() - start < duration) {\n" -" try {\n" -" bar.call(this, 10 * 1000);\n" -" } catch(e) {}\n" -" }\n" -"}"; - +static const char* call_function_test_source = + "%NeverOptimizeFunction(bar);\n" + "%NeverOptimizeFunction(start);\n" + "function bar(n) {\n" + " var s = 0;\n" + " for (var i = 0; i < n; i++) s += i * i * i;\n" + " return s;\n" + "}\n" + "function start(duration) {\n" + " var start = Date.now();\n" + " do {\n" + " for (var i = 0; i < 100; ++i)\n" + " bar.call(this, 1000);\n" + " } while (Date.now() - start < duration);\n" + "}"; // Test that if we sampled thread when it was inside FunctionCall buitin then // its caller frame will be '(unresolved function)' as we have no reliable way @@ -1192,6 +1117,7 @@ static const char* call_function_test_source = "function bar(iterations) {\n" // 1 1 bar [-1] #7 // 19 19 (program) [-1] #2 TEST(FunctionCallSample) { + i::FLAG_allow_natives_syntax = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -1206,60 +1132,38 @@ TEST(FunctionCallSample) { v8::Local<v8::Value> args[] = { v8::Integer::New(env->GetIsolate(), duration_ms)}; v8::CpuProfile* profile = - RunProfiler(env.local(), function, args, arraysize(args), 100); + RunProfiler(env.local(), function, args, arraysize(args), 1000); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - { - ScopedVector<v8::Local<v8::String> > names(4); - names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName); - names[1] = v8_str(ProfileGenerator::kProgramEntryName); - names[2] = v8_str("start"); - names[3] = v8_str(i::ProfileGenerator::kUnresolvedFunctionName); - // Don't allow |bar| and |call| nodes to be at the top level. - CheckChildrenNames(env.local(), root, names); - } - - // In case of GC stress tests all samples may be in GC phase and there - // 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.local(), root, "start"); - CHECK(is_gc_stress_testing || startNode); - if (startNode) { - ScopedVector<v8::Local<v8::String> > names(2); - names[0] = v8_str("bar"); - names[1] = v8_str("call"); - CheckChildrenNames(env.local(), startNode, names); - } + const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start"); + GetChild(env.local(), start_node, "bar"); - const v8::CpuProfileNode* unresolvedNode = FindChild( + const v8::CpuProfileNode* unresolved_node = FindChild( env.local(), root, i::ProfileGenerator::kUnresolvedFunctionName); - if (unresolvedNode) { - ScopedVector<v8::Local<v8::String> > names(1); - names[0] = v8_str("call"); - CheckChildrenNames(env.local(), unresolvedNode, names); - } + CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "call")); profile->Delete(); } - static const char* function_apply_test_source = - "function bar(iterations) {\n" + "%NeverOptimizeFunction(bar);\n" + "%NeverOptimizeFunction(test);\n" + "%NeverOptimizeFunction(start);\n" + "function bar(n) {\n" + " var s = 0;\n" + " for (var i = 0; i < n; i++) s += i * i * i;\n" + " return s;\n" "}\n" "function test() {\n" - " bar.apply(this, [10 * 1000]);\n" + " bar.apply(this, [1000]);\n" "}\n" "function start(duration) {\n" " var start = Date.now();\n" - " while (Date.now() - start < duration) {\n" - " try {\n" - " test();\n" - " } catch(e) {}\n" - " }\n" + " do {\n" + " for (var i = 0; i < 100; ++i) test();\n" + " } while (Date.now() - start < duration);\n" "}"; - // [Top down]: // 94 0 (root) [-1] #0 1 // 2 2 (garbage collector) [-1] #0 7 @@ -1268,9 +1172,9 @@ static const char* function_apply_test_source = // 1 1 apply [-1] #0 9 // 32 21 test [-1] #16 4 // 2 2 bar [-1] #16 6 -// 9 9 apply [-1] #0 5 // 10 10 (program) [-1] #0 2 TEST(FunctionApplySample) { + i::FLAG_allow_natives_syntax = true; LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -1282,64 +1186,32 @@ TEST(FunctionApplySample) { v8::Integer::New(env->GetIsolate(), duration_ms)}; v8::CpuProfile* profile = - RunProfiler(env.local(), function, args, arraysize(args), 100); + RunProfiler(env.local(), function, args, arraysize(args), 1000); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - { - ScopedVector<v8::Local<v8::String> > names(3); - names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName); - names[1] = v8_str(ProfileGenerator::kProgramEntryName); - names[2] = v8_str("start"); - // Don't allow |test|, |bar| and |apply| nodes to be at the top level. - CheckChildrenNames(env.local(), root, names); - } + const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start"); + const v8::CpuProfileNode* test_node = + GetChild(env.local(), start_node, "test"); + GetChild(env.local(), test_node, "bar"); - const v8::CpuProfileNode* startNode = FindChild(env.local(), root, "start"); - if (startNode) { - { - ScopedVector<v8::Local<v8::String> > names(2); - names[0] = v8_str("test"); - names[1] = v8_str(ProfileGenerator::kUnresolvedFunctionName); - CheckChildrenNames(env.local(), startNode, names); - } - - const v8::CpuProfileNode* testNode = - FindChild(env.local(), startNode, "test"); - if (testNode) { - ScopedVector<v8::Local<v8::String> > names(3); - names[0] = v8_str("bar"); - names[1] = v8_str("apply"); - // apply calls "get length" before invoking the function itself - // and we may get hit into it. - names[2] = v8_str("get length"); - CheckChildrenNames(env.local(), testNode, names); - } - - if (const v8::CpuProfileNode* unresolvedNode = - FindChild(env.local(), startNode, - ProfileGenerator::kUnresolvedFunctionName)) { - ScopedVector<v8::Local<v8::String> > names(1); - names[0] = v8_str("apply"); - CheckChildrenNames(env.local(), unresolvedNode, names); - GetChild(env.local(), unresolvedNode, "apply"); - } - } + const v8::CpuProfileNode* unresolved_node = FindChild( + env.local(), start_node, ProfileGenerator::kUnresolvedFunctionName); + CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "apply")); profile->Delete(); } - static const char* cpu_profiler_deep_stack_test_source = -"function foo(n) {\n" -" if (n)\n" -" foo(n - 1);\n" -" else\n" -" startProfiling('my_profile');\n" -"}\n" -"function start() {\n" -" foo(250);\n" -"}\n"; - + "function foo(n) {\n" + " if (n)\n" + " foo(n - 1);\n" + " else\n" + " collectSample();\n" + "}\n" + "function start() {\n" + " startProfiling('my_profile');\n" + " foo(250);\n" + "}\n"; // Check a deep stack // @@ -1350,8 +1222,7 @@ static const char* cpu_profiler_deep_stack_test_source = // 0 foo 21 #4 no reason // 0 foo 21 #5 no reason // .... -// 0 foo 21 #253 no reason -// 1 startProfiling 0 #254 +// 0 foo 21 #254 no reason TEST(CpuProfileDeepStack) { v8::HandleScope scope(CcTest::isolate()); v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION); @@ -1369,37 +1240,29 @@ TEST(CpuProfileDeepStack) { reinterpret_cast<i::CpuProfile*>(profile)->Print(); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - { - ScopedVector<v8::Local<v8::String> > names(3); - names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName); - names[1] = v8_str(ProfileGenerator::kProgramEntryName); - names[2] = v8_str("start"); - CheckChildrenNames(env, root, names); - } - const v8::CpuProfileNode* node = GetChild(env, root, "start"); - for (int i = 0; i < 250; ++i) { + for (int i = 0; i <= 250; ++i) { node = GetChild(env, node, "foo"); } - // TODO(alph): - // In theory there must be one more 'foo' and a 'startProfiling' nodes, - // but due to unstable top frame extraction these might be missing. + CHECK(!FindChild(env, node, "foo")); profile->Delete(); } - static const char* js_native_js_test_source = - "function foo() {\n" - " startProfiling('my_profile');\n" + "%NeverOptimizeFunction(foo);\n" + "%NeverOptimizeFunction(bar);\n" + "%NeverOptimizeFunction(start);\n" + "function foo(n) {\n" + " var s = 0;\n" + " for (var i = 0; i < n; i++) s += i * i * i;\n" + " return s;\n" "}\n" "function bar() {\n" - " try { foo(); } catch(e) {}\n" + " foo(1000);\n" "}\n" "function start() {\n" - " try {\n" - " CallJsFunction(bar);\n" - " } catch(e) {}\n" + " CallJsFunction(bar);\n" "}"; static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) { @@ -1410,7 +1273,6 @@ static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) { .ToLocalChecked(); } - // [Top down]: // 58 0 (root) #0 1 // 2 2 (program) #0 2 @@ -1419,6 +1281,7 @@ static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) { // 55 1 bar #16 5 // 54 54 foo #16 6 TEST(JsNativeJsSample) { + 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); @@ -1433,47 +1296,35 @@ TEST(JsNativeJsSample) { CompileRun(js_native_js_test_source); v8::Local<v8::Function> function = GetFunction(env, "start"); - v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0); + v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 1000); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - { - ScopedVector<v8::Local<v8::String> > names(3); - names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName); - names[1] = v8_str(ProfileGenerator::kProgramEntryName); - names[2] = v8_str("start"); - CheckChildrenNames(env, root, names); - } - - const v8::CpuProfileNode* startNode = GetChild(env, root, "start"); - CHECK_EQ(1, startNode->GetChildrenCount()); - const v8::CpuProfileNode* nativeFunctionNode = - GetChild(env, startNode, "CallJsFunction"); - - CHECK_EQ(1, nativeFunctionNode->GetChildrenCount()); - const v8::CpuProfileNode* barNode = GetChild(env, nativeFunctionNode, "bar"); - - CHECK_EQ(1, barNode->GetChildrenCount()); - GetChild(env, barNode, "foo"); + const v8::CpuProfileNode* start_node = GetChild(env, root, "start"); + const v8::CpuProfileNode* native_node = + GetChild(env, start_node, "CallJsFunction"); + const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar"); + GetChild(env, bar_node, "foo"); profile->Delete(); } - static const char* js_native_js_runtime_js_test_source = - "function foo() {\n" - " startProfiling('my_profile');\n" + "%NeverOptimizeFunction(foo);\n" + "%NeverOptimizeFunction(bar);\n" + "%NeverOptimizeFunction(start);\n" + "function foo(n) {\n" + " var s = 0;\n" + " for (var i = 0; i < n; i++) s += i * i * i;\n" + " return s;\n" "}\n" "var bound = foo.bind(this);\n" "function bar() {\n" - " try { bound(); } catch(e) {}\n" + " bound(1000);\n" "}\n" "function start() {\n" - " try {\n" - " CallJsFunction(bar);\n" - " } catch(e) {}\n" + " CallJsFunction(bar);\n" "}"; - // [Top down]: // 57 0 (root) #0 1 // 55 1 start #16 3 @@ -1482,6 +1333,7 @@ static const char* js_native_js_runtime_js_test_source = // 51 51 foo #16 6 // 2 2 (program) #0 2 TEST(JsNativeJsRuntimeJsSample) { + 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); @@ -1495,57 +1347,39 @@ TEST(JsNativeJsRuntimeJsSample) { CompileRun(js_native_js_runtime_js_test_source); v8::Local<v8::Function> function = GetFunction(env, "start"); - - v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0); + v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 1000); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - ScopedVector<v8::Local<v8::String> > names(3); - names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName); - names[1] = v8_str(ProfileGenerator::kProgramEntryName); - names[2] = v8_str("start"); - CheckChildrenNames(env, root, names); - - const v8::CpuProfileNode* startNode = GetChild(env, root, "start"); - CHECK_EQ(1, startNode->GetChildrenCount()); - const v8::CpuProfileNode* nativeFunctionNode = - GetChild(env, startNode, "CallJsFunction"); - - CHECK_EQ(1, nativeFunctionNode->GetChildrenCount()); - const v8::CpuProfileNode* barNode = GetChild(env, 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, barNode, "foo"); + const v8::CpuProfileNode* start_node = GetChild(env, root, "start"); + const v8::CpuProfileNode* native_node = + GetChild(env, start_node, "CallJsFunction"); + const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar"); + GetChild(env, bar_node, "foo"); profile->Delete(); } - static void CallJsFunction2(const v8::FunctionCallbackInfo<v8::Value>& info) { v8::base::OS::Print("In CallJsFunction2\n"); CallJsFunction(info); } - static const char* js_native1_js_native2_js_test_source = + "%NeverOptimizeFunction(foo);\n" + "%NeverOptimizeFunction(bar);\n" + "%NeverOptimizeFunction(start);\n" "function foo() {\n" - " try {\n" - " startProfiling('my_profile');\n" - " } catch(e) {}\n" + " var s = 0;\n" + " for (var i = 0; i < 1000; i++) s += i * i * i;\n" + " return s;\n" "}\n" "function bar() {\n" " CallJsFunction2(foo);\n" "}\n" "function start() {\n" - " try {\n" - " CallJsFunction1(bar);\n" - " } catch(e) {}\n" + " CallJsFunction1(bar);\n" "}"; - // [Top down]: // 57 0 (root) #0 1 // 55 1 start #16 3 @@ -1555,14 +1389,15 @@ static const char* js_native1_js_native2_js_test_source = // 54 54 foo #16 7 // 2 2 (program) #0 2 TEST(JsNative1JsNative2JsSample) { + 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::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New( - env->GetIsolate(), CallJsFunction); v8::Local<v8::Function> func1 = - func_template->GetFunction(env).ToLocalChecked(); + v8::FunctionTemplate::New(env->GetIsolate(), CallJsFunction) + ->GetFunction(env) + .ToLocalChecked(); func1->SetName(v8_str("CallJsFunction1")); env->Global()->Set(env, v8_str("CallJsFunction1"), func1).FromJust(); @@ -1576,38 +1411,109 @@ TEST(JsNative1JsNative2JsSample) { CompileRun(js_native1_js_native2_js_test_source); v8::Local<v8::Function> function = GetFunction(env, "start"); - v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0); + v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 1000); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - ScopedVector<v8::Local<v8::String> > names(3); - names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName); - names[1] = v8_str(ProfileGenerator::kProgramEntryName); - names[2] = v8_str("start"); - CheckChildrenNames(env, root, names); + const v8::CpuProfileNode* start_node = GetChild(env, root, "start"); + const v8::CpuProfileNode* native_node1 = + GetChild(env, start_node, "CallJsFunction1"); + const v8::CpuProfileNode* bar_node = GetChild(env, native_node1, "bar"); + const v8::CpuProfileNode* native_node2 = + GetChild(env, bar_node, "CallJsFunction2"); + GetChild(env, native_node2, "foo"); - const v8::CpuProfileNode* startNode = GetChild(env, root, "start"); - CHECK_EQ(1, startNode->GetChildrenCount()); - const v8::CpuProfileNode* nativeNode1 = - GetChild(env, startNode, "CallJsFunction1"); + profile->Delete(); +} - CHECK_EQ(1, nativeNode1->GetChildrenCount()); - const v8::CpuProfileNode* barNode = GetChild(env, nativeNode1, "bar"); +static const char* js_force_collect_sample_source = + "function start() {\n" + " CallCollectSample();\n" + "}"; - CHECK_EQ(1, barNode->GetChildrenCount()); - const v8::CpuProfileNode* nativeNode2 = - GetChild(env, barNode, "CallJsFunction2"); +TEST(CollectSampleAPI) { + v8::HandleScope scope(CcTest::isolate()); + v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION); + v8::Context::Scope context_scope(env); - CHECK_EQ(1, nativeNode2->GetChildrenCount()); - GetChild(env, nativeNode2, "foo"); + v8::Local<v8::FunctionTemplate> func_template = + v8::FunctionTemplate::New(env->GetIsolate(), CallCollectSample); + v8::Local<v8::Function> func = + func_template->GetFunction(env).ToLocalChecked(); + func->SetName(v8_str("CallCollectSample")); + env->Global()->Set(env, v8_str("CallCollectSample"), func).FromJust(); + + CompileRun(js_force_collect_sample_source); + v8::Local<v8::Function> function = GetFunction(env, "start"); + v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0); + + const v8::CpuProfileNode* root = profile->GetTopDownRoot(); + const v8::CpuProfileNode* start_node = GetChild(env, root, "start"); + CHECK_LE(1, start_node->GetChildrenCount()); + GetChild(env, start_node, "CallCollectSample"); profile->Delete(); } +static const char* js_native_js_runtime_multiple_test_source = + "%NeverOptimizeFunction(foo);\n" + "%NeverOptimizeFunction(bar);\n" + "%NeverOptimizeFunction(start);\n" + "function foo() {\n" + " return Math.sin(Math.random());\n" + "}\n" + "var bound = foo.bind(this);\n" + "function bar() {\n" + " return bound();\n" + "}\n" + "function start() {\n" + " startProfiling('my_profile');\n" + " var startTime = Date.now();\n" + " do {\n" + " CallJsFunction(bar);\n" + " } while (Date.now() - startTime < 200);\n" + "}"; + +// The test check multiple entrances/exits between JS and native code. +// +// [Top down]: +// (root) #0 1 +// start #16 3 +// CallJsFunction #0 4 +// bar #16 5 +// foo #16 6 +// (program) #0 2 +TEST(JsNativeJsRuntimeJsSampleMultiple) { + 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::Local<v8::FunctionTemplate> func_template = + v8::FunctionTemplate::New(env->GetIsolate(), CallJsFunction); + v8::Local<v8::Function> func = + func_template->GetFunction(env).ToLocalChecked(); + func->SetName(v8_str("CallJsFunction")); + env->Global()->Set(env, v8_str("CallJsFunction"), func).FromJust(); + + CompileRun(js_native_js_runtime_multiple_test_source); + v8::Local<v8::Function> function = GetFunction(env, "start"); + + v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 500, 500); + + const v8::CpuProfileNode* root = profile->GetTopDownRoot(); + const v8::CpuProfileNode* start_node = GetChild(env, root, "start"); + const v8::CpuProfileNode* native_node = + GetChild(env, start_node, "CallJsFunction"); + const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar"); + GetChild(env, bar_node, "foo"); + + profile->Delete(); +} // [Top down]: -// 6 0 (root) #0 1 -// 3 3 (program) #0 2 -// 3 3 (idle) #0 3 +// 0 (root) #0 1 +// 2 (program) #0 2 +// 3 (idle) #0 3 TEST(IdleTime) { LocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -1618,17 +1524,14 @@ TEST(IdleTime) { i::Isolate* isolate = CcTest::i_isolate(); i::ProfilerEventsProcessor* processor = isolate->cpu_profiler()->processor(); - processor->AddCurrentStack(isolate); + processor->AddCurrentStack(isolate, true); cpu_profiler->SetIdle(true); - for (int i = 0; i < 3; i++) { - processor->AddCurrentStack(isolate); + processor->AddCurrentStack(isolate, true); } - cpu_profiler->SetIdle(false); - processor->AddCurrentStack(isolate); - + processor->AddCurrentStack(isolate, true); v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name); CHECK(profile); @@ -1636,26 +1539,19 @@ TEST(IdleTime) { reinterpret_cast<i::CpuProfile*>(profile)->Print(); const v8::CpuProfileNode* root = profile->GetTopDownRoot(); - ScopedVector<v8::Local<v8::String> > names(3); - names[0] = v8_str(ProfileGenerator::kGarbageCollectorEntryName); - names[1] = v8_str(ProfileGenerator::kProgramEntryName); - names[2] = v8_str(ProfileGenerator::kIdleEntryName); - CheckChildrenNames(env.local(), root, names); - - const v8::CpuProfileNode* programNode = + const v8::CpuProfileNode* program_node = GetChild(env.local(), root, ProfileGenerator::kProgramEntryName); - CHECK_EQ(0, programNode->GetChildrenCount()); - CHECK_GE(programNode->GetHitCount(), 3u); + CHECK_EQ(0, program_node->GetChildrenCount()); + CHECK_GE(program_node->GetHitCount(), 2u); - const v8::CpuProfileNode* idleNode = + const v8::CpuProfileNode* idle_node = GetChild(env.local(), root, ProfileGenerator::kIdleEntryName); - CHECK_EQ(0, idleNode->GetChildrenCount()); - CHECK_GE(idleNode->GetHitCount(), 3u); + CHECK_EQ(0, idle_node->GetChildrenCount()); + CHECK_GE(idle_node->GetHitCount(), 3u); profile->Delete(); } - static void CheckFunctionDetails(v8::Isolate* isolate, const v8::CpuProfileNode* node, const char* name, const char* script_name, @@ -1672,17 +1568,21 @@ static void CheckFunctionDetails(v8::Isolate* isolate, TEST(FunctionDetails) { + 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::Local<v8::Script> script_a = CompileWithOrigin( - " function foo\n() { try { bar(); } catch(e) {} }\n" + "%NeverOptimizeFunction(foo);\n" + "%NeverOptimizeFunction(bar);\n" + " function foo\n() { bar(); }\n" " function bar() { startProfiling(); }\n", "script_a"); script_a->Run(env).ToLocalChecked(); v8::Local<v8::Script> script_b = CompileWithOrigin( - "\n\n function baz() { try { foo(); } catch(e) {} }\n" + "%NeverOptimizeFunction(baz);" + "\n\n function baz() { foo(); }\n" "\n\nbaz();\n" "stopProfiling();\n", "script_b"); @@ -1706,10 +1606,10 @@ TEST(FunctionDetails) { script_b->GetUnboundScript()->GetId(), 3, 16); const v8::CpuProfileNode* foo = GetChild(env, baz, "foo"); CheckFunctionDetails(env->GetIsolate(), foo, "foo", "script_a", - script_a->GetUnboundScript()->GetId(), 2, 1); + script_a->GetUnboundScript()->GetId(), 4, 1); const v8::CpuProfileNode* bar = GetChild(env, foo, "bar"); CheckFunctionDetails(env->GetIsolate(), bar, "bar", "script_a", - script_a->GetUnboundScript()->GetId(), 3, 14); + script_a->GetUnboundScript()->GetId(), 5, 14); } diff --git a/deps/v8/test/cctest/test-debug.cc b/deps/v8/test/cctest/test-debug.cc index 914bda1d4e..dd483c06d5 100644 --- a/deps/v8/test/cctest/test-debug.cc +++ b/deps/v8/test/cctest/test-debug.cc @@ -302,18 +302,6 @@ static void ChangeScriptBreakPointConditionFromJS(v8::Isolate* isolate, } -static void ChangeScriptBreakPointIgnoreCountFromJS(v8::Isolate* isolate, - int break_point_number, - int ignoreCount) { - EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer; - SNPrintF(buffer, - "debug.Debug.changeScriptBreakPointIgnoreCount(%d, %d)", - break_point_number, ignoreCount); - buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0'; - CompileRunChecked(isolate, buffer.start()); -} - - // Change break on exception. static void ChangeBreakOnException(bool caught, bool uncaught) { v8::internal::Debug* debug = CcTest::i_isolate()->debug(); @@ -1717,72 +1705,6 @@ TEST(ConditionalScriptBreakPoint) { } -// Test ignore count on script break points. -TEST(ScriptBreakPointIgnoreCount) { - break_point_hit_count = 0; - DebugLocalContext env; - v8::HandleScope scope(env->GetIsolate()); - env.ExposeDebug(); - - v8::Debug::SetDebugEventListener(env->GetIsolate(), - DebugEventBreakPointHitCount); - - v8::Local<v8::String> script = v8_str(env->GetIsolate(), - "function f() {\n" - " a = 0; // line 1\n" - "};"); - - // Compile the script and get function f. - v8::Local<v8::Context> context = env.context(); - v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(env->GetIsolate(), "test")); - v8::Script::Compile(context, script, &origin) - .ToLocalChecked() - ->Run(context) - .ToLocalChecked(); - v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( - env->Global() - ->Get(context, v8_str(env->GetIsolate(), "f")) - .ToLocalChecked()); - - // Set script break point on line 1 (in function f). - int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0); - - // Call f with different ignores on the script break point. - break_point_hit_count = 0; - ChangeScriptBreakPointIgnoreCountFromJS(env->GetIsolate(), sbp, 1); - f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - CHECK_EQ(0, break_point_hit_count); - f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - CHECK_EQ(1, break_point_hit_count); - - ChangeScriptBreakPointIgnoreCountFromJS(env->GetIsolate(), sbp, 5); - break_point_hit_count = 0; - for (int i = 0; i < 10; i++) { - f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - } - CHECK_EQ(5, break_point_hit_count); - - // Reload the script and get f again checking that the ignore survives. - v8::Script::Compile(context, script, &origin) - .ToLocalChecked() - ->Run(context) - .ToLocalChecked(); - f = v8::Local<v8::Function>::Cast( - env->Global() - ->Get(context, v8_str(env->GetIsolate(), "f")) - .ToLocalChecked()); - - break_point_hit_count = 0; - for (int i = 0; i < 10; i++) { - f->Call(context, env->Global(), 0, NULL).ToLocalChecked(); - } - CHECK_EQ(5, break_point_hit_count); - - v8::Debug::SetDebugEventListener(env->GetIsolate(), nullptr); - CheckDebuggerUnloaded(env->GetIsolate()); -} - - // Test that script break points survive when a script is reloaded. TEST(ScriptBreakPointReload) { break_point_hit_count = 0; @@ -4405,7 +4327,6 @@ TEST(DisableBreak) { CheckDebuggerUnloaded(env->GetIsolate()); } - TEST(DisableDebuggerStatement) { DebugLocalContext env; v8::HandleScope scope(env->GetIsolate()); @@ -7396,7 +7317,7 @@ static void DebugEventBreakWithOptimizedStack( CHECK(argument_name->Equals(context, v8_str(isolate, "count")) .FromJust()); // Get the value of the first argument in frame i. If the - // funtion is optimized the value will be undefined, otherwise + // function is optimized the value will be undefined, otherwise // the value will be '1 - i'. // // TODO(3141533): We should be able to get the real value for @@ -8073,3 +7994,81 @@ TEST(NoInterruptsInDebugListener) { v8::Debug::SetDebugEventListener(env->GetIsolate(), NoInterruptsOnDebugEvent); CompileRun("void(0);"); } + +class TestBreakLocation : public i::BreakLocation { + public: + using i::BreakLocation::GetIterator; + using i::BreakLocation::Iterator; +}; + +TEST(BreakLocationIterator) { + DebugLocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + v8::HandleScope scope(isolate); + + v8::Local<v8::Value> result = CompileRun( + "function f() {\n" + " debugger; \n" + " f(); \n" + " debugger; \n" + "} \n" + "f"); + Handle<i::Object> function_obj = v8::Utils::OpenHandle(*result); + Handle<i::JSFunction> function = Handle<i::JSFunction>::cast(function_obj); + Handle<i::SharedFunctionInfo> shared(function->shared()); + + EnableDebugger(isolate); + CHECK(i_isolate->debug()->EnsureDebugInfo(shared, function)); + + Handle<i::DebugInfo> debug_info(shared->GetDebugInfo()); + int code_size = debug_info->abstract_code()->Size(); + + bool found_return = false; + bool found_call = false; + bool found_debugger = false; + + // Test public interface. + for (int i = 0; i < code_size; i++) { + i::BreakLocation location = i::BreakLocation::FromCodeOffset(debug_info, i); + if (location.IsCall()) found_call = true; + if (location.IsReturn()) found_return = true; + if (location.IsDebuggerStatement()) found_debugger = true; + } + CHECK(found_call); + CHECK(found_return); + CHECK(found_debugger); + + // Test underlying implementation. + TestBreakLocation::Iterator* iterator = + TestBreakLocation::GetIterator(debug_info, i::ALL_BREAK_LOCATIONS); + CHECK(iterator->GetBreakLocation().IsDebuggerStatement()); + CHECK_EQ(7, iterator->GetBreakLocation().position()); + iterator->Next(); + CHECK(iterator->GetBreakLocation().IsDebugBreakSlot()); + CHECK_EQ(22, iterator->GetBreakLocation().position()); + iterator->Next(); + CHECK(iterator->GetBreakLocation().IsCall()); + CHECK_EQ(22, iterator->GetBreakLocation().position()); + iterator->Next(); + CHECK(iterator->GetBreakLocation().IsDebuggerStatement()); + CHECK_EQ(37, iterator->GetBreakLocation().position()); + iterator->Next(); + CHECK(iterator->GetBreakLocation().IsReturn()); + CHECK_EQ(50, iterator->GetBreakLocation().position()); + iterator->Next(); + CHECK(iterator->Done()); + delete iterator; + + iterator = TestBreakLocation::GetIterator(debug_info, i::CALLS_AND_RETURNS); + CHECK(iterator->GetBreakLocation().IsCall()); + CHECK_EQ(22, iterator->GetBreakLocation().position()); + iterator->Next(); + CHECK(iterator->GetBreakLocation().IsReturn()); + CHECK_EQ(50, iterator->GetBreakLocation().position()); + iterator->Next(); + CHECK(iterator->Done()); + delete iterator; + + DisableDebugger(isolate); +} diff --git a/deps/v8/test/cctest/test-disasm-arm.cc b/deps/v8/test/cctest/test-disasm-arm.cc index b3b8a0358e..74144f25c6 100644 --- a/deps/v8/test/cctest/test-disasm-arm.cc +++ b/deps/v8/test/cctest/test-disasm-arm.cc @@ -362,6 +362,7 @@ TEST(Type3) { SET_UP(); if (CpuFeatures::IsSupported(ARMv7)) { + CpuFeatureScope scope(&assm, ARMv7); COMPARE(ubfx(r0, r1, 5, 10), "e7e902d1 ubfx r0, r1, #5, #10"); COMPARE(ubfx(r1, r0, 5, 10), @@ -437,6 +438,9 @@ TEST(Type3) { COMPARE(uxth(r3, r4, 8), "e6ff3474 uxth r3, r4, ror #8"); COMPARE(uxtah(r3, r4, r5, 24), "e6f43c75 uxtah r3, r4, r5, ror #24"); + + COMPARE(rbit(r1, r2), "e6ff1f32 rbit r1, r2"); + COMPARE(rbit(r10, ip), "e6ffaf3c rbit r10, ip"); } COMPARE(smmla(r0, r1, r2, r3), "e7503211 smmla r0, r1, r2, r3"); @@ -657,18 +661,27 @@ TEST(Vfp) { COMPARE(vmls(s6, s4, s5, cc), "3e023a62 vmlscc.f32 s6, s4, s5"); - COMPARE(vcvt_u32_f64(s0, d0), - "eebc0bc0 vcvt.u32.f64 s0, d0"); - COMPARE(vcvt_s32_f64(s0, d0), - "eebd0bc0 vcvt.s32.f64 s0, d0"); - COMPARE(vcvt_f64_u32(d0, s1), - "eeb80b60 vcvt.f64.u32 d0, s1"); - COMPARE(vcvt_f64_s32(d0, s1), - "eeb80be0 vcvt.f64.s32 d0, s1"); - COMPARE(vcvt_f32_s32(s0, s2), - "eeb80ac1 vcvt.f32.s32 s0, s2"); - COMPARE(vcvt_f64_s32(d0, 2), - "eeba0bcf vcvt.f64.s32 d0, d0, #2"); + COMPARE(vcvt_f32_f64(s31, d15), + "eef7fbcf vcvt.f32.f64 s31, d15"); + COMPARE(vcvt_f32_s32(s30, s29), + "eeb8faee vcvt.f32.s32 s30, s29"); + COMPARE(vcvt_f64_f32(d14, s28), + "eeb7eace vcvt.f64.f32 d14, s28"); + COMPARE(vcvt_f64_s32(d13, s27), + "eeb8dbed vcvt.f64.s32 d13, s27"); + COMPARE(vcvt_f64_u32(d12, s26), + "eeb8cb4d vcvt.f64.u32 d12, s26"); + COMPARE(vcvt_s32_f32(s25, s24), + "eefdcacc vcvt.s32.f32 s25, s24"); + COMPARE(vcvt_s32_f64(s23, d11), + "eefdbbcb vcvt.s32.f64 s23, d11"); + COMPARE(vcvt_u32_f32(s22, s21), + "eebcbaea vcvt.u32.f32 s22, s21"); + COMPARE(vcvt_u32_f64(s20, d10), + "eebcabca vcvt.u32.f64 s20, d10"); + + COMPARE(vcvt_f64_s32(d9, 2), + "eeba9bcf vcvt.f64.s32 d9, d9, #2"); if (CpuFeatures::IsSupported(VFP32DREGS)) { COMPARE(vmov(d3, d27), @@ -742,12 +755,27 @@ TEST(Vfp) { COMPARE(vmla(d16, d17, d18), "ee410ba2 vmla.f64 d16, d17, d18"); - COMPARE(vcvt_u32_f64(s0, d16), - "eebc0be0 vcvt.u32.f64 s0, d16"); - COMPARE(vcvt_s32_f64(s0, d16), - "eebd0be0 vcvt.s32.f64 s0, d16"); - COMPARE(vcvt_f64_u32(d16, s1), - "eef80b60 vcvt.f64.u32 d16, s1"); + COMPARE(vcvt_f32_f64(s0, d31), + "eeb70bef vcvt.f32.f64 s0, d31"); + COMPARE(vcvt_f32_s32(s1, s2), + "eef80ac1 vcvt.f32.s32 s1, s2"); + COMPARE(vcvt_f64_f32(d30, s3), + "eef7eae1 vcvt.f64.f32 d30, s3"); + COMPARE(vcvt_f64_s32(d29, s4), + "eef8dbc2 vcvt.f64.s32 d29, s4"); + COMPARE(vcvt_f64_u32(d28, s5), + "eef8cb62 vcvt.f64.u32 d28, s5"); + COMPARE(vcvt_s32_f32(s6, s7), + "eebd3ae3 vcvt.s32.f32 s6, s7"); + COMPARE(vcvt_s32_f64(s8, d27), + "eebd4beb vcvt.s32.f64 s8, d27"); + COMPARE(vcvt_u32_f32(s9, s10), + "eefc4ac5 vcvt.u32.f32 s9, s10"); + COMPARE(vcvt_u32_f64(s11, d26), + "eefc5bea vcvt.u32.f64 s11, d26"); + + COMPARE(vcvt_f64_s32(d25, 2), + "eefa9bcf vcvt.f64.s32 d25, d25, #2"); } } @@ -1003,3 +1031,45 @@ TEST(LoadStore) { VERIFY_RUN(); } + + +TEST(Barrier) { + SET_UP(); + + if (CpuFeatures::IsSupported(ARMv7)) { + CpuFeatureScope scope(&assm, ARMv7); + + COMPARE(dmb(OSHLD), + "f57ff051 dmb oshld"); + COMPARE(dmb(OSHST), + "f57ff052 dmb oshst"); + COMPARE(dmb(OSH), + "f57ff053 dmb osh"); + COMPARE(dmb(NSHLD), + "f57ff055 dmb nshld"); + COMPARE(dmb(NSHST), + "f57ff056 dmb nshst"); + COMPARE(dmb(NSH), + "f57ff057 dmb nsh"); + COMPARE(dmb(ISHLD), + "f57ff059 dmb ishld"); + COMPARE(dmb(ISHST), + "f57ff05a dmb ishst"); + COMPARE(dmb(ISH), + "f57ff05b dmb ish"); + COMPARE(dmb(LD), + "f57ff05d dmb ld"); + COMPARE(dmb(ST), + "f57ff05e dmb st"); + COMPARE(dmb(SY), + "f57ff05f dmb sy"); + + COMPARE(dsb(ISH), + "f57ff04b dsb ish"); + + COMPARE(isb(ISH), + "f57ff06b isb ish"); + } + + VERIFY_RUN(); +} diff --git a/deps/v8/test/cctest/test-extra.js b/deps/v8/test/cctest/test-extra.js index dfb6c8012c..b3752d97b2 100644 --- a/deps/v8/test/cctest/test-extra.js +++ b/deps/v8/test/cctest/test-extra.js @@ -12,6 +12,15 @@ return binding.runtime(3); }; + binding.testFunctionToString = function() { + function foo() { return 1; } + return foo.toString(); + }; + + binding.testStackTrace = function(f) { + return f(); + } + // Exercise all of the extras utils: // - v8.createPrivateSymbol // - v8.simpleBind, v8.uncurryThis diff --git a/deps/v8/test/cctest/test-field-type-tracking.cc b/deps/v8/test/cctest/test-field-type-tracking.cc index 89456bd6ba..cee3600314 100644 --- a/deps/v8/test/cctest/test-field-type-tracking.cc +++ b/deps/v8/test/cctest/test-field-type-tracking.cc @@ -12,6 +12,7 @@ #include "src/compilation-cache.h" #include "src/execution.h" #include "src/factory.h" +#include "src/field-type.h" #include "src/global-handles.h" #include "src/ic/stub-cache.h" #include "src/macro-assembler.h" @@ -88,7 +89,7 @@ class Expectations { PropertyType types_[MAX_PROPERTIES]; PropertyAttributes attributes_[MAX_PROPERTIES]; Representation representations_[MAX_PROPERTIES]; - // HeapType for kField, value for DATA_CONSTANT and getter for + // FieldType for kField, value for DATA_CONSTANT and getter for // ACCESSOR_CONSTANT. Handle<Object> values_[MAX_PROPERTIES]; // Setter for ACCESSOR_CONSTANT. @@ -142,25 +143,25 @@ class Expectations { os << "\n"; } - Handle<HeapType> GetFieldType(int index) { + Handle<FieldType> GetFieldType(int index) { CHECK(index < MAX_PROPERTIES); CHECK(types_[index] == DATA || types_[index] == ACCESSOR); - return Handle<HeapType>::cast(values_[index]); + return Handle<FieldType>::cast(values_[index]); } void SetDataField(int index, PropertyAttributes attrs, - Representation representation, Handle<HeapType> value) { + Representation representation, Handle<FieldType> value) { Init(index, DATA, attrs, representation, value); } void SetDataField(int index, Representation representation, - Handle<HeapType> value) { + Handle<FieldType> value) { SetDataField(index, attributes_[index], representation, value); } void SetAccessorField(int index, PropertyAttributes attrs) { Init(index, ACCESSOR, attrs, Representation::Tagged(), - HeapType::Any(isolate_)); + FieldType::Any(isolate_)); } void SetAccessorField(int index) { @@ -216,7 +217,7 @@ class Expectations { CHECK(index < number_of_properties_); representations_[index] = Representation::Tagged(); if (types_[index] == DATA || types_[index] == ACCESSOR) { - values_[index] = HeapType::Any(isolate_); + values_[index] = FieldType::Any(isolate_); } } @@ -232,8 +233,8 @@ class Expectations { switch (type) { case DATA: case ACCESSOR: { - HeapType* type = descriptors->GetFieldType(descriptor); - return HeapType::cast(expected_value)->Equals(type); + FieldType* type = descriptors->GetFieldType(descriptor); + return FieldType::cast(expected_value) == type; } case DATA_CONSTANT: @@ -280,7 +281,7 @@ class Expectations { Handle<Map> AddDataField(Handle<Map> map, PropertyAttributes attributes, Representation representation, - Handle<HeapType> heap_type) { + Handle<FieldType> heap_type) { CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); int property_index = number_of_properties_++; SetDataField(property_index, attributes, representation, heap_type); @@ -306,7 +307,7 @@ class Expectations { Handle<Map> TransitionToDataField(Handle<Map> map, PropertyAttributes attributes, Representation representation, - Handle<HeapType> heap_type, + Handle<FieldType> heap_type, Handle<Object> value) { CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); int property_index = number_of_properties_++; @@ -332,7 +333,7 @@ class Expectations { Handle<Map> FollowDataTransition(Handle<Map> map, PropertyAttributes attributes, Representation representation, - Handle<HeapType> heap_type) { + Handle<FieldType> heap_type) { CHECK_EQ(number_of_properties_, map->NumberOfOwnDescriptors()); int property_index = number_of_properties_++; SetDataField(property_index, attributes, representation, heap_type); @@ -421,8 +422,8 @@ TEST(ReconfigureAccessorToNonExistingDataField) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> none_type = HeapType::None(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> none_type = FieldType::None(isolate); Handle<AccessorPair> pair = CreateAccessorPair(true, true); Expectations expectations(isolate); @@ -533,12 +534,12 @@ TEST(ReconfigureAccessorToNonExistingDataFieldHeavy) { // 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, + Representation from_representation, Handle<FieldType> from_type, + Representation to_representation, Handle<FieldType> to_type, + Representation expected_representation, Handle<FieldType> expected_type, bool expected_deprecation, bool expected_field_type_dependency) { Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); CHECK(detach_property_at_index >= -1 && detach_property_at_index < kPropCount); @@ -639,11 +640,10 @@ static void TestGeneralizeRepresentation( CHECK_EQ(*new_map, *updated_map); } - static void TestGeneralizeRepresentation( - Representation from_representation, Handle<HeapType> from_type, - Representation to_representation, Handle<HeapType> to_type, - Representation expected_representation, Handle<HeapType> expected_type, + Representation from_representation, Handle<FieldType> from_type, + Representation to_representation, Handle<FieldType> to_type, + Representation expected_representation, Handle<FieldType> expected_type, bool expected_deprecation, bool expected_field_type_dependency) { // Check the cases when the map being reconfigured is a part of the // transition tree. @@ -670,19 +670,18 @@ static void TestGeneralizeRepresentation( // Check that reconfiguration to the very same field works correctly. Representation representation = from_representation; - Handle<HeapType> type = from_type; + Handle<FieldType> type = from_type; TestGeneralizeRepresentation(-1, 2, representation, type, representation, type, representation, type, false, false); } } - static void TestGeneralizeRepresentation(Representation from_representation, - Handle<HeapType> from_type, + Handle<FieldType> from_type, Representation to_representation, - Handle<HeapType> to_type, + Handle<FieldType> to_type, Representation expected_representation, - Handle<HeapType> expected_type) { + Handle<FieldType> expected_type) { const bool expected_deprecation = true; const bool expected_field_type_dependency = false; @@ -692,11 +691,10 @@ static void TestGeneralizeRepresentation(Representation from_representation, expected_field_type_dependency); } - static void TestGeneralizeRepresentationTrivial( - Representation from_representation, Handle<HeapType> from_type, - Representation to_representation, Handle<HeapType> to_type, - Representation expected_representation, Handle<HeapType> expected_type, + Representation from_representation, Handle<FieldType> from_type, + Representation to_representation, Handle<FieldType> to_type, + Representation expected_representation, Handle<FieldType> expected_type, bool expected_field_type_dependency = true) { const bool expected_deprecation = false; @@ -711,7 +709,7 @@ TEST(GeneralizeRepresentationSmiToDouble) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); TestGeneralizeRepresentation(Representation::Smi(), any_type, Representation::Double(), any_type, @@ -723,9 +721,9 @@ TEST(GeneralizeRepresentationSmiToTagged) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); TestGeneralizeRepresentation(Representation::Smi(), any_type, Representation::HeapObject(), value_type, @@ -737,9 +735,9 @@ TEST(GeneralizeRepresentationDoubleToTagged) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); TestGeneralizeRepresentation(Representation::Double(), any_type, Representation::HeapObject(), value_type, @@ -751,9 +749,9 @@ TEST(GeneralizeRepresentationHeapObjectToTagged) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); TestGeneralizeRepresentation(Representation::HeapObject(), value_type, Representation::Smi(), any_type, @@ -765,29 +763,23 @@ TEST(GeneralizeRepresentationHeapObjectToHeapObject) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); - const int kMaxClassesPerFieldType = 1; - Handle<HeapType> current_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> current_type = + FieldType::Class(Map::Create(isolate, 0), isolate); - for (int i = 0; i < kMaxClassesPerFieldType; i++) { - Handle<HeapType> new_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> new_type = + FieldType::Class(Map::Create(isolate, 0), isolate); - Handle<HeapType> expected_type = - (i < kMaxClassesPerFieldType - 1) - ? HeapType::Union(current_type, new_type, isolate) - : any_type; + Handle<FieldType> expected_type = any_type; TestGeneralizeRepresentationTrivial( Representation::HeapObject(), current_type, Representation::HeapObject(), new_type, Representation::HeapObject(), expected_type); current_type = expected_type; - } - Handle<HeapType> new_type = HeapType::Class(Map::Create(isolate, 0), isolate); + new_type = FieldType::Class(Map::Create(isolate, 0), isolate); TestGeneralizeRepresentationTrivial( Representation::HeapObject(), any_type, Representation::HeapObject(), @@ -799,8 +791,8 @@ TEST(GeneralizeRepresentationNoneToSmi) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> none_type = HeapType::None(isolate); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> none_type = FieldType::None(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); // None -> Smi representation change is trivial. TestGeneralizeRepresentationTrivial(Representation::None(), none_type, @@ -813,8 +805,8 @@ TEST(GeneralizeRepresentationNoneToDouble) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> none_type = HeapType::None(isolate); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> none_type = FieldType::None(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); // None -> Double representation change is NOT trivial. TestGeneralizeRepresentation(Representation::None(), none_type, @@ -827,9 +819,9 @@ TEST(GeneralizeRepresentationNoneToHeapObject) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> none_type = HeapType::None(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> none_type = FieldType::None(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); // None -> HeapObject representation change is trivial. TestGeneralizeRepresentationTrivial(Representation::None(), none_type, @@ -842,8 +834,8 @@ TEST(GeneralizeRepresentationNoneToTagged) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> none_type = HeapType::None(isolate); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> none_type = FieldType::None(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); // None -> HeapObject representation change is trivial. TestGeneralizeRepresentationTrivial(Representation::None(), none_type, @@ -861,7 +853,7 @@ TEST(GeneralizeRepresentationWithAccessorProperties) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); Handle<AccessorPair> pair = CreateAccessorPair(true, true); const int kAccessorProp = kPropCount / 2; @@ -932,9 +924,9 @@ TEST(GeneralizeRepresentationWithAccessorProperties) { // where "p2A" and "p2B" differ only in the attributes. // static void TestReconfigureDataFieldAttribute_GeneralizeRepresentation( - Representation from_representation, Handle<HeapType> from_type, - Representation to_representation, Handle<HeapType> to_type, - Representation expected_representation, Handle<HeapType> expected_type) { + Representation from_representation, Handle<FieldType> from_type, + Representation to_representation, Handle<FieldType> to_type, + Representation expected_representation, Handle<FieldType> expected_type) { Isolate* isolate = CcTest::i_isolate(); Expectations expectations(isolate); @@ -1016,9 +1008,9 @@ static void TestReconfigureDataFieldAttribute_GeneralizeRepresentation( // where "p2A" and "p2B" differ only in the attributes. // static void TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial( - Representation from_representation, Handle<HeapType> from_type, - Representation to_representation, Handle<HeapType> to_type, - Representation expected_representation, Handle<HeapType> expected_type, + Representation from_representation, Handle<FieldType> from_type, + Representation to_representation, Handle<FieldType> to_type, + Representation expected_representation, Handle<FieldType> expected_type, bool expected_field_type_dependency = true) { Isolate* isolate = CcTest::i_isolate(); @@ -1096,7 +1088,7 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationSmiToDouble) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); TestReconfigureDataFieldAttribute_GeneralizeRepresentation( Representation::Smi(), any_type, Representation::Double(), any_type, @@ -1108,9 +1100,9 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationSmiToTagged) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); TestReconfigureDataFieldAttribute_GeneralizeRepresentation( Representation::Smi(), any_type, Representation::HeapObject(), value_type, @@ -1122,9 +1114,9 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationDoubleToTagged) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); TestReconfigureDataFieldAttribute_GeneralizeRepresentation( Representation::Double(), any_type, Representation::HeapObject(), @@ -1136,29 +1128,22 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationHeapObjToHeapObj) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); - const int kMaxClassesPerFieldType = 1; - Handle<HeapType> current_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> current_type = + FieldType::Class(Map::Create(isolate, 0), isolate); - for (int i = 0; i < kMaxClassesPerFieldType; i++) { - Handle<HeapType> new_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> new_type = + FieldType::Class(Map::Create(isolate, 0), isolate); - Handle<HeapType> expected_type = - (i < kMaxClassesPerFieldType - 1) - ? HeapType::Union(current_type, new_type, isolate) - : any_type; + Handle<FieldType> expected_type = any_type; - TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial( - Representation::HeapObject(), current_type, - Representation::HeapObject(), new_type, Representation::HeapObject(), - expected_type); - current_type = expected_type; - } + TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial( + Representation::HeapObject(), current_type, Representation::HeapObject(), + new_type, Representation::HeapObject(), expected_type); + current_type = expected_type; - Handle<HeapType> new_type = HeapType::Class(Map::Create(isolate, 0), isolate); + new_type = FieldType::Class(Map::Create(isolate, 0), isolate); TestReconfigureDataFieldAttribute_GeneralizeRepresentationTrivial( Representation::HeapObject(), any_type, Representation::HeapObject(), @@ -1170,9 +1155,9 @@ TEST(ReconfigureDataFieldAttribute_GeneralizeRepresentationHeapObjectToTagged) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); TestReconfigureDataFieldAttribute_GeneralizeRepresentation( Representation::HeapObject(), value_type, Representation::Smi(), any_type, @@ -1268,7 +1253,7 @@ template <typename TestConfig, typename Checker> static void TestReconfigureProperty_CustomPropertyAfterTargetMap( TestConfig& config, Checker& checker) { Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); const int kCustomPropIndex = kPropCount - 2; Expectations expectations(isolate); @@ -1391,8 +1376,8 @@ TEST(ReconfigureDataFieldAttribute_DataConstantToDataFieldAfterTargetMap) { void UpdateExpectations(int property_index, Expectations& expectations) { Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> function_type = - HeapType::Class(isolate->sloppy_function_map(), isolate); + Handle<FieldType> function_type = + FieldType::Class(isolate->sloppy_function_map(), isolate); expectations.SetDataField(property_index, Representation::HeapObject(), function_type); } @@ -1523,7 +1508,7 @@ TEST(ReconfigureDataFieldAttribute_AccConstantToDataFieldAfterTargetMap) { return expectations.AddAccessorConstant(map, NONE, pair_); } else { Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); return expectations.AddDataField(map, NONE, Representation::Smi(), any_type); } @@ -1547,7 +1532,7 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); Expectations expectations(isolate); @@ -1638,9 +1623,9 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) { template <typename TestConfig> static void TestGeneralizeRepresentationWithSpecialTransition( TestConfig& config, Representation from_representation, - Handle<HeapType> from_type, Representation to_representation, - Handle<HeapType> to_type, Representation expected_representation, - Handle<HeapType> expected_type) { + Handle<FieldType> from_type, Representation to_representation, + Handle<FieldType> to_type, Representation expected_representation, + Handle<FieldType> expected_type) { Isolate* isolate = CcTest::i_isolate(); Expectations expectations(isolate); @@ -1730,9 +1715,9 @@ TEST(ElementsKindTransitionFromMapOwningDescriptor) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); struct TestConfig { Handle<Map> Transition(Handle<Map> map) { @@ -1754,14 +1739,14 @@ TEST(ElementsKindTransitionFromMapNotOwningDescriptor) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); struct TestConfig { Handle<Map> Transition(Handle<Map> map) { Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); // Add one more transition to |map| in order to prevent descriptors // ownership. @@ -1789,9 +1774,9 @@ TEST(ForObservedTransitionFromMapOwningDescriptor) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); struct TestConfig { Handle<Map> Transition(Handle<Map> map) { @@ -1812,14 +1797,14 @@ TEST(ForObservedTransitionFromMapNotOwningDescriptor) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); struct TestConfig { Handle<Map> Transition(Handle<Map> map) { Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); // Add one more transition to |map| in order to prevent descriptors // ownership. @@ -1847,9 +1832,9 @@ TEST(PrototypeTransitionFromMapOwningDescriptor) { v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); struct TestConfig { Handle<JSObject> prototype_; @@ -1881,9 +1866,9 @@ TEST(PrototypeTransitionFromMapNotOwningDescriptor) { v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); - Handle<HeapType> value_type = - HeapType::Class(Map::Create(isolate, 0), isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); + Handle<FieldType> value_type = + FieldType::Class(Map::Create(isolate, 0), isolate); struct TestConfig { Handle<JSObject> prototype_; @@ -1896,7 +1881,7 @@ TEST(PrototypeTransitionFromMapNotOwningDescriptor) { Handle<Map> Transition(Handle<Map> map) { Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); // Add one more transition to |map| in order to prevent descriptors // ownership. @@ -1928,11 +1913,11 @@ TEST(PrototypeTransitionFromMapNotOwningDescriptor) { struct TransitionToDataFieldOperator { Representation representation_; PropertyAttributes attributes_; - Handle<HeapType> heap_type_; + Handle<FieldType> heap_type_; Handle<Object> value_; TransitionToDataFieldOperator(Representation representation, - Handle<HeapType> heap_type, + Handle<FieldType> heap_type, Handle<Object> value, PropertyAttributes attributes = NONE) : representation_(representation), @@ -1979,11 +1964,11 @@ struct ReconfigureAsDataPropertyOperator { int descriptor_; Representation representation_; PropertyAttributes attributes_; - Handle<HeapType> heap_type_; + Handle<FieldType> heap_type_; ReconfigureAsDataPropertyOperator(int descriptor, Representation representation, - Handle<HeapType> heap_type, + Handle<FieldType> heap_type, PropertyAttributes attributes = NONE) : descriptor_(descriptor), representation_(representation), @@ -2019,10 +2004,10 @@ struct FieldGeneralizationChecker { int descriptor_; Representation representation_; PropertyAttributes attributes_; - Handle<HeapType> heap_type_; + Handle<FieldType> heap_type_; FieldGeneralizationChecker(int descriptor, Representation representation, - Handle<HeapType> heap_type, + Handle<FieldType> heap_type, PropertyAttributes attributes = NONE) : descriptor_(descriptor), representation_(representation), @@ -2085,7 +2070,7 @@ template <typename TransitionOp1, typename TransitionOp2, typename Checker> static void TestTransitionTo(TransitionOp1& transition_op1, TransitionOp2& transition_op2, Checker& checker) { Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); Expectations expectations(isolate); @@ -2113,7 +2098,7 @@ TEST(TransitionDataFieldToDataField) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); Handle<Object> value1 = handle(Smi::FromInt(0), isolate); TransitionToDataFieldOperator transition_op1(Representation::Smi(), any_type, @@ -2148,8 +2133,8 @@ TEST(TransitionDataConstantToAnotherDataConstant) { v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); - Handle<HeapType> function_type = - HeapType::Class(isolate->sloppy_function_map(), isolate); + Handle<FieldType> function_type = + FieldType::Class(isolate->sloppy_function_map(), isolate); Handle<JSFunction> js_func1 = factory->NewFunction(factory->empty_string()); TransitionToDataConstantOperator transition_op1(js_func1); @@ -2168,7 +2153,7 @@ TEST(TransitionDataConstantToDataField) { v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); Handle<JSFunction> js_func1 = factory->NewFunction(factory->empty_string()); TransitionToDataConstantOperator transition_op1(js_func1); diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index a2fd09e9f5..87119b8571 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -2071,7 +2071,7 @@ TEST(AccessorInfo) { const v8::HeapGraphNode* length_accessor = GetProperty(descriptors, v8::HeapGraphEdge::kInternal, "4"); CHECK(length_accessor); - CHECK_EQ(0, strcmp("system / ExecutableAccessorInfo", + CHECK_EQ(0, strcmp("system / AccessorInfo", *v8::String::Utf8Value(length_accessor->GetName()))); const v8::HeapGraphNode* name = GetProperty(length_accessor, v8::HeapGraphEdge::kInternal, "name"); @@ -2852,3 +2852,161 @@ TEST(AddressToTraceMap) { CHECK_EQ(0u, map.size()); CHECK_EQ(0u, map.GetTraceNodeId(ToAddress(0x400))); } + + +static const v8::AllocationProfile::Node* FindAllocationProfileNode( + v8::AllocationProfile& profile, const Vector<const char*>& names) { + v8::AllocationProfile::Node* node = profile.GetRootNode(); + for (int i = 0; node != nullptr && i < names.length(); ++i) { + const char* name = names[i]; + auto children = node->children; + node = nullptr; + for (v8::AllocationProfile::Node* child : children) { + v8::String::Utf8Value child_name(child->name); + if (strcmp(*child_name, name) == 0) { + node = child; + break; + } + } + } + return node; +} + + +TEST(SamplingHeapProfiler) { + v8::HandleScope scope(v8::Isolate::GetCurrent()); + LocalContext env; + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + + // Turn off always_opt. Inlining can cause stack traces to be shorter than + // what we expect in this test. + v8::internal::FLAG_always_opt = false; + + // Suppress randomness to avoid flakiness in tests. + v8::internal::FLAG_sampling_heap_profiler_suppress_randomness = true; + + const char* script_source = + "var A = [];\n" + "function bar(size) { return new Array(size); }\n" + "var foo = function() {\n" + " for (var i = 0; i < 1024; ++i) {\n" + " A[i] = bar(1024);\n" + " }\n" + "}\n" + "foo();"; + + // Sample should be empty if requested before sampling has started. + { + v8::AllocationProfile* profile = heap_profiler->GetAllocationProfile(); + CHECK(profile == nullptr); + } + + int count_1024 = 0; + { + heap_profiler->StartSamplingHeapProfiler(1024); + CompileRun(script_source); + + v8::base::SmartPointer<v8::AllocationProfile> profile( + heap_profiler->GetAllocationProfile()); + CHECK(!profile.is_empty()); + + const char* names[] = {"", "foo", "bar"}; + auto node_bar = FindAllocationProfileNode( + *profile, Vector<const char*>(names, arraysize(names))); + CHECK(node_bar); + + // Count the number of allocations we sampled from bar. + for (auto allocation : node_bar->allocations) { + count_1024 += allocation.count; + } + + heap_profiler->StopSamplingHeapProfiler(); + } + + // Samples should get cleared once sampling is stopped. + { + v8::AllocationProfile* profile = heap_profiler->GetAllocationProfile(); + CHECK(profile == nullptr); + } + + // Sampling at a higher rate should give us similar numbers of objects. + { + heap_profiler->StartSamplingHeapProfiler(128); + CompileRun(script_source); + + v8::base::SmartPointer<v8::AllocationProfile> profile( + heap_profiler->GetAllocationProfile()); + CHECK(!profile.is_empty()); + + const char* names[] = {"", "foo", "bar"}; + auto node_bar = FindAllocationProfileNode( + *profile, Vector<const char*>(names, arraysize(names))); + CHECK(node_bar); + + // Count the number of allocations we sampled from bar. + int count_128 = 0; + for (auto allocation : node_bar->allocations) { + count_128 += allocation.count; + } + + // We should have similar unsampled counts of allocations. Though + // we will sample different numbers of objects at different rates, + // the unsampling process should produce similar final estimates + // at the true number of allocations. However, the process to + // determine these unsampled counts is probabilisitic so we need to + // account for error. + double max_count = std::max(count_128, count_1024); + double min_count = std::min(count_128, count_1024); + double percent_difference = (max_count - min_count) / min_count; + CHECK_LT(percent_difference, 0.15); + + heap_profiler->StopSamplingHeapProfiler(); + } + + // A more complicated test cases with deeper call graph and dynamically + // generated function names. + { + heap_profiler->StartSamplingHeapProfiler(64); + CompileRun(record_trace_tree_source); + + v8::base::SmartPointer<v8::AllocationProfile> profile( + heap_profiler->GetAllocationProfile()); + CHECK(!profile.is_empty()); + + const char* names1[] = {"", "start", "f_0_0", "f_0_1", "f_0_2"}; + auto node1 = FindAllocationProfileNode( + *profile, Vector<const char*>(names1, arraysize(names1))); + CHECK(node1); + + const char* names2[] = {"", "generateFunctions"}; + auto node2 = FindAllocationProfileNode( + *profile, Vector<const char*>(names2, arraysize(names2))); + CHECK(node2); + + heap_profiler->StopSamplingHeapProfiler(); + } +} + + +TEST(SamplingHeapProfilerApiAllocation) { + v8::HandleScope scope(v8::Isolate::GetCurrent()); + LocalContext env; + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + + // Suppress randomness to avoid flakiness in tests. + v8::internal::FLAG_sampling_heap_profiler_suppress_randomness = true; + + heap_profiler->StartSamplingHeapProfiler(256); + + for (int i = 0; i < 8 * 1024; ++i) v8::Object::New(env->GetIsolate()); + + v8::base::SmartPointer<v8::AllocationProfile> profile( + heap_profiler->GetAllocationProfile()); + CHECK(!profile.is_empty()); + const char* names[] = {"(V8 API)"}; + auto node = FindAllocationProfileNode( + *profile, Vector<const char*>(names, arraysize(names))); + CHECK(node); + + heap_profiler->StopSamplingHeapProfiler(); +} diff --git a/deps/v8/test/cctest/test-inobject-slack-tracking.cc b/deps/v8/test/cctest/test-inobject-slack-tracking.cc index 6ce77c9416..5cc4e94a02 100644 --- a/deps/v8/test/cctest/test-inobject-slack-tracking.cc +++ b/deps/v8/test/cctest/test-inobject-slack-tracking.cc @@ -61,9 +61,9 @@ Handle<T> GetLexical(const char* name) { ScriptContextTable::LookupResult lookup_result; if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) { Handle<Object> result = - FixedArray::get(ScriptContextTable::GetContext( + FixedArray::get(*ScriptContextTable::GetContext( script_contexts, lookup_result.context_index), - lookup_result.slot_index); + lookup_result.slot_index, isolate); return Handle<T>::cast(result); } return Handle<T>(); diff --git a/deps/v8/test/cctest/test-log-stack-tracer.cc b/deps/v8/test/cctest/test-log-stack-tracer.cc index 7254ee084f..21dafda4a9 100644 --- a/deps/v8/test/cctest/test-log-stack-tracer.cc +++ b/deps/v8/test/cctest/test-log-stack-tracer.cc @@ -83,6 +83,11 @@ static void construct_call(const v8::FunctionCallbackInfo<v8::Value>& args) { frame_iterator.Advance(); CHECK(frame_iterator.frame()->is_construct()); frame_iterator.Advance(); + if (i::FLAG_ignition) { + // Skip over bytecode handler frame. + CHECK(frame_iterator.frame()->type() == i::StackFrame::STUB); + frame_iterator.Advance(); + } i::StackFrame* calling_frame = frame_iterator.frame(); CHECK(calling_frame->is_java_script()); @@ -175,7 +180,8 @@ TEST(CFromJSStackTrace) { // TickSample::Trace CHECK(sample.has_external_callback); - CHECK_EQ(FUNCTION_ADDR(i::TraceExtension::Trace), sample.external_callback); + CHECK_EQ(FUNCTION_ADDR(i::TraceExtension::Trace), + sample.external_callback_entry); // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" unsigned base = 0; @@ -229,7 +235,8 @@ TEST(PureJSStackTrace) { // CHECK(sample.has_external_callback); - CHECK_EQ(FUNCTION_ADDR(i::TraceExtension::JSTrace), sample.external_callback); + CHECK_EQ(FUNCTION_ADDR(i::TraceExtension::JSTrace), + sample.external_callback_entry); // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" unsigned base = 0; diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc index adbd1a5a37..8077f65ae3 100644 --- a/deps/v8/test/cctest/test-log.cc +++ b/deps/v8/test/cctest/test-log.cc @@ -370,10 +370,14 @@ TEST(LogCallbacks) { i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true)); CHECK(exists); + Address ObjMethod1_entry = reinterpret_cast<Address>(ObjMethod1); +#if USES_FUNCTION_DESCRIPTORS + ObjMethod1_entry = *FUNCTION_ENTRYPOINT_ADDRESS(ObjMethod1_entry); +#endif i::EmbeddedVector<char, 100> ref_data; i::SNPrintF(ref_data, "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"method1\"", - reinterpret_cast<intptr_t>(ObjMethod1)); + reinterpret_cast<intptr_t>(ObjMethod1_entry)); CHECK(StrNStr(log.start(), ref_data.start(), log.length())); log.Dispose(); @@ -419,22 +423,34 @@ TEST(LogAccessorCallbacks) { i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true)); CHECK(exists); + Address Prop1Getter_entry = reinterpret_cast<Address>(Prop1Getter); +#if USES_FUNCTION_DESCRIPTORS + Prop1Getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop1Getter_entry); +#endif EmbeddedVector<char, 100> prop1_getter_record; i::SNPrintF(prop1_getter_record, "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"get prop1\"", - reinterpret_cast<intptr_t>(Prop1Getter)); + reinterpret_cast<intptr_t>(Prop1Getter_entry)); CHECK(StrNStr(log.start(), prop1_getter_record.start(), log.length())); + Address Prop1Setter_entry = reinterpret_cast<Address>(Prop1Setter); +#if USES_FUNCTION_DESCRIPTORS + Prop1Setter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop1Setter_entry); +#endif EmbeddedVector<char, 100> prop1_setter_record; i::SNPrintF(prop1_setter_record, "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"set prop1\"", - reinterpret_cast<intptr_t>(Prop1Setter)); + reinterpret_cast<intptr_t>(Prop1Setter_entry)); CHECK(StrNStr(log.start(), prop1_setter_record.start(), log.length())); + Address Prop2Getter_entry = reinterpret_cast<Address>(Prop2Getter); +#if USES_FUNCTION_DESCRIPTORS + Prop2Getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop2Getter_entry); +#endif EmbeddedVector<char, 100> prop2_getter_record; i::SNPrintF(prop2_getter_record, "code-creation,Callback,-2,0x%" V8PRIxPTR ",1,\"get prop2\"", - reinterpret_cast<intptr_t>(Prop2Getter)); + reinterpret_cast<intptr_t>(Prop2Getter_entry)); CHECK(StrNStr(log.start(), prop2_getter_record.start(), log.length())); log.Dispose(); } diff --git a/deps/v8/test/cctest/test-macro-assembler-mips.cc b/deps/v8/test/cctest/test-macro-assembler-mips.cc index 696ca010ca..77dc859022 100644 --- a/deps/v8/test/cctest/test-macro-assembler-mips.cc +++ b/deps/v8/test/cctest/test-macro-assembler-mips.cc @@ -185,7 +185,7 @@ TEST(jump_tables4) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); - MacroAssembler assembler(isolate, NULL, 0, + MacroAssembler assembler(isolate, nullptr, 0, v8::internal::CodeObjectRequired::kYes); MacroAssembler* masm = &assembler; @@ -193,11 +193,9 @@ TEST(jump_tables4) { int values[kNumCases]; isolate->random_number_generator()->NextBytes(values, sizeof(values)); Label labels[kNumCases]; - Label near_start, end; - - __ addiu(sp, sp, -4); - __ sw(ra, MemOperand(sp)); + Label near_start, end, done; + __ Push(ra); __ mov(v0, zero_reg); __ Branch(&end); @@ -209,35 +207,17 @@ TEST(jump_tables4) { __ addiu(v0, v0, 1); } - Label done; - { - __ BlockTrampolinePoolFor(kNumCases + 6); - PredictableCodeSizeScope predictable( - masm, (kNumCases + 6) * Assembler::kInstrSize); - Label here; - - __ bal(&here); - __ sll(at, a0, 2); // In delay slot. - __ bind(&here); - __ addu(at, at, ra); - __ lw(at, MemOperand(at, 4 * Assembler::kInstrSize)); - __ jr(at); - __ nop(); // Branch delay slot nop. - for (int i = 0; i < kNumCases; ++i) { - __ dd(&labels[i]); - } - } + __ GenerateSwitchTable(a0, kNumCases, + [&labels](size_t i) { return labels + i; }); for (int i = 0; i < kNumCases; ++i) { __ bind(&labels[i]); - __ lui(v0, (values[i] >> 16) & 0xffff); - __ ori(v0, v0, values[i] & 0xffff); + __ li(v0, values[i]); __ Branch(&done); } __ bind(&done); - __ lw(ra, MemOperand(sp)); - __ addiu(sp, sp, 4); + __ Pop(ra); __ jr(ra); __ nop(); @@ -279,23 +259,21 @@ TEST(jump_tables5) { Label labels[kNumCases]; Label done; - __ addiu(sp, sp, -4); - __ sw(ra, MemOperand(sp)); + __ Push(ra); { - __ BlockTrampolinePoolFor(kNumCases * 2 + 7 + 1); + __ BlockTrampolinePoolFor(kNumCases + 6 + 1); PredictableCodeSizeScope predictable( - masm, kNumCases * kPointerSize + ((7 + 1) * Assembler::kInstrSize)); - Label here; - - __ bal(&here); - __ sll(at, a0, 2); // In delay slot. - __ bind(&here); - __ addu(at, at, ra); - __ lw(at, MemOperand(at, 6 * Assembler::kInstrSize)); + masm, kNumCases * kPointerSize + ((6 + 1) * Assembler::kInstrSize)); + + __ addiupc(at, 6 + 1); + __ lsa(at, at, a0, 2); + __ lw(at, MemOperand(at)); __ jalr(at); __ nop(); // Branch delay slot nop. __ bc(&done); + // A nop instruction must be generated by the forbidden slot guard + // (Assembler::dd(Label*)). for (int i = 0; i < kNumCases; ++i) { __ dd(&labels[i]); } @@ -303,15 +281,13 @@ TEST(jump_tables5) { for (int i = 0; i < kNumCases; ++i) { __ bind(&labels[i]); - __ lui(v0, (values[i] >> 16) & 0xffff); - __ ori(v0, v0, values[i] & 0xffff); + __ li(v0, values[i]); __ jr(ra); __ nop(); } __ bind(&done); - __ lw(ra, MemOperand(sp)); - __ addiu(sp, sp, 4); + __ Pop(ra); __ jr(ra); __ nop(); diff --git a/deps/v8/test/cctest/test-macro-assembler-mips64.cc b/deps/v8/test/cctest/test-macro-assembler-mips64.cc index 684b554236..e74703b8f8 100644 --- a/deps/v8/test/cctest/test-macro-assembler-mips64.cc +++ b/deps/v8/test/cctest/test-macro-assembler-mips64.cc @@ -228,7 +228,7 @@ TEST(jump_tables4) { CcTest::InitializeVM(); Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); - MacroAssembler assembler(isolate, NULL, 0, + MacroAssembler assembler(isolate, nullptr, 0, v8::internal::CodeObjectRequired::kYes); MacroAssembler* masm = &assembler; @@ -236,11 +236,9 @@ TEST(jump_tables4) { int values[kNumCases]; isolate->random_number_generator()->NextBytes(values, sizeof(values)); Label labels[kNumCases]; - Label near_start, end; - - __ daddiu(sp, sp, -8); - __ sd(ra, MemOperand(sp)); + Label near_start, end, done; + __ Push(ra); __ mov(v0, zero_reg); __ Branch(&end); @@ -252,36 +250,17 @@ TEST(jump_tables4) { __ addiu(v0, v0, 1); } - __ Align(8); - Label done; - { - __ BlockTrampolinePoolFor(kNumCases * 2 + 6); - PredictableCodeSizeScope predictable( - masm, (kNumCases * 2 + 6) * Assembler::kInstrSize); - Label here; - - __ bal(&here); - __ dsll(at, a0, 3); // In delay slot. - __ bind(&here); - __ daddu(at, at, ra); - __ ld(at, MemOperand(at, 4 * Assembler::kInstrSize)); - __ jr(at); - __ nop(); // Branch delay slot nop. - for (int i = 0; i < kNumCases; ++i) { - __ dd(&labels[i]); - } - } + __ GenerateSwitchTable(a0, kNumCases, + [&labels](size_t i) { return labels + i; }); for (int i = 0; i < kNumCases; ++i) { __ bind(&labels[i]); - __ lui(v0, (values[i] >> 16) & 0xffff); - __ ori(v0, v0, values[i] & 0xffff); + __ li(v0, values[i]); __ Branch(&done); } __ bind(&done); - __ ld(ra, MemOperand(sp)); - __ daddiu(sp, sp, 8); + __ Pop(ra); __ jr(ra); __ nop(); @@ -323,21 +302,22 @@ TEST(jump_tables5) { Label labels[kNumCases]; Label done; - __ daddiu(sp, sp, -8); - __ sd(ra, MemOperand(sp)); + __ Push(ra); + + // Opposite of Align(8) as we have unaligned number of instructions in the + // following block before the first dd(). + if ((masm->pc_offset() & 7) == 0) { + __ nop(); + } - __ Align(8); { - __ BlockTrampolinePoolFor(kNumCases * 2 + 7 + 1); + __ BlockTrampolinePoolFor(kNumCases * 2 + 6 + 1); PredictableCodeSizeScope predictable( - masm, kNumCases * kPointerSize + ((7 + 1) * Assembler::kInstrSize)); - Label here; - - __ bal(&here); - __ dsll(at, a0, 3); // In delay slot. - __ bind(&here); - __ daddu(at, at, ra); - __ ld(at, MemOperand(at, 6 * Assembler::kInstrSize)); + masm, kNumCases * kPointerSize + ((6 + 1) * Assembler::kInstrSize)); + + __ addiupc(at, 6 + 1); + __ dlsa(at, at, a0, 3); + __ ld(at, MemOperand(at)); __ jalr(at); __ nop(); // Branch delay slot nop. __ bc(&done); @@ -351,15 +331,13 @@ TEST(jump_tables5) { for (int i = 0; i < kNumCases; ++i) { __ bind(&labels[i]); - __ lui(v0, (values[i] >> 16) & 0xffff); - __ ori(v0, v0, values[i] & 0xffff); + __ li(v0, values[i]); __ jr(ra); __ nop(); } __ bind(&done); - __ ld(ra, MemOperand(sp)); - __ daddiu(sp, sp, 8); + __ Pop(ra); __ jr(ra); __ nop(); diff --git a/deps/v8/test/cctest/test-object-observe.cc b/deps/v8/test/cctest/test-object-observe.cc index f0af22e27a..5164b87df7 100644 --- a/deps/v8/test/cctest/test-object-observe.cc +++ b/deps/v8/test/cctest/test-object-observe.cc @@ -1026,9 +1026,9 @@ TEST(UseCountObjectGetNotifier) { CHECK_EQ(1, use_counts[v8::Isolate::kObjectObserve]); } - static bool NamedAccessCheckAlwaysAllow(Local<v8::Context> accessing_context, - Local<v8::Object> accessed_object) { + Local<v8::Object> accessed_object, + Local<v8::Value> data) { return true; } diff --git a/deps/v8/test/cctest/test-parsing.cc b/deps/v8/test/cctest/test-parsing.cc index 52493145dc..b04fb94d3a 100644 --- a/deps/v8/test/cctest/test-parsing.cc +++ b/deps/v8/test/cctest/test-parsing.cc @@ -1500,7 +1500,6 @@ i::Handle<i::String> FormatMessage(i::Vector<unsigned> data) { return i::MessageTemplate::FormatMessage(isolate, message, arg_object); } - enum ParserFlag { kAllowLazy, kAllowNatives, @@ -1511,10 +1510,10 @@ enum ParserFlag { kAllowHarmonyDestructuringAssignment, kAllowHarmonyNewTarget, kAllowStrongMode, - kNoLegacyConst + kNoLegacyConst, + kAllowHarmonyFunctionSent }; - enum ParserSyncTestResult { kSuccessOrError, kSuccess, @@ -1536,6 +1535,8 @@ void SetParserFlags(i::ParserBase<Traits>* parser, flags.Contains(kAllowHarmonyDestructuringAssignment)); parser->set_allow_strong_mode(flags.Contains(kAllowStrongMode)); parser->set_allow_legacy_const(!flags.Contains(kNoLegacyConst)); + parser->set_allow_harmony_function_sent( + flags.Contains(kAllowHarmonyFunctionSent)); } @@ -3712,6 +3713,8 @@ TEST(ErrorsArrowFormalParameters) { TEST(ErrorsArrowFunctions) { // Tests that parser and preparser generate the same kind of errors // on invalid arrow function syntax. + + // clang-format off const char* context_data[][2] = { {"", ";"}, {"v = ", ";"}, @@ -3812,8 +3815,14 @@ TEST(ErrorsArrowFunctions) { "(c, a.b) => {}", "(a['b'], c) => {}", "(c, a['b']) => {}", + + // crbug.com/582626 + "(...rest - a) => b", + "(a, ...b - 10) => b", + NULL }; + // clang-format on // The test is quite slow, so run it with a reduced set of flags. static const ParserFlag flags[] = {kAllowLazy}; @@ -4445,6 +4454,7 @@ TEST(ClassDeclarationNoErrors) { TEST(ClassBodyNoErrors) { + // clang-format off // Tests that parser and preparser accept valid class syntax. const char* context_data[][2] = {{"(class {", "});"}, {"(class extends Base {", "});"}, @@ -4467,6 +4477,8 @@ TEST(ClassBodyNoErrors) { "; *g() {}", "*g() {}; *h(x) {}", "static() {}", + "get static() {}", + "set static(v) {}", "static m() {}", "static get x() {}", "static set x(v) {}", @@ -4476,10 +4488,23 @@ TEST(ClassBodyNoErrors) { "static get static() {}", "static set static(v) {}", "*static() {}", + "static *static() {}", "*get() {}", "*set() {}", "static *g() {}", + + // Escaped 'static' should be allowed anywhere + // static-as-PropertyName is. + "st\\u0061tic() {}", + "get st\\u0061tic() {}", + "set st\\u0061tic(v) {}", + "static st\\u0061tic() {}", + "static get st\\u0061tic() {}", + "static set st\\u0061tic(v) {}", + "*st\\u0061tic() {}", + "static *st\\u0061tic() {}", NULL}; + // clang-format on static const ParserFlag always_flags[] = { kAllowHarmonySloppy @@ -4928,6 +4953,23 @@ TEST(ConstParsingInForIn) { } +TEST(StatementParsingInForIn) { + const char* context_data[][2] = {{"", ""}, + {"'use strict';", ""}, + {"function foo(){ 'use strict';", "}"}, + {NULL, NULL}}; + + const char* data[] = {"for(x in {}, {}) {}", "for(var x in {}, {}) {}", + "for(let x in {}, {}) {}", "for(const x in {}, {}) {}", + NULL}; + + static const ParserFlag always_flags[] = { + kAllowHarmonySloppy, kAllowHarmonySloppyLet, kNoLegacyConst}; + RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, always_flags, + arraysize(always_flags)); +} + + TEST(ConstParsingInForInError) { const char* context_data[][2] = {{"'use strict';", ""}, {"function foo(){ 'use strict';", "}"}, @@ -5101,6 +5143,76 @@ TEST(ForOfNoDeclarationsError) { } +TEST(ForOfInOperator) { + const char* context_data[][2] = {{"", ""}, + {"'use strict';", ""}, + {"function foo(){ 'use strict';", "}"}, + {NULL, NULL}}; + + const char* data[] = { + "for(x of 'foo' in {}) {}", "for(var x of 'foo' in {}) {}", + "for(let x of 'foo' in {}) {}", "for(const x of 'foo' in {}) {}", NULL}; + + static const ParserFlag always_flags[] = { + kAllowHarmonySloppy, kAllowHarmonySloppyLet, kNoLegacyConst}; + RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(ForOfYieldIdentifier) { + const char* context_data[][2] = {{"", ""}, {NULL, NULL}}; + + const char* data[] = {"for(x of yield) {}", "for(var x of yield) {}", + "for(let x of yield) {}", "for(const x of yield) {}", + NULL}; + + static const ParserFlag always_flags[] = { + kAllowHarmonySloppy, kAllowHarmonySloppyLet, kNoLegacyConst}; + RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(ForOfYieldExpression) { + const char* context_data[][2] = {{"", ""}, + {"'use strict';", ""}, + {"function foo(){ 'use strict';", "}"}, + {NULL, NULL}}; + + const char* data[] = {"function* g() { for(x of yield) {} }", + "function* g() { for(var x of yield) {} }", + "function* g() { for(let x of yield) {} }", + "function* g() { for(const x of yield) {} }", NULL}; + + static const ParserFlag always_flags[] = { + kAllowHarmonySloppy, kAllowHarmonySloppyLet, kNoLegacyConst}; + RunParserSyncTest(context_data, data, kSuccess, nullptr, 0, always_flags, + arraysize(always_flags)); +} + + +TEST(ForOfExpressionError) { + const char* context_data[][2] = {{"", ""}, + {"'use strict';", ""}, + {"function foo(){ 'use strict';", "}"}, + {NULL, NULL}}; + + const char* data[] = { + "for(x of [], []) {}", "for(var x of [], []) {}", + "for(let x of [], []) {}", "for(const x of [], []) {}", + + // AssignmentExpression should be validated statically: + "for(x of { y = 23 }) {}", "for(var x of { y = 23 }) {}", + "for(let x of { y = 23 }) {}", "for(const x of { y = 23 }) {}", NULL}; + + static const ParserFlag always_flags[] = { + kAllowHarmonySloppy, kAllowHarmonySloppyLet, kNoLegacyConst}; + RunParserSyncTest(context_data, data, kError, nullptr, 0, always_flags, + arraysize(always_flags)); +} + + TEST(InvalidUnicodeEscapes) { const char* context_data[][2] = {{"", ""}, {"'use strict';", ""}, @@ -5558,6 +5670,7 @@ TEST(ComputedPropertyNameShorthandError) { TEST(BasicImportExportParsing) { i::FLAG_harmony_modules = true; + // clang-format off const char* kSources[] = { "export let x = 0;", "export var y = 0;", @@ -5569,7 +5682,11 @@ TEST(BasicImportExportParsing) { "var a, b, c; export { a, b as baz, c };", "var d, e; export { d as dreary, e, };", "export default function f() {}", + "export default function() {}", + "export default function*() {}", "export default class C {}", + "export default class {}" + "export default class extends C {}" "export default 42", "var x; export default x = 7", "export { Q } from 'somemodule.js';", @@ -5596,6 +5713,7 @@ TEST(BasicImportExportParsing) { "import { static as s } from 'm.js';", "import { let as l } from 'm.js';", }; + // clang-format on i::Isolate* isolate = CcTest::i_isolate(); i::Factory* factory = isolate->factory(); @@ -5652,6 +5770,7 @@ TEST(BasicImportExportParsing) { TEST(ImportExportParsingErrors) { i::FLAG_harmony_modules = true; + // clang-format off const char* kErrorSources[] = { "export {", "var a; export { a", @@ -5680,6 +5799,10 @@ TEST(ImportExportParsingErrors) { "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 };", + "export function() {}", + "export function*() {}", + "export class {}", + "export class extends C {}", "import from;", "import from 'm.js';", @@ -5708,11 +5831,8 @@ TEST(ImportExportParsingErrors) { "import * as x, * as y from 'm.js';", "import {x}, {y} from 'm.js';", "import * as x, {y} from 'm.js';", - - // TODO(ES6): These two forms should be supported - "export default function() {};", - "export default class {};" }; + // clang-format on i::Isolate* isolate = CcTest::i_isolate(); i::Factory* factory = isolate->factory(); @@ -6538,61 +6658,9 @@ TEST(StrongModeFreeVariablesDeclaredInGlobalPrototype) { } -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(CcTest::isolate()); - - // 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(CcTest::isolate()); - v8_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(CcTest::isolate()); - v8_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)); - } -} - +static const ParserFlag kAllDestructuringFlags[] = { + kAllowHarmonyDestructuring, kAllowHarmonyDestructuringAssignment, + kAllowHarmonyDefaultParameters}; TEST(DestructuringPositiveTests) { i::FLAG_harmony_destructuring_bind = true; @@ -6650,6 +6718,8 @@ TEST(DestructuringPositiveTests) { static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring}; RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, data, kSuccess, NULL, 0, + kAllDestructuringFlags, arraysize(kAllDestructuringFlags)); } @@ -6727,6 +6797,10 @@ TEST(DestructuringNegativeTests) { "[...rest,...rest1]", "[a,b,...rest,...rest1]", "[a,,..rest,...rest1]", + "[x, y, ...z = 1]", + "[...z = 1]", + "[x, y, ...[z] = [1]]", + "[...[z] = [1]]", "{ x : 3 }", "{ x : 'foo' }", "{ x : /foo/ }", @@ -6739,6 +6813,9 @@ TEST(DestructuringNegativeTests) { // clang-format on RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, data, kError, NULL, 0, + kAllDestructuringFlags, + arraysize(kAllDestructuringFlags)); } { // All modes. @@ -6759,6 +6836,9 @@ TEST(DestructuringNegativeTests) { // clang-format on RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, data, kError, NULL, 0, + kAllDestructuringFlags, + arraysize(kAllDestructuringFlags)); } { // Strict mode. @@ -6779,6 +6859,9 @@ TEST(DestructuringNegativeTests) { // clang-format on RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, data, kError, NULL, 0, + kAllDestructuringFlags, + arraysize(kAllDestructuringFlags)); } { // 'yield' in generators. @@ -6797,6 +6880,9 @@ TEST(DestructuringNegativeTests) { // clang-format on RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags, arraysize(always_flags)); + RunParserSyncTest(context_data, data, kError, NULL, 0, + kAllDestructuringFlags, + arraysize(kAllDestructuringFlags)); } { // Declaration-specific errors @@ -7083,6 +7169,8 @@ TEST(DestructuringAssignmentNegativeTests) { "[...x,]", "[x, y, ...z = 1]", "[...z = 1]", + "[x, y, ...[z] = [1]]", + "[...[z] = [1]]", // v8:4657 "({ x: x4, x: (x+=1e4) })", @@ -7333,14 +7421,7 @@ TEST(DefaultParametersYieldInInitializers) { "x, y=f(yield)", "{x=f(yield)}", "[x=f(yield)]", - NULL - }; - // TODO(wingo): These aren't really destructuring assignment patterns; we're - // just splitting them for now until the parser gets support for arrow - // function arguments that look like destructuring assignments. When that - // happens we should unify destructuring_assignment_data and parameter_data. - const char* destructuring_assignment_data[] = { "{x}=yield", "[x]=yield", @@ -7359,26 +7440,16 @@ TEST(DefaultParametersYieldInInitializers) { RunParserSyncTest(sloppy_function_context_data, parameter_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); - RunParserSyncTest(sloppy_function_context_data, destructuring_assignment_data, - kSuccess, NULL, 0, always_flags, arraysize(always_flags)); RunParserSyncTest(sloppy_arrow_context_data, parameter_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); - RunParserSyncTest(sloppy_arrow_context_data, destructuring_assignment_data, - kSuccess, NULL, 0, always_flags, arraysize(always_flags)); RunParserSyncTest(strict_function_context_data, parameter_data, kError, NULL, 0, always_flags, arraysize(always_flags)); - RunParserSyncTest(strict_function_context_data, destructuring_assignment_data, - kError, NULL, 0, always_flags, arraysize(always_flags)); RunParserSyncTest(strict_arrow_context_data, parameter_data, kError, NULL, 0, always_flags, arraysize(always_flags)); - RunParserSyncTest(strict_arrow_context_data, destructuring_assignment_data, - kError, NULL, 0, always_flags, arraysize(always_flags)); RunParserSyncTest(generator_context_data, parameter_data, kError, NULL, 0, always_flags, arraysize(always_flags)); - RunParserSyncTest(generator_context_data, destructuring_assignment_data, - kError, NULL, 0, always_flags, arraysize(always_flags)); } @@ -7689,6 +7760,13 @@ TEST(LetSloppyOnly) { "for (const [let] = 1; let < 1; let++) {}", "for (const [let] in {}) {}", "for (const [let] of []) {}", + + // Sprinkle in the escaped version too. + "let l\\u0065t = 1", + "const l\\u0065t = 1", + "let [l\\u0065t] = 1", + "const [l\\u0065t] = 1", + "for (let l\\u0065t in {}) {}", NULL }; // clang-format on @@ -7747,6 +7825,7 @@ TEST(EscapedKeywords) { "wh\\u0069le (true) { }", "w\\u0069th (this.scope) { }", "(function*() { y\\u0069eld 1; })()", + "(function*() { var y\\u0069eld = 1; })()", "var \\u0065num = 1;", "var { \\u0065num } = {}", @@ -7784,7 +7863,11 @@ TEST(EscapedKeywords) { "do { ; } wh\\u0069le (true) { }", "(function*() { return (n++, y\\u0069eld 1); })()", "class C { st\\u0061tic bar() {} }", + "class C { st\\u0061tic *bar() {} }", + "class C { st\\u0061tic get bar() {} }", + "class C { st\\u0061tic set bar() {} }", + // TODO(adamk): These should not be errors in sloppy mode. "(y\\u0069eld);", "var y\\u0069eld = 1;", "var { y\\u0069eld } = {};", @@ -7810,14 +7893,14 @@ TEST(EscapedKeywords) { }; // clang-format on - RunParserSyncTest(sloppy_context_data, let_data, kError, NULL, 0, + RunParserSyncTest(sloppy_context_data, let_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); RunParserSyncTest(strict_context_data, let_data, kError, NULL, 0, always_flags, arraysize(always_flags)); static const ParserFlag sloppy_let_flags[] = { kAllowHarmonySloppy, kAllowHarmonySloppyLet, kAllowHarmonyDestructuring}; - RunParserSyncTest(sloppy_context_data, let_data, kError, NULL, 0, + RunParserSyncTest(sloppy_context_data, let_data, kSuccess, NULL, 0, sloppy_let_flags, arraysize(sloppy_let_flags)); // Non-errors in sloppy mode @@ -7839,6 +7922,9 @@ TEST(EscapedKeywords) { "(publ\\u0069c);", "var publ\\u0069c = 1;", "var { publ\\u0069c } = {};", + "(st\\u0061tic);", + "var st\\u0061tic = 1;", + "var { st\\u0061tic } = {};", NULL}; RunParserSyncTest(sloppy_context_data, valid_data, kSuccess, NULL, 0, always_flags, arraysize(always_flags)); @@ -7850,9 +7936,55 @@ TEST(EscapedKeywords) { TEST(MiscSyntaxErrors) { + // clang-format off const char* context_data[][2] = { - {"'use strict'", ""}, {"", ""}, {NULL, NULL}}; - const char* error_data[] = {"for (();;) {}", NULL}; + { "'use strict'", "" }, + { "", "" }, + { NULL, NULL } + }; + const char* error_data[] = { + "for (();;) {}", + + // crbug.com/582626 + "{ NaN ,chA((evarA=new t ( l = !.0[((... co -a0([1]))=> greturnkf", + NULL + }; + // clang-format on RunParserSyncTest(context_data, error_data, kError, NULL, 0, NULL, 0); } + +TEST(FunctionSentErrors) { + // clang-format off + const char* context_data[][2] = { + { "'use strict'", "" }, + { "", "" }, + { NULL, NULL } + }; + const char* error_data[] = { + "var x = function.sent", + "function* g() { yield function.s\\u0065nt; }", + NULL + }; + // clang-format on + + static const ParserFlag always_flags[] = {kAllowHarmonyFunctionSent}; + RunParserSyncTest(context_data, error_data, kError, always_flags, + arraysize(always_flags)); +} + +TEST(NewTargetErrors) { + // clang-format off + const char* context_data[][2] = { + { "'use strict'", "" }, + { "", "" }, + { NULL, NULL } + }; + const char* error_data[] = { + "var x = new.target", + "function f() { return new.t\\u0061rget; }", + NULL + }; + // clang-format on + RunParserSyncTest(context_data, error_data, kError); +} diff --git a/deps/v8/test/cctest/test-profile-generator.cc b/deps/v8/test/cctest/test-profile-generator.cc index 82c0f30bd6..fa7dc155ee 100644 --- a/deps/v8/test/cctest/test-profile-generator.cc +++ b/deps/v8/test/cctest/test-profile-generator.cc @@ -428,11 +428,13 @@ TEST(SampleIds) { // (root)#1 -> aaa #2 -> bbb #4 -> ccc #5 - sample2 // -> ccc #6 -> aaa #7 - sample3 TickSample sample1; + sample1.timestamp = v8::base::TimeTicks::HighResolutionNow(); sample1.pc = ToAddress(0x1600); sample1.stack[0] = ToAddress(0x1510); sample1.frames_count = 1; generator.RecordTickSample(sample1); TickSample sample2; + sample2.timestamp = v8::base::TimeTicks::HighResolutionNow(); sample2.pc = ToAddress(0x1925); sample2.stack[0] = ToAddress(0x1780); sample2.stack[1] = ToAddress(0x10000); // non-existent. @@ -440,6 +442,7 @@ TEST(SampleIds) { sample2.frames_count = 3; generator.RecordTickSample(sample2); TickSample sample3; + sample3.timestamp = v8::base::TimeTicks::HighResolutionNow(); sample3.pc = ToAddress(0x1510); sample3.stack[0] = ToAddress(0x1910); sample3.stack[1] = ToAddress(0x1610); diff --git a/deps/v8/test/cctest/test-regexp.cc b/deps/v8/test/cctest/test-regexp.cc index a91058cc24..14ec12f21b 100644 --- a/deps/v8/test/cctest/test-regexp.cc +++ b/deps/v8/test/cctest/test-regexp.cc @@ -96,7 +96,7 @@ static bool CheckParse(const char* input) { FlatStringReader reader(CcTest::i_isolate(), CStrVector(input)); RegExpCompileData result; return v8::internal::RegExpParser::ParseRegExp( - CcTest::i_isolate(), &zone, &reader, false, false, &result); + CcTest::i_isolate(), &zone, &reader, JSRegExp::kNone, &result); } @@ -106,8 +106,10 @@ static void CheckParseEq(const char* input, const char* expected, Zone zone; FlatStringReader reader(CcTest::i_isolate(), CStrVector(input)); RegExpCompileData result; - CHECK(v8::internal::RegExpParser::ParseRegExp( - CcTest::i_isolate(), &zone, &reader, false, unicode, &result)); + JSRegExp::Flags flags = JSRegExp::kNone; + if (unicode) flags |= JSRegExp::kUnicode; + CHECK(v8::internal::RegExpParser::ParseRegExp(CcTest::i_isolate(), &zone, + &reader, flags, &result)); CHECK(result.tree != NULL); CHECK(result.error.is_null()); std::ostringstream os; @@ -125,7 +127,7 @@ static bool CheckSimple(const char* input) { FlatStringReader reader(CcTest::i_isolate(), CStrVector(input)); RegExpCompileData result; CHECK(v8::internal::RegExpParser::ParseRegExp( - CcTest::i_isolate(), &zone, &reader, false, false, &result)); + CcTest::i_isolate(), &zone, &reader, JSRegExp::kNone, &result)); CHECK(result.tree != NULL); CHECK(result.error.is_null()); return result.simple; @@ -143,7 +145,7 @@ static MinMaxPair CheckMinMaxMatch(const char* input) { FlatStringReader reader(CcTest::i_isolate(), CStrVector(input)); RegExpCompileData result; CHECK(v8::internal::RegExpParser::ParseRegExp( - CcTest::i_isolate(), &zone, &reader, false, false, &result)); + CcTest::i_isolate(), &zone, &reader, JSRegExp::kNone, &result)); CHECK(result.tree != NULL); CHECK(result.error.is_null()); int min_match = result.tree->min_match(); @@ -206,8 +208,8 @@ void TestRegExpParser(bool lookbehind) { } CheckParseEq("()", "(^ %)"); CheckParseEq("(?=)", "(-> + %)"); - CheckParseEq("[]", "^[\\x00-\\uffff]"); // Doesn't compile on windows - CheckParseEq("[^]", "[\\x00-\\uffff]"); // \uffff isn't in codepage 1252 + CheckParseEq("[]", "^[\\x00-\\u{10ffff}]"); // Doesn't compile on windows + CheckParseEq("[^]", "[\\x00-\\u{10ffff}]"); // \uffff isn't in codepage 1252 CheckParseEq("[x]", "[x]"); CheckParseEq("[xyz]", "[x y z]"); CheckParseEq("[a-zA-Z0-9]", "[a-z A-Z 0-9]"); @@ -316,6 +318,10 @@ void TestRegExpParser(bool lookbehind) { CheckParseEq("\\u{12345}{3}", "(# 3 3 g '\\ud808\\udf45')", true); CheckParseEq("\\u{12345}*", "(# 0 - g '\\ud808\\udf45')", true); + CheckParseEq("\\ud808\\udf45*", "(# 0 - g '\\ud808\\udf45')", true); + CheckParseEq("[\\ud808\\udf45-\\ud809\\udccc]", "[\\u{012345}-\\u{0124cc}]", + true); + CHECK_SIMPLE("", false); CHECK_SIMPLE("a", true); CHECK_SIMPLE("a|b", false); @@ -454,7 +460,7 @@ static void ExpectError(const char* input, FlatStringReader reader(CcTest::i_isolate(), CStrVector(input)); RegExpCompileData result; CHECK(!v8::internal::RegExpParser::ParseRegExp( - CcTest::i_isolate(), &zone, &reader, false, false, &result)); + CcTest::i_isolate(), &zone, &reader, JSRegExp::kNone, &result)); CHECK(result.tree == NULL); CHECK(!result.error.is_null()); v8::base::SmartArrayPointer<char> str = result.error->ToCString(ALLOW_NULLS); @@ -523,7 +529,7 @@ static void TestCharacterClassEscapes(uc16 c, bool (pred)(uc16 c)) { ZoneList<CharacterRange>* ranges = new(&zone) ZoneList<CharacterRange>(2, &zone); CharacterRange::AddClassEscape(c, ranges, &zone); - for (unsigned i = 0; i < (1 << 16); i++) { + for (uc32 i = 0; i < (1 << 16); i++) { bool in_class = false; for (int j = 0; !in_class && j < ranges->length(); j++) { CharacterRange& range = ranges->at(j); @@ -550,17 +556,19 @@ static RegExpNode* Compile(const char* input, bool multiline, bool unicode, Isolate* isolate = CcTest::i_isolate(); FlatStringReader reader(isolate, CStrVector(input)); RegExpCompileData compile_data; + JSRegExp::Flags flags = JSRegExp::kNone; + if (multiline) flags = JSRegExp::kMultiline; + if (unicode) flags = JSRegExp::kUnicode; if (!v8::internal::RegExpParser::ParseRegExp(CcTest::i_isolate(), zone, - &reader, multiline, unicode, - &compile_data)) + &reader, flags, &compile_data)) return NULL; Handle<String> pattern = isolate->factory() ->NewStringFromUtf8(CStrVector(input)) .ToHandleChecked(); Handle<String> sample_subject = isolate->factory()->NewStringFromUtf8(CStrVector("")).ToHandleChecked(); - RegExpEngine::Compile(isolate, zone, &compile_data, false, false, multiline, - false, pattern, sample_subject, is_one_byte); + RegExpEngine::Compile(isolate, zone, &compile_data, flags, pattern, + sample_subject, is_one_byte); return compile_data.node; } @@ -678,7 +686,7 @@ TEST(DispatchTableConstruction) { for (int i = 0; i < kRangeCount; i++) { uc16* range = ranges[i]; for (int j = 0; j < 2 * kRangeSize; j += 2) - table.AddRange(CharacterRange(range[j], range[j + 1]), i, &zone); + table.AddRange(CharacterRange::Range(range[j], range[j + 1]), i, &zone); } // Check that the table looks as we would expect for (int p = 0; p < kLimit; p++) { @@ -1178,16 +1186,16 @@ TEST(MacroAssemblerNativeBackRefNoCase) { m.WriteCurrentPositionToRegister(2, 0); m.AdvanceCurrentPosition(3); m.WriteCurrentPositionToRegister(3, 0); - m.CheckNotBackReferenceIgnoreCase(2, false, &fail); // Match "AbC". - m.CheckNotBackReferenceIgnoreCase(2, false, &fail); // Match "ABC". + m.CheckNotBackReferenceIgnoreCase(2, false, false, &fail); // Match "AbC". + m.CheckNotBackReferenceIgnoreCase(2, false, false, &fail); // Match "ABC". Label expected_fail; - m.CheckNotBackReferenceIgnoreCase(2, false, &expected_fail); + m.CheckNotBackReferenceIgnoreCase(2, false, false, &expected_fail); m.Bind(&fail); m.Fail(); m.Bind(&expected_fail); m.AdvanceCurrentPosition(3); // Skip "xYz" - m.CheckNotBackReferenceIgnoreCase(2, false, &succ); + m.CheckNotBackReferenceIgnoreCase(2, false, false, &succ); m.Fail(); m.Bind(&succ); @@ -1490,7 +1498,7 @@ TEST(AddInverseToTable) { int from = PseudoRandom(t + 87, i + 25) % kLimit; int to = from + (PseudoRandom(i + 87, t + 25) % (kLimit / 20)); if (to > kLimit) to = kLimit; - ranges->Add(CharacterRange(from, to), &zone); + ranges->Add(CharacterRange::Range(from, to), &zone); } DispatchTable table(&zone); DispatchTableConstructor cons(&table, false, &zone); @@ -1507,7 +1515,7 @@ TEST(AddInverseToTable) { Zone zone; ZoneList<CharacterRange>* ranges = new(&zone) ZoneList<CharacterRange>(1, &zone); - ranges->Add(CharacterRange(0xFFF0, 0xFFFE), &zone); + ranges->Add(CharacterRange::Range(0xFFF0, 0xFFFE), &zone); DispatchTable table(&zone); DispatchTableConstructor cons(&table, false, &zone); cons.set_choice_index(0); @@ -1621,7 +1629,9 @@ static void TestRangeCaseIndependence(Isolate* isolate, CharacterRange input, int count = expected.length(); ZoneList<CharacterRange>* list = new(&zone) ZoneList<CharacterRange>(count, &zone); - input.AddCaseEquivalents(isolate, &zone, list, false); + list->Add(input, &zone); + CharacterRange::AddCaseEquivalents(isolate, &zone, list, false); + list->Remove(0); // Remove the input before checking results. CHECK_EQ(count, list->length()); for (int i = 0; i < list->length(); i++) { CHECK_EQ(expected[i].from(), list->at(i).from()); @@ -1645,31 +1655,33 @@ TEST(CharacterRangeCaseIndependence) { CharacterRange::Singleton('A')); TestSimpleRangeCaseIndependence(isolate, CharacterRange::Singleton('z'), CharacterRange::Singleton('Z')); - TestSimpleRangeCaseIndependence(isolate, CharacterRange('a', 'z'), - CharacterRange('A', 'Z')); - TestSimpleRangeCaseIndependence(isolate, CharacterRange('c', 'f'), - CharacterRange('C', 'F')); - TestSimpleRangeCaseIndependence(isolate, CharacterRange('a', 'b'), - CharacterRange('A', 'B')); - TestSimpleRangeCaseIndependence(isolate, CharacterRange('y', 'z'), - CharacterRange('Y', 'Z')); - TestSimpleRangeCaseIndependence(isolate, CharacterRange('a' - 1, 'z' + 1), - CharacterRange('A', 'Z')); - TestSimpleRangeCaseIndependence(isolate, CharacterRange('A', 'Z'), - CharacterRange('a', 'z')); - TestSimpleRangeCaseIndependence(isolate, CharacterRange('C', 'F'), - CharacterRange('c', 'f')); - TestSimpleRangeCaseIndependence(isolate, CharacterRange('A' - 1, 'Z' + 1), - CharacterRange('a', 'z')); + TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('a', 'z'), + CharacterRange::Range('A', 'Z')); + TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('c', 'f'), + CharacterRange::Range('C', 'F')); + TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('a', 'b'), + CharacterRange::Range('A', 'B')); + TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('y', 'z'), + CharacterRange::Range('Y', 'Z')); + TestSimpleRangeCaseIndependence(isolate, + CharacterRange::Range('a' - 1, 'z' + 1), + CharacterRange::Range('A', 'Z')); + TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('A', 'Z'), + CharacterRange::Range('a', 'z')); + TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('C', 'F'), + CharacterRange::Range('c', 'f')); + TestSimpleRangeCaseIndependence(isolate, + CharacterRange::Range('A' - 1, 'Z' + 1), + CharacterRange::Range('a', 'z')); // Here we need to add [l-z] to complete the case independence of // [A-Za-z] but we expect [a-z] to be added since we always add a // whole block at a time. - TestSimpleRangeCaseIndependence(isolate, CharacterRange('A', 'k'), - CharacterRange('a', 'z')); + TestSimpleRangeCaseIndependence(isolate, CharacterRange::Range('A', 'k'), + CharacterRange::Range('a', 'z')); } -static bool InClass(uc16 c, ZoneList<CharacterRange>* ranges) { +static bool InClass(uc32 c, ZoneList<CharacterRange>* ranges) { if (ranges == NULL) return false; for (int i = 0; i < ranges->length(); i++) { @@ -1681,29 +1693,46 @@ static bool InClass(uc16 c, ZoneList<CharacterRange>* ranges) { } -TEST(CharClassDifference) { +TEST(UnicodeRangeSplitter) { Zone zone; ZoneList<CharacterRange>* base = new(&zone) ZoneList<CharacterRange>(1, &zone); base->Add(CharacterRange::Everything(), &zone); - Vector<const int> overlay = CharacterRange::GetWordBounds(); - ZoneList<CharacterRange>* included = NULL; - ZoneList<CharacterRange>* excluded = NULL; - CharacterRange::Split(base, overlay, &included, &excluded, &zone); - for (int i = 0; i < (1 << 16); i++) { - bool in_base = InClass(i, base); - if (in_base) { - bool in_overlay = false; - for (int j = 0; !in_overlay && j < overlay.length(); j += 2) { - if (overlay[j] <= i && i < overlay[j+1]) - in_overlay = true; - } - CHECK_EQ(in_overlay, InClass(i, included)); - CHECK_EQ(!in_overlay, InClass(i, excluded)); - } else { - CHECK(!InClass(i, included)); - CHECK(!InClass(i, excluded)); - } + UnicodeRangeSplitter splitter(&zone, base); + // BMP + for (uc32 c = 0; c < 0xd800; c++) { + CHECK(InClass(c, splitter.bmp())); + CHECK(!InClass(c, splitter.lead_surrogates())); + CHECK(!InClass(c, splitter.trail_surrogates())); + CHECK(!InClass(c, splitter.non_bmp())); + } + // Lead surrogates + for (uc32 c = 0xd800; c < 0xdbff; c++) { + CHECK(!InClass(c, splitter.bmp())); + CHECK(InClass(c, splitter.lead_surrogates())); + CHECK(!InClass(c, splitter.trail_surrogates())); + CHECK(!InClass(c, splitter.non_bmp())); + } + // Trail surrogates + for (uc32 c = 0xdc00; c < 0xdfff; c++) { + CHECK(!InClass(c, splitter.bmp())); + CHECK(!InClass(c, splitter.lead_surrogates())); + CHECK(InClass(c, splitter.trail_surrogates())); + CHECK(!InClass(c, splitter.non_bmp())); + } + // BMP + for (uc32 c = 0xe000; c < 0xffff; c++) { + CHECK(InClass(c, splitter.bmp())); + CHECK(!InClass(c, splitter.lead_surrogates())); + CHECK(!InClass(c, splitter.trail_surrogates())); + CHECK(!InClass(c, splitter.non_bmp())); + } + // Non-BMP + for (uc32 c = 0x10000; c < 0x10ffff; c++) { + CHECK(!InClass(c, splitter.bmp())); + CHECK(!InClass(c, splitter.lead_surrogates())); + CHECK(!InClass(c, splitter.trail_surrogates())); + CHECK(InClass(c, splitter.non_bmp())); } } @@ -1714,9 +1743,9 @@ TEST(CanonicalizeCharacterSets) { new(&zone) ZoneList<CharacterRange>(4, &zone); CharacterSet set(list); - list->Add(CharacterRange(10, 20), &zone); - list->Add(CharacterRange(30, 40), &zone); - list->Add(CharacterRange(50, 60), &zone); + list->Add(CharacterRange::Range(10, 20), &zone); + list->Add(CharacterRange::Range(30, 40), &zone); + list->Add(CharacterRange::Range(50, 60), &zone); set.Canonicalize(); CHECK_EQ(3, list->length()); CHECK_EQ(10, list->at(0).from()); @@ -1727,9 +1756,9 @@ TEST(CanonicalizeCharacterSets) { CHECK_EQ(60, list->at(2).to()); list->Rewind(0); - list->Add(CharacterRange(10, 20), &zone); - list->Add(CharacterRange(50, 60), &zone); - list->Add(CharacterRange(30, 40), &zone); + list->Add(CharacterRange::Range(10, 20), &zone); + list->Add(CharacterRange::Range(50, 60), &zone); + list->Add(CharacterRange::Range(30, 40), &zone); set.Canonicalize(); CHECK_EQ(3, list->length()); CHECK_EQ(10, list->at(0).from()); @@ -1740,11 +1769,11 @@ TEST(CanonicalizeCharacterSets) { CHECK_EQ(60, list->at(2).to()); list->Rewind(0); - list->Add(CharacterRange(30, 40), &zone); - list->Add(CharacterRange(10, 20), &zone); - list->Add(CharacterRange(25, 25), &zone); - list->Add(CharacterRange(100, 100), &zone); - list->Add(CharacterRange(1, 1), &zone); + list->Add(CharacterRange::Range(30, 40), &zone); + list->Add(CharacterRange::Range(10, 20), &zone); + list->Add(CharacterRange::Range(25, 25), &zone); + list->Add(CharacterRange::Range(100, 100), &zone); + list->Add(CharacterRange::Range(1, 1), &zone); set.Canonicalize(); CHECK_EQ(5, list->length()); CHECK_EQ(1, list->at(0).from()); @@ -1759,9 +1788,9 @@ TEST(CanonicalizeCharacterSets) { CHECK_EQ(100, list->at(4).to()); list->Rewind(0); - list->Add(CharacterRange(10, 19), &zone); - list->Add(CharacterRange(21, 30), &zone); - list->Add(CharacterRange(20, 20), &zone); + list->Add(CharacterRange::Range(10, 19), &zone); + list->Add(CharacterRange::Range(21, 30), &zone); + list->Add(CharacterRange::Range(20, 20), &zone); set.Canonicalize(); CHECK_EQ(1, list->length()); CHECK_EQ(10, list->at(0).from()); diff --git a/deps/v8/test/cctest/test-transitions.cc b/deps/v8/test/cctest/test-transitions.cc index 8834f9ade1..b7eb50f1c9 100644 --- a/deps/v8/test/cctest/test-transitions.cc +++ b/deps/v8/test/cctest/test-transitions.cc @@ -10,6 +10,7 @@ #include "src/compilation-cache.h" #include "src/execution.h" #include "src/factory.h" +#include "src/field-type.h" #include "src/global-handles.h" #include "test/cctest/cctest.h" @@ -51,13 +52,13 @@ TEST(TransitionArray_SimpleFieldTransitions) { Handle<Map> map0 = Map::Create(isolate, 0); Handle<Map> map1 = - Map::CopyWithField(map0, name1, handle(HeapType::Any(), isolate), - attributes, Representation::Tagged(), - OMIT_TRANSITION).ToHandleChecked(); + Map::CopyWithField(map0, name1, handle(FieldType::Any(), isolate), + attributes, Representation::Tagged(), OMIT_TRANSITION) + .ToHandleChecked(); Handle<Map> map2 = - Map::CopyWithField(map0, name2, handle(HeapType::Any(), isolate), - attributes, Representation::Tagged(), - OMIT_TRANSITION).ToHandleChecked(); + Map::CopyWithField(map0, name2, handle(FieldType::Any(), isolate), + attributes, Representation::Tagged(), OMIT_TRANSITION) + .ToHandleChecked(); CHECK(map0->raw_transitions()->IsSmi()); @@ -102,13 +103,13 @@ TEST(TransitionArray_FullFieldTransitions) { Handle<Map> map0 = Map::Create(isolate, 0); Handle<Map> map1 = - Map::CopyWithField(map0, name1, handle(HeapType::Any(), isolate), - attributes, Representation::Tagged(), - OMIT_TRANSITION).ToHandleChecked(); + Map::CopyWithField(map0, name1, handle(FieldType::Any(), isolate), + attributes, Representation::Tagged(), OMIT_TRANSITION) + .ToHandleChecked(); Handle<Map> map2 = - Map::CopyWithField(map0, name2, handle(HeapType::Any(), isolate), - attributes, Representation::Tagged(), - OMIT_TRANSITION).ToHandleChecked(); + Map::CopyWithField(map0, name2, handle(FieldType::Any(), isolate), + attributes, Representation::Tagged(), OMIT_TRANSITION) + .ToHandleChecked(); CHECK(map0->raw_transitions()->IsSmi()); @@ -159,10 +160,10 @@ TEST(TransitionArray_DifferentFieldNames) { EmbeddedVector<char, 64> buffer; SNPrintF(buffer, "prop%d", i); Handle<String> name = factory->InternalizeUtf8String(buffer.start()); - Handle<Map> map = - Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate), - attributes, Representation::Tagged(), - OMIT_TRANSITION).ToHandleChecked(); + Handle<Map> map = Map::CopyWithField( + map0, name, handle(FieldType::Any(), isolate), + attributes, Representation::Tagged(), OMIT_TRANSITION) + .ToHandleChecked(); names[i] = name; maps[i] = map; @@ -208,10 +209,10 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) { for (int i = 0; i < ATTRS_COUNT; i++) { PropertyAttributes attributes = static_cast<PropertyAttributes>(i); - Handle<Map> map = - Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate), - attributes, Representation::Tagged(), - OMIT_TRANSITION).ToHandleChecked(); + Handle<Map> map = Map::CopyWithField( + map0, name, handle(FieldType::Any(), isolate), + attributes, Representation::Tagged(), OMIT_TRANSITION) + .ToHandleChecked(); attr_maps[i] = map; TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION); @@ -252,9 +253,9 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) { SNPrintF(buffer, "prop%d", i); Handle<String> name = factory->InternalizeUtf8String(buffer.start()); Handle<Map> map = - Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate), NONE, - Representation::Tagged(), - OMIT_TRANSITION).ToHandleChecked(); + Map::CopyWithField(map0, name, handle(FieldType::Any(), isolate), NONE, + Representation::Tagged(), OMIT_TRANSITION) + .ToHandleChecked(); names[i] = name; maps[i] = map; @@ -270,10 +271,10 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) { for (int i = 0; i < ATTRS_COUNT; i++) { PropertyAttributes attributes = static_cast<PropertyAttributes>(i); - Handle<Map> map = - Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate), - attributes, Representation::Tagged(), - OMIT_TRANSITION).ToHandleChecked(); + Handle<Map> map = Map::CopyWithField( + map0, name, handle(FieldType::Any(), isolate), + attributes, Representation::Tagged(), OMIT_TRANSITION) + .ToHandleChecked(); attr_maps[i] = map; TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION); diff --git a/deps/v8/test/cctest/test-types.cc b/deps/v8/test/cctest/test-types.cc index 4549654501..2e658b0255 100644 --- a/deps/v8/test/cctest/test-types.cc +++ b/deps/v8/test/cctest/test-types.cc @@ -27,109 +27,43 @@ static bool IsInteger(i::Object* x) { typedef uint32_t bitset; - -struct ZoneRep { - typedef void* Struct; - - static bool IsStruct(Type* t, int tag) { - return !IsBitset(t) && reinterpret_cast<intptr_t>(AsStruct(t)[0]) == tag; - } - static bool IsBitset(Type* t) { return reinterpret_cast<uintptr_t>(t) & 1; } - // HACK: the number 5 below is the value of StructuralType::kUnionTag. - static bool IsUnion(Type* t) { return t->IsUnionForTesting(); } - - static Struct* AsStruct(Type* t) { - return reinterpret_cast<Struct*>(t); - } - static bitset AsBitset(Type* t) { - return static_cast<bitset>(reinterpret_cast<uintptr_t>(t) ^ 1u); - } - static Struct* AsUnion(Type* t) { - return AsStruct(t); - } - static int Length(Struct* structured) { - return static_cast<int>(reinterpret_cast<intptr_t>(structured[1])); - } - - static Zone* ToRegion(Zone* zone, Isolate* isolate) { return zone; } - - struct BitsetType : Type::BitsetType { - using Type::BitsetType::New; - using Type::BitsetType::Glb; - using Type::BitsetType::Lub; - using Type::BitsetType::IsInhabited; - }; -}; - - -struct HeapRep { - typedef FixedArray Struct; - - static bool IsStruct(Handle<HeapType> t, int tag) { - return t->IsFixedArray() && Smi::cast(AsStruct(t)->get(0))->value() == tag; - } - static bool IsBitset(Handle<HeapType> t) { return t->IsSmi(); } - // HACK: the number 5 below is the value of StructuralType::kUnionTag. - static bool IsUnion(Handle<HeapType> t) { return t->IsUnionForTesting(); } - - static Struct* AsStruct(Handle<HeapType> t) { return FixedArray::cast(*t); } - static bitset AsBitset(Handle<HeapType> t) { - return static_cast<bitset>(reinterpret_cast<uintptr_t>(*t)); - } - static Struct* AsUnion(Handle<HeapType> t) { return AsStruct(t); } - static int Length(Struct* structured) { return structured->length() - 1; } - - static Isolate* ToRegion(Zone* zone, Isolate* isolate) { return isolate; } - - struct BitsetType : HeapType::BitsetType { - using HeapType::BitsetType::New; - using HeapType::BitsetType::Glb; - using HeapType::BitsetType::Lub; - using HeapType::BitsetType::IsInhabited; - static bitset Glb(Handle<HeapType> type) { return Glb(*type); } - static bitset Lub(Handle<HeapType> type) { return Lub(*type); } - }; -}; - - -template<class Type, class TypeHandle, class Region, class Rep> -struct Tests : Rep { - typedef Types<Type, TypeHandle, Region> TypesInstance; - typedef typename TypesInstance::TypeVector::iterator TypeIterator; - typedef typename TypesInstance::MapVector::iterator MapIterator; - typedef typename TypesInstance::ValueVector::iterator ValueIterator; +struct Tests { + typedef Types::TypeVector::iterator TypeIterator; + typedef Types::MapVector::iterator MapIterator; + typedef Types::ValueVector::iterator ValueIterator; Isolate* isolate; HandleScope scope; Zone zone; - TypesInstance T; + Types T; Tests() : isolate(CcTest::InitIsolateOnce()), scope(isolate), zone(), - T(Rep::ToRegion(&zone, isolate), isolate, - isolate->random_number_generator()) {} - - bool Equal(TypeHandle type1, TypeHandle type2) { - return - type1->Equals(type2) && - this->IsBitset(type1) == this->IsBitset(type2) && - this->IsUnion(type1) == this->IsUnion(type2) && - type1->NumClasses() == type2->NumClasses() && - type1->NumConstants() == type2->NumConstants() && - (!this->IsBitset(type1) || - this->AsBitset(type1) == this->AsBitset(type2)) && - (!this->IsUnion(type1) || - this->Length(this->AsUnion(type1)) == - this->Length(this->AsUnion(type2))); + T(&zone, isolate, isolate->random_number_generator()) {} + + bool IsBitset(Type* type) { return type->IsBitsetForTesting(); } + bool IsUnion(Type* type) { return type->IsUnionForTesting(); } + BitsetType::bitset AsBitset(Type* type) { return type->AsBitsetForTesting(); } + UnionType* AsUnion(Type* type) { return type->AsUnionForTesting(); } + + bool Equal(Type* type1, Type* type2) { + return type1->Equals(type2) && + this->IsBitset(type1) == this->IsBitset(type2) && + this->IsUnion(type1) == this->IsUnion(type2) && + type1->NumClasses() == type2->NumClasses() && + type1->NumConstants() == type2->NumConstants() && + (!this->IsBitset(type1) || + this->AsBitset(type1) == this->AsBitset(type2)) && + (!this->IsUnion(type1) || + this->AsUnion(type1)->LengthForTesting() == + this->AsUnion(type2)->LengthForTesting()); } - void CheckEqual(TypeHandle type1, TypeHandle type2) { - CHECK(Equal(type1, type2)); - } + void CheckEqual(Type* type1, Type* type2) { CHECK(Equal(type1, type2)); } - void CheckSub(TypeHandle type1, TypeHandle type2) { + void CheckSub(Type* type1, Type* type2) { CHECK(type1->Is(type2)); CHECK(!type2->Is(type1)); if (this->IsBitset(type1) && this->IsBitset(type2)) { @@ -137,7 +71,7 @@ struct Tests : Rep { } } - void CheckSubOrEqual(TypeHandle type1, TypeHandle type2) { + void CheckSubOrEqual(Type* type1, Type* type2) { CHECK(type1->Is(type2)); if (this->IsBitset(type1) && this->IsBitset(type2)) { CHECK((this->AsBitset(type1) | this->AsBitset(type2)) @@ -145,7 +79,7 @@ struct Tests : Rep { } } - void CheckUnordered(TypeHandle type1, TypeHandle type2) { + void CheckUnordered(Type* type1, Type* type2) { CHECK(!type1->Is(type2)); CHECK(!type2->Is(type1)); if (this->IsBitset(type1) && this->IsBitset(type2)) { @@ -153,12 +87,12 @@ struct Tests : Rep { } } - void CheckOverlap(TypeHandle type1, TypeHandle type2) { + void CheckOverlap(Type* type1, Type* type2) { CHECK(type1->Maybe(type2)); CHECK(type2->Maybe(type1)); } - void CheckDisjoint(TypeHandle type1, TypeHandle type2) { + void CheckDisjoint(Type* type1, Type* type2) { CHECK(!type1->Is(type2)); CHECK(!type2->Is(type1)); CHECK(!type1->Maybe(type2)); @@ -167,7 +101,7 @@ struct Tests : Rep { void IsSomeType() { for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle t = *it; + Type* t = *it; CHECK(1 == this->IsBitset(t) + t->IsClass() + t->IsConstant() + t->IsRange() + this->IsUnion(t) + t->IsArray() + t->IsFunction() + t->IsContext()); @@ -185,9 +119,9 @@ struct Tests : Rep { // Union(T1, T2) is bitset for bitsets T1,T2 for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle union12 = T.Union(type1, type2); + Type* type1 = *it1; + Type* type2 = *it2; + Type* union12 = T.Union(type1, type2); CHECK(!(this->IsBitset(type1) && this->IsBitset(type2)) || this->IsBitset(union12)); } @@ -196,9 +130,9 @@ struct Tests : Rep { // Intersect(T1, T2) is bitset for bitsets T1,T2 for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle intersect12 = T.Intersect(type1, type2); + Type* type1 = *it1; + Type* type2 = *it2; + Type* intersect12 = T.Intersect(type1, type2); CHECK(!(this->IsBitset(type1) && this->IsBitset(type2)) || this->IsBitset(intersect12)); } @@ -207,9 +141,9 @@ struct Tests : Rep { // Union(T1, T2) is bitset if T2 is bitset and T1->Is(T2) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle union12 = T.Union(type1, type2); + Type* type1 = *it1; + Type* type2 = *it2; + Type* union12 = T.Union(type1, type2); CHECK(!(this->IsBitset(type2) && type1->Is(type2)) || this->IsBitset(union12)); } @@ -218,9 +152,9 @@ struct Tests : Rep { // Union(T1, T2) is bitwise disjunction for bitsets T1,T2 for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle union12 = T.Union(type1, type2); + Type* type1 = *it1; + Type* type2 = *it2; + Type* union12 = T.Union(type1, type2); if (this->IsBitset(type1) && this->IsBitset(type2)) { CHECK( (this->AsBitset(type1) | this->AsBitset(type2)) == @@ -232,10 +166,10 @@ struct Tests : Rep { // Intersect(T1, T2) is bitwise conjunction for bitsets T1,T2 (modulo None) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; + Type* type1 = *it1; + Type* type2 = *it2; if (this->IsBitset(type1) && this->IsBitset(type2)) { - TypeHandle intersect12 = T.Intersect(type1, type2); + Type* intersect12 = T.Intersect(type1, type2); bitset bits = this->AsBitset(type1) & this->AsBitset(type2); CHECK(bits == this->AsBitset(intersect12)); } @@ -251,28 +185,26 @@ struct Tests : Rep { counter++; printf("Counter: %i\n", counter); fflush(stdout); - TypeHandle type1 = *it1; - TypeHandle representation = T.Representation(type1); - TypeHandle semantic = T.Semantic(type1); - TypeHandle composed = T.Union(representation, semantic); + Type* type1 = *it1; + Type* representation = T.Representation(type1); + Type* semantic = T.Semantic(type1); + Type* composed = T.Union(representation, semantic); CHECK(type1->Equals(composed)); } // Pointwiseness of Union. for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle representation1 = T.Representation(type1); - TypeHandle semantic1 = T.Semantic(type1); - TypeHandle representation2 = T.Representation(type2); - TypeHandle semantic2 = T.Semantic(type2); - TypeHandle direct_union = T.Union(type1, type2); - TypeHandle representation_union = - T.Union(representation1, representation2); - TypeHandle semantic_union = T.Union(semantic1, semantic2); - TypeHandle composed_union = - T.Union(representation_union, semantic_union); + Type* type1 = *it1; + Type* type2 = *it2; + Type* representation1 = T.Representation(type1); + Type* semantic1 = T.Semantic(type1); + Type* representation2 = T.Representation(type2); + Type* semantic2 = T.Semantic(type2); + Type* direct_union = T.Union(type1, type2); + Type* representation_union = T.Union(representation1, representation2); + Type* semantic_union = T.Union(semantic1, semantic2); + Type* composed_union = T.Union(representation_union, semantic_union); CHECK(direct_union->Equals(composed_union)); } } @@ -280,17 +212,17 @@ struct Tests : Rep { // Pointwiseness of Intersect. for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle representation1 = T.Representation(type1); - TypeHandle semantic1 = T.Semantic(type1); - TypeHandle representation2 = T.Representation(type2); - TypeHandle semantic2 = T.Semantic(type2); - TypeHandle direct_intersection = T.Intersect(type1, type2); - TypeHandle representation_intersection = + Type* type1 = *it1; + Type* type2 = *it2; + Type* representation1 = T.Representation(type1); + Type* semantic1 = T.Semantic(type1); + Type* representation2 = T.Representation(type2); + Type* semantic2 = T.Semantic(type2); + Type* direct_intersection = T.Intersect(type1, type2); + Type* representation_intersection = T.Intersect(representation1, representation2); - TypeHandle semantic_intersection = T.Intersect(semantic1, semantic2); - TypeHandle composed_intersection = + Type* semantic_intersection = T.Intersect(semantic1, semantic2); + Type* composed_intersection = T.Union(representation_intersection, semantic_intersection); CHECK(direct_intersection->Equals(composed_intersection)); } @@ -299,12 +231,12 @@ struct Tests : Rep { // Pointwiseness of Is. for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle representation1 = T.Representation(type1); - TypeHandle semantic1 = T.Semantic(type1); - TypeHandle representation2 = T.Representation(type2); - TypeHandle semantic2 = T.Semantic(type2); + Type* type1 = *it1; + Type* type2 = *it2; + Type* representation1 = T.Representation(type1); + Type* semantic1 = T.Semantic(type1); + Type* representation2 = T.Representation(type2); + Type* semantic2 = T.Semantic(type2); bool representation_is = representation1->Is(representation2); bool semantic_is = semantic1->Is(semantic2); bool direct_is = type1->Is(type2); @@ -317,14 +249,14 @@ struct Tests : Rep { // Constructor for (MapIterator mt = T.maps.begin(); mt != T.maps.end(); ++mt) { Handle<i::Map> map = *mt; - TypeHandle type = T.Class(map); + Type* type = T.Class(map); CHECK(type->IsClass()); } // Map attribute for (MapIterator mt = T.maps.begin(); mt != T.maps.end(); ++mt) { Handle<i::Map> map = *mt; - TypeHandle type = T.Class(map); + Type* type = T.Class(map); CHECK(*map == *type->AsClass()->Map()); } @@ -333,8 +265,8 @@ struct Tests : Rep { for (MapIterator mt2 = T.maps.begin(); mt2 != T.maps.end(); ++mt2) { Handle<i::Map> map1 = *mt1; Handle<i::Map> map2 = *mt2; - TypeHandle type1 = T.Class(map1); - TypeHandle type2 = T.Class(map2); + Type* type1 = T.Class(map1); + Type* type2 = T.Class(map2); CHECK(Equal(type1, type2) == (*map1 == *map2)); } } @@ -344,14 +276,14 @@ struct Tests : Rep { // Constructor for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle<i::Object> value = *vt; - TypeHandle type = T.Constant(value); + Type* type = T.Constant(value); CHECK(type->IsConstant()); } // Value attribute for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle<i::Object> value = *vt; - TypeHandle type = T.Constant(value); + Type* type = T.Constant(value); CHECK(*value == *type->AsConstant()->Value()); } @@ -360,8 +292,8 @@ struct Tests : Rep { for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) { Handle<i::Object> value1 = *vt1; Handle<i::Object> value2 = *vt2; - TypeHandle type1 = T.Constant(value1); - TypeHandle type2 = T.Constant(value2); + Type* type1 = T.Constant(value1); + Type* type2 = T.Constant(value2); CHECK(Equal(type1, type2) == (*value1 == *value2)); } } @@ -424,7 +356,7 @@ struct Tests : Rep { double min = (*i)->Number(); double max = (*j)->Number(); if (min > max) std::swap(min, max); - TypeHandle type = T.Range(min, max); + Type* type = T.Range(min, max); CHECK(type->IsRange()); } } @@ -435,7 +367,7 @@ struct Tests : Rep { double min = (*i)->Number(); double max = (*j)->Number(); if (min > max) std::swap(min, max); - TypeHandle type = T.Range(min, max); + Type* type = T.Range(min, max); CHECK(min == type->AsRange()->Min()); CHECK(max == type->AsRange()->Max()); } @@ -457,8 +389,8 @@ struct Tests : Rep { double max2 = (*j2)->Number(); if (min1 > max1) std::swap(min1, max1); if (min2 > max2) std::swap(min2, max2); - TypeHandle type1 = T.Range(min1, max1); - TypeHandle type2 = T.Range(min2, max2); + Type* type1 = T.Range(min1, max1); + Type* type2 = T.Range(min2, max2); CHECK(Equal(type1, type2) == (min1 == min2 && max1 == max2)); } } @@ -469,25 +401,25 @@ struct Tests : Rep { void Context() { // Constructor for (int i = 0; i < 20; ++i) { - TypeHandle type = T.Random(); - TypeHandle context = T.Context(type); - CHECK(context->Iscontext()); + Type* type = T.Random(); + Type* context = T.Context(type); + CHECK(context->IsContext()); } // Attributes for (int i = 0; i < 20; ++i) { - TypeHandle type = T.Random(); - TypeHandle context = T.Context(type); + Type* type = T.Random(); + Type* context = T.Context(type); CheckEqual(type, context->AsContext()->Outer()); } // Functionality & Injectivity: Context(T1) = Context(T2) iff T1 = T2 for (int i = 0; i < 20; ++i) { for (int j = 0; j < 20; ++j) { - TypeHandle type1 = T.Random(); - TypeHandle type2 = T.Random(); - TypeHandle context1 = T.Context(type1); - TypeHandle context2 = T.Context(type2); + Type* type1 = T.Random(); + Type* type2 = T.Random(); + Type* context1 = T.Context(type1); + Type* context2 = T.Context(type2); CHECK(Equal(context1, context2) == Equal(type1, type2)); } } @@ -496,25 +428,25 @@ struct Tests : Rep { void Array() { // Constructor for (int i = 0; i < 20; ++i) { - TypeHandle type = T.Random(); - TypeHandle array = T.Array1(type); + Type* type = T.Random(); + Type* array = T.Array1(type); CHECK(array->IsArray()); } // Attributes for (int i = 0; i < 20; ++i) { - TypeHandle type = T.Random(); - TypeHandle array = T.Array1(type); + Type* type = T.Random(); + Type* array = T.Array1(type); CheckEqual(type, array->AsArray()->Element()); } // Functionality & Injectivity: Array(T1) = Array(T2) iff T1 = T2 for (int i = 0; i < 20; ++i) { for (int j = 0; j < 20; ++j) { - TypeHandle type1 = T.Random(); - TypeHandle type2 = T.Random(); - TypeHandle array1 = T.Array1(type1); - TypeHandle array2 = T.Array1(type2); + Type* type1 = T.Random(); + Type* type2 = T.Random(); + Type* array1 = T.Array1(type1); + Type* array2 = T.Array1(type2); CHECK(Equal(array1, array2) == Equal(type1, type2)); } } @@ -525,12 +457,12 @@ struct Tests : Rep { for (int i = 0; i < 20; ++i) { for (int j = 0; j < 20; ++j) { for (int k = 0; k < 20; ++k) { - TypeHandle type1 = T.Random(); - TypeHandle type2 = T.Random(); - TypeHandle type3 = T.Random(); - TypeHandle function0 = T.Function0(type1, type2); - TypeHandle function1 = T.Function1(type1, type2, type3); - TypeHandle function2 = T.Function2(type1, type2, type3); + Type* type1 = T.Random(); + Type* type2 = T.Random(); + Type* type3 = T.Random(); + Type* function0 = T.Function0(type1, type2); + Type* function1 = T.Function1(type1, type2, type3); + Type* function2 = T.Function2(type1, type2, type3); CHECK(function0->IsFunction()); CHECK(function1->IsFunction()); CHECK(function2->IsFunction()); @@ -542,12 +474,12 @@ struct Tests : Rep { for (int i = 0; i < 20; ++i) { for (int j = 0; j < 20; ++j) { for (int k = 0; k < 20; ++k) { - TypeHandle type1 = T.Random(); - TypeHandle type2 = T.Random(); - TypeHandle type3 = T.Random(); - TypeHandle function0 = T.Function0(type1, type2); - TypeHandle function1 = T.Function1(type1, type2, type3); - TypeHandle function2 = T.Function2(type1, type2, type3); + Type* type1 = T.Random(); + Type* type2 = T.Random(); + Type* type3 = T.Random(); + Type* function0 = T.Function0(type1, type2); + Type* function1 = T.Function1(type1, type2, type3); + Type* function2 = T.Function2(type1, type2, type3); CHECK_EQ(0, function0->AsFunction()->Arity()); CHECK_EQ(1, function1->AsFunction()->Arity()); CHECK_EQ(2, function2->AsFunction()->Arity()); @@ -568,17 +500,17 @@ struct Tests : Rep { for (int i = 0; i < 20; ++i) { for (int j = 0; j < 20; ++j) { for (int k = 0; k < 20; ++k) { - TypeHandle type1 = T.Random(); - TypeHandle type2 = T.Random(); - TypeHandle type3 = T.Random(); - TypeHandle function01 = T.Function0(type1, type2); - TypeHandle function02 = T.Function0(type1, type3); - TypeHandle function03 = T.Function0(type3, type2); - TypeHandle function11 = T.Function1(type1, type2, type2); - TypeHandle function12 = T.Function1(type1, type2, type3); - TypeHandle function21 = T.Function2(type1, type2, type2); - TypeHandle function22 = T.Function2(type1, type2, type3); - TypeHandle function23 = T.Function2(type1, type3, type2); + Type* type1 = T.Random(); + Type* type2 = T.Random(); + Type* type3 = T.Random(); + Type* function01 = T.Function0(type1, type2); + Type* function02 = T.Function0(type1, type3); + Type* function03 = T.Function0(type3, type2); + Type* function11 = T.Function1(type1, type2, type2); + Type* function12 = T.Function1(type1, type2, type3); + Type* function21 = T.Function2(type1, type2, type2); + Type* function22 = T.Function2(type1, type2, type3); + Type* function23 = T.Function2(type1, type3, type2); CHECK(Equal(function01, function02) == Equal(type2, type3)); CHECK(Equal(function01, function03) == Equal(type1, type3)); CHECK(Equal(function11, function12) == Equal(type2, type3)); @@ -593,8 +525,8 @@ struct Tests : Rep { // Constant(V)->Is(Of(V)) for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle<i::Object> value = *vt; - TypeHandle const_type = T.Constant(value); - TypeHandle of_type = T.Of(value); + Type* const_type = T.Constant(value); + Type* of_type = T.Of(value); CHECK(const_type->Is(of_type)); } @@ -602,9 +534,9 @@ struct Tests : Rep { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { Handle<i::Object> value = *vt; - TypeHandle type = *it; - TypeHandle const_type = T.Constant(value); - TypeHandle of_type = T.Of(value); + Type* type = *it; + Type* const_type = T.Constant(value); + Type* of_type = T.Of(value); CHECK(!of_type->Is(type) || const_type->Is(type)); } } @@ -613,9 +545,9 @@ struct Tests : Rep { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { Handle<i::Object> value = *vt; - TypeHandle type = *it; - TypeHandle const_type = T.Constant(value); - TypeHandle of_type = T.Of(value); + Type* type = *it; + Type* const_type = T.Constant(value); + Type* of_type = T.Of(value); CHECK(!const_type->Is(type) || of_type->Is(type) || type->Maybe(const_type)); } @@ -626,16 +558,16 @@ struct Tests : Rep { // Constant(V)->NowIs(NowOf(V)) for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle<i::Object> value = *vt; - TypeHandle const_type = T.Constant(value); - TypeHandle nowof_type = T.NowOf(value); + Type* const_type = T.Constant(value); + Type* nowof_type = T.NowOf(value); CHECK(const_type->NowIs(nowof_type)); } // NowOf(V)->Is(Of(V)) for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle<i::Object> value = *vt; - TypeHandle nowof_type = T.NowOf(value); - TypeHandle of_type = T.Of(value); + Type* nowof_type = T.NowOf(value); + Type* of_type = T.Of(value); CHECK(nowof_type->Is(of_type)); } @@ -643,9 +575,9 @@ struct Tests : Rep { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { Handle<i::Object> value = *vt; - TypeHandle type = *it; - TypeHandle const_type = T.Constant(value); - TypeHandle nowof_type = T.NowOf(value); + Type* type = *it; + Type* const_type = T.Constant(value); + Type* nowof_type = T.NowOf(value); CHECK(!nowof_type->NowIs(type) || const_type->NowIs(type)); } } @@ -655,9 +587,9 @@ struct Tests : Rep { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { Handle<i::Object> value = *vt; - TypeHandle type = *it; - TypeHandle const_type = T.Constant(value); - TypeHandle nowof_type = T.NowOf(value); + Type* type = *it; + Type* const_type = T.Constant(value); + Type* nowof_type = T.NowOf(value); CHECK(!const_type->NowIs(type) || nowof_type->NowIs(type) || type->Maybe(const_type)); } @@ -668,9 +600,9 @@ struct Tests : Rep { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { Handle<i::Object> value = *vt; - TypeHandle type = *it; - TypeHandle const_type = T.Constant(value); - TypeHandle nowof_type = T.NowOf(value); + Type* type = *it; + Type* const_type = T.Constant(value); + Type* nowof_type = T.NowOf(value); CHECK(!const_type->Is(type) || nowof_type->Is(type) || type->Maybe(const_type)); } @@ -682,10 +614,10 @@ struct Tests : Rep { // TODO(neis): Need to ignore representation for this to be true. /* for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; if (this->IsBitset(type) && type->Is(T.Number) && !type->Is(T.None) && !type->Is(T.NaN)) { - TypeHandle range = T.Range( + Type* range = T.Range( isolate->factory()->NewNumber(type->Min()), isolate->factory()->NewNumber(type->Max())); CHECK(range->Is(type)); @@ -695,7 +627,7 @@ struct Tests : Rep { // If b is regular numeric bitset, then b->Min() and b->Max() are integers. for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; if (this->IsBitset(type) && type->Is(T.Number) && !type->Is(T.NaN)) { CHECK(IsInteger(type->Min()) && IsInteger(type->Max())); } @@ -705,8 +637,8 @@ struct Tests : Rep { // b1->Min() >= b2->Min() and b1->Max() <= b2->Max(). for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; + Type* type1 = *it1; + Type* type2 = *it2; if (this->IsBitset(type1) && type1->Is(type2) && type2->Is(T.Number) && !type1->Is(T.NaN) && !type2->Is(T.NaN)) { CHECK(type1->Min() >= type2->Min()); @@ -717,10 +649,9 @@ struct Tests : Rep { // Lub(Range(x,y))->Min() <= x and y <= Lub(Range(x,y))->Max() for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; if (type->IsRange()) { - TypeHandle lub = Rep::BitsetType::New( - Rep::BitsetType::Lub(type), T.region()); + Type* lub = BitsetType::NewForTesting(BitsetType::Lub(type)); CHECK(lub->Min() <= type->Min() && type->Max() <= lub->Max()); } } @@ -728,7 +659,7 @@ struct Tests : Rep { // Rangification: If T->Is(Range(-inf,+inf)) and T is inhabited, then // T->Is(Range(T->Min(), T->Max())). for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; CHECK(!type->Is(T.Integer) || !type->IsInhabited() || type->Is(T.Range(type->Min(), type->Max()))); } @@ -737,19 +668,17 @@ struct Tests : Rep { void BitsetGlb() { // Lower: (T->BitsetGlb())->Is(T) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; - TypeHandle glb = - Rep::BitsetType::New(Rep::BitsetType::Glb(type), T.region()); + Type* type = *it; + Type* glb = BitsetType::NewForTesting(BitsetType::Glb(type)); CHECK(glb->Is(type)); } // Greatest: If T1->IsBitset() and T1->Is(T2), then T1->Is(T2->BitsetGlb()) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle glb2 = - Rep::BitsetType::New(Rep::BitsetType::Glb(type2), T.region()); + Type* type1 = *it1; + Type* type2 = *it2; + Type* glb2 = BitsetType::NewForTesting(BitsetType::Glb(type2)); CHECK(!this->IsBitset(type1) || !type1->Is(type2) || type1->Is(glb2)); } } @@ -757,12 +686,10 @@ struct Tests : Rep { // Monotonicity: T1->Is(T2) implies (T1->BitsetGlb())->Is(T2->BitsetGlb()) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle glb1 = - Rep::BitsetType::New(Rep::BitsetType::Glb(type1), T.region()); - TypeHandle glb2 = - Rep::BitsetType::New(Rep::BitsetType::Glb(type2), T.region()); + Type* type1 = *it1; + Type* type2 = *it2; + Type* glb1 = BitsetType::NewForTesting(BitsetType::Glb(type1)); + Type* glb2 = BitsetType::NewForTesting(BitsetType::Glb(type2)); CHECK(!type1->Is(type2) || glb1->Is(glb2)); } } @@ -771,19 +698,17 @@ struct Tests : Rep { void BitsetLub() { // Upper: T->Is(T->BitsetLub()) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; - TypeHandle lub = - Rep::BitsetType::New(Rep::BitsetType::Lub(type), T.region()); + Type* type = *it; + Type* lub = BitsetType::NewForTesting(BitsetType::Lub(type)); CHECK(type->Is(lub)); } // Least: If T2->IsBitset() and T1->Is(T2), then (T1->BitsetLub())->Is(T2) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle lub1 = - Rep::BitsetType::New(Rep::BitsetType::Lub(type1), T.region()); + Type* type1 = *it1; + Type* type2 = *it2; + Type* lub1 = BitsetType::NewForTesting(BitsetType::Lub(type1)); CHECK(!this->IsBitset(type2) || !type1->Is(type2) || lub1->Is(type2)); } } @@ -791,12 +716,10 @@ struct Tests : Rep { // Monotonicity: T1->Is(T2) implies (T1->BitsetLub())->Is(T2->BitsetLub()) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle lub1 = - Rep::BitsetType::New(Rep::BitsetType::Lub(type1), T.region()); - TypeHandle lub2 = - Rep::BitsetType::New(Rep::BitsetType::Lub(type2), T.region()); + Type* type1 = *it1; + Type* type2 = *it2; + Type* lub1 = BitsetType::NewForTesting(BitsetType::Lub(type1)); + Type* lub2 = BitsetType::NewForTesting(BitsetType::Lub(type2)); CHECK(!type1->Is(type2) || lub1->Is(lub2)); } } @@ -805,31 +728,31 @@ struct Tests : Rep { void Is1() { // Least Element (Bottom): None->Is(T) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; CHECK(T.None->Is(type)); } // Greatest Element (Top): T->Is(Any) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; CHECK(type->Is(T.Any)); } // Bottom Uniqueness: T->Is(None) implies T = None for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; if (type->Is(T.None)) CheckEqual(type, T.None); } // Top Uniqueness: Any->Is(T) implies T = Any for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; if (T.Any->Is(type)) CheckEqual(type, T.Any); } // Reflexivity: T->Is(T) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; CHECK(type->Is(type)); } @@ -837,9 +760,9 @@ struct Tests : Rep { for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle type3 = *it3; + Type* type1 = *it1; + Type* type2 = *it2; + Type* type3 = *it3; CHECK(!(type1->Is(type2) && type2->Is(type3)) || type1->Is(type3)); } } @@ -848,8 +771,8 @@ struct Tests : Rep { // Antisymmetry: T1->Is(T2) and T2->Is(T1) iff T1 = T2 for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; + Type* type1 = *it1; + Type* type2 = *it2; CHECK((type1->Is(type2) && type2->Is(type1)) == Equal(type1, type2)); } } @@ -857,8 +780,8 @@ struct Tests : Rep { // (In-)Compatibilities. for (TypeIterator i = T.types.begin(); i != T.types.end(); ++i) { for (TypeIterator j = T.types.begin(); j != T.types.end(); ++j) { - TypeHandle type1 = *i; - TypeHandle type2 = *j; + Type* type1 = *i; + Type* type2 = *j; CHECK(!type1->Is(type2) || this->IsBitset(type2) || this->IsUnion(type2) || this->IsUnion(type1) || (type1->IsClass() && type2->IsClass()) || @@ -880,8 +803,8 @@ struct Tests : Rep { for (MapIterator mt2 = T.maps.begin(); mt2 != T.maps.end(); ++mt2) { Handle<i::Map> map1 = *mt1; Handle<i::Map> map2 = *mt2; - TypeHandle class_type1 = T.Class(map1); - TypeHandle class_type2 = T.Class(map2); + Type* class_type1 = T.Class(map1); + Type* class_type2 = T.Class(map2); CHECK(class_type1->Is(class_type2) == (*map1 == *map2)); } } @@ -901,8 +824,8 @@ struct Tests : Rep { double max2 = (*j2)->Number(); if (min1 > max1) std::swap(min1, max1); if (min2 > max2) std::swap(min2, max2); - TypeHandle type1 = T.Range(min1, max1); - TypeHandle type2 = T.Range(min2, max2); + Type* type1 = T.Range(min1, max1); + Type* type2 = T.Range(min2, max2); CHECK(type1->Is(type2) == (min1 >= min2 && max1 <= max2)); } } @@ -914,8 +837,8 @@ struct Tests : Rep { for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) { Handle<i::Object> value1 = *vt1; Handle<i::Object> value2 = *vt2; - TypeHandle const_type1 = T.Constant(value1); - TypeHandle const_type2 = T.Constant(value2); + Type* const_type1 = T.Constant(value1); + Type* const_type2 = T.Constant(value2); CHECK(const_type1->Is(const_type2) == (*value1 == *value2)); } } @@ -923,10 +846,10 @@ struct Tests : Rep { // Context(T1)->Is(Context(T2)) iff T1 = T2 for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle outer1 = *it1; - TypeHandle outer2 = *it2; - TypeHandle type1 = T.Context(outer1); - TypeHandle type2 = T.Context(outer2); + Type* outer1 = *it1; + Type* outer2 = *it2; + Type* type1 = T.Context(outer1); + Type* type2 = T.Context(outer2); CHECK(type1->Is(type2) == outer1->Equals(outer2)); } } @@ -934,10 +857,10 @@ struct Tests : Rep { // Array(T1)->Is(Array(T2)) iff T1 = T2 for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle element1 = *it1; - TypeHandle element2 = *it2; - TypeHandle type1 = T.Array1(element1); - TypeHandle type2 = T.Array1(element2); + Type* element1 = *it1; + Type* element2 = *it2; + Type* type1 = T.Array1(element1); + Type* type2 = T.Array1(element2); CHECK(type1->Is(type2) == element1->Equals(element2)); } } @@ -945,12 +868,12 @@ struct Tests : Rep { // Function0(S1, T1)->Is(Function0(S2, T2)) iff S1 = S2 and T1 = T2 for (TypeIterator i = T.types.begin(); i != T.types.end(); ++i) { for (TypeIterator j = T.types.begin(); j != T.types.end(); ++j) { - TypeHandle result1 = *i; - TypeHandle receiver1 = *j; - TypeHandle type1 = T.Function0(result1, receiver1); - TypeHandle result2 = T.Random(); - TypeHandle receiver2 = T.Random(); - TypeHandle type2 = T.Function0(result2, receiver2); + Type* result1 = *i; + Type* receiver1 = *j; + Type* type1 = T.Function0(result1, receiver1); + Type* result2 = T.Random(); + Type* receiver2 = T.Random(); + Type* type2 = T.Function0(result2, receiver2); CHECK(type1->Is(type2) == (result1->Equals(result2) && receiver1->Equals(receiver2))); } @@ -961,7 +884,7 @@ struct Tests : Rep { // If IsInteger(v) then Constant(v)->Is(Range(v, v)). for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; if (type->IsConstant() && IsInteger(*type->AsConstant()->Value())) { CHECK(type->Is(T.Range(type->AsConstant()->Value()->Number(), type->AsConstant()->Value()->Number()))); @@ -971,8 +894,8 @@ struct Tests : Rep { // If Constant(x)->Is(Range(min,max)) then IsInteger(v) and min <= x <= max. for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; + Type* type1 = *it1; + Type* type2 = *it2; if (type1->IsConstant() && type2->IsRange() && type1->Is(type2)) { double x = type1->AsConstant()->Value()->Number(); double min = type2->AsRange()->Min(); @@ -984,10 +907,9 @@ struct Tests : Rep { // Lub(Range(x,y))->Is(T.Union(T.Integral32, T.OtherNumber)) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; if (type->IsRange()) { - TypeHandle lub = Rep::BitsetType::New( - Rep::BitsetType::Lub(type), T.region()); + Type* lub = BitsetType::NewForTesting(BitsetType::Lub(type)); CHECK(lub->Is(T.PlainNumber)); } } @@ -1068,31 +990,31 @@ struct Tests : Rep { void NowIs() { // Least Element (Bottom): None->NowIs(T) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; CHECK(T.None->NowIs(type)); } // Greatest Element (Top): T->NowIs(Any) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; CHECK(type->NowIs(T.Any)); } // Bottom Uniqueness: T->NowIs(None) implies T = None for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; if (type->NowIs(T.None)) CheckEqual(type, T.None); } // Top Uniqueness: Any->NowIs(T) implies T = Any for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; if (T.Any->NowIs(type)) CheckEqual(type, T.Any); } // Reflexivity: T->NowIs(T) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; CHECK(type->NowIs(type)); } @@ -1100,9 +1022,9 @@ struct Tests : Rep { for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle type3 = *it3; + Type* type1 = *it1; + Type* type2 = *it2; + Type* type3 = *it3; CHECK(!(type1->NowIs(type2) && type2->NowIs(type3)) || type1->NowIs(type3)); } @@ -1112,8 +1034,8 @@ struct Tests : Rep { // Antisymmetry: T1->NowIs(T2) and T2->NowIs(T1) iff T1 = T2 for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; + Type* type1 = *it1; + Type* type2 = *it2; CHECK((type1->NowIs(type2) && type2->NowIs(type1)) == Equal(type1, type2)); } @@ -1122,8 +1044,8 @@ struct Tests : Rep { // T1->Is(T2) implies T1->NowIs(T2) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; + Type* type1 = *it1; + Type* type2 = *it2; CHECK(!type1->Is(type2) || type1->NowIs(type2)); } } @@ -1133,8 +1055,8 @@ struct Tests : Rep { for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) { Handle<i::Object> value1 = *vt1; Handle<i::Object> value2 = *vt2; - TypeHandle const_type1 = T.Constant(value1); - TypeHandle const_type2 = T.Constant(value2); + Type* const_type1 = T.Constant(value1); + Type* const_type2 = T.Constant(value2); CHECK(const_type1->NowIs(const_type2) == (*value1 == *value2)); } } @@ -1144,8 +1066,8 @@ struct Tests : Rep { for (MapIterator mt2 = T.maps.begin(); mt2 != T.maps.end(); ++mt2) { Handle<i::Map> map1 = *mt1; Handle<i::Map> map2 = *mt2; - TypeHandle class_type1 = T.Class(map1); - TypeHandle class_type2 = T.Class(map2); + Type* class_type1 = T.Class(map1); + Type* class_type2 = T.Class(map2); CHECK(class_type1->NowIs(class_type2) == (*map1 == *map2)); } } @@ -1155,8 +1077,8 @@ struct Tests : Rep { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle<i::Map> map = *mt; Handle<i::Object> value = *vt; - TypeHandle const_type = T.Constant(value); - TypeHandle class_type = T.Class(map); + Type* const_type = T.Constant(value); + Type* class_type = T.Class(map); CHECK((value->IsHeapObject() && i::HeapObject::cast(*value)->map() == *map) == const_type->NowIs(class_type)); @@ -1168,8 +1090,8 @@ struct Tests : Rep { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle<i::Map> map = *mt; Handle<i::Object> value = *vt; - TypeHandle const_type = T.Constant(value); - TypeHandle class_type = T.Class(map); + Type* const_type = T.Constant(value); + Type* class_type = T.Class(map); CHECK(!class_type->NowIs(const_type)); } } @@ -1179,9 +1101,9 @@ struct Tests : Rep { // T->Contains(V) iff Constant(V)->Is(T) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { - TypeHandle type = *it; + Type* type = *it; Handle<i::Object> value = *vt; - TypeHandle const_type = T.Constant(value); + Type* const_type = T.Constant(value); CHECK(type->Contains(value) == const_type->Is(type)); } } @@ -1191,9 +1113,9 @@ struct Tests : Rep { // T->NowContains(V) iff Constant(V)->NowIs(T) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { - TypeHandle type = *it; + Type* type = *it; Handle<i::Object> value = *vt; - TypeHandle const_type = T.Constant(value); + Type* const_type = T.Constant(value); CHECK(type->NowContains(value) == const_type->NowIs(type)); } } @@ -1201,7 +1123,7 @@ struct Tests : Rep { // T->Contains(V) implies T->NowContains(V) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { - TypeHandle type = *it; + Type* type = *it; Handle<i::Object> value = *vt; CHECK(!type->Contains(value) || type->NowContains(value)); } @@ -1210,9 +1132,9 @@ struct Tests : Rep { // NowOf(V)->Is(T) implies T->NowContains(V) for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { - TypeHandle type = *it; + Type* type = *it; Handle<i::Object> value = *vt; - TypeHandle nowof_type = T.Of(value); + Type* nowof_type = T.Of(value); CHECK(!nowof_type->NowIs(type) || type->NowContains(value)); } } @@ -1221,27 +1143,27 @@ struct Tests : Rep { void Maybe() { // T->Maybe(Any) iff T inhabited for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; CHECK(type->Maybe(T.Any) == type->IsInhabited()); } // T->Maybe(None) never for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; CHECK(!type->Maybe(T.None)); } // Reflexivity upto Inhabitation: T->Maybe(T) iff T inhabited for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; + Type* type = *it; CHECK(type->Maybe(type) == type->IsInhabited()); } // Symmetry: T1->Maybe(T2) iff T2->Maybe(T1) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; + Type* type1 = *it1; + Type* type2 = *it2; CHECK(type1->Maybe(type2) == type2->Maybe(type1)); } } @@ -1249,8 +1171,8 @@ struct Tests : Rep { // T1->Maybe(T2) implies T1, T2 inhabited for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; + Type* type1 = *it1; + Type* type2 = *it2; CHECK(!type1->Maybe(type2) || (type1->IsInhabited() && type2->IsInhabited())); } @@ -1259,9 +1181,9 @@ struct Tests : Rep { // T1->Maybe(T2) implies Intersect(T1, T2) inhabited for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle intersect12 = T.Intersect(type1, type2); + Type* type1 = *it1; + Type* type2 = *it2; + Type* intersect12 = T.Intersect(type1, type2); CHECK(!type1->Maybe(type2) || intersect12->IsInhabited()); } } @@ -1269,8 +1191,8 @@ struct Tests : Rep { // T1->Is(T2) and T1 inhabited implies T1->Maybe(T2) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; + Type* type1 = *it1; + Type* type2 = *it2; CHECK(!(type1->Is(type2) && type1->IsInhabited()) || type1->Maybe(type2)); } @@ -1281,8 +1203,8 @@ struct Tests : Rep { for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) { Handle<i::Object> value1 = *vt1; Handle<i::Object> value2 = *vt2; - TypeHandle const_type1 = T.Constant(value1); - TypeHandle const_type2 = T.Constant(value2); + Type* const_type1 = T.Constant(value1); + Type* const_type2 = T.Constant(value2); CHECK(const_type1->Maybe(const_type2) == (*value1 == *value2)); } } @@ -1292,8 +1214,8 @@ struct Tests : Rep { for (MapIterator mt2 = T.maps.begin(); mt2 != T.maps.end(); ++mt2) { Handle<i::Map> map1 = *mt1; Handle<i::Map> map2 = *mt2; - TypeHandle class_type1 = T.Class(map1); - TypeHandle class_type2 = T.Class(map2); + Type* class_type1 = T.Class(map1); + Type* class_type2 = T.Class(map2); CHECK(class_type1->Maybe(class_type2) == (*map1 == *map2)); } } @@ -1305,8 +1227,8 @@ struct Tests : Rep { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle<i::Map> map = *mt; Handle<i::Object> value = *vt; - TypeHandle const_type = T.Constant(value); - TypeHandle class_type = T.Class(map); + Type* const_type = T.Constant(value); + Type* class_type = T.Class(map); CHECK(!const_type->Maybe(class_type)); } } @@ -1319,8 +1241,8 @@ struct Tests : Rep { for (ValueIterator vt = T.values.begin(); vt != T.values.end(); ++vt) { Handle<i::Map> map = *mt; Handle<i::Object> value = *vt; - TypeHandle const_type = T.Constant(value); - TypeHandle class_type = T.Class(map); + Type* const_type = T.Constant(value); + Type* class_type = T.Class(map); CHECK(!class_type->Maybe(const_type)); } } @@ -1383,32 +1305,32 @@ struct Tests : Rep { void Union1() { // Identity: Union(T, None) = T for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; - TypeHandle union_type = T.Union(type, T.None); + Type* type = *it; + Type* union_type = T.Union(type, T.None); CheckEqual(union_type, type); } // Domination: Union(T, Any) = Any for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; - TypeHandle union_type = T.Union(type, T.Any); + Type* type = *it; + Type* union_type = T.Union(type, T.Any); CheckEqual(union_type, T.Any); } // Idempotence: Union(T, T) = T for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; - TypeHandle union_type = T.Union(type, type); + Type* type = *it; + Type* union_type = T.Union(type, type); CheckEqual(union_type, type); } // Commutativity: Union(T1, T2) = Union(T2, T1) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle union12 = T.Union(type1, type2); - TypeHandle union21 = T.Union(type2, type1); + Type* type1 = *it1; + Type* type2 = *it2; + Type* union12 = T.Union(type1, type2); + Type* union21 = T.Union(type2, type1); CheckEqual(union12, union21); } } @@ -1421,13 +1343,13 @@ struct Tests : Rep { for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle type3 = *it3; - TypeHandle union12 = T.Union(type1, type2); - TypeHandle union23 = T.Union(type2, type3); - TypeHandle union1_23 = T.Union(type1, union23); - TypeHandle union12_3 = T.Union(union12, type3); + Type* type1 = *it1; + Type* type2 = *it2; + Type* type3 = *it3; + Type* union12 = T.Union(type1, type2); + Type* union23 = T.Union(type2, type3); + Type* union1_23 = T.Union(type1, union23); + Type* union12_3 = T.Union(union12, type3); CheckEqual(union1_23, union12_3); } } @@ -1437,9 +1359,9 @@ struct Tests : Rep { // Meet: T1->Is(Union(T1, T2)) and T2->Is(Union(T1, T2)) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle union12 = T.Union(type1, type2); + Type* type1 = *it1; + Type* type2 = *it2; + Type* union12 = T.Union(type1, type2); CHECK(type1->Is(union12)); CHECK(type2->Is(union12)); } @@ -1448,9 +1370,9 @@ struct Tests : Rep { // Upper Boundedness: T1->Is(T2) implies Union(T1, T2) = T2 for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle union12 = T.Union(type1, type2); + Type* type1 = *it1; + Type* type2 = *it2; + Type* union12 = T.Union(type1, type2); if (type1->Is(type2)) CheckEqual(union12, type2); } } @@ -1463,11 +1385,11 @@ struct Tests : Rep { for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle type3 = *it3; - TypeHandle union13 = T.Union(type1, type3); - TypeHandle union23 = T.Union(type2, type3); + Type* type1 = *it1; + Type* type2 = *it2; + Type* type3 = *it3; + Type* union13 = T.Union(type1, type3); + Type* union23 = T.Union(type2, type3); CHECK(!type1->Is(type2) || union13->Is(union23)); } } @@ -1485,10 +1407,10 @@ struct Tests : Rep { for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle type3 = *it3; - TypeHandle union12 = T.Union(type1, type2); + Type* type1 = *it1; + Type* type2 = *it2; + Type* type3 = *it3; + Type* union12 = T.Union(type1, type2); CHECK(!(type1->Is(type3) && type2->Is(type3)) || union12->Is(type3)); } } @@ -1502,10 +1424,10 @@ struct Tests : Rep { HandleScope scope(isolate); for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = it2; it3 != T.types.end(); ++it3) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle type3 = *it3; - TypeHandle union23 = T.Union(type2, type3); + Type* type1 = *it1; + Type* type2 = *it2; + Type* type3 = *it3; + Type* union23 = T.Union(type2, type3); CHECK(!(type1->Is(type2) || type1->Is(type3)) || type1->Is(union23)); } } @@ -1628,32 +1550,32 @@ struct Tests : Rep { void Intersect() { // Identity: Intersect(T, Any) = T for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; - TypeHandle intersect_type = T.Intersect(type, T.Any); + Type* type = *it; + Type* intersect_type = T.Intersect(type, T.Any); CheckEqual(intersect_type, type); } // Domination: Intersect(T, None) = None for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; - TypeHandle intersect_type = T.Intersect(type, T.None); + Type* type = *it; + Type* intersect_type = T.Intersect(type, T.None); CheckEqual(intersect_type, T.None); } // Idempotence: Intersect(T, T) = T for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type = *it; - TypeHandle intersect_type = T.Intersect(type, type); + Type* type = *it; + Type* intersect_type = T.Intersect(type, type); CheckEqual(intersect_type, type); } // Commutativity: Intersect(T1, T2) = Intersect(T2, T1) for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle intersect12 = T.Intersect(type1, type2); - TypeHandle intersect21 = T.Intersect(type2, type1); + Type* type1 = *it1; + Type* type2 = *it2; + Type* intersect12 = T.Intersect(type1, type2); + Type* intersect21 = T.Intersect(type2, type1); CheckEqual(intersect12, intersect21); } } @@ -1669,13 +1591,13 @@ struct Tests : Rep { for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle type3 = *it3; - TypeHandle intersect12 = T.Intersect(type1, type2); - TypeHandle intersect23 = T.Intersect(type2, type3); - TypeHandle intersect1_23 = T.Intersect(type1, intersect23); - TypeHandle intersect12_3 = T.Intersect(intersect12, type3); + Type* type1 = *it1; + Type* type2 = *it2; + Type* type3 = *it3; + Type* intersect12 = T.Intersect(type1, type2); + Type* intersect23 = T.Intersect(type2, type3); + Type* intersect1_23 = T.Intersect(type1, intersect23); + Type* intersect12_3 = T.Intersect(intersect12, type3); CheckEqual(intersect1_23, intersect12_3); } } @@ -1691,9 +1613,9 @@ struct Tests : Rep { /* for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle intersect12 = T.Intersect(type1, type2); + Type* type1 = *it1; + Type* type2 = *it2; + Type* intersect12 = T.Intersect(type1, type2); CHECK(intersect12->Is(type1)); CHECK(intersect12->Is(type2)); } @@ -1703,9 +1625,9 @@ struct Tests : Rep { // Lower Boundedness: T1->Is(T2) implies Intersect(T1, T2) = T1 for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle intersect12 = T.Intersect(type1, type2); + Type* type1 = *it1; + Type* type2 = *it2; + Type* intersect12 = T.Intersect(type1, type2); if (type1->Is(type2)) CheckEqual(intersect12, type1); } } @@ -1719,11 +1641,11 @@ struct Tests : Rep { for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle type3 = *it3; - TypeHandle intersect13 = T.Intersect(type1, type3); - TypeHandle intersect23 = T.Intersect(type2, type3); + Type* type1 = *it1; + Type* type2 = *it2; + Type* type3 = *it3; + Type* intersect13 = T.Intersect(type1, type3); + Type* intersect23 = T.Intersect(type2, type3); CHECK(!type1->Is(type2) || intersect13->Is(intersect23)); } } @@ -1739,10 +1661,10 @@ struct Tests : Rep { for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle type3 = *it3; - TypeHandle intersect12 = T.Intersect(type1, type2); + Type* type1 = *it1; + Type* type2 = *it2; + Type* type3 = *it3; + Type* intersect12 = T.Intersect(type1, type2); CHECK(!(type1->Is(type3) || type2->Is(type3)) || intersect12->Is(type3)); } @@ -1755,10 +1677,10 @@ struct Tests : Rep { HandleScope scope(isolate); for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle type3 = *it3; - TypeHandle intersect23 = T.Intersect(type2, type3); + Type* type1 = *it1; + Type* type2 = *it2; + Type* type3 = *it3; + Type* intersect23 = T.Intersect(type2, type3); CHECK(!(type1->Is(type2) && type1->Is(type3)) || type1->Is(intersect23)); } @@ -1871,14 +1793,14 @@ struct Tests : Rep { for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle type3 = *it3; - TypeHandle union12 = T.Union(type1, type2); - TypeHandle union13 = T.Union(type1, type3); - TypeHandle intersect23 = T.Intersect(type2, type3); - TypeHandle union1_23 = T.Union(type1, intersect23); - TypeHandle intersect12_13 = T.Intersect(union12, union13); + Type* type1 = *it1; + Type* type2 = *it2; + Type* type3 = *it3; + Type* union12 = T.Union(type1, type2); + Type* union13 = T.Union(type1, type3); + Type* intersect23 = T.Intersect(type2, type3); + Type* union1_23 = T.Union(type1, intersect23); + Type* intersect12_13 = T.Intersect(union12, union13); CHECK(Equal(union1_23, intersect12_13)); } } @@ -1894,14 +1816,14 @@ struct Tests : Rep { for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - TypeHandle type3 = *it3; - TypeHandle intersect12 = T.Intersect(type1, type2); - TypeHandle intersect13 = T.Intersect(type1, type3); - TypeHandle union23 = T.Union(type2, type3); - TypeHandle intersect1_23 = T.Intersect(type1, union23); - TypeHandle union12_13 = T.Union(intersect12, intersect13); + Type* type1 = *it1; + Type* type2 = *it2; + Type* type3 = *it3; + Type* intersect12 = T.Intersect(type1, type2); + Type* intersect13 = T.Intersect(type1, type3); + Type* union23 = T.Union(type2, type3); + Type* intersect1_23 = T.Intersect(type1, union23); + Type* union12_13 = T.Union(intersect12, intersect13); CHECK(Equal(intersect1_23, union12_13)); } } @@ -1912,9 +1834,9 @@ struct Tests : Rep { void GetRange() { // GetRange(Range(a, b)) = Range(a, b). for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { - TypeHandle type1 = *it1; + Type* type1 = *it1; if (type1->IsRange()) { - typename Type::RangeType* range = type1->GetRange(); + RangeType* range = type1->GetRange()->AsRange(); CHECK(type1->Min() == range->Min()); CHECK(type1->Max() == range->Max()); } @@ -1923,10 +1845,10 @@ struct Tests : Rep { // GetRange(Union(Constant(x), Range(min,max))) == Range(min, max). for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; + Type* type1 = *it1; + Type* type2 = *it2; if (type1->IsConstant() && type2->IsRange()) { - TypeHandle u = T.Union(type1, type2); + Type* u = T.Union(type1, type2); CHECK(type2->Min() == u->GetRange()->Min()); CHECK(type2->Max() == u->GetRange()->Max()); @@ -1935,201 +1857,69 @@ struct Tests : Rep { } } - template<class Type2, class TypeHandle2, class Region2, class Rep2> - void Convert() { - Types<Type2, TypeHandle2, Region2> T2(Rep2::ToRegion(&zone, isolate), - isolate, - isolate->random_number_generator()); - for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) { - TypeHandle type1 = *it; - TypeHandle2 type2 = T2.template Convert<Type>(type1); - TypeHandle type3 = T.template Convert<Type2>(type2); - CheckEqual(type1, type3); - } - } - void HTypeFromType() { for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) { for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) { - TypeHandle type1 = *it1; - TypeHandle type2 = *it2; - HType htype1 = HType::FromType<Type>(type1); - HType htype2 = HType::FromType<Type>(type2); + Type* type1 = *it1; + Type* type2 = *it2; + HType htype1 = HType::FromType(type1); + HType htype2 = HType::FromType(type2); CHECK(!type1->Is(type2) || htype1.IsSubtypeOf(htype2)); } } } }; -typedef Tests<Type, Type*, Zone, ZoneRep> ZoneTests; -typedef Tests<HeapType, Handle<HeapType>, Isolate, HeapRep> HeapTests; - - -TEST(IsSomeType_zone) { ZoneTests().IsSomeType(); } - - -TEST(IsSomeType_heap) { HeapTests().IsSomeType(); } - - -TEST(PointwiseRepresentation_zone) { ZoneTests().PointwiseRepresentation(); } - - -TEST(PointwiseRepresentation_heap) { HeapTests().PointwiseRepresentation(); } - - -TEST(BitsetType_zone) { ZoneTests().Bitset(); } - - -TEST(BitsetType_heap) { HeapTests().Bitset(); } - - -TEST(ClassType_zone) { ZoneTests().Class(); } - - -TEST(ClassType_heap) { HeapTests().Class(); } - - -TEST(ConstantType_zone) { ZoneTests().Constant(); } - - -TEST(ConstantType_heap) { HeapTests().Constant(); } - - -TEST(RangeType_zone) { ZoneTests().Range(); } - - -TEST(RangeType_heap) { HeapTests().Range(); } - - -TEST(ArrayType_zone) { ZoneTests().Array(); } - - -TEST(ArrayType_heap) { HeapTests().Array(); } - - -TEST(FunctionType_zone) { ZoneTests().Function(); } - +TEST(IsSomeType_zone) { Tests().IsSomeType(); } -TEST(FunctionType_heap) { HeapTests().Function(); } +TEST(PointwiseRepresentation_zone) { Tests().PointwiseRepresentation(); } +TEST(BitsetType_zone) { Tests().Bitset(); } -TEST(Of_zone) { ZoneTests().Of(); } +TEST(ClassType_zone) { Tests().Class(); } +TEST(ConstantType_zone) { Tests().Constant(); } -TEST(Of_heap) { HeapTests().Of(); } +TEST(RangeType_zone) { Tests().Range(); } +TEST(ArrayType_zone) { Tests().Array(); } -TEST(NowOf_zone) { ZoneTests().NowOf(); } +TEST(FunctionType_zone) { Tests().Function(); } +TEST(Of_zone) { Tests().Of(); } -TEST(NowOf_heap) { HeapTests().NowOf(); } +TEST(NowOf_zone) { Tests().NowOf(); } +TEST(MinMax_zone) { Tests().MinMax(); } -TEST(MinMax_zone) { ZoneTests().MinMax(); } +TEST(BitsetGlb_zone) { Tests().BitsetGlb(); } +TEST(BitsetLub_zone) { Tests().BitsetLub(); } -TEST(MinMax_heap) { HeapTests().MinMax(); } +TEST(Is1_zone) { Tests().Is1(); } +TEST(Is2_zone) { Tests().Is2(); } -TEST(BitsetGlb_zone) { ZoneTests().BitsetGlb(); } +TEST(NowIs_zone) { Tests().NowIs(); } +TEST(Contains_zone) { Tests().Contains(); } -TEST(BitsetGlb_heap) { HeapTests().BitsetGlb(); } +TEST(NowContains_zone) { Tests().NowContains(); } +TEST(Maybe_zone) { Tests().Maybe(); } -TEST(BitsetLub_zone) { ZoneTests().BitsetLub(); } +TEST(Union1_zone) { Tests().Union1(); } +TEST(Union2_zone) { Tests().Union2(); } -TEST(BitsetLub_heap) { HeapTests().BitsetLub(); } - - -TEST(Is1_zone) { ZoneTests().Is1(); } - - -TEST(Is1_heap) { HeapTests().Is1(); } - - -TEST(Is2_zone) { ZoneTests().Is2(); } - - -TEST(Is2_heap) { HeapTests().Is2(); } - - -TEST(NowIs_zone) { ZoneTests().NowIs(); } - - -TEST(NowIs_heap) { HeapTests().NowIs(); } - - -TEST(Contains_zone) { ZoneTests().Contains(); } - - -TEST(Contains_heap) { HeapTests().Contains(); } - - -TEST(NowContains_zone) { ZoneTests().NowContains(); } - - -TEST(NowContains_heap) { HeapTests().NowContains(); } - - -TEST(Maybe_zone) { ZoneTests().Maybe(); } - - -TEST(Maybe_heap) { HeapTests().Maybe(); } - - -TEST(Union1_zone) { ZoneTests().Union1(); } - - -TEST(Union1_heap) { HeapTests().Union1(); } - - -TEST(Union2_zone) { ZoneTests().Union2(); } - - -TEST(Union2_heap) { HeapTests().Union2(); } - - -TEST(Union3_zone) { ZoneTests().Union3(); } - - -TEST(Union3_heap) { HeapTests().Union3(); } - - -TEST(Union4_zone) { ZoneTests().Union4(); } - - -TEST(Union4_heap) { HeapTests().Union4(); } - - -TEST(Intersect_zone) { ZoneTests().Intersect(); } - - -TEST(Intersect_heap) { HeapTests().Intersect(); } - - -TEST(Distributivity_zone) { ZoneTests().Distributivity(); } - - -TEST(Distributivity_heap) { HeapTests().Distributivity(); } - - -TEST(GetRange_zone) { ZoneTests().GetRange(); } - - -TEST(GetRange_heap) { HeapTests().GetRange(); } - - -TEST(Convert_zone) { - ZoneTests().Convert<HeapType, Handle<HeapType>, Isolate, HeapRep>(); -} - +TEST(Union3_zone) { Tests().Union3(); } -TEST(Convert_heap) { HeapTests().Convert<Type, Type*, Zone, ZoneRep>(); } +TEST(Union4_zone) { Tests().Union4(); } +TEST(Intersect_zone) { Tests().Intersect(); } -TEST(HTypeFromType_zone) { ZoneTests().HTypeFromType(); } +TEST(Distributivity_zone) { Tests().Distributivity(); } +TEST(GetRange_zone) { Tests().GetRange(); } -TEST(HTypeFromType_heap) { HeapTests().HTypeFromType(); } +TEST(HTypeFromType_zone) { Tests().HTypeFromType(); } diff --git a/deps/v8/test/cctest/test-unboxed-doubles.cc b/deps/v8/test/cctest/test-unboxed-doubles.cc index 3906d848de..f195a31c79 100644 --- a/deps/v8/test/cctest/test-unboxed-doubles.cc +++ b/deps/v8/test/cctest/test-unboxed-doubles.cc @@ -10,6 +10,7 @@ #include "src/compilation-cache.h" #include "src/execution.h" #include "src/factory.h" +#include "src/field-type.h" #include "src/global-handles.h" #include "src/heap/slots-buffer.h" #include "src/ic/ic.h" @@ -947,7 +948,7 @@ TEST(DescriptorArrayTrimming) { const int kSplitFieldIndex = 32; const int kTrimmedLayoutDescriptorLength = 64; - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::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, @@ -1035,7 +1036,7 @@ TEST(DoScavenge) { // 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<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); Handle<Map> map = Map::Create(isolate, 10); map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE, Representation::Double(), @@ -1060,7 +1061,7 @@ TEST(DoScavenge) { CcTest::heap()->CollectGarbage(i::NEW_SPACE); // Create temp object in the new space. - Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS); + Handle<JSArray> temp = factory->NewJSArray(0, FAST_ELEMENTS); CHECK(isolate->heap()->new_space()->Contains(*temp)); // Construct a double value that looks like a pointer to the new space object @@ -1097,7 +1098,7 @@ TEST(DoScavengeWithIncrementalWriteBarrier) { // 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<FieldType> any_type = FieldType::Any(isolate); Handle<Map> map = Map::Create(isolate, 10); map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE, Representation::Double(), @@ -1321,7 +1322,7 @@ TEST(LayoutDescriptorSharing) { CcTest::InitializeVM(); v8::HandleScope scope(CcTest::isolate()); Isolate* isolate = CcTest::i_isolate(); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); Handle<Map> split_map; { @@ -1363,65 +1364,6 @@ TEST(LayoutDescriptorSharing) { } -TEST(StoreBufferScanOnScavenge) { - CcTest::InitializeVM(); - Isolate* isolate = CcTest::i_isolate(); - Factory* factory = isolate->factory(); - v8::HandleScope scope(CcTest::isolate()); - - 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(); - - // Create object in new space. - Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED); - - Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5); - obj->WriteToField(0, *heap_number); - - { - // Ensure the object is properly set up. - DescriptorArray* descriptors = map->instance_descriptors(); - CHECK(descriptors->GetDetails(0).representation().IsDouble()); - 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 - CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now - - CHECK(isolate->heap()->old_space()->Contains(*obj)); - - // Create temp object in the new space. - Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS); - CHECK(isolate->heap()->new_space()->Contains(*temp)); - - // Construct a double value that looks like a pointer to the new space object - // and store it into the obj. - Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize; - double boom_value = bit_cast<double>(fake_object); - - FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0); - Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE); - obj->FastPropertyAtPut(field_index, *boom_number); - - // Enforce scan on scavenge for the obj's page. - MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); - chunk->set_scan_on_scavenge(true); - - // Trigger GCs and force evacuation. Should not crash there. - CcTest::heap()->CollectAllGarbage(); - - CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index)); -} - - static void TestWriteBarrier(Handle<Map> map, Handle<Map> new_map, int tagged_descriptor, int double_descriptor, bool check_tagged_value = true) { @@ -1580,7 +1522,7 @@ static void TestWriteBarrierObjectShiftFieldsRight( Isolate* isolate = CcTest::i_isolate(); v8::HandleScope scope(CcTest::isolate()); - Handle<HeapType> any_type = HeapType::Any(isolate); + Handle<FieldType> any_type = FieldType::Any(isolate); CompileRun("function func() { return 1; }"); @@ -1608,9 +1550,7 @@ static void TestWriteBarrierObjectShiftFieldsRight( } } - -// TODO(ishell): enable when this issue is fixed. -DISABLED_TEST(WriteBarrierObjectShiftFieldsRight) { +TEST(WriteBarrierObjectShiftFieldsRight) { TestWriteBarrierObjectShiftFieldsRight(OLD_TO_NEW_WRITE_BARRIER); } diff --git a/deps/v8/test/cctest/test-weakmaps.cc b/deps/v8/test/cctest/test-weakmaps.cc index 2630110c59..781ad1f69f 100644 --- a/deps/v8/test/cctest/test-weakmaps.cc +++ b/deps/v8/test/cctest/test-weakmaps.cc @@ -193,7 +193,7 @@ TEST(Regress2060a) { HandleScope scope(isolate); for (int i = 0; i < 32; i++) { Handle<JSObject> object = factory->NewJSObject(function, TENURED); - CHECK(!heap->InNewSpace(object->address())); + CHECK(!heap->InNewSpace(*object)); CHECK(!first_page->Contains(object->address())); int32_t hash = Object::GetOrCreateHash(isolate, key)->value(); JSWeakCollection::Set(weakmap, key, object, hash); @@ -231,7 +231,7 @@ TEST(Regress2060b) { Handle<JSObject> keys[32]; for (int i = 0; i < 32; i++) { keys[i] = factory->NewJSObject(function, TENURED); - CHECK(!heap->InNewSpace(keys[i]->address())); + CHECK(!heap->InNewSpace(*keys[i])); CHECK(!first_page->Contains(keys[i]->address())); } Handle<JSWeakMap> weakmap = AllocateJSWeakMap(isolate); diff --git a/deps/v8/test/cctest/test-weaksets.cc b/deps/v8/test/cctest/test-weaksets.cc index 6998e0f749..643bb48ab1 100644 --- a/deps/v8/test/cctest/test-weaksets.cc +++ b/deps/v8/test/cctest/test-weaksets.cc @@ -192,7 +192,7 @@ TEST(WeakSet_Regress2060a) { HandleScope scope(isolate); for (int i = 0; i < 32; i++) { Handle<JSObject> object = factory->NewJSObject(function, TENURED); - CHECK(!heap->InNewSpace(object->address())); + CHECK(!heap->InNewSpace(*object)); CHECK(!first_page->Contains(object->address())); int32_t hash = Object::GetOrCreateHash(isolate, key)->value(); JSWeakCollection::Set(weakset, key, object, hash); @@ -230,7 +230,7 @@ TEST(WeakSet_Regress2060b) { Handle<JSObject> keys[32]; for (int i = 0; i < 32; i++) { keys[i] = factory->NewJSObject(function, TENURED); - CHECK(!heap->InNewSpace(keys[i]->address())); + CHECK(!heap->InNewSpace(*keys[i])); CHECK(!first_page->Contains(keys[i]->address())); } Handle<JSWeakSet> weakset = AllocateJSWeakSet(isolate); diff --git a/deps/v8/test/cctest/trace-extension.cc b/deps/v8/test/cctest/trace-extension.cc index ea2b2cee3d..77a29e990b 100644 --- a/deps/v8/test/cctest/trace-extension.cc +++ b/deps/v8/test/cctest/trace-extension.cc @@ -108,7 +108,7 @@ void TraceExtension::DoTrace(Address fp) { regs.sp = reinterpret_cast<Address>(trace_env.sample) - 10240; trace_env.sample->Init(CcTest::i_isolate(), regs, - TickSample::kSkipCEntryFrame); + TickSample::kSkipCEntryFrame, true); } diff --git a/deps/v8/test/cctest/types-fuzz.h b/deps/v8/test/cctest/types-fuzz.h index 5c43e8e694..79e460856c 100644 --- a/deps/v8/test/cctest/types-fuzz.h +++ b/deps/v8/test/cctest/types-fuzz.h @@ -35,19 +35,18 @@ namespace v8 { namespace internal { -template<class Type, class TypeHandle, class Region> class Types { public: - Types(Region* region, Isolate* isolate, v8::base::RandomNumberGenerator* rng) - : region_(region), isolate_(isolate), rng_(rng) { - #define DECLARE_TYPE(name, value) \ - name = Type::name(region); \ - types.push_back(name); + Types(Zone* zone, Isolate* isolate, v8::base::RandomNumberGenerator* rng) + : zone_(zone), isolate_(isolate), rng_(rng) { +#define DECLARE_TYPE(name, value) \ + name = Type::name(); \ + types.push_back(name); PROPER_BITSET_TYPE_LIST(DECLARE_TYPE) #undef DECLARE_TYPE - SignedSmall = Type::SignedSmall(region); - UnsignedSmall = Type::UnsignedSmall(region); + SignedSmall = Type::SignedSmall(); + UnsignedSmall = Type::UnsignedSmall(); object_map = isolate->factory()->NewMap( JS_OBJECT_TYPE, JSObject::kHeaderSize); @@ -56,16 +55,16 @@ class Types { number_map = isolate->factory()->NewMap( HEAP_NUMBER_TYPE, HeapNumber::kSize); uninitialized_map = isolate->factory()->uninitialized_map(); - ObjectClass = Type::Class(object_map, region); - ArrayClass = Type::Class(array_map, region); - NumberClass = Type::Class(number_map, region); - UninitializedClass = Type::Class(uninitialized_map, region); + ObjectClass = Type::Class(object_map, zone); + ArrayClass = Type::Class(array_map, zone); + NumberClass = Type::Class(number_map, zone); + UninitializedClass = Type::Class(uninitialized_map, zone); maps.push_back(object_map); maps.push_back(array_map); maps.push_back(uninitialized_map); for (MapVector::iterator it = maps.begin(); it != maps.end(); ++it) { - types.push_back(Type::Class(*it, region)); + types.push_back(Type::Class(*it, zone)); } smi = handle(Smi::FromInt(666), isolate); @@ -74,13 +73,13 @@ class Types { object2 = isolate->factory()->NewJSObjectFromMap(object_map); array = isolate->factory()->NewJSArray(20); uninitialized = isolate->factory()->uninitialized_value(); - SmiConstant = Type::Constant(smi, region); - Signed32Constant = Type::Constant(signed32, region); + SmiConstant = Type::Constant(smi, zone); + Signed32Constant = Type::Constant(signed32, zone); - ObjectConstant1 = Type::Constant(object1, region); - ObjectConstant2 = Type::Constant(object2, region); - ArrayConstant = Type::Constant(array, region); - UninitializedConstant = Type::Constant(uninitialized, region); + ObjectConstant1 = Type::Constant(object1, zone); + ObjectConstant2 = Type::Constant(object2, zone); + ArrayConstant = Type::Constant(array, zone); + UninitializedConstant = Type::Constant(uninitialized, zone); values.push_back(smi); values.push_back(signed32); @@ -89,7 +88,7 @@ class Types { values.push_back(array); values.push_back(uninitialized); for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) { - types.push_back(Type::Constant(*it, region)); + types.push_back(Type::Constant(*it, zone)); } integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY)); @@ -103,16 +102,16 @@ class Types { if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x)); } - Integer = Type::Range(-V8_INFINITY, +V8_INFINITY, region); + Integer = Type::Range(-V8_INFINITY, +V8_INFINITY, zone); - NumberArray = Type::Array(Number, region); - StringArray = Type::Array(String, region); - AnyArray = Type::Array(Any, region); + NumberArray = Type::Array(Number, zone); + StringArray = Type::Array(String, zone); + AnyArray = Type::Array(Any, zone); - SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region); - NumberFunction1 = Type::Function(Number, Number, region); - NumberFunction2 = Type::Function(Number, Number, Number, region); - MethodFunction = Type::Function(String, Object, 0, region); + SignedFunction1 = Type::Function(SignedSmall, SignedSmall, zone); + NumberFunction1 = Type::Function(Number, Number, zone); + NumberFunction2 = Type::Function(Number, Number, Number, zone); + MethodFunction = Type::Function(String, Object, 0, zone); for (int i = 0; i < 30; ++i) { types.push_back(Fuzz()); @@ -131,40 +130,40 @@ class Types { Handle<i::JSArray> array; Handle<i::Oddball> uninitialized; - #define DECLARE_TYPE(name, value) TypeHandle name; +#define DECLARE_TYPE(name, value) Type* name; PROPER_BITSET_TYPE_LIST(DECLARE_TYPE) #undef DECLARE_TYPE -#define DECLARE_TYPE(name, value) TypeHandle Mask##name##ForTesting; +#define DECLARE_TYPE(name, value) Type* Mask##name##ForTesting; MASK_BITSET_TYPE_LIST(DECLARE_TYPE) #undef DECLARE_TYPE - TypeHandle SignedSmall; - TypeHandle UnsignedSmall; + Type* SignedSmall; + Type* UnsignedSmall; - TypeHandle ObjectClass; - TypeHandle ArrayClass; - TypeHandle NumberClass; - TypeHandle UninitializedClass; + Type* ObjectClass; + Type* ArrayClass; + Type* NumberClass; + Type* UninitializedClass; - TypeHandle SmiConstant; - TypeHandle Signed32Constant; - TypeHandle ObjectConstant1; - TypeHandle ObjectConstant2; - TypeHandle ArrayConstant; - TypeHandle UninitializedConstant; + Type* SmiConstant; + Type* Signed32Constant; + Type* ObjectConstant1; + Type* ObjectConstant2; + Type* ArrayConstant; + Type* UninitializedConstant; - TypeHandle Integer; + Type* Integer; - TypeHandle NumberArray; - TypeHandle StringArray; - TypeHandle AnyArray; + Type* NumberArray; + Type* StringArray; + Type* AnyArray; - TypeHandle SignedFunction1; - TypeHandle NumberFunction1; - TypeHandle NumberFunction2; - TypeHandle MethodFunction; + Type* SignedFunction1; + Type* NumberFunction1; + Type* NumberFunction2; + Type* MethodFunction; - typedef std::vector<TypeHandle> TypeVector; + typedef std::vector<Type*> TypeVector; typedef std::vector<Handle<i::Map> > MapVector; typedef std::vector<Handle<i::Object> > ValueVector; @@ -173,94 +172,70 @@ class Types { ValueVector values; ValueVector integers; // "Integer" values used for range limits. - TypeHandle Of(Handle<i::Object> value) { - return Type::Of(value, region_); - } + Type* Of(Handle<i::Object> value) { return Type::Of(value, zone_); } - TypeHandle NowOf(Handle<i::Object> value) { - return Type::NowOf(value, region_); - } + Type* NowOf(Handle<i::Object> value) { return Type::NowOf(value, zone_); } - TypeHandle Class(Handle<i::Map> map) { - return Type::Class(map, region_); - } + Type* Class(Handle<i::Map> map) { return Type::Class(map, zone_); } - TypeHandle Constant(Handle<i::Object> value) { - return Type::Constant(value, region_); + Type* Constant(Handle<i::Object> value) { + return Type::Constant(value, zone_); } - TypeHandle Range(double min, double max) { - return Type::Range(min, max, region_); - } + Type* Range(double min, double max) { return Type::Range(min, max, zone_); } - TypeHandle Context(TypeHandle outer) { - return Type::Context(outer, region_); - } + Type* Context(Type* outer) { return Type::Context(outer, zone_); } - TypeHandle Array1(TypeHandle element) { - return Type::Array(element, region_); - } + Type* Array1(Type* element) { return Type::Array(element, zone_); } - TypeHandle Function0(TypeHandle result, TypeHandle receiver) { - return Type::Function(result, receiver, 0, region_); + Type* Function0(Type* result, Type* receiver) { + return Type::Function(result, receiver, 0, zone_); } - TypeHandle Function1(TypeHandle result, TypeHandle receiver, TypeHandle arg) { - TypeHandle type = Type::Function(result, receiver, 1, region_); + Type* Function1(Type* result, Type* receiver, Type* arg) { + Type* type = Type::Function(result, receiver, 1, zone_); type->AsFunction()->InitParameter(0, arg); return type; } - TypeHandle Function2(TypeHandle result, TypeHandle arg1, TypeHandle arg2) { - return Type::Function(result, arg1, arg2, region_); + Type* Function2(Type* result, Type* arg1, Type* arg2) { + return Type::Function(result, arg1, arg2, zone_); } - TypeHandle Union(TypeHandle t1, TypeHandle t2) { - return Type::Union(t1, t2, region_); - } + Type* Union(Type* t1, Type* t2) { return Type::Union(t1, t2, zone_); } - TypeHandle Intersect(TypeHandle t1, TypeHandle t2) { - return Type::Intersect(t1, t2, region_); - } + Type* Intersect(Type* t1, Type* t2) { return Type::Intersect(t1, t2, zone_); } - TypeHandle Representation(TypeHandle t) { - return Type::Representation(t, region_); - } + Type* Representation(Type* t) { return Type::Representation(t, zone_); } - // TypeHandle Semantic(TypeHandle t) { return Intersect(t, + // Type* Semantic(Type* t) { return Intersect(t, // MaskSemanticForTesting); } - TypeHandle Semantic(TypeHandle t) { return Type::Semantic(t, region_); } + Type* Semantic(Type* t) { return Type::Semantic(t, zone_); } - template<class Type2, class TypeHandle2> - TypeHandle Convert(TypeHandle2 t) { - return Type::template Convert<Type2>(t, region_); - } - - TypeHandle Random() { + Type* Random() { return types[rng_->NextInt(static_cast<int>(types.size()))]; } - TypeHandle Fuzz(int depth = 4) { + Type* Fuzz(int depth = 4) { switch (rng_->NextInt(depth == 0 ? 3 : 20)) { case 0: { // bitset #define COUNT_BITSET_TYPES(type, value) + 1 int n = 0 PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES); #undef COUNT_BITSET_TYPES // Pick a bunch of named bitsets and return their intersection. - TypeHandle result = Type::Any(region_); + Type* result = Type::Any(); for (int i = 0, m = 1 + rng_->NextInt(3); i < m; ++i) { int j = rng_->NextInt(n); - #define PICK_BITSET_TYPE(type, value) \ - if (j-- == 0) { \ - TypeHandle tmp = Type::Intersect( \ - result, Type::type(region_), region_); \ - if (tmp->Is(Type::None()) && i != 0) { \ - break; \ - } else { \ - result = tmp; \ - continue; \ - } \ - } +#define PICK_BITSET_TYPE(type, value) \ + if (j-- == 0) { \ + Type* tmp = Type::Intersect(result, Type::type(), zone_); \ + if (tmp->Is(Type::None()) && i != 0) { \ + break; \ + } else { \ + result = tmp; \ + continue; \ + } \ + } PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE) #undef PICK_BITSET_TYPE } @@ -268,11 +243,11 @@ class Types { } case 1: { // class int i = rng_->NextInt(static_cast<int>(maps.size())); - return Type::Class(maps[i], region_); + return Type::Class(maps[i], zone_); } case 2: { // constant int i = rng_->NextInt(static_cast<int>(values.size())); - return Type::Constant(values[i], region_); + return Type::Constant(values[i], zone_); } case 3: { // range int i = rng_->NextInt(static_cast<int>(integers.size())); @@ -280,26 +255,26 @@ class Types { double min = integers[i]->Number(); double max = integers[j]->Number(); if (min > max) std::swap(min, max); - return Type::Range(min, max, region_); + return Type::Range(min, max, zone_); } case 4: { // context int depth = rng_->NextInt(3); - TypeHandle type = Type::Internal(region_); - for (int i = 0; i < depth; ++i) type = Type::Context(type, region_); + Type* type = Type::Internal(); + for (int i = 0; i < depth; ++i) type = Type::Context(type, zone_); return type; } case 5: { // array - TypeHandle element = Fuzz(depth / 2); - return Type::Array(element, region_); + Type* element = Fuzz(depth / 2); + return Type::Array(element, zone_); } case 6: case 7: { // function - TypeHandle result = Fuzz(depth / 2); - TypeHandle receiver = Fuzz(depth / 2); + Type* result = Fuzz(depth / 2); + Type* receiver = Fuzz(depth / 2); int arity = rng_->NextInt(3); - TypeHandle type = Type::Function(result, receiver, arity, region_); + Type* type = Type::Function(result, receiver, arity, zone_); for (int i = 0; i < type->AsFunction()->Arity(); ++i) { - TypeHandle parameter = Fuzz(depth / 2); + Type* parameter = Fuzz(depth / 2); type->AsFunction()->InitParameter(i, parameter); } return type; @@ -309,21 +284,21 @@ class Types { #define COUNT_SIMD_TYPE(NAME, Name, name, lane_count, lane_type) +1 SIMD128_TYPES(COUNT_SIMD_TYPE); #undef COUNT_SIMD_TYPE - TypeHandle (*simd_constructors[num_simd_types])(Isolate*, Region*) = { + Type* (*simd_constructors[num_simd_types])(Isolate*, Zone*) = { #define COUNT_SIMD_TYPE(NAME, Name, name, lane_count, lane_type) \ &Type::Name, - SIMD128_TYPES(COUNT_SIMD_TYPE) + SIMD128_TYPES(COUNT_SIMD_TYPE) #undef COUNT_SIMD_TYPE }; - return simd_constructors[rng_->NextInt(num_simd_types)]( - isolate_, region_); + return simd_constructors[rng_->NextInt(num_simd_types)](isolate_, + zone_); } default: { // union int n = rng_->NextInt(10); - TypeHandle type = None; + Type* type = None; for (int i = 0; i < n; ++i) { - TypeHandle operand = Fuzz(depth - 1); - type = Type::Union(type, operand, region_); + Type* operand = Fuzz(depth - 1); + type = Type::Union(type, operand, zone_); } return type; } @@ -331,10 +306,10 @@ class Types { UNREACHABLE(); } - Region* region() { return region_; } + Zone* zone() { return zone_; } private: - Region* region_; + Zone* zone_; Isolate* isolate_; v8::base::RandomNumberGenerator* rng_; }; diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-js.cc b/deps/v8/test/cctest/wasm/test-run-wasm-js.cc index 6fcde645cb..0b33808781 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-js.cc +++ b/deps/v8/test/cctest/wasm/test-run-wasm-js.cc @@ -3,12 +3,14 @@ // found in the LICENSE file. #include <stdint.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include "src/wasm/wasm-macro-gen.h" #include "test/cctest/cctest.h" +#include "test/cctest/compiler/value-helper.h" #include "test/cctest/wasm/test-signatures.h" #include "test/cctest/wasm/wasm-run-utils.h" @@ -24,39 +26,79 @@ using namespace v8::internal::wasm; } while (false) -static uint32_t AddJsFunction(TestingModule* module, FunctionSig* sig, - const char* source) { +#define ADD_CODE(vec, ...) \ + do { \ + byte __buf[] = {__VA_ARGS__}; \ + for (size_t i = 0; i < sizeof(__buf); i++) vec.push_back(__buf[i]); \ + } while (false) + + +namespace { +// A helper for generating predictable but unique argument values that +// are easy to debug (e.g. with misaligned stacks). +class PredictableInputValues { + public: + int base_; + explicit PredictableInputValues(int base) : base_(base) {} + double arg_d(int which) { return base_ * which + ((which & 1) * 0.5); } + float arg_f(int which) { return base_ * which + ((which & 1) * 0.25); } + int32_t arg_i(int which) { return base_ * which + ((which & 1) * kMinInt); } + int64_t arg_l(int which) { + return base_ * which + ((which & 1) * (0x04030201LL << 32)); + } +}; + + +uint32_t AddJsFunction(TestingModule* module, FunctionSig* sig, + const char* source) { Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle( *v8::Local<v8::Function>::Cast(CompileRun(source)))); module->AddFunction(sig, Handle<Code>::null()); uint32_t index = static_cast<uint32_t>(module->module->functions->size() - 1); Isolate* isolate = CcTest::InitIsolateOnce(); - Handle<Code> code = CompileWasmToJSWrapper(isolate, module, jsfunc, index); - module->function_code->at(index) = code; + Handle<Code> code = + CompileWasmToJSWrapper(isolate, module, jsfunc, sig, "test"); + module->instance->function_code->at(index) = code; return index; } -static Handle<JSFunction> WrapCode(ModuleEnv* module, uint32_t index) { +uint32_t AddJSSelector(TestingModule* module, FunctionSig* sig, int which) { + const int kMaxParams = 8; + static const char* formals[kMaxParams] = { + "", "a", "a,b", "a,b,c", + "a,b,c,d", "a,b,c,d,e", "a,b,c,d,e,f", "a,b,c,d,e,f,g", + }; + CHECK_LT(which, static_cast<int>(sig->parameter_count())); + CHECK_LT(static_cast<int>(sig->parameter_count()), kMaxParams); + + i::EmbeddedVector<char, 256> source; + char param = 'a' + which; + SNPrintF(source, "(function(%s) { return %c; })", + formals[sig->parameter_count()], param); + + return AddJsFunction(module, sig, source.start()); +} + + +Handle<JSFunction> WrapCode(ModuleEnv* module, uint32_t index) { Isolate* isolate = module->module->shared_isolate; // Wrap the code so it can be called as a JS function. Handle<String> name = isolate->factory()->NewStringFromStaticChars("main"); Handle<JSObject> module_object = Handle<JSObject>(0, isolate); - Handle<Code> code = module->function_code->at(index); + Handle<Code> code = module->instance->function_code->at(index); WasmJs::InstallWasmFunctionMap(isolate, isolate->native_context()); return compiler::CompileJSToWasmWrapper(isolate, module, name, code, module_object, index); } -static void EXPECT_CALL(double expected, Handle<JSFunction> jsfunc, double a, - double b) { +void EXPECT_CALL(double expected, Handle<JSFunction> jsfunc, + Handle<Object>* buffer, int count) { Isolate* isolate = jsfunc->GetIsolate(); - Handle<Object> buffer[] = {isolate->factory()->NewNumber(a), - isolate->factory()->NewNumber(b)}; Handle<Object> global(isolate->context()->global_object(), isolate); MaybeHandle<Object> retval = - Execution::Call(isolate, jsfunc, global, 2, buffer); + Execution::Call(isolate, jsfunc, global, count, buffer); CHECK(!retval.is_null()); Handle<Object> result = retval.ToHandleChecked(); @@ -64,17 +106,26 @@ static void EXPECT_CALL(double expected, Handle<JSFunction> jsfunc, double a, CHECK_EQ(expected, Smi::cast(*result)->value()); } else { CHECK(result->IsHeapNumber()); - CHECK_EQ(expected, HeapNumber::cast(*result)->value()); + CheckFloatEq(expected, HeapNumber::cast(*result)->value()); } } +void EXPECT_CALL(double expected, Handle<JSFunction> jsfunc, double a, + double b) { + Isolate* isolate = jsfunc->GetIsolate(); + Handle<Object> buffer[] = {isolate->factory()->NewNumber(a), + isolate->factory()->NewNumber(b)}; + EXPECT_CALL(expected, jsfunc, buffer, 2); +} +} // namespace + TEST(Run_Int32Sub_jswrapped) { TestSignatures sigs; TestingModule module; - WasmFunctionCompiler t(sigs.i_ii()); + WasmFunctionCompiler t(sigs.i_ii(), &module); BUILD(t, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); - Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); + Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd()); EXPECT_CALL(33, jsfunc, 44, 11); EXPECT_CALL(-8723487, jsfunc, -8000000, 723487); @@ -84,9 +135,9 @@ TEST(Run_Int32Sub_jswrapped) { TEST(Run_Float32Div_jswrapped) { TestSignatures sigs; TestingModule module; - WasmFunctionCompiler t(sigs.f_ff()); + WasmFunctionCompiler t(sigs.f_ff(), &module); BUILD(t, WASM_F32_DIV(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); - Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); + Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd()); EXPECT_CALL(92, jsfunc, 46, 0.5); EXPECT_CALL(64, jsfunc, -16, -0.25); @@ -96,9 +147,9 @@ TEST(Run_Float32Div_jswrapped) { TEST(Run_Float64Add_jswrapped) { TestSignatures sigs; TestingModule module; - WasmFunctionCompiler t(sigs.d_dd()); + WasmFunctionCompiler t(sigs.d_dd(), &module); BUILD(t, WASM_F64_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); - Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); + Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd()); EXPECT_CALL(3, jsfunc, 2, 1); EXPECT_CALL(-5.5, jsfunc, -5.25, -0.25); @@ -108,9 +159,9 @@ TEST(Run_Float64Add_jswrapped) { TEST(Run_I32Popcount_jswrapped) { TestSignatures sigs; TestingModule module; - WasmFunctionCompiler t(sigs.i_i()); + WasmFunctionCompiler t(sigs.i_i(), &module); BUILD(t, WASM_I32_POPCNT(WASM_GET_LOCAL(0))); - Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); + Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd()); EXPECT_CALL(2, jsfunc, 9, 0); EXPECT_CALL(3, jsfunc, 11, 0); @@ -121,8 +172,7 @@ TEST(Run_I32Popcount_jswrapped) { #if !V8_TARGET_ARCH_ARM64 -// TODO(titzer): fix wasm->JS calls on arm64 (wrapper issues) - +// TODO(titzer): dynamic frame alignment on arm64 TEST(Run_CallJS_Add_jswrapped) { TestSignatures sigs; TestingModule module; @@ -131,11 +181,252 @@ TEST(Run_CallJS_Add_jswrapped) { AddJsFunction(&module, sigs.i_i(), "(function(a) { return a + 99; })"); BUILD(t, WASM_CALL_FUNCTION(js_index, WASM_GET_LOCAL(0))); - Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd(&module)); + Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd()); EXPECT_CALL(101, jsfunc, 2, -8); EXPECT_CALL(199, jsfunc, 100, -1); EXPECT_CALL(-666666801, jsfunc, -666666900, -1); } +#endif + + +void RunJSSelectTest(int which) { +#if !V8_TARGET_ARCH_ARM + // TODO(titzer): fix tests on arm and reenable + const int kMaxParams = 8; + PredictableInputValues inputs(0x100); + LocalType type = kAstF64; + LocalType types[kMaxParams + 1] = {type, type, type, type, type, + type, type, type, type}; + for (int num_params = which + 1; num_params < kMaxParams; num_params++) { + HandleScope scope(CcTest::InitIsolateOnce()); + FunctionSig sig(1, num_params, types); + + TestingModule module; + uint32_t js_index = AddJSSelector(&module, &sig, which); + WasmFunctionCompiler t(&sig, &module); + + { + std::vector<byte> code; + ADD_CODE(code, kExprCallFunction, static_cast<byte>(js_index)); + + for (int i = 0; i < num_params; i++) { + ADD_CODE(code, WASM_F64(inputs.arg_d(i))); + } + + size_t end = code.size(); + code.push_back(0); + t.Build(&code[0], &code[end]); + } + + Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd()); + double expected = inputs.arg_d(which); + EXPECT_CALL(expected, jsfunc, 0.0, 0.0); + } +#endif +} + + +TEST(Run_JSSelect_0) { RunJSSelectTest(0); } + +TEST(Run_JSSelect_1) { RunJSSelectTest(1); } + +TEST(Run_JSSelect_2) { RunJSSelectTest(2); } + +TEST(Run_JSSelect_3) { RunJSSelectTest(3); } + +TEST(Run_JSSelect_4) { RunJSSelectTest(4); } + +TEST(Run_JSSelect_5) { RunJSSelectTest(5); } + +TEST(Run_JSSelect_6) { RunJSSelectTest(6); } + +TEST(Run_JSSelect_7) { RunJSSelectTest(7); } + + +void RunWASMSelectTest(int which) { + PredictableInputValues inputs(0x200); + Isolate* isolate = CcTest::InitIsolateOnce(); + const int kMaxParams = 8; + for (int num_params = which + 1; num_params < kMaxParams; num_params++) { + LocalType type = kAstF64; + LocalType types[kMaxParams + 1] = {type, type, type, type, type, + type, type, type, type}; + FunctionSig sig(1, num_params, types); + + TestingModule module; + WasmFunctionCompiler t(&sig, &module); + BUILD(t, WASM_GET_LOCAL(which)); + Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd()); + + Handle<Object> args[] = { + isolate->factory()->NewNumber(inputs.arg_d(0)), + isolate->factory()->NewNumber(inputs.arg_d(1)), + isolate->factory()->NewNumber(inputs.arg_d(2)), + isolate->factory()->NewNumber(inputs.arg_d(3)), + isolate->factory()->NewNumber(inputs.arg_d(4)), + isolate->factory()->NewNumber(inputs.arg_d(5)), + isolate->factory()->NewNumber(inputs.arg_d(6)), + isolate->factory()->NewNumber(inputs.arg_d(7)), + }; + + double expected = inputs.arg_d(which); + EXPECT_CALL(expected, jsfunc, args, kMaxParams); + } +} + + +TEST(Run_WASMSelect_0) { RunWASMSelectTest(0); } + +TEST(Run_WASMSelect_1) { RunWASMSelectTest(1); } + +TEST(Run_WASMSelect_2) { RunWASMSelectTest(2); } + +TEST(Run_WASMSelect_3) { RunWASMSelectTest(3); } + +TEST(Run_WASMSelect_4) { RunWASMSelectTest(4); } + +TEST(Run_WASMSelect_5) { RunWASMSelectTest(5); } + +TEST(Run_WASMSelect_6) { RunWASMSelectTest(6); } + +TEST(Run_WASMSelect_7) { RunWASMSelectTest(7); } + + +void RunWASMSelectAlignTest(int num_args, int num_params) { + PredictableInputValues inputs(0x300); + Isolate* isolate = CcTest::InitIsolateOnce(); + const int kMaxParams = 4; + DCHECK_LE(num_args, kMaxParams); + LocalType type = kAstF64; + LocalType types[kMaxParams + 1] = {type, type, type, type, type}; + FunctionSig sig(1, num_params, types); + + for (int which = 0; which < num_params; which++) { + TestingModule module; + WasmFunctionCompiler t(&sig, &module); + BUILD(t, WASM_GET_LOCAL(which)); + Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd()); + + Handle<Object> args[] = { + isolate->factory()->NewNumber(inputs.arg_d(0)), + isolate->factory()->NewNumber(inputs.arg_d(1)), + isolate->factory()->NewNumber(inputs.arg_d(2)), + isolate->factory()->NewNumber(inputs.arg_d(3)), + }; + + double nan = std::numeric_limits<double>::quiet_NaN(); + double expected = which < num_args ? inputs.arg_d(which) : nan; + EXPECT_CALL(expected, jsfunc, args, num_args); + } +} + + +TEST(Run_WASMSelectAlign_0) { + RunWASMSelectAlignTest(0, 1); + RunWASMSelectAlignTest(0, 2); +} + + +TEST(Run_WASMSelectAlign_1) { + RunWASMSelectAlignTest(1, 2); + RunWASMSelectAlignTest(1, 3); +} + + +TEST(Run_WASMSelectAlign_2) { + RunWASMSelectAlignTest(2, 3); + RunWASMSelectAlignTest(2, 4); +} + + +TEST(Run_WASMSelectAlign_3) { + RunWASMSelectAlignTest(3, 3); + RunWASMSelectAlignTest(3, 4); +} + + +TEST(Run_WASMSelectAlign_4) { + RunWASMSelectAlignTest(4, 3); + RunWASMSelectAlignTest(4, 4); +} + + +void RunJSSelectAlignTest(int num_args, int num_params) { + PredictableInputValues inputs(0x400); + Isolate* isolate = CcTest::InitIsolateOnce(); + Factory* factory = isolate->factory(); + const int kMaxParams = 4; + CHECK_LE(num_args, kMaxParams); + CHECK_LE(num_params, kMaxParams); + LocalType type = kAstF64; + LocalType types[kMaxParams + 1] = {type, type, type, type, type}; + FunctionSig sig(1, num_params, types); + + // Build the calling code. + std::vector<byte> code; + ADD_CODE(code, kExprCallFunction, 0); + + for (int i = 0; i < num_params; i++) { + ADD_CODE(code, WASM_GET_LOCAL(i)); + } + + size_t end = code.size(); + code.push_back(0); + + // Call different select JS functions. + for (int which = 0; which < num_params; which++) { + HandleScope scope(isolate); + TestingModule module; + uint32_t js_index = AddJSSelector(&module, &sig, which); + CHECK_EQ(0, js_index); + WasmFunctionCompiler t(&sig, &module); + t.Build(&code[0], &code[end]); + + Handle<JSFunction> jsfunc = WrapCode(&module, t.CompileAndAdd()); + + Handle<Object> args[] = { + factory->NewNumber(inputs.arg_d(0)), + factory->NewNumber(inputs.arg_d(1)), + factory->NewNumber(inputs.arg_d(2)), + factory->NewNumber(inputs.arg_d(3)), + }; + + double nan = std::numeric_limits<double>::quiet_NaN(); + double expected = which < num_args ? inputs.arg_d(which) : nan; + EXPECT_CALL(expected, jsfunc, args, num_args); + } +} + +TEST(Run_JSSelectAlign_0) { + RunJSSelectAlignTest(0, 1); + RunJSSelectAlignTest(0, 2); +} + + +TEST(Run_JSSelectAlign_2) { + RunJSSelectAlignTest(2, 3); + RunJSSelectAlignTest(2, 4); +} + + +TEST(Run_JSSelectAlign_4) { + RunJSSelectAlignTest(4, 3); + RunJSSelectAlignTest(4, 4); +} + + +#if !V8_TARGET_ARCH_ARM64 +// TODO(titzer): dynamic frame alignment on arm64 +TEST(Run_JSSelectAlign_1) { + RunJSSelectAlignTest(1, 2); + RunJSSelectAlignTest(1, 3); +} + + +TEST(Run_JSSelectAlign_3) { + RunJSSelectAlignTest(3, 3); + RunJSSelectAlignTest(3, 4); +} #endif diff --git a/deps/v8/test/cctest/wasm/test-run-wasm-module.cc b/deps/v8/test/cctest/wasm/test-run-wasm-module.cc index 3b7bae1dda..905e8e4932 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm-module.cc +++ b/deps/v8/test/cctest/wasm/test-run-wasm-module.cc @@ -6,6 +6,7 @@ #include <string.h> #include "src/wasm/encoder.h" +#include "src/wasm/wasm-js.h" #include "src/wasm/wasm-macro-gen.h" #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-opcodes.h" @@ -18,9 +19,13 @@ using namespace v8::internal::compiler; using namespace v8::internal::wasm; +#if !V8_TARGET_ARCH_ARM64 +// TODO(titzer): fix arm64 frame alignment. namespace { void TestModule(WasmModuleIndex* module, int32_t expected_result) { Isolate* isolate = CcTest::InitIsolateOnce(); + HandleScope scope(isolate); + WasmJs::InstallWasmFunctionMap(isolate, isolate->native_context()); int32_t result = CompileAndRunWasmModule(isolate, module->Begin(), module->End()); CHECK_EQ(expected_result, result); @@ -50,6 +55,8 @@ TEST(Run_WasmModule_CallAdd_rev) { }; Isolate* isolate = CcTest::InitIsolateOnce(); + HandleScope scope(isolate); + WasmJs::InstallWasmFunctionMap(isolate, isolate->native_context()); int32_t result = CompileAndRunWasmModule(isolate, data, data + arraysize(data)); CHECK_EQ(99, result); @@ -197,3 +204,5 @@ TEST(Run_WasmModule_Global) { TestModule(writer->WriteTo(&zone), 97); } #endif + +#endif // !V8_TARGET_ARCH_ARM64 diff --git a/deps/v8/test/cctest/wasm/test-run-wasm.cc b/deps/v8/test/cctest/wasm/test-run-wasm.cc index 445c3f0aed..a6f07f7af0 100644 --- a/deps/v8/test/cctest/wasm/test-run-wasm.cc +++ b/deps/v8/test/cctest/wasm/test-run-wasm.cc @@ -26,7 +26,7 @@ using namespace v8::internal::wasm; TEST(Run_WasmInt8Const) { - WasmRunner<int8_t> r; + WasmRunner<int32_t> r; const byte kExpectedValue = 121; // return(kExpectedValue) BUILD(r, WASM_I8(kExpectedValue)); @@ -35,7 +35,7 @@ TEST(Run_WasmInt8Const) { TEST(Run_WasmInt8Const_fallthru1) { - WasmRunner<int8_t> r; + WasmRunner<int32_t> r; const byte kExpectedValue = 122; // kExpectedValue BUILD(r, WASM_I8(kExpectedValue)); @@ -44,7 +44,7 @@ TEST(Run_WasmInt8Const_fallthru1) { TEST(Run_WasmInt8Const_fallthru2) { - WasmRunner<int8_t> r; + WasmRunner<int32_t> r; const byte kExpectedValue = 123; // -99 kExpectedValue BUILD(r, WASM_I8(-99), WASM_I8(kExpectedValue)); @@ -54,10 +54,10 @@ TEST(Run_WasmInt8Const_fallthru2) { TEST(Run_WasmInt8Const_all) { for (int value = -128; value <= 127; value++) { - WasmRunner<int8_t> r; + WasmRunner<int32_t> r; // return(value) BUILD(r, WASM_I8(value)); - int8_t result = r.Call(); + int32_t result = r.Call(); CHECK_EQ(value, result); } } @@ -84,10 +84,9 @@ TEST(Run_WasmInt32Const_many) { TEST(Run_WasmMemorySize) { - WasmRunner<int32_t> r; TestingModule module; + WasmRunner<int32_t> r(&module); module.AddMemory(1024); - r.env()->module = &module; BUILD(r, kExprMemorySize); CHECK_EQ(1024, r.Call()); } @@ -116,6 +115,23 @@ TEST(Run_WasmInt64Const_many) { } #endif +TEST(Run_WasmI32ConvertI64) { + FOR_INT64_INPUTS(i) { + WasmRunner<int32_t> r; + BUILD(r, WASM_I32_CONVERT_I64(WASM_I64(*i))); + CHECK_EQ(static_cast<int32_t>(*i), r.Call()); + } +} + +TEST(Run_WasmI64AndConstants) { + FOR_INT64_INPUTS(i) { + FOR_INT64_INPUTS(j) { + WasmRunner<int32_t> r; + BUILD(r, WASM_I32_CONVERT_I64(WASM_I64_AND(WASM_I64(*i), WASM_I64(*j)))); + CHECK_EQ(static_cast<int32_t>(*i & *j), r.Call()); + } + } +} TEST(Run_WasmInt32Param0) { WasmRunner<int32_t> r(MachineType::Int32()); @@ -179,9 +195,6 @@ TEST(Run_WasmInt32Add_P2) { } -// TODO(titzer): Fix for nosee4 and re-enable. -#if 0 - TEST(Run_WasmFloat32Add) { WasmRunner<int32_t> r; // int(11.5f + 44.5f) @@ -198,8 +211,6 @@ TEST(Run_WasmFloat64Add) { CHECK_EQ(57, r.Call()); } -#endif - void TestInt32Binop(WasmOpcode opcode, int32_t expected, int32_t a, int32_t b) { { @@ -216,7 +227,6 @@ void TestInt32Binop(WasmOpcode opcode, int32_t expected, int32_t a, int32_t b) { } } - TEST(Run_WasmInt32Binops) { TestInt32Binop(kExprI32Add, 88888888, 33333333, 55555555); TestInt32Binop(kExprI32Sub, -1111111, 7777777, 8888888); @@ -594,10 +604,9 @@ TEST(Run_WASM_Int32DivU_byzero_const) { TEST(Run_WASM_Int32DivS_trap_effect) { - WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); TestingModule module; module.AddMemoryElems<int32_t>(8); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32()); BUILD(r, WASM_IF_ELSE(WASM_GET_LOCAL(0), @@ -793,10 +802,6 @@ void TestFloat64UnopWithConvert(WasmOpcode opcode, int32_t expected, double a) { } } - -// TODO(titzer): Fix for nosee4 and re-enable. -#if 0 - TEST(Run_WasmFloat32Binops) { TestFloat32Binop(kExprF32Eq, 1, 8.125f, 8.125f); TestFloat32Binop(kExprF32Ne, 1, 8.125f, 8.127f); @@ -811,7 +816,6 @@ TEST(Run_WasmFloat32Binops) { TestFloat32BinopWithConvert(kExprF32Div, 11, 22.1f, 2.0f); } - TEST(Run_WasmFloat32Unops) { TestFloat32UnopWithConvert(kExprF32Abs, 8, 8.125f); TestFloat32UnopWithConvert(kExprF32Abs, 9, -9.125f); @@ -819,7 +823,6 @@ TEST(Run_WasmFloat32Unops) { TestFloat32UnopWithConvert(kExprF32Sqrt, 12, 144.4f); } - TEST(Run_WasmFloat64Binops) { TestFloat64Binop(kExprF64Eq, 1, 16.25, 16.25); TestFloat64Binop(kExprF64Ne, 1, 16.25, 16.15); @@ -834,7 +837,6 @@ TEST(Run_WasmFloat64Binops) { TestFloat64BinopWithConvert(kExprF64Div, -1111, -2222.3, 2); } - TEST(Run_WasmFloat64Unops) { TestFloat64UnopWithConvert(kExprF64Abs, 108, 108.125); TestFloat64UnopWithConvert(kExprF64Abs, 209, -209.125); @@ -842,9 +844,6 @@ TEST(Run_WasmFloat64Unops) { TestFloat64UnopWithConvert(kExprF64Sqrt, 13, 169.4); } -#endif - - TEST(Run_WasmFloat32Neg) { WasmRunner<float> r(MachineType::Float32()); BUILD(r, WASM_F32_NEG(WASM_GET_LOCAL(0))); @@ -962,8 +961,8 @@ TEST(Run_Wasm_Return_F64) { TEST(Run_Wasm_Select) { WasmRunner<int32_t> r(MachineType::Int32()); - // return select(a, 11, 22); - BUILD(r, WASM_SELECT(WASM_GET_LOCAL(0), WASM_I8(11), WASM_I8(22))); + // return select(11, 22, a); + BUILD(r, WASM_SELECT(WASM_I8(11), WASM_I8(22), WASM_GET_LOCAL(0))); FOR_INT32_INPUTS(i) { int32_t expected = *i ? 11 : 22; CHECK_EQ(expected, r.Call(*i)); @@ -973,22 +972,38 @@ TEST(Run_Wasm_Select) { TEST(Run_Wasm_Select_strict1) { WasmRunner<int32_t> r(MachineType::Int32()); - // select(a, a = 11, 22); return a - BUILD(r, - WASM_BLOCK(2, WASM_SELECT(WASM_GET_LOCAL(0), - WASM_SET_LOCAL(0, WASM_I8(11)), WASM_I8(22)), - WASM_GET_LOCAL(0))); - FOR_INT32_INPUTS(i) { CHECK_EQ(11, r.Call(*i)); } + // select(a=0, a=1, a=2); return a + BUILD(r, WASM_BLOCK(2, WASM_SELECT(WASM_SET_LOCAL(0, WASM_I8(0)), + WASM_SET_LOCAL(0, WASM_I8(1)), + WASM_SET_LOCAL(0, WASM_I8(2))), + WASM_GET_LOCAL(0))); + FOR_INT32_INPUTS(i) { CHECK_EQ(2, r.Call(*i)); } } TEST(Run_Wasm_Select_strict2) { WasmRunner<int32_t> r(MachineType::Int32()); - // select(a, 11, a = 22); return a; - BUILD(r, WASM_BLOCK(2, WASM_SELECT(WASM_GET_LOCAL(0), WASM_I8(11), - WASM_SET_LOCAL(0, WASM_I8(22))), - WASM_GET_LOCAL(0))); - FOR_INT32_INPUTS(i) { CHECK_EQ(22, r.Call(*i)); } + r.env()->AddLocals(kAstI32, 2); + // select(b=5, c=6, a) + BUILD(r, WASM_SELECT(WASM_SET_LOCAL(1, WASM_I8(5)), + WASM_SET_LOCAL(2, WASM_I8(6)), WASM_GET_LOCAL(0))); + FOR_INT32_INPUTS(i) { + int32_t expected = *i ? 5 : 6; + CHECK_EQ(expected, r.Call(*i)); + } +} + +TEST(Run_Wasm_Select_strict3) { + WasmRunner<int32_t> r(MachineType::Int32()); + r.env()->AddLocals(kAstI32, 2); + // select(b=5, c=6, a=b) + BUILD(r, WASM_SELECT(WASM_SET_LOCAL(1, WASM_I8(5)), + WASM_SET_LOCAL(2, WASM_I8(6)), + WASM_SET_LOCAL(0, WASM_GET_LOCAL(1)))); + FOR_INT32_INPUTS(i) { + int32_t expected = 5; + CHECK_EQ(expected, r.Call(*i)); + } } @@ -1002,6 +1017,34 @@ TEST(Run_Wasm_BrIf_strict) { FOR_INT32_INPUTS(i) { CHECK_EQ(99, r.Call(*i)); } } +TEST(Run_Wasm_TableSwitch0a) { + WasmRunner<int32_t> r(MachineType::Int32()); + BUILD(r, WASM_BLOCK(2, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(0)), + WASM_TABLESWITCH_BODY0(WASM_GET_LOCAL(0)), WASM_I8(91))); + FOR_INT32_INPUTS(i) { CHECK_EQ(91, r.Call(*i)); } +} + +TEST(Run_Wasm_TableSwitch0b) { + WasmRunner<int32_t> r(MachineType::Int32()); + BUILD(r, WASM_BLOCK( + 2, WASM_TABLESWITCH_OP(0, 2, WASM_CASE_BR(0), WASM_CASE_BR(0)), + WASM_TABLESWITCH_BODY0(WASM_GET_LOCAL(0)), WASM_I8(92))); + FOR_INT32_INPUTS(i) { CHECK_EQ(92, r.Call(*i)); } +} + +TEST(Run_Wasm_TableSwitch0c) { + WasmRunner<int32_t> r(MachineType::Int32()); + BUILD(r, + WASM_BLOCK(2, WASM_BLOCK(2, WASM_TABLESWITCH_OP(0, 2, WASM_CASE_BR(0), + WASM_CASE_BR(1)), + WASM_TABLESWITCH_BODY0(WASM_GET_LOCAL(0)), + WASM_RETURN(WASM_I8(76))), + WASM_I8(77))); + FOR_INT32_INPUTS(i) { + int32_t expected = *i == 0 ? 76 : 77; + CHECK_EQ(expected, r.Call(*i)); + } +} TEST(Run_Wasm_TableSwitch1) { WasmRunner<int32_t> r(MachineType::Int32()); @@ -1178,10 +1221,9 @@ TEST(Run_Wasm_TableSwitch4_fallthru_br) { TEST(Run_Wasm_F32ReinterpretI32) { - WasmRunner<int32_t> r; TestingModule module; int32_t* memory = module.AddMemoryElems<int32_t>(8); - r.env()->module = &module; + WasmRunner<int32_t> r(&module); BUILD(r, WASM_I32_REINTERPRET_F32( WASM_LOAD_MEM(MachineType::Float32(), WASM_ZERO))); @@ -1195,10 +1237,9 @@ TEST(Run_Wasm_F32ReinterpretI32) { TEST(Run_Wasm_I32ReinterpretF32) { - WasmRunner<int32_t> r(MachineType::Int32()); TestingModule module; int32_t* memory = module.AddMemoryElems<int32_t>(8); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); BUILD(r, WASM_BLOCK( 2, WASM_STORE_MEM(MachineType::Float32(), WASM_ZERO, @@ -1214,10 +1255,9 @@ TEST(Run_Wasm_I32ReinterpretF32) { TEST(Run_Wasm_ReturnStore) { - WasmRunner<int32_t> r; TestingModule module; int32_t* memory = module.AddMemoryElems<int32_t>(8); - r.env()->module = &module; + WasmRunner<int32_t> r(&module); BUILD(r, WASM_STORE_MEM(MachineType::Int32(), WASM_ZERO, WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO))); @@ -1231,16 +1271,43 @@ TEST(Run_Wasm_ReturnStore) { TEST(Run_Wasm_VoidReturn1) { - WasmRunner<void> r; - BUILD(r, kExprNop); - r.Call(); + // We use a wrapper function because WasmRunner<void> does not exist. + + // Build the test function. + TestSignatures sigs; + TestingModule module; + WasmFunctionCompiler t(sigs.v_v(), &module); + BUILD(t, kExprNop); + uint32_t index = t.CompileAndAdd(); + + const int32_t kExpected = -414444; + // Build the calling function. + WasmRunner<int32_t> r; + r.env()->module = &module; + BUILD(r, WASM_BLOCK(2, WASM_CALL_FUNCTION0(index), WASM_I32(kExpected))); + + int32_t result = r.Call(); + CHECK_EQ(kExpected, result); } TEST(Run_Wasm_VoidReturn2) { - WasmRunner<void> r; - BUILD(r, WASM_RETURN0); - r.Call(); + // We use a wrapper function because WasmRunner<void> does not exist. + // Build the test function. + TestSignatures sigs; + TestingModule module; + WasmFunctionCompiler t(sigs.v_v(), &module); + BUILD(t, WASM_RETURN0); + uint32_t index = t.CompileAndAdd(); + + const int32_t kExpected = -414444; + // Build the calling function. + WasmRunner<int32_t> r; + r.env()->module = &module; + BUILD(r, WASM_BLOCK(2, WASM_CALL_FUNCTION0(index), WASM_I32(kExpected))); + + int32_t result = r.Call(); + CHECK_EQ(kExpected, result); } @@ -1260,7 +1327,7 @@ TEST(Run_Wasm_Block_If_P) { TEST(Run_Wasm_Block_BrIf_P) { WasmRunner<int32_t> r(MachineType::Int32()); - BUILD(r, WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_I8(51)), + BUILD(r, WASM_BLOCK(2, WASM_BRV_IF(0, WASM_I8(51), WASM_GET_LOCAL(0)), WASM_I8(52))); FOR_INT32_INPUTS(i) { int32_t expected = *i ? 51 : 52; @@ -1427,11 +1494,10 @@ TEST(Run_Wasm_Loop_if_break_fallthru) { TEST(Run_Wasm_LoadMemI32) { - WasmRunner<int32_t> r(MachineType::Int32()); TestingModule module; int32_t* memory = module.AddMemoryElems<int32_t>(8); + WasmRunner<int32_t> r(&module, MachineType::Int32()); module.RandomizeMemory(1111); - r.env()->module = &module; BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_I8(0))); @@ -1447,11 +1513,10 @@ TEST(Run_Wasm_LoadMemI32) { TEST(Run_Wasm_LoadMemI32_oob) { - WasmRunner<int32_t> r(MachineType::Uint32()); TestingModule module; int32_t* memory = module.AddMemoryElems<int32_t>(8); + WasmRunner<int32_t> r(&module, MachineType::Uint32()); module.RandomizeMemory(1111); - r.env()->module = &module; BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0))); @@ -1468,12 +1533,11 @@ TEST(Run_Wasm_LoadMemI32_oob) { TEST(Run_Wasm_LoadMemI32_oob_asm) { - WasmRunner<int32_t> r(MachineType::Uint32()); TestingModule module; module.asm_js = true; int32_t* memory = module.AddMemoryElems<int32_t>(8); + WasmRunner<int32_t> r(&module, MachineType::Uint32()); module.RandomizeMemory(1112); - r.env()->module = &module; BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0))); @@ -1502,8 +1566,7 @@ TEST(Run_Wasm_LoadMem_offset_oob) { for (size_t m = 0; m < arraysize(machineTypes); m++) { module.RandomizeMemory(1116 + static_cast<int>(m)); - WasmRunner<int32_t> r(MachineType::Uint32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Uint32()); uint32_t boundary = 24 - WasmOpcodes::MemSize(machineTypes[m]); BUILD(r, WASM_LOAD_MEM_OFFSET(machineTypes[m], 8, WASM_GET_LOCAL(0)), @@ -1519,11 +1582,10 @@ TEST(Run_Wasm_LoadMem_offset_oob) { TEST(Run_Wasm_LoadMemI32_offset) { - WasmRunner<int32_t> r(MachineType::Int32()); TestingModule module; int32_t* memory = module.AddMemoryElems<int32_t>(4); + WasmRunner<int32_t> r(&module, MachineType::Int32()); module.RandomizeMemory(1111); - r.env()->module = &module; BUILD(r, WASM_LOAD_MEM_OFFSET(MachineType::Int32(), 4, WASM_GET_LOCAL(0))); @@ -1545,18 +1607,17 @@ TEST(Run_Wasm_LoadMemI32_offset) { } -// TODO(titzer): Fix for mips and re-enable. #if !V8_TARGET_ARCH_MIPS && !V8_TARGET_ARCH_MIPS64 -TEST(Run_Wasm_LoadMemI32_const_oob) { - TestingModule module; +TEST(Run_Wasm_LoadMemI32_const_oob_misaligned) { const int kMemSize = 12; - module.AddMemoryElems<byte>(kMemSize); - + // TODO(titzer): Fix misaligned accesses on MIPS and re-enable. for (int offset = 0; offset < kMemSize + 5; offset++) { for (int index = 0; index < kMemSize + 5; index++) { - WasmRunner<int32_t> r; - r.env()->module = &module; + TestingModule module; + module.AddMemoryElems<byte>(kMemSize); + + WasmRunner<int32_t> r(&module); module.RandomizeMemory(); BUILD(r, @@ -1574,12 +1635,34 @@ TEST(Run_Wasm_LoadMemI32_const_oob) { #endif +TEST(Run_Wasm_LoadMemI32_const_oob) { + const int kMemSize = 24; + for (int offset = 0; offset < kMemSize + 5; offset += 4) { + for (int index = 0; index < kMemSize + 5; index += 4) { + TestingModule module; + module.AddMemoryElems<byte>(kMemSize); + + WasmRunner<int32_t> r(&module); + module.RandomizeMemory(); + + BUILD(r, + WASM_LOAD_MEM_OFFSET(MachineType::Int32(), offset, WASM_I8(index))); + + if ((offset + index) <= (kMemSize - sizeof(int32_t))) { + CHECK_EQ(module.raw_val_at<int32_t>(offset + index), r.Call()); + } else { + CHECK_TRAP(r.Call()); + } + } + } +} + + TEST(Run_Wasm_StoreMemI32_offset) { - WasmRunner<int32_t> r(MachineType::Int32()); - const int32_t kWritten = 0xaabbccdd; TestingModule module; int32_t* memory = module.AddMemoryElems<int32_t>(4); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); + const int32_t kWritten = 0xaabbccdd; BUILD(r, WASM_STORE_MEM_OFFSET(MachineType::Int32(), 4, WASM_GET_LOCAL(0), WASM_I32(kWritten))); @@ -1618,8 +1701,7 @@ TEST(Run_Wasm_StoreMem_offset_oob) { for (size_t m = 0; m < arraysize(machineTypes); m++) { module.RandomizeMemory(1119 + static_cast<int>(m)); - WasmRunner<int32_t> r(MachineType::Uint32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Uint32()); BUILD(r, WASM_STORE_MEM_OFFSET(machineTypes[m], 8, WASM_GET_LOCAL(0), WASM_LOAD_MEM(machineTypes[m], WASM_ZERO)), @@ -1639,10 +1721,9 @@ TEST(Run_Wasm_StoreMem_offset_oob) { #if WASM_64 TEST(Run_Wasm_F64ReinterpretI64) { - WasmRunner<int64_t> r; TestingModule module; int64_t* memory = module.AddMemoryElems<int64_t>(8); - r.env()->module = &module; + WasmRunner<int64_t> r(&module); BUILD(r, WASM_I64_REINTERPRET_F64( WASM_LOAD_MEM(MachineType::Float64(), WASM_ZERO))); @@ -1656,10 +1737,9 @@ TEST(Run_Wasm_F64ReinterpretI64) { TEST(Run_Wasm_I64ReinterpretF64) { - WasmRunner<int64_t> r(MachineType::Int64()); TestingModule module; int64_t* memory = module.AddMemoryElems<int64_t>(8); - r.env()->module = &module; + WasmRunner<int64_t> r(&module, MachineType::Int64()); BUILD(r, WASM_BLOCK( 2, WASM_STORE_MEM(MachineType::Float64(), WASM_ZERO, @@ -1675,11 +1755,10 @@ TEST(Run_Wasm_I64ReinterpretF64) { TEST(Run_Wasm_LoadMemI64) { - WasmRunner<int64_t> r; TestingModule module; int64_t* memory = module.AddMemoryElems<int64_t>(8); module.RandomizeMemory(1111); - r.env()->module = &module; + WasmRunner<int64_t> r(&module); BUILD(r, WASM_LOAD_MEM(MachineType::Int64(), WASM_I8(0))); @@ -1697,11 +1776,10 @@ TEST(Run_Wasm_LoadMemI64) { TEST(Run_Wasm_LoadMemI32_P) { const int kNumElems = 8; - WasmRunner<int32_t> r(MachineType::Int32()); TestingModule module; int32_t* memory = module.AddMemoryElems<int32_t>(kNumElems); + WasmRunner<int32_t> r(&module, MachineType::Int32()); module.RandomizeMemory(2222); - r.env()->module = &module; BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0))); @@ -1712,12 +1790,11 @@ TEST(Run_Wasm_LoadMemI32_P) { TEST(Run_Wasm_MemI32_Sum) { - WasmRunner<uint32_t> r(MachineType::Int32()); const int kNumElems = 20; - const byte kSum = r.AllocateLocal(kAstI32); TestingModule module; uint32_t* memory = module.AddMemoryElems<uint32_t>(kNumElems); - r.env()->module = &module; + WasmRunner<uint32_t> r(&module, MachineType::Int32()); + const byte kSum = r.AllocateLocal(kAstI32); BUILD(r, WASM_BLOCK( 2, WASM_WHILE( @@ -1746,11 +1823,10 @@ TEST(Run_Wasm_MemI32_Sum) { TEST(Run_Wasm_CheckMachIntsZero) { - WasmRunner<uint32_t> r(MachineType::Int32()); const int kNumElems = 55; TestingModule module; module.AddMemoryElems<uint32_t>(kNumElems); - r.env()->module = &module; + WasmRunner<uint32_t> r(&module, MachineType::Int32()); BUILD(r, kExprBlock, 2, kExprLoop, 1, kExprIf, kExprGetLocal, 0, kExprBr, 0, kExprIfElse, kExprI32LoadMem, 0, kExprGetLocal, 0, kExprBr, 2, @@ -1763,8 +1839,6 @@ TEST(Run_Wasm_CheckMachIntsZero) { TEST(Run_Wasm_MemF32_Sum) { - WasmRunner<int32_t> r(MachineType::Int32()); - const byte kSum = r.AllocateLocal(kAstF32); const int kSize = 5; TestingModule module; module.AddMemoryElems<float>(kSize); @@ -1774,7 +1848,8 @@ TEST(Run_Wasm_MemF32_Sum) { buffer[2] = -77.25; buffer[3] = 66666.25; buffer[4] = 5555.25; - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); + const byte kSum = r.AllocateLocal(kAstF32); BUILD(r, WASM_BLOCK( 3, WASM_WHILE( @@ -1799,12 +1874,11 @@ TEST(Run_Wasm_MemF32_Sum) { #if WASM_64 TEST(Run_Wasm_MemI64_Sum) { - WasmRunner<uint64_t> r(MachineType::Int32()); const int kNumElems = 20; - const byte kSum = r.AllocateLocal(kAstI64); TestingModule module; uint64_t* memory = module.AddMemoryElems<uint64_t>(kNumElems); - r.env()->module = &module; + WasmRunner<uint64_t> r(&module, MachineType::Int32()); + const byte kSum = r.AllocateLocal(kAstI64); BUILD(r, WASM_BLOCK( 2, WASM_WHILE( @@ -1836,14 +1910,13 @@ TEST(Run_Wasm_MemI64_Sum) { template <typename T> T GenerateAndRunFold(WasmOpcode binop, T* buffer, size_t size, LocalType astType, MachineType memType) { - WasmRunner<int32_t> r(MachineType::Int32()); - const byte kAccum = r.AllocateLocal(astType); TestingModule module; module.AddMemoryElems<T>(size); for (size_t i = 0; i < size; i++) { module.raw_mem_start<T>()[i] = buffer[i]; } - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); + const byte kAccum = r.AllocateLocal(astType); BUILD( r, @@ -1882,10 +1955,9 @@ TEST(Build_Wasm_Infinite_Loop) { TEST(Build_Wasm_Infinite_Loop_effect) { - WasmRunner<int32_t> r(MachineType::Int32()); TestingModule module; module.AddMemoryElems<int8_t>(16); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); // Only build the graph and compile, don't run. BUILD(r, WASM_LOOP(1, WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO))); @@ -1970,7 +2042,7 @@ TEST(Run_Wasm_Infinite_Loop_not_taken2) { TEST(Run_Wasm_Infinite_Loop_not_taken2_brif) { WasmRunner<int32_t> r(MachineType::Int32()); - BUILD(r, WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_I8(45)), + BUILD(r, WASM_BLOCK(2, WASM_BRV_IF(0, WASM_I8(45), WASM_GET_LOCAL(0)), WASM_INFINITE_LOOP)); // Run the code, but don't go into the infinite loop. CHECK_EQ(45, r.Call(1)); @@ -2022,8 +2094,7 @@ TEST(Run_Wasm_Int32LoadInt8_signext) { int8_t* memory = module.AddMemoryElems<int8_t>(kNumElems); module.RandomizeMemory(); memory[0] = -1; - WasmRunner<int32_t> r(MachineType::Int32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); BUILD(r, WASM_LOAD_MEM(MachineType::Int8(), WASM_GET_LOCAL(0))); for (size_t i = 0; i < kNumElems; i++) { @@ -2038,8 +2109,7 @@ TEST(Run_Wasm_Int32LoadInt8_zeroext) { byte* memory = module.AddMemory(kNumElems); module.RandomizeMemory(77); memory[0] = 255; - WasmRunner<int32_t> r(MachineType::Int32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); BUILD(r, WASM_LOAD_MEM(MachineType::Uint8(), WASM_GET_LOCAL(0))); for (size_t i = 0; i < kNumElems; i++) { @@ -2054,8 +2124,7 @@ TEST(Run_Wasm_Int32LoadInt16_signext) { byte* memory = module.AddMemory(kNumBytes); module.RandomizeMemory(888); memory[1] = 200; - WasmRunner<int32_t> r(MachineType::Int32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); BUILD(r, WASM_LOAD_MEM(MachineType::Int16(), WASM_GET_LOCAL(0))); for (size_t i = 0; i < kNumBytes; i += 2) { @@ -2071,8 +2140,7 @@ TEST(Run_Wasm_Int32LoadInt16_zeroext) { byte* memory = module.AddMemory(kNumBytes); module.RandomizeMemory(9999); memory[1] = 204; - WasmRunner<int32_t> r(MachineType::Int32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); BUILD(r, WASM_LOAD_MEM(MachineType::Uint16(), WASM_GET_LOCAL(0))); for (size_t i = 0; i < kNumBytes; i += 2) { @@ -2085,8 +2153,7 @@ TEST(Run_Wasm_Int32LoadInt16_zeroext) { TEST(Run_WasmInt32Global) { TestingModule module; int32_t* global = module.AddGlobal<int32_t>(MachineType::Int32()); - WasmRunner<int32_t> r(MachineType::Int32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); // global = global + p0 BUILD(r, WASM_STORE_GLOBAL( 0, WASM_I32_ADD(WASM_LOAD_GLOBAL(0), WASM_GET_LOCAL(0)))); @@ -2109,8 +2176,7 @@ TEST(Run_WasmInt32Globals_DontAlias) { for (int g = 0; g < kNumGlobals; g++) { // global = global + p0 - WasmRunner<int32_t> r(MachineType::Int32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); BUILD(r, WASM_STORE_GLOBAL( g, WASM_I32_ADD(WASM_LOAD_GLOBAL(g), WASM_GET_LOCAL(0)))); @@ -2134,8 +2200,7 @@ TEST(Run_WasmInt32Globals_DontAlias) { TEST(Run_WasmInt64Global) { TestingModule module; int64_t* global = module.AddGlobal<int64_t>(MachineType::Int64()); - WasmRunner<int32_t> r(MachineType::Int32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); // global = global + p0 BUILD(r, WASM_BLOCK(2, WASM_STORE_GLOBAL( 0, WASM_I64_ADD( @@ -2156,8 +2221,7 @@ TEST(Run_WasmInt64Global) { TEST(Run_WasmFloat32Global) { TestingModule module; float* global = module.AddGlobal<float>(MachineType::Float32()); - WasmRunner<int32_t> r(MachineType::Int32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); // global = global + p0 BUILD(r, WASM_BLOCK(2, WASM_STORE_GLOBAL( 0, WASM_F32_ADD( @@ -2177,8 +2241,7 @@ TEST(Run_WasmFloat32Global) { TEST(Run_WasmFloat64Global) { TestingModule module; double* global = module.AddGlobal<double>(MachineType::Float64()); - WasmRunner<int32_t> r(MachineType::Int32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); // global = global + p0 BUILD(r, WASM_BLOCK(2, WASM_STORE_GLOBAL( 0, WASM_F64_ADD( @@ -2209,8 +2272,7 @@ TEST(Run_WasmMixedGlobals) { float* var_float = module.AddGlobal<float>(MachineType::Float32()); double* var_double = module.AddGlobal<double>(MachineType::Float64()); - WasmRunner<int32_t> r(MachineType::Int32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32()); BUILD( r, @@ -2312,13 +2374,12 @@ TEST(Run_WasmCallEmpty) { // Build the target function. TestSignatures sigs; TestingModule module; - WasmFunctionCompiler t(sigs.i_v()); + WasmFunctionCompiler t(sigs.i_v(), &module); BUILD(t, WASM_I32(kExpected)); - uint32_t index = t.CompileAndAdd(&module); + uint32_t index = t.CompileAndAdd(); // Build the calling function. - WasmRunner<int32_t> r; - r.env()->module = &module; + WasmRunner<int32_t> r(&module); BUILD(r, WASM_CALL_FUNCTION0(index)); int32_t result = r.Call(); @@ -2326,22 +2387,18 @@ TEST(Run_WasmCallEmpty) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST(Run_WasmCallF32StackParameter) { // Build the target function. LocalType param_types[20]; for (int i = 0; i < 20; i++) param_types[i] = kAstF32; FunctionSig sig(1, 19, param_types); TestingModule module; - WasmFunctionCompiler t(&sig); + WasmFunctionCompiler t(&sig, &module); BUILD(t, WASM_GET_LOCAL(17)); - uint32_t index = t.CompileAndAdd(&module); + uint32_t index = t.CompileAndAdd(); // Build the calling function. - WasmRunner<float> r; - r.env()->module = &module; + WasmRunner<float> r(&module); BUILD(r, WASM_CALL_FUNCTION( index, WASM_F32(1.0f), WASM_F32(2.0f), WASM_F32(4.0f), WASM_F32(8.0f), WASM_F32(16.0f), WASM_F32(32.0f), @@ -2361,13 +2418,12 @@ TEST(Run_WasmCallF64StackParameter) { for (int i = 0; i < 20; i++) param_types[i] = kAstF64; FunctionSig sig(1, 19, param_types); TestingModule module; - WasmFunctionCompiler t(&sig); + WasmFunctionCompiler t(&sig, &module); BUILD(t, WASM_GET_LOCAL(17)); - uint32_t index = t.CompileAndAdd(&module); + uint32_t index = t.CompileAndAdd(); // Build the calling function. - WasmRunner<double> r; - r.env()->module = &module; + WasmRunner<double> r(&module); BUILD(r, WASM_CALL_FUNCTION(index, WASM_F64(1.0), WASM_F64(2.0), WASM_F64(4.0), WASM_F64(8.0), WASM_F64(16.0), WASM_F64(32.0), WASM_F64(64.0), WASM_F64(128.0), @@ -2380,8 +2436,50 @@ TEST(Run_WasmCallF64StackParameter) { CHECK_EQ(256.5, result); } -#endif +TEST(Run_WasmCallI64Parameter) { + // Build the target function. + LocalType param_types[20]; + for (int i = 0; i < 20; i++) param_types[i] = kAstI64; + param_types[3] = kAstI32; + param_types[4] = kAstI32; + FunctionSig sig(1, 19, param_types); + for (int i = 0; i < 19; i++) { + TestingModule module; + WasmFunctionCompiler t(&sig, &module); + if (i == 2 || i == 3) { + continue; + } else { + BUILD(t, WASM_GET_LOCAL(i)); + } + uint32_t index = t.CompileAndAdd(); + + // Build the calling function. + WasmRunner<int32_t> r; + r.env()->module = &module; + BUILD(r, + WASM_I32_CONVERT_I64(WASM_CALL_FUNCTION( + index, WASM_I64(0xbcd12340000000b), WASM_I64(0xbcd12340000000c), + WASM_I32(0xd), WASM_I32_CONVERT_I64(WASM_I64(0xbcd12340000000e)), + WASM_I64(0xbcd12340000000f), WASM_I64(0xbcd1234000000010), + WASM_I64(0xbcd1234000000011), WASM_I64(0xbcd1234000000012), + WASM_I64(0xbcd1234000000013), WASM_I64(0xbcd1234000000014), + WASM_I64(0xbcd1234000000015), WASM_I64(0xbcd1234000000016), + WASM_I64(0xbcd1234000000017), WASM_I64(0xbcd1234000000018), + WASM_I64(0xbcd1234000000019), WASM_I64(0xbcd123400000001a), + WASM_I64(0xbcd123400000001b), WASM_I64(0xbcd123400000001c), + WASM_I64(0xbcd123400000001d)))); + CHECK_EQ(i + 0xb, r.Call()); + } +} + +TEST(Run_WasmI64And) { + WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); + BUILD(r, WASM_I64_AND(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); + FOR_INT64_INPUTS(i) { + FOR_INT64_INPUTS(j) { CHECK_EQ((*i) & (*j), r.Call(*i, *j)); } + } +} TEST(Run_WasmCallVoid) { const byte kMemOffset = 8; @@ -2392,15 +2490,13 @@ TEST(Run_WasmCallVoid) { TestingModule module; module.AddMemory(16); module.RandomizeMemory(); - WasmFunctionCompiler t(sigs.v_v()); - t.env.module = &module; + WasmFunctionCompiler t(sigs.v_v(), &module); BUILD(t, WASM_STORE_MEM(MachineType::Int32(), WASM_I8(kMemOffset), WASM_I32(kExpected))); - uint32_t index = t.CompileAndAdd(&module); + uint32_t index = t.CompileAndAdd(); // Build the calling function. - WasmRunner<int32_t> r; - r.env()->module = &module; + WasmRunner<int32_t> r(&module); BUILD(r, WASM_CALL_FUNCTION0(index), WASM_LOAD_MEM(MachineType::Int32(), WASM_I8(kMemOffset))); @@ -2414,13 +2510,12 @@ TEST(Run_WasmCall_Int32Add) { // Build the target function. TestSignatures sigs; TestingModule module; - WasmFunctionCompiler t(sigs.i_ii()); + WasmFunctionCompiler t(sigs.i_ii(), &module); BUILD(t, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); - uint32_t index = t.CompileAndAdd(&module); + uint32_t index = t.CompileAndAdd(); // Build the caller function. - WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32()); - r.env()->module = &module; + WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32()); BUILD(r, WASM_CALL_FUNCTION(index, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); FOR_INT32_INPUTS(i) { @@ -2438,13 +2533,12 @@ TEST(Run_WasmCall_Int64Sub) { // Build the target function. TestSignatures sigs; TestingModule module; - WasmFunctionCompiler t(sigs.l_ll()); + WasmFunctionCompiler t(sigs.l_ll(), &module); BUILD(t, WASM_I64_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); - uint32_t index = t.CompileAndAdd(&module); + uint32_t index = t.CompileAndAdd(); // Build the caller function. - WasmRunner<int64_t> r(MachineType::Int64(), MachineType::Int64()); - r.env()->module = &module; + WasmRunner<int64_t> r(&module, MachineType::Int64(), MachineType::Int64()); BUILD(r, WASM_CALL_FUNCTION(index, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); FOR_INT32_INPUTS(i) { @@ -2465,16 +2559,15 @@ TEST(Run_WasmCall_Int64Sub) { TEST(Run_WasmCall_Float32Sub) { TestSignatures sigs; - WasmFunctionCompiler t(sigs.f_ff()); + TestingModule module; + WasmFunctionCompiler t(sigs.f_ff(), &module); // Build the target function. - TestingModule module; BUILD(t, WASM_F32_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); - uint32_t index = t.CompileAndAdd(&module); + uint32_t index = t.CompileAndAdd(); // Builder the caller function. - WasmRunner<float> r(MachineType::Float32(), MachineType::Float32()); - r.env()->module = &module; + WasmRunner<float> r(&module, MachineType::Float32(), MachineType::Float32()); BUILD(r, WASM_CALL_FUNCTION(index, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); FOR_FLOAT32_INPUTS(i) { @@ -2487,10 +2580,9 @@ TEST(Run_WasmCall_Float32Sub) { TEST(Run_WasmCall_Float64Sub) { - WasmRunner<int32_t> r; TestingModule module; double* memory = module.AddMemoryElems<double>(16); - r.env()->module = &module; + WasmRunner<int32_t> r(&module); // TODO(titzer): convert to a binop test. BUILD(r, WASM_BLOCK( @@ -2560,36 +2652,32 @@ static void Run_WasmMixedCall_N(int start) { for (int i = 0; i < num_params; i++) { b.AddParam(WasmOpcodes::LocalTypeFor(memtypes[i])); } - WasmFunctionCompiler t(b.Build()); - t.env.module = &module; + WasmFunctionCompiler t(b.Build(), &module); BUILD(t, WASM_GET_LOCAL(which)); - index = t.CompileAndAdd(&module); + index = t.CompileAndAdd(); // ========================================================================= // Build the calling function. // ========================================================================= - WasmRunner<int32_t> r; - r.env()->module = &module; + WasmRunner<int32_t> r(&module); - { - std::vector<byte> code; - ADD_CODE(code, - static_cast<byte>(WasmOpcodes::LoadStoreOpcodeOf(result, true)), - WasmOpcodes::LoadStoreAccessOf(false)); - ADD_CODE(code, WASM_ZERO); - ADD_CODE(code, kExprCallFunction, static_cast<byte>(index)); - - for (int i = 0; i < num_params; i++) { - int offset = (i + 1) * kElemSize; - ADD_CODE(code, WASM_LOAD_MEM(memtypes[i], WASM_I8(offset))); - } + std::vector<byte> code; + ADD_CODE(code, + static_cast<byte>(WasmOpcodes::LoadStoreOpcodeOf(result, true)), + WasmOpcodes::LoadStoreAccessOf(false)); + ADD_CODE(code, WASM_ZERO); + ADD_CODE(code, kExprCallFunction, static_cast<byte>(index)); - ADD_CODE(code, WASM_I32(kExpected)); - size_t end = code.size(); - code.push_back(0); - r.Build(&code[0], &code[end]); + for (int i = 0; i < num_params; i++) { + int offset = (i + 1) * kElemSize; + ADD_CODE(code, WASM_LOAD_MEM(memtypes[i], WASM_I8(offset))); } + ADD_CODE(code, WASM_I32(kExpected)); + size_t end = code.size(); + code.push_back(0); + r.Build(&code[0], &code[end]); + // Run the code. for (int t = 0; t < 10; t++) { module.RandomizeMemory(); @@ -2612,6 +2700,27 @@ TEST(Run_WasmMixedCall_1) { Run_WasmMixedCall_N(1); } TEST(Run_WasmMixedCall_2) { Run_WasmMixedCall_N(2); } TEST(Run_WasmMixedCall_3) { Run_WasmMixedCall_N(3); } +TEST(Run_Wasm_AddCall) { + TestSignatures sigs; + TestingModule module; + WasmFunctionCompiler t1(sigs.i_ii(), &module); + BUILD(t1, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); + t1.CompileAndAdd(); + + WasmRunner<int32_t> r(&module, MachineType::Int32()); + byte local = r.AllocateLocal(kAstI32); + BUILD(r, + WASM_BLOCK(2, WASM_SET_LOCAL(local, WASM_I8(99)), + WASM_I32_ADD( + WASM_CALL_FUNCTION(t1.function_index_, WASM_GET_LOCAL(0), + WASM_GET_LOCAL(0)), + WASM_CALL_FUNCTION(t1.function_index_, WASM_GET_LOCAL(1), + WASM_GET_LOCAL(local))))); + + CHECK_EQ(198, r.Call(0)); + CHECK_EQ(200, r.Call(1)); + CHECK_EQ(100, r.Call(-49)); +} TEST(Run_Wasm_CountDown_expr) { WasmRunner<int32_t> r(MachineType::Int32()); @@ -2646,7 +2755,7 @@ TEST(Run_Wasm_ExprBlock2b) { TEST(Run_Wasm_ExprBlock2c) { WasmRunner<int32_t> r(MachineType::Int32()); - BUILD(r, WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_I8(1)), + BUILD(r, WASM_BLOCK(2, WASM_BRV_IF(0, WASM_I8(1), WASM_GET_LOCAL(0)), WASM_I8(1))); CHECK_EQ(1, r.Call(0)); CHECK_EQ(1, r.Call(1)); @@ -2655,7 +2764,7 @@ TEST(Run_Wasm_ExprBlock2c) { TEST(Run_Wasm_ExprBlock2d) { WasmRunner<int32_t> r(MachineType::Int32()); - BUILD(r, WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_I8(1)), + BUILD(r, WASM_BLOCK(2, WASM_BRV_IF(0, WASM_I8(1), WASM_GET_LOCAL(0)), WASM_I8(2))); CHECK_EQ(2, r.Call(0)); CHECK_EQ(1, r.Call(1)); @@ -2688,16 +2797,16 @@ TEST(Run_Wasm_ExprBlock_ManualSwitch) { TEST(Run_Wasm_ExprBlock_ManualSwitch_brif) { WasmRunner<int32_t> r(MachineType::Int32()); BUILD(r, - WASM_BLOCK(6, WASM_BRV_IF(0, WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(1)), - WASM_I8(11)), - WASM_BRV_IF(0, WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(2)), - WASM_I8(12)), - WASM_BRV_IF(0, WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(3)), - WASM_I8(13)), - WASM_BRV_IF(0, WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(4)), - WASM_I8(14)), - WASM_BRV_IF(0, WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(5)), - WASM_I8(15)), + WASM_BLOCK(6, WASM_BRV_IF(0, WASM_I8(11), + WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(1))), + WASM_BRV_IF(0, WASM_I8(12), + WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(2))), + WASM_BRV_IF(0, WASM_I8(13), + WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(3))), + WASM_BRV_IF(0, WASM_I8(14), + WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(4))), + WASM_BRV_IF(0, WASM_I8(15), + WASM_I32_EQ(WASM_GET_LOCAL(0), WASM_I8(5))), WASM_I8(99))); CHECK_EQ(99, r.Call(0)); CHECK_EQ(11, r.Call(1)); @@ -2781,10 +2890,9 @@ TEST(Run_Wasm_LoadStoreI64_sx) { kExprI64LoadMem}; for (size_t m = 0; m < arraysize(loads); m++) { - WasmRunner<int64_t> r; TestingModule module; byte* memory = module.AddMemoryElems<byte>(16); - r.env()->module = &module; + WasmRunner<int64_t> r(&module); byte code[] = {kExprI64StoreMem, 0, kExprI8Const, 8, loads[m], 0, kExprI8Const, 0}; @@ -2813,19 +2921,16 @@ TEST(Run_Wasm_LoadStoreI64_sx) { TEST(Run_Wasm_SimpleCallIndirect) { - Isolate* isolate = CcTest::InitIsolateOnce(); - - WasmRunner<int32_t> r(MachineType::Int32()); TestSignatures sigs; TestingModule module; - r.env()->module = &module; - WasmFunctionCompiler t1(sigs.i_ii()); + + WasmFunctionCompiler t1(sigs.i_ii(), &module); BUILD(t1, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); - t1.CompileAndAdd(&module); + t1.CompileAndAdd(/*sig_index*/ 1); - WasmFunctionCompiler t2(sigs.i_ii()); + WasmFunctionCompiler t2(sigs.i_ii(), &module); BUILD(t2, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); - t2.CompileAndAdd(&module); + t2.CompileAndAdd(/*sig_index*/ 1); // Signature table. module.AddSignature(sigs.f_ff()); @@ -2833,20 +2938,12 @@ TEST(Run_Wasm_SimpleCallIndirect) { module.AddSignature(sigs.d_dd()); // Function table. - int table_size = 2; - module.module->function_table = new std::vector<uint16_t>; - module.module->function_table->push_back(0); - module.module->function_table->push_back(1); - - // Function table. - Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size); - fixed->set(0, Smi::FromInt(1)); - fixed->set(1, Smi::FromInt(1)); - fixed->set(2, *module.function_code->at(0)); - fixed->set(3, *module.function_code->at(1)); - module.function_table = fixed; + int table[] = {0, 1}; + module.AddIndirectFunctionTable(table, 2); + module.PopulateIndirectFunctionTable(); // Builder the caller function. + WasmRunner<int32_t> r(&module, MachineType::Int32()); BUILD(r, WASM_CALL_INDIRECT(1, WASM_GET_LOCAL(0), WASM_I8(66), WASM_I8(22))); CHECK_EQ(88, r.Call(0)); @@ -2856,20 +2953,16 @@ TEST(Run_Wasm_SimpleCallIndirect) { TEST(Run_Wasm_MultipleCallIndirect) { - Isolate* isolate = CcTest::InitIsolateOnce(); - - WasmRunner<int32_t> r(MachineType::Int32(), MachineType::Int32(), - MachineType::Int32()); TestSignatures sigs; TestingModule module; - r.env()->module = &module; - WasmFunctionCompiler t1(sigs.i_ii()); + + WasmFunctionCompiler t1(sigs.i_ii(), &module); BUILD(t1, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); - t1.CompileAndAdd(&module); + t1.CompileAndAdd(/*sig_index*/ 1); - WasmFunctionCompiler t2(sigs.i_ii()); + WasmFunctionCompiler t2(sigs.i_ii(), &module); BUILD(t2, WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); - t2.CompileAndAdd(&module); + t2.CompileAndAdd(/*sig_index*/ 1); // Signature table. module.AddSignature(sigs.f_ff()); @@ -2877,20 +2970,13 @@ TEST(Run_Wasm_MultipleCallIndirect) { module.AddSignature(sigs.d_dd()); // Function table. - int table_size = 2; - module.module->function_table = new std::vector<uint16_t>; - module.module->function_table->push_back(0); - module.module->function_table->push_back(1); - - // Function table. - Handle<FixedArray> fixed = isolate->factory()->NewFixedArray(2 * table_size); - fixed->set(0, Smi::FromInt(1)); - fixed->set(1, Smi::FromInt(1)); - fixed->set(2, *module.function_code->at(0)); - fixed->set(3, *module.function_code->at(1)); - module.function_table = fixed; + int table[] = {0, 1}; + module.AddIndirectFunctionTable(table, 2); + module.PopulateIndirectFunctionTable(); // Builder the caller function. + WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32(), + MachineType::Int32()); BUILD(r, WASM_I32_ADD(WASM_CALL_INDIRECT(1, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)), @@ -2908,42 +2994,56 @@ TEST(Run_Wasm_MultipleCallIndirect) { CHECK_TRAP(r.Call(2, 1, 0)); } +TEST(Run_Wasm_CallIndirect_NoTable) { + TestSignatures sigs; + TestingModule module; + + // One function. + WasmFunctionCompiler t1(sigs.i_ii(), &module); + BUILD(t1, WASM_I32_ADD(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); + t1.CompileAndAdd(/*sig_index*/ 1); -// TODO(titzer): Fix for nosee4 and re-enable. -#if 0 + // Signature table. + module.AddSignature(sigs.f_ff()); + module.AddSignature(sigs.i_ii()); + + // Builder the caller function. + WasmRunner<int32_t> r(&module, MachineType::Int32()); + BUILD(r, WASM_CALL_INDIRECT(1, WASM_GET_LOCAL(0), WASM_I8(66), WASM_I8(22))); + + CHECK_TRAP(r.Call(0)); + CHECK_TRAP(r.Call(1)); + CHECK_TRAP(r.Call(2)); +} TEST(Run_Wasm_F32Floor) { WasmRunner<float> r(MachineType::Float32()); BUILD(r, WASM_F32_FLOOR(WASM_GET_LOCAL(0))); - FOR_FLOAT32_INPUTS(i) { CheckFloatEq(floor(*i), r.Call(*i)); } + FOR_FLOAT32_INPUTS(i) { CheckFloatEq(floorf(*i), r.Call(*i)); } } - TEST(Run_Wasm_F32Ceil) { WasmRunner<float> r(MachineType::Float32()); BUILD(r, WASM_F32_CEIL(WASM_GET_LOCAL(0))); - FOR_FLOAT32_INPUTS(i) { CheckFloatEq(ceil(*i), r.Call(*i)); } + FOR_FLOAT32_INPUTS(i) { CheckFloatEq(ceilf(*i), r.Call(*i)); } } - TEST(Run_Wasm_F32Trunc) { WasmRunner<float> r(MachineType::Float32()); BUILD(r, WASM_F32_TRUNC(WASM_GET_LOCAL(0))); - FOR_FLOAT32_INPUTS(i) { CheckFloatEq(trunc(*i), r.Call(*i)); } + FOR_FLOAT32_INPUTS(i) { CheckFloatEq(truncf(*i), r.Call(*i)); } } - TEST(Run_Wasm_F32NearestInt) { WasmRunner<float> r(MachineType::Float32()); BUILD(r, WASM_F32_NEARESTINT(WASM_GET_LOCAL(0))); - FOR_FLOAT32_INPUTS(i) { CheckFloatEq(nearbyint(*i), r.Call(*i)); } + FOR_FLOAT32_INPUTS(i) { CheckFloatEq(nearbyintf(*i), r.Call(*i)); } } - TEST(Run_Wasm_F64Floor) { WasmRunner<double> r(MachineType::Float64()); BUILD(r, WASM_F64_FLOOR(WASM_GET_LOCAL(0))); @@ -2951,7 +3051,6 @@ TEST(Run_Wasm_F64Floor) { FOR_FLOAT64_INPUTS(i) { CheckDoubleEq(floor(*i), r.Call(*i)); } } - TEST(Run_Wasm_F64Ceil) { WasmRunner<double> r(MachineType::Float64()); BUILD(r, WASM_F64_CEIL(WASM_GET_LOCAL(0))); @@ -2959,7 +3058,6 @@ TEST(Run_Wasm_F64Ceil) { FOR_FLOAT64_INPUTS(i) { CheckDoubleEq(ceil(*i), r.Call(*i)); } } - TEST(Run_Wasm_F64Trunc) { WasmRunner<double> r(MachineType::Float64()); BUILD(r, WASM_F64_TRUNC(WASM_GET_LOCAL(0))); @@ -2967,7 +3065,6 @@ TEST(Run_Wasm_F64Trunc) { FOR_FLOAT64_INPUTS(i) { CheckDoubleEq(trunc(*i), r.Call(*i)); } } - TEST(Run_Wasm_F64NearestInt) { WasmRunner<double> r(MachineType::Float64()); BUILD(r, WASM_F64_NEARESTINT(WASM_GET_LOCAL(0))); @@ -2975,9 +3072,6 @@ TEST(Run_Wasm_F64NearestInt) { FOR_FLOAT64_INPUTS(i) { CheckDoubleEq(nearbyint(*i), r.Call(*i)); } } -#endif - - TEST(Run_Wasm_F32Min) { WasmRunner<float> r(MachineType::Float32(), MachineType::Float32()); BUILD(r, WASM_F32_MIN(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); @@ -3073,6 +3167,74 @@ TEST(Run_Wasm_F64Max) { } } +// TODO(ahaas): Fix on arm and reenable. +#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 + +TEST(Run_Wasm_F32Min_Snan) { + // Test that the instruction does not return a signalling NaN. + { + WasmRunner<float> r; + BUILD(r, + WASM_F32_MIN(WASM_F32(bit_cast<float>(0xff80f1e2)), WASM_F32(57.67))); + CHECK_EQ(0xffc0f1e2, bit_cast<uint32_t>(r.Call())); + } + { + WasmRunner<float> r; + BUILD(r, + WASM_F32_MIN(WASM_F32(45.73), WASM_F32(bit_cast<float>(0x7f80f1e2)))); + CHECK_EQ(0x7fc0f1e2, bit_cast<uint32_t>(r.Call())); + } +} + +TEST(Run_Wasm_F32Max_Snan) { + // Test that the instruction does not return a signalling NaN. + { + WasmRunner<float> r; + BUILD(r, + WASM_F32_MAX(WASM_F32(bit_cast<float>(0xff80f1e2)), WASM_F32(57.67))); + CHECK_EQ(0xffc0f1e2, bit_cast<uint32_t>(r.Call())); + } + { + WasmRunner<float> r; + BUILD(r, + WASM_F32_MAX(WASM_F32(45.73), WASM_F32(bit_cast<float>(0x7f80f1e2)))); + CHECK_EQ(0x7fc0f1e2, bit_cast<uint32_t>(r.Call())); + } +} + +TEST(Run_Wasm_F64Min_Snan) { + // Test that the instruction does not return a signalling NaN. + { + WasmRunner<double> r; + BUILD(r, WASM_F64_MIN(WASM_F64(bit_cast<double>(0xfff000000000f1e2)), + WASM_F64(57.67))); + CHECK_EQ(0xfff800000000f1e2, bit_cast<uint64_t>(r.Call())); + } + { + WasmRunner<double> r; + BUILD(r, WASM_F64_MIN(WASM_F64(45.73), + WASM_F64(bit_cast<double>(0x7ff000000000f1e2)))); + CHECK_EQ(0x7ff800000000f1e2, bit_cast<uint64_t>(r.Call())); + } +} + +TEST(Run_Wasm_F64Max_Snan) { + // Test that the instruction does not return a signalling NaN. + { + WasmRunner<double> r; + BUILD(r, WASM_F64_MAX(WASM_F64(bit_cast<double>(0xfff000000000f1e2)), + WASM_F64(57.67))); + CHECK_EQ(0xfff800000000f1e2, bit_cast<uint64_t>(r.Call())); + } + { + WasmRunner<double> r; + BUILD(r, WASM_F64_MAX(WASM_F64(45.73), + WASM_F64(bit_cast<double>(0x7ff000000000f1e2)))); + CHECK_EQ(0x7ff800000000f1e2, bit_cast<uint64_t>(r.Call())); + } +} + +#endif #if WASM_64 TEST(Run_Wasm_F32SConvertI64) { @@ -3251,4 +3413,48 @@ TEST(Run_Wasm_F32CopySign) { } } + +#endif + + +void CompileCallIndirectMany(LocalType param) { + // Make sure we don't run out of registers when compiling indirect calls + // with many many parameters. + TestSignatures sigs; + for (byte num_params = 0; num_params < 40; num_params++) { + Zone zone; + HandleScope scope(CcTest::InitIsolateOnce()); + TestingModule module; + FunctionSig* sig = sigs.many(&zone, kAstStmt, param, num_params); + + module.AddSignature(sig); + module.AddSignature(sig); + module.AddIndirectFunctionTable(nullptr, 0); + + WasmFunctionCompiler t(sig, &module); + + std::vector<byte> code; + ADD_CODE(code, kExprCallIndirect, 1); + ADD_CODE(code, kExprI8Const, 0); + for (byte p = 0; p < num_params; p++) { + ADD_CODE(code, kExprGetLocal, p); + } + + t.Build(&code[0], &code[0] + code.size()); + t.Compile(); + } +} + + +TEST(Compile_Wasm_CallIndirect_Many_i32) { CompileCallIndirectMany(kAstI32); } + + +#if WASM_64 +TEST(Compile_Wasm_CallIndirect_Many_i64) { CompileCallIndirectMany(kAstI64); } #endif + + +TEST(Compile_Wasm_CallIndirect_Many_f32) { CompileCallIndirectMany(kAstF32); } + + +TEST(Compile_Wasm_CallIndirect_Many_f64) { CompileCallIndirectMany(kAstF64); } diff --git a/deps/v8/test/cctest/wasm/test-signatures.h b/deps/v8/test/cctest/wasm/test-signatures.h index 30ea605386..a5bc7b4f14 100644 --- a/deps/v8/test/cctest/wasm/test-signatures.h +++ b/deps/v8/test/cctest/wasm/test-signatures.h @@ -72,6 +72,15 @@ class TestSignatures { FunctionSig* v_ii() { return &sig_v_ii; } FunctionSig* v_iii() { return &sig_v_iii; } + FunctionSig* many(Zone* zone, LocalType ret, LocalType param, int count) { + FunctionSig::Builder builder(zone, ret == kAstStmt ? 0 : 1, count); + if (ret != kAstStmt) builder.AddReturn(ret); + for (int i = 0; i < count; i++) { + builder.AddParam(param); + } + return builder.Build(); + } + private: LocalType kIntTypes4[4]; LocalType kLongTypes4[4]; diff --git a/deps/v8/test/cctest/wasm/wasm-run-utils.h b/deps/v8/test/cctest/wasm/wasm-run-utils.h index cc23b46b73..7ee3981885 100644 --- a/deps/v8/test/cctest/wasm/wasm-run-utils.h +++ b/deps/v8/test/cctest/wasm/wasm-run-utils.h @@ -12,7 +12,10 @@ #include "src/base/utils/random-number-generator.h" #include "src/compiler/graph-visualizer.h" +#include "src/compiler/int64-lowering.h" #include "src/compiler/js-graph.h" +#include "src/compiler/node.h" +#include "src/compiler/pipeline.h" #include "src/compiler/wasm-compiler.h" #include "src/wasm/ast-decoder.h" @@ -20,8 +23,10 @@ #include "src/wasm/wasm-module.h" #include "src/wasm/wasm-opcodes.h" +#include "src/zone.h" + #include "test/cctest/cctest.h" -#include "test/cctest/compiler/codegen-tester.h" +#include "test/cctest/compiler/call-tester.h" #include "test/cctest/compiler/graph-builder-tester.h" // TODO(titzer): pull WASM_64 up to a common header. @@ -31,6 +36,8 @@ #define WASM_64 0 #endif +static const uint32_t kMaxFunctions = 10; + // TODO(titzer): check traps more robustly in tests. // Currently, in tests, we just return 0xdeadbeef from the function in which // the trap occurs if the runtime context is not available to throw a JavaScript @@ -41,6 +48,9 @@ CHECK_EQ(0xdeadbeefdeadbeef, (bit_cast<uint64_t>(x)) & 0xFFFFFFFFFFFFFFFF) #define CHECK_TRAP(x) CHECK_TRAP32(x) +#define WASM_RUNNER_MAX_NUM_PARAMETERS 4 +#define WASM_WRAPPER_RETURN_VALUE 8754 + namespace { using namespace v8::base; using namespace v8::internal; @@ -50,47 +60,51 @@ using namespace v8::internal::wasm; inline void init_env(FunctionEnv* env, FunctionSig* sig) { env->module = nullptr; env->sig = sig; - env->local_int32_count = 0; - env->local_int64_count = 0; - env->local_float32_count = 0; - env->local_float64_count = 0; + env->local_i32_count = 0; + env->local_i64_count = 0; + env->local_f32_count = 0; + env->local_f64_count = 0; env->SumLocals(); } const uint32_t kMaxGlobalsSize = 128; // A helper for module environments that adds the ability to allocate memory -// and global variables. +// and global variables. Contains a built-in {WasmModule} and +// {WasmModuleInstance}. class TestingModule : public ModuleEnv { public: - TestingModule() : mem_size(0), global_offset(0) { - globals_area = 0; - mem_start = 0; - mem_end = 0; - module = nullptr; + TestingModule() : instance_(&module_), global_offset(0) { + module_.shared_isolate = CcTest::InitIsolateOnce(); + module = &module_; + instance = &instance_; + instance->module = &module_; + instance->globals_start = global_data; + instance->globals_size = kMaxGlobalsSize; + instance->mem_start = nullptr; + instance->mem_size = 0; + instance->function_code = nullptr; linker = nullptr; - function_code = nullptr; asm_js = false; memset(global_data, 0, sizeof(global_data)); } ~TestingModule() { - if (mem_start) { - free(raw_mem_start<byte>()); + if (instance->mem_start) { + free(instance->mem_start); + } + if (instance->function_code) { + delete instance->function_code; } - if (function_code) delete function_code; - if (module) delete module; } byte* AddMemory(size_t size) { - CHECK_EQ(0, mem_start); - CHECK_EQ(0, mem_size); - mem_start = reinterpret_cast<uintptr_t>(malloc(size)); - CHECK(mem_start); - byte* raw = raw_mem_start<byte>(); - memset(raw, 0, size); - mem_end = mem_start + size; - mem_size = size; + CHECK_NULL(instance->mem_start); + CHECK_EQ(0, instance->mem_size); + instance->mem_start = reinterpret_cast<byte*>(malloc(size)); + CHECK(instance->mem_start); + memset(instance->mem_start, 0, size); + instance->mem_size = size; return raw_mem_start<byte>(); } @@ -103,11 +117,10 @@ class TestingModule : public ModuleEnv { template <typename T> T* AddGlobal(MachineType mem_type) { WasmGlobal* global = AddGlobal(mem_type); - return reinterpret_cast<T*>(globals_area + global->offset); + return reinterpret_cast<T*>(instance->globals_start + global->offset); } byte AddSignature(FunctionSig* sig) { - AllocModule(); if (!module->signatures) { module->signatures = new std::vector<FunctionSig*>(); } @@ -119,33 +132,33 @@ class TestingModule : public ModuleEnv { template <typename T> T* raw_mem_start() { - DCHECK(mem_start); - return reinterpret_cast<T*>(mem_start); + DCHECK(instance->mem_start); + return reinterpret_cast<T*>(instance->mem_start); } template <typename T> T* raw_mem_end() { - DCHECK(mem_end); - return reinterpret_cast<T*>(mem_end); + DCHECK(instance->mem_start); + return reinterpret_cast<T*>(instance->mem_start + instance->mem_size); } template <typename T> T raw_mem_at(int i) { - DCHECK(mem_start); - return reinterpret_cast<T*>(mem_start)[i]; + DCHECK(instance->mem_start); + return reinterpret_cast<T*>(instance->mem_start)[i]; } template <typename T> T raw_val_at(int i) { T val; - memcpy(&val, reinterpret_cast<void*>(mem_start + i), sizeof(T)); + memcpy(&val, reinterpret_cast<void*>(instance->mem_start + i), sizeof(T)); return val; } // Zero-initialize the memory. void BlankMemory() { byte* raw = raw_mem_start<byte>(); - memset(raw, 0, mem_size); + memset(raw, 0, instance->mem_size); } // Pseudo-randomly intialize the memory. @@ -157,26 +170,57 @@ class TestingModule : public ModuleEnv { rng.NextBytes(raw, end - raw); } - WasmFunction* AddFunction(FunctionSig* sig, Handle<Code> code) { - AllocModule(); + int AddFunction(FunctionSig* sig, Handle<Code> code) { if (module->functions == nullptr) { module->functions = new std::vector<WasmFunction>(); - function_code = new std::vector<Handle<Code>>(); + // TODO(titzer): Reserving space here to avoid the underlying WasmFunction + // structs from moving. + module->functions->reserve(kMaxFunctions); + instance->function_code = new std::vector<Handle<Code>>(); + } + uint32_t index = static_cast<uint32_t>(module->functions->size()); + module->functions->push_back( + {sig, index, 0, 0, 0, 0, 0, 0, 0, false, false}); + instance->function_code->push_back(code); + DCHECK_LT(index, kMaxFunctions); // limited for testing. + return index; + } + + void SetFunctionCode(uint32_t index, Handle<Code> code) { + instance->function_code->at(index) = code; + } + + void AddIndirectFunctionTable(int* functions, int table_size) { + Isolate* isolate = module->shared_isolate; + Handle<FixedArray> fixed = + isolate->factory()->NewFixedArray(2 * table_size); + instance->function_table = fixed; + module->function_table = new std::vector<uint16_t>(); + for (int i = 0; i < table_size; i++) { + module->function_table->push_back(functions[i]); + } + } + + void PopulateIndirectFunctionTable() { + if (instance->function_table.is_null()) return; + int table_size = static_cast<int>(module->function_table->size()); + for (int i = 0; i < table_size; i++) { + int function_index = module->function_table->at(i); + WasmFunction* function = &module->functions->at(function_index); + instance->function_table->set(i, Smi::FromInt(function->sig_index)); + instance->function_table->set( + i + table_size, *instance->function_code->at(function_index)); } - module->functions->push_back({sig, 0, 0, 0, 0, 0, 0, 0, false, false}); - function_code->push_back(code); - return &module->functions->back(); } private: - size_t mem_size; + WasmModule module_; + WasmModuleInstance instance_; uint32_t global_offset; - byte global_data[kMaxGlobalsSize]; + V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data. WasmGlobal* AddGlobal(MachineType mem_type) { - AllocModule(); - if (globals_area == 0) { - globals_area = reinterpret_cast<uintptr_t>(global_data); + if (!module->globals) { module->globals = new std::vector<WasmGlobal>(); } byte size = WasmOpcodes::MemSize(mem_type); @@ -187,15 +231,6 @@ class TestingModule : public ModuleEnv { CHECK_LT(global_offset, kMaxGlobalsSize); return &module->globals->back(); } - void AllocModule() { - if (module == nullptr) { - module = new WasmModule(); - module->shared_isolate = CcTest::InitIsolateOnce(); - module->globals = nullptr; - module->functions = nullptr; - module->data_segments = nullptr; - } - } }; @@ -212,39 +247,212 @@ inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, FunctionEnv* env, str << ", msg = " << result.error_msg.get(); FATAL(str.str().c_str()); } + builder.Int64LoweringForTesting(); if (FLAG_trace_turbo_graph) { OFStream os(stdout); os << AsRPO(*jsgraph->graph()); } } +template <typename ReturnType> +class WasmFunctionWrapper : public HandleAndZoneScope, + private GraphAndBuilders { + public: + WasmFunctionWrapper() + : GraphAndBuilders(main_zone()), + inner_code_node_(nullptr), + signature_(nullptr) { + // One additional parameter for the pointer to the return value memory. + Signature<MachineType>::Builder sig_builder( + zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1); + + sig_builder.AddReturn(MachineType::Int32()); + for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) { + sig_builder.AddParam(MachineType::Pointer()); + } + signature_ = sig_builder.Build(); + } + + void Init(CallDescriptor* descriptor, MachineType p0 = MachineType::None(), + MachineType p1 = MachineType::None(), + MachineType p2 = MachineType::None(), + MachineType p3 = MachineType::None()) { + // Create the TF graph for the wrapper. The wrapper always takes four + // pointers as parameters, but may not pass the values of all pointers to + // the actual test function. + + // Function, effect, and control. + Node** parameters = + zone()->template NewArray<Node*>(WASM_RUNNER_MAX_NUM_PARAMETERS + 3); + graph()->SetStart(graph()->NewNode(common()->Start(6))); + Node* effect = graph()->start(); + int parameter_count = 0; + + // Dummy node which gets replaced in SetInnerCode. + inner_code_node_ = graph()->NewNode(common()->Int32Constant(0)); + parameters[parameter_count++] = inner_code_node_; + + if (p0 != MachineType::None()) { + parameters[parameter_count] = graph()->NewNode( + machine()->Load(p0), + graph()->NewNode(common()->Parameter(0), graph()->start()), + graph()->NewNode(common()->Int32Constant(0)), effect, + graph()->start()); + effect = parameters[parameter_count++]; + } + if (p1 != MachineType::None()) { + parameters[parameter_count] = graph()->NewNode( + machine()->Load(p0), + graph()->NewNode(common()->Parameter(1), graph()->start()), + graph()->NewNode(common()->Int32Constant(0)), effect, + graph()->start()); + effect = parameters[parameter_count++]; + } + if (p2 != MachineType::None()) { + parameters[parameter_count] = graph()->NewNode( + machine()->Load(p0), + graph()->NewNode(common()->Parameter(2), graph()->start()), + graph()->NewNode(common()->Int32Constant(0)), effect, + graph()->start()); + effect = parameters[parameter_count++]; + } + if (p3 != MachineType::None()) { + parameters[parameter_count] = graph()->NewNode( + machine()->Load(p0), + graph()->NewNode(common()->Parameter(3), graph()->start()), + graph()->NewNode(common()->Int32Constant(0)), effect, + graph()->start()); + effect = parameters[parameter_count++]; + } + + parameters[parameter_count++] = effect; + parameters[parameter_count++] = graph()->start(); + Node* call = graph()->NewNode(common()->Call(descriptor), parameter_count, + parameters); + + effect = graph()->NewNode( + machine()->Store( + StoreRepresentation(MachineTypeForC<ReturnType>().representation(), + WriteBarrierKind::kNoWriteBarrier)), + graph()->NewNode(common()->Parameter(WASM_RUNNER_MAX_NUM_PARAMETERS), + graph()->start()), + graph()->NewNode(common()->Int32Constant(0)), call, effect, + graph()->start()); + Node* r = graph()->NewNode( + common()->Return(), + graph()->NewNode(common()->Int32Constant(WASM_WRAPPER_RETURN_VALUE)), + effect, graph()->start()); + graph()->SetEnd(graph()->NewNode(common()->End(2), r, graph()->start())); + } + + void SetInnerCode(Handle<Code> code_handle) { + NodeProperties::ChangeOp(inner_code_node_, + common()->HeapConstant(code_handle)); + } + + Handle<Code> GetWrapperCode() { + if (code_.is_null()) { + Isolate* isolate = CcTest::InitIsolateOnce(); + + CallDescriptor* descriptor = + Linkage::GetSimplifiedCDescriptor(zone(), signature_, true); + + if (kPointerSize == 4) { + // One additional parameter for the pointer of the return value. + Signature<MachineRepresentation>::Builder rep_builder( + zone(), 1, WASM_RUNNER_MAX_NUM_PARAMETERS + 1); + + rep_builder.AddReturn(MachineRepresentation::kWord32); + for (int i = 0; i < WASM_RUNNER_MAX_NUM_PARAMETERS + 1; i++) { + rep_builder.AddParam(MachineRepresentation::kWord32); + } + Int64Lowering r(graph(), machine(), common(), zone(), + rep_builder.Build()); + r.LowerGraph(); + } + + CompilationInfo info("testing", isolate, graph()->zone()); + code_ = + Pipeline::GenerateCodeForTesting(&info, descriptor, graph(), nullptr); + CHECK(!code_.is_null()); +#ifdef ENABLE_DISASSEMBLER + if (FLAG_print_opt_code) { + OFStream os(stdout); + code_->Disassemble("wasm wrapper", os); + } +#endif + } -// A helper for compiling functions that are only internally callable WASM code. + return code_; + } + + Signature<MachineType>* signature() const { return signature_; } + + private: + Node* inner_code_node_; + Handle<Code> code_; + Signature<MachineType>* signature_; +}; + +// A helper for compiling WASM functions for testing. This class can create a +// standalone function if {module} is NULL or a function within a +// {TestingModule}. It contains the internal state for compilation (i.e. +// TurboFan graph) and, later, interpretation. class WasmFunctionCompiler : public HandleAndZoneScope, private GraphAndBuilders { public: - explicit WasmFunctionCompiler(FunctionSig* sig, ModuleEnv* module = nullptr) + explicit WasmFunctionCompiler(FunctionSig* sig, TestingModule* module) : GraphAndBuilders(main_zone()), jsgraph(this->isolate(), this->graph(), this->common(), nullptr, nullptr, this->machine()), - descriptor_(nullptr) { + descriptor_(nullptr), + testing_module_(module) { init_env(&env, sig); env.module = module; + if (module) { + // Get a new function from the testing module. + function_ = nullptr; + function_index_ = module->AddFunction(sig, Handle<Code>::null()); + } else { + // Create our own function. + function_ = new WasmFunction(); + function_->sig = sig; + function_index_ = 0; + } + } + + ~WasmFunctionCompiler() { + if (function_) delete function_; } JSGraph jsgraph; FunctionEnv env; // The call descriptor is initialized when the function is compiled. CallDescriptor* descriptor_; + TestingModule* testing_module_; + WasmFunction* function_; + int function_index_; Isolate* isolate() { return main_isolate(); } Graph* graph() const { return main_graph_; } Zone* zone() const { return graph()->zone(); } CommonOperatorBuilder* common() { return &main_common_; } MachineOperatorBuilder* machine() { return &main_machine_; } + void InitializeDescriptor() { + if (descriptor_ == nullptr) { + descriptor_ = env.module->GetWasmCallDescriptor(main_zone(), env.sig); + } + } CallDescriptor* descriptor() { return descriptor_; } void Build(const byte* start, const byte* end) { + // Transfer local counts before compiling. + function()->local_i32_count = env.local_i32_count; + function()->local_i64_count = env.local_i64_count; + function()->local_f32_count = env.local_f32_count; + function()->local_f64_count = env.local_f64_count; + + // Build the TurboFan graph. TestBuildingGraph(main_zone(), &jsgraph, &env, start, end); } @@ -256,11 +464,16 @@ class WasmFunctionCompiler : public HandleAndZoneScope, return b; } - Handle<Code> Compile(ModuleEnv* module) { - descriptor_ = module->GetWasmCallDescriptor(this->zone(), env.sig); + // TODO(titzer): remove me. + Handle<Code> Compile() { + InitializeDescriptor(); + CallDescriptor* desc = descriptor_; + if (kPointerSize == 4) { + desc = testing_module_->GetI32WasmCallDescriptor(this->zone(), desc); + } CompilationInfo info("wasm compile", this->isolate(), this->zone()); Handle<Code> result = - Pipeline::GenerateCodeForTesting(&info, descriptor_, this->graph()); + Pipeline::GenerateCodeForTesting(&info, desc, this->graph()); #ifdef ENABLE_DISASSEMBLER if (!result.is_null() && FLAG_print_opt_code) { OFStream os(stdout); @@ -271,16 +484,20 @@ class WasmFunctionCompiler : public HandleAndZoneScope, return result; } - uint32_t CompileAndAdd(TestingModule* module) { - uint32_t index = 0; - if (module->module && module->module->functions) { - index = static_cast<uint32_t>(module->module->functions->size()); - } - module->AddFunction(env.sig, Compile(module)); - return index; + // TODO(titzer): remove me. + uint32_t CompileAndAdd(uint16_t sig_index = 0) { + CHECK(testing_module_); + function()->sig_index = sig_index; + Handle<Code> code = Compile(); + testing_module_->SetFunctionCode(function_index_, code); + return static_cast<uint32_t>(function_index_); } -}; + WasmFunction* function() { + if (function_) return function_; + return &testing_module_->module->functions->at(function_index_); + } +}; // A helper class to build graphs from Wasm bytecode, generate machine // code, and run that code. @@ -291,11 +508,28 @@ class WasmRunner { MachineType p1 = MachineType::None(), MachineType p2 = MachineType::None(), MachineType p3 = MachineType::None()) - : signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, + : compiled_(false), + + signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, + GetParameterCount(p0, p1, p2, p3), storage_), + compiler_(&signature_, nullptr) { + InitSigStorage(p0, p1, p2, p3); + } + + WasmRunner(TestingModule* module, MachineType p0 = MachineType::None(), + MachineType p1 = MachineType::None(), + MachineType p2 = MachineType::None(), + MachineType p3 = MachineType::None()) + : compiled_(false), + signature_(MachineTypeForC<ReturnType>() == MachineType::None() ? 0 : 1, GetParameterCount(p0, p1, p2, p3), storage_), - compiler_(&signature_), - call_wrapper_(p0, p1, p2, p3), - compilation_done_(false) { + compiler_(&signature_, module) { + DCHECK(module); + InitSigStorage(p0, p1, p2, p3); + } + + void InitSigStorage(MachineType p0, MachineType p1, MachineType p2, + MachineType p3) { int index = 0; MachineType ret = MachineTypeForC<ReturnType>(); if (ret != MachineType::None()) { @@ -309,56 +543,60 @@ class WasmRunner { storage_[index++] = WasmOpcodes::LocalTypeFor(p2); if (p3 != MachineType::None()) storage_[index++] = WasmOpcodes::LocalTypeFor(p3); - } + compiler_.InitializeDescriptor(); + wrapper_.Init(compiler_.descriptor(), p0, p1, p2, p3); + } FunctionEnv* env() { return &compiler_.env; } - - // Builds a graph from the given Wasm code, and generates the machine + // Builds a graph from the given Wasm code and generates the machine // code and call wrapper for that graph. This method must not be called // more than once. void Build(const byte* start, const byte* end) { - DCHECK(!compilation_done_); - compilation_done_ = true; - // Build the TF graph. + CHECK(!compiled_); + compiled_ = true; + + // Build the TF graph within the compiler. compiler_.Build(start, end); // Generate code. - Handle<Code> code = compiler_.Compile(env()->module); - - // Construct the call wrapper. - Node* inputs[5]; - int input_count = 0; - inputs[input_count++] = call_wrapper_.HeapConstant(code); - for (size_t i = 0; i < signature_.parameter_count(); i++) { - inputs[input_count++] = call_wrapper_.Parameter(i); + Handle<Code> code = compiler_.Compile(); + + if (compiler_.testing_module_) { + // Update the table of function code in the module. + compiler_.testing_module_->SetFunctionCode(compiler_.function_index_, + code); } - call_wrapper_.Return(call_wrapper_.AddNode( - call_wrapper_.common()->Call(compiler_.descriptor()), input_count, - inputs)); + wrapper_.SetInnerCode(code); } - ReturnType Call() { return call_wrapper_.Call(); } + ReturnType Call() { return Call(0, 0, 0, 0); } template <typename P0> ReturnType Call(P0 p0) { - return call_wrapper_.Call(p0); + return Call(p0, 0, 0, 0); } template <typename P0, typename P1> ReturnType Call(P0 p0, P1 p1) { - return call_wrapper_.Call(p0, p1); + return Call(p0, p1, 0, 0); } template <typename P0, typename P1, typename P2> ReturnType Call(P0 p0, P1 p1, P2 p2) { - return call_wrapper_.Call(p0, p1, p2); + return Call(p0, p1, p2, 0); } template <typename P0, typename P1, typename P2, typename P3> ReturnType Call(P0 p0, P1 p1, P2 p2, P3 p3) { - return call_wrapper_.Call(p0, p1, p2, p3); + CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(), + wrapper_.GetWrapperCode(), wrapper_.signature()); + ReturnType return_value; + int32_t result = runner.Call<void*, void*, void*, void*, void*>( + &p0, &p1, &p2, &p3, &return_value); + CHECK_EQ(WASM_WRAPPER_RETURN_VALUE, result); + return return_value; } byte AllocateLocal(LocalType type) { @@ -369,12 +607,13 @@ class WasmRunner { return b; } - private: - LocalType storage_[5]; + protected: + Zone zone; + bool compiled_; + LocalType storage_[WASM_RUNNER_MAX_NUM_PARAMETERS]; FunctionSig signature_; WasmFunctionCompiler compiler_; - BufferedRawMachineAssemblerTester<ReturnType> call_wrapper_; - bool compilation_done_; + WasmFunctionWrapper<ReturnType> wrapper_; static size_t GetParameterCount(MachineType p0, MachineType p1, MachineType p2, MachineType p3) { diff --git a/deps/v8/test/default.gyp b/deps/v8/test/default.gyp index 53a8d7d4a2..efc0406895 100644 --- a/deps/v8/test/default.gyp +++ b/deps/v8/test/default.gyp @@ -11,6 +11,7 @@ 'type': 'none', 'dependencies': [ 'cctest/cctest.gyp:cctest_run', + 'fuzzer/fuzzer.gyp:fuzzer_run', 'intl/intl.gyp:intl_run', 'message/message.gyp:message_run', 'mjsunit/mjsunit.gyp:mjsunit_run', diff --git a/deps/v8/test/default.isolate b/deps/v8/test/default.isolate index 68044cf15b..416137c5b5 100644 --- a/deps/v8/test/default.isolate +++ b/deps/v8/test/default.isolate @@ -2,8 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. { + 'variables': { + 'command': [ + '../tools/run-tests.py', + ], + }, 'includes': [ 'cctest/cctest.isolate', + 'fuzzer/fuzzer.isolate', 'intl/intl.isolate', 'message/message.isolate', 'mjsunit/mjsunit.isolate', diff --git a/deps/v8/test/fuzzer/DEPS b/deps/v8/test/fuzzer/DEPS new file mode 100644 index 0000000000..3e73aa244f --- /dev/null +++ b/deps/v8/test/fuzzer/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+src", +] diff --git a/deps/v8/test/fuzzer/fuzzer-support.cc b/deps/v8/test/fuzzer/fuzzer-support.cc new file mode 100644 index 0000000000..cf3ee8c6fd --- /dev/null +++ b/deps/v8/test/fuzzer/fuzzer-support.cc @@ -0,0 +1,100 @@ +// Copyright 2016 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 "test/fuzzer/fuzzer-support.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "include/libplatform/libplatform.h" + +namespace v8_fuzzer { + +namespace { + +FuzzerSupport* g_fuzzer_support = nullptr; + +void DeleteFuzzerSupport() { + if (g_fuzzer_support) { + delete g_fuzzer_support; + g_fuzzer_support = nullptr; + } +} + +} // namespace + +class FuzzerSupport::ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { + public: + virtual void* Allocate(size_t length) { + void* data = AllocateUninitialized(length); + return data == NULL ? data : memset(data, 0, length); + } + virtual void* AllocateUninitialized(size_t length) { return malloc(length); } + virtual void Free(void* data, size_t) { free(data); } +}; + +FuzzerSupport::FuzzerSupport(int* argc, char*** argv) { + v8::V8::SetFlagsFromCommandLine(argc, *argv, true); + v8::V8::InitializeICU(); + v8::V8::InitializeExternalStartupData((*argv)[0]); + platform_ = v8::platform::CreateDefaultPlatform(); + v8::V8::InitializePlatform(platform_); + v8::V8::Initialize(); + + allocator_ = new ArrayBufferAllocator; + v8::Isolate::CreateParams create_params; + create_params.array_buffer_allocator = allocator_; + isolate_ = v8::Isolate::New(create_params); + + { + v8::Isolate::Scope isolate_scope(isolate_); + v8::HandleScope handle_scope(isolate_); + context_.Reset(isolate_, v8::Context::New(isolate_)); + } +} + +FuzzerSupport::~FuzzerSupport() { + { + v8::Isolate::Scope isolate_scope(isolate_); + while (v8::platform::PumpMessageLoop(platform_, isolate_)) /* empty */ + ; + + v8::HandleScope handle_scope(isolate_); + context_.Reset(); + } + + isolate_->Dispose(); + isolate_ = nullptr; + + delete allocator_; + allocator_ = nullptr; + + v8::V8::Dispose(); + v8::V8::ShutdownPlatform(); + + delete platform_; + platform_ = nullptr; +} + +// static +FuzzerSupport* FuzzerSupport::Get() { return g_fuzzer_support; } + +v8::Isolate* FuzzerSupport::GetIsolate() { return isolate_; } + +v8::Local<v8::Context> FuzzerSupport::GetContext() { + v8::Isolate::Scope isolate_scope(isolate_); + v8::EscapableHandleScope handle_scope(isolate_); + v8::Local<v8::Context> context = + v8::Local<v8::Context>::New(isolate_, context_); + return handle_scope.Escape(context); +} + +} // namespace v8_fuzzer + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + v8_fuzzer::g_fuzzer_support = new v8_fuzzer::FuzzerSupport(argc, argv); + atexit(&v8_fuzzer::DeleteFuzzerSupport); + return 0; +} diff --git a/deps/v8/test/fuzzer/fuzzer-support.h b/deps/v8/test/fuzzer/fuzzer-support.h new file mode 100644 index 0000000000..0241c53665 --- /dev/null +++ b/deps/v8/test/fuzzer/fuzzer-support.h @@ -0,0 +1,37 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef TEST_FUZZER_FUZZER_SUPPORT_H_ +#define TEST_FUZZER_FUZZER_SUPPORT_H_ + +#include "include/v8.h" + +namespace v8_fuzzer { + +class FuzzerSupport { + public: + FuzzerSupport(int* argc, char*** argv); + ~FuzzerSupport(); + + static FuzzerSupport* Get(); + + v8::Isolate* GetIsolate(); + v8::Local<v8::Context> GetContext(); + + private: + // Prevent copying. Not implemented. + FuzzerSupport(const FuzzerSupport&); + FuzzerSupport& operator=(const FuzzerSupport&); + + class ArrayBufferAllocator; + + v8::Platform* platform_; + ArrayBufferAllocator* allocator_; + v8::Isolate* isolate_; + v8::Global<v8::Context> context_; +}; + +} // namespace + +#endif // TEST_FUZZER_FUZZER_SUPPORT_H_ diff --git a/deps/v8/test/fuzzer/fuzzer.cc b/deps/v8/test/fuzzer/fuzzer.cc new file mode 100644 index 0000000000..71a26b86b3 --- /dev/null +++ b/deps/v8/test/fuzzer/fuzzer.cc @@ -0,0 +1,56 @@ +// Copyright 2016 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 <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv); +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); + +int main(int argc, char* argv[]) { + if (LLVMFuzzerInitialize(&argc, &argv)) { + fprintf(stderr, "Failed to initialize fuzzer target\n"); + return 1; + } + + if (argc < 2) { + fprintf(stderr, "USAGE: %s <input>\n", argv[0]); + return 1; + } + + FILE* input = fopen(argv[1], "rb"); + + if (!input) { + fprintf(stderr, "Failed to open '%s'\n", argv[1]); + return 1; + } + + fseek(input, 0, SEEK_END); + long size = ftell(input); + fseek(input, 0, SEEK_SET); + + uint8_t* data = reinterpret_cast<uint8_t*>(malloc(size)); + if (!data) { + fclose(input); + fprintf(stderr, "Failed to allocate %ld bytes\n", size); + return 1; + } + + size_t bytes_read = fread(data, 1, size, input); + fclose(input); + + if (bytes_read != size) { + free(data); + fprintf(stderr, "Failed to read %s\n", argv[1]); + return 1; + } + + int result = LLVMFuzzerTestOneInput(data, size); + + free(data); + + return result; +} diff --git a/deps/v8/test/fuzzer/fuzzer.gyp b/deps/v8/test/fuzzer/fuzzer.gyp new file mode 100644 index 0000000000..5fc338cb58 --- /dev/null +++ b/deps/v8/test/fuzzer/fuzzer.gyp @@ -0,0 +1,134 @@ +# Copyright 2016 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. + +{ + 'variables': { + 'v8_code': 1, + }, + 'includes': ['../../build/toolchain.gypi', '../../build/features.gypi'], + 'targets': [ + { + 'target_name': 'json_fuzzer', + 'type': 'executable', + 'dependencies': [ + 'json_fuzzer_lib', + ], + 'include_dirs': [ + '../..', + ], + 'sources': [ + 'fuzzer.cc', + ], + }, + { + 'target_name': 'json_fuzzer_lib', + 'type': 'static_library', + 'dependencies': [ + 'fuzzer_support', + ], + 'include_dirs': [ + '../..', + ], + 'sources': [ ### gcmole(all) ### + 'json.cc', + ], + }, + { + 'target_name': 'parser_fuzzer', + 'type': 'executable', + 'dependencies': [ + 'parser_fuzzer_lib', + ], + 'include_dirs': [ + '../..', + ], + 'sources': [ + 'fuzzer.cc', + ], + }, + { + 'target_name': 'parser_fuzzer_lib', + 'type': 'static_library', + 'dependencies': [ + 'fuzzer_support', + ], + 'include_dirs': [ + '../..', + ], + 'sources': [ ### gcmole(all) ### + 'parser.cc', + ], + }, + { + 'target_name': 'regexp_fuzzer', + 'type': 'executable', + 'dependencies': [ + 'regexp_fuzzer_lib', + ], + 'include_dirs': [ + '../..', + ], + 'sources': [ + 'fuzzer.cc', + ], + }, + { + 'target_name': 'regexp_fuzzer_lib', + 'type': 'static_library', + 'dependencies': [ + 'fuzzer_support', + ], + 'include_dirs': [ + '../..', + ], + 'sources': [ ### gcmole(all) ### + 'regexp.cc', + ], + }, + { + 'target_name': 'fuzzer_support', + 'type': 'static_library', + 'dependencies': [ + '../../tools/gyp/v8.gyp:v8_libplatform', + ], + 'include_dirs': [ + '../..', + ], + 'sources': [ ### gcmole(all) ### + 'fuzzer-support.cc', + 'fuzzer-support.h', + ], + 'conditions': [ + ['component=="shared_library"', { + # fuzzers can't be built against a shared library, so we need to + # depend on the underlying static target in that case. + 'dependencies': ['../../tools/gyp/v8.gyp:v8_maybe_snapshot'], + }, { + 'dependencies': ['../../tools/gyp/v8.gyp:v8'], + }], + ], + }, + ], + 'conditions': [ + ['test_isolation_mode != "noop"', { + 'targets': [ + { + 'target_name': 'fuzzer_run', + 'type': 'none', + 'dependencies': [ + 'json_fuzzer', + 'parser_fuzzer', + 'regexp_fuzzer', + ], + 'includes': [ + '../../build/isolate.gypi', + ], + 'sources': [ + 'fuzzer.isolate', + ], + }, + ], + }], + ], +} diff --git a/deps/v8/test/fuzzer/fuzzer.isolate b/deps/v8/test/fuzzer/fuzzer.isolate new file mode 100644 index 0000000000..286be2f24a --- /dev/null +++ b/deps/v8/test/fuzzer/fuzzer.isolate @@ -0,0 +1,22 @@ +# Copyright 2016 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. + +{ + 'variables': { + 'files': [ + '<(PRODUCT_DIR)/json_fuzzer<(EXECUTABLE_SUFFIX)', + '<(PRODUCT_DIR)/parser_fuzzer<(EXECUTABLE_SUFFIX)', + '<(PRODUCT_DIR)/regexp_fuzzer<(EXECUTABLE_SUFFIX)', + './fuzzer.status', + './testcfg.py', + './json/', + './parser/', + './regexp/', + ], + }, + 'includes': [ + '../../src/base.isolate', + '../../tools/testrunner/testrunner.isolate', + ], +} diff --git a/deps/v8/test/fuzzer/fuzzer.status b/deps/v8/test/fuzzer/fuzzer.status new file mode 100644 index 0000000000..df922bbf4e --- /dev/null +++ b/deps/v8/test/fuzzer/fuzzer.status @@ -0,0 +1,7 @@ +# Copyright 2016 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. + +[ + +] diff --git a/deps/v8/test/fuzzer/json.cc b/deps/v8/test/fuzzer/json.cc new file mode 100644 index 0000000000..f20e9b9a3b --- /dev/null +++ b/deps/v8/test/fuzzer/json.cc @@ -0,0 +1,31 @@ +// Copyright 2016 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 <limits.h> +#include <stddef.h> +#include <stdint.h> + +#include "include/v8.h" +#include "test/fuzzer/fuzzer-support.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + v8_fuzzer::FuzzerSupport* support = v8_fuzzer::FuzzerSupport::Get(); + v8::Isolate* isolate = support->GetIsolate(); + + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Context::Scope context_scope(support->GetContext()); + v8::TryCatch try_catch(isolate); + + if (size > INT_MAX) return 0; + v8::Local<v8::String> source; + if (!v8::String::NewFromOneByte(isolate, data, v8::NewStringType::kNormal, + static_cast<int>(size)) + .ToLocal(&source)) { + return 0; + } + + v8::JSON::Parse(isolate, source).IsEmpty(); + return 0; +} diff --git a/deps/v8/test/fuzzer/json/json b/deps/v8/test/fuzzer/json/json new file mode 100644 index 0000000000..f3400b3721 --- /dev/null +++ b/deps/v8/test/fuzzer/json/json @@ -0,0 +1 @@ +{"json": 1} diff --git a/deps/v8/test/fuzzer/json/not-json b/deps/v8/test/fuzzer/json/not-json new file mode 100644 index 0000000000..6b7a9f4e0c --- /dev/null +++ b/deps/v8/test/fuzzer/json/not-json @@ -0,0 +1 @@ +not json diff --git a/deps/v8/test/fuzzer/parser.cc b/deps/v8/test/fuzzer/parser.cc new file mode 100644 index 0000000000..aee4c0dab7 --- /dev/null +++ b/deps/v8/test/fuzzer/parser.cc @@ -0,0 +1,42 @@ +// Copyright 2016 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 <limits.h> +#include <stddef.h> +#include <stdint.h> + +#include "include/v8.h" +#include "src/objects.h" +#include "src/parsing/parser.h" +#include "src/parsing/preparser.h" +#include "test/fuzzer/fuzzer-support.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + v8_fuzzer::FuzzerSupport* support = v8_fuzzer::FuzzerSupport::Get(); + v8::Isolate* isolate = support->GetIsolate(); + + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Context::Scope context_scope(support->GetContext()); + v8::TryCatch try_catch(isolate); + + v8::internal::Isolate* i_isolate = + reinterpret_cast<v8::internal::Isolate*>(isolate); + v8::internal::Factory* factory = i_isolate->factory(); + + if (size > INT_MAX) return 0; + v8::internal::MaybeHandle<v8::internal::String> source = + factory->NewStringFromOneByte( + v8::internal::Vector<const uint8_t>(data, static_cast<int>(size))); + if (source.is_null()) return 0; + + v8::internal::Handle<v8::internal::Script> script = + factory->NewScript(source.ToHandleChecked()); + v8::internal::Zone zone; + v8::internal::ParseInfo info(&zone, script); + info.set_global(); + v8::internal::Parser parser(&info); + parser.Parse(&info); + return 0; +} diff --git a/deps/v8/test/fuzzer/parser/hello-world b/deps/v8/test/fuzzer/parser/hello-world new file mode 100644 index 0000000000..6be02374db --- /dev/null +++ b/deps/v8/test/fuzzer/parser/hello-world @@ -0,0 +1 @@ +console.log('hello world'); diff --git a/deps/v8/test/fuzzer/regexp.cc b/deps/v8/test/fuzzer/regexp.cc new file mode 100644 index 0000000000..eb51da8ac7 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp.cc @@ -0,0 +1,75 @@ +// Copyright 2016 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 <limits.h> +#include <stddef.h> +#include <stdint.h> + +#include "include/v8.h" +#include "src/factory.h" +#include "src/objects-inl.h" +#include "src/objects.h" +#include "src/regexp/jsregexp.h" +#include "test/fuzzer/fuzzer-support.h" + +namespace i = v8::internal; + +void Test(v8::Isolate* isolate, i::Handle<i::JSRegExp> regexp, + i::Handle<i::String> subject, i::Handle<i::JSArray> results_array) { + v8::TryCatch try_catch(isolate); + USE(i::RegExpImpl::Exec(regexp, subject, 0, results_array)); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + v8_fuzzer::FuzzerSupport* support = v8_fuzzer::FuzzerSupport::Get(); + v8::Isolate* isolate = support->GetIsolate(); + + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + v8::Context::Scope context_scope(support->GetContext()); + v8::TryCatch try_catch(isolate); + + i::FLAG_harmony_unicode_regexps = true; + i::FLAG_harmony_regexp_lookbehind = true; + + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + i::Factory* factory = i_isolate->factory(); + + if (size > INT_MAX) return 0; + i::MaybeHandle<i::String> maybe_source = factory->NewStringFromOneByte( + i::Vector<const uint8_t>(data, static_cast<int>(size))); + i::Handle<i::String> source; + if (!maybe_source.ToHandle(&source)) return 0; + + static const int kAllFlags = i::JSRegExp::kGlobal | i::JSRegExp::kIgnoreCase | + i::JSRegExp::kMultiline | i::JSRegExp::kSticky | + i::JSRegExp::kUnicode; + + const uint8_t one_byte_array[6] = {'f', 'o', 'o', 'b', 'a', 'r'}; + const i::uc16 two_byte_array[6] = {'f', 0xD83D, 0xDCA9, 'b', 'a', 0x2603}; + + i::Handle<i::JSArray> results_array = factory->NewJSArray(5); + i::Handle<i::String> one_byte = + factory->NewStringFromOneByte(i::Vector<const uint8_t>(one_byte_array, 6)) + .ToHandleChecked(); + i::Handle<i::String> two_byte = + factory->NewStringFromTwoByte(i::Vector<const i::uc16>(two_byte_array, 6)) + .ToHandleChecked(); + + for (int flags = 0; flags <= kAllFlags; flags++) { + i::Handle<i::JSRegExp> regexp; + { + v8::TryCatch try_catch(isolate); + i::MaybeHandle<i::JSRegExp> maybe_regexp = + i::JSRegExp::New(source, static_cast<i::JSRegExp::Flags>(flags)); + if (!maybe_regexp.ToHandle(®exp)) continue; + } + Test(isolate, regexp, one_byte, results_array); + Test(isolate, regexp, two_byte, results_array); + Test(isolate, regexp, factory->empty_string(), results_array); + Test(isolate, regexp, source, results_array); + } + + return 0; +} diff --git a/deps/v8/test/fuzzer/regexp/test00 b/deps/v8/test/fuzzer/regexp/test00 new file mode 100644 index 0000000000..d2a71aece8 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test00 @@ -0,0 +1 @@ +a* diff --git a/deps/v8/test/fuzzer/regexp/test01 b/deps/v8/test/fuzzer/regexp/test01 new file mode 100644 index 0000000000..83877e955f --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test01 @@ -0,0 +1 @@ +xyz{93}? diff --git a/deps/v8/test/fuzzer/regexp/test02 b/deps/v8/test/fuzzer/regexp/test02 new file mode 100644 index 0000000000..d27d2ce6ba --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test02 @@ -0,0 +1 @@ +(foo|bar|baz) diff --git a/deps/v8/test/fuzzer/regexp/test03 b/deps/v8/test/fuzzer/regexp/test03 new file mode 100644 index 0000000000..da14770d64 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test03 @@ -0,0 +1 @@ +[^] diff --git a/deps/v8/test/fuzzer/regexp/test04 b/deps/v8/test/fuzzer/regexp/test04 new file mode 100644 index 0000000000..a672b260b0 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test04 @@ -0,0 +1 @@ +[\d] diff --git a/deps/v8/test/fuzzer/regexp/test05 b/deps/v8/test/fuzzer/regexp/test05 new file mode 100644 index 0000000000..edcff4e452 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test05 @@ -0,0 +1 @@ +\c1 diff --git a/deps/v8/test/fuzzer/regexp/test06 b/deps/v8/test/fuzzer/regexp/test06 new file mode 100644 index 0000000000..74c75c65b0 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test06 @@ -0,0 +1 @@ +[a\]c] diff --git a/deps/v8/test/fuzzer/regexp/test07 b/deps/v8/test/fuzzer/regexp/test07 new file mode 100644 index 0000000000..2ed8704014 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test07 @@ -0,0 +1 @@ +\00011 diff --git a/deps/v8/test/fuzzer/regexp/test08 b/deps/v8/test/fuzzer/regexp/test08 new file mode 100644 index 0000000000..62d553ccfe --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test08 @@ -0,0 +1 @@ +(x)(x)(x)\2* diff --git a/deps/v8/test/fuzzer/regexp/test09 b/deps/v8/test/fuzzer/regexp/test09 new file mode 100644 index 0000000000..291650041b --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test09 @@ -0,0 +1 @@ +(?=a)?a diff --git a/deps/v8/test/fuzzer/regexp/test10 b/deps/v8/test/fuzzer/regexp/test10 new file mode 100644 index 0000000000..8aac6957c3 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test10 @@ -0,0 +1 @@ +\1\2(a(?<=\1(b\1\2))\2)\1 diff --git a/deps/v8/test/fuzzer/regexp/test11 b/deps/v8/test/fuzzer/regexp/test11 new file mode 100644 index 0000000000..f9101ec517 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test11 @@ -0,0 +1 @@ +\x34 diff --git a/deps/v8/test/fuzzer/regexp/test12 b/deps/v8/test/fuzzer/regexp/test12 new file mode 100644 index 0000000000..c418bbd6f4 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test12 @@ -0,0 +1 @@ +\u{12345}|\u{23456} diff --git a/deps/v8/test/fuzzer/regexp/test13 b/deps/v8/test/fuzzer/regexp/test13 new file mode 100644 index 0000000000..6e50a55528 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test13 @@ -0,0 +1 @@ +^a diff --git a/deps/v8/test/fuzzer/regexp/test14 b/deps/v8/test/fuzzer/regexp/test14 new file mode 100644 index 0000000000..5020b3bd00 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test14 @@ -0,0 +1 @@ +a{1,1}? diff --git a/deps/v8/test/fuzzer/regexp/test15 b/deps/v8/test/fuzzer/regexp/test15 new file mode 100644 index 0000000000..d1c4bdef9f --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test15 @@ -0,0 +1 @@ +a\d diff --git a/deps/v8/test/fuzzer/regexp/test16 b/deps/v8/test/fuzzer/regexp/test16 new file mode 100644 index 0000000000..c2d990e791 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test16 @@ -0,0 +1 @@ +a[\q] diff --git a/deps/v8/test/fuzzer/regexp/test17 b/deps/v8/test/fuzzer/regexp/test17 new file mode 100644 index 0000000000..d62fa9dc3f --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test17 @@ -0,0 +1 @@ +\0 diff --git a/deps/v8/test/fuzzer/regexp/test18 b/deps/v8/test/fuzzer/regexp/test18 new file mode 100644 index 0000000000..3836c6fe54 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test18 @@ -0,0 +1 @@ +a{1z} diff --git a/deps/v8/test/fuzzer/regexp/test19 b/deps/v8/test/fuzzer/regexp/test19 new file mode 100644 index 0000000000..7eafbfde9f --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test19 @@ -0,0 +1 @@ +{12z} diff --git a/deps/v8/test/fuzzer/regexp/test20 b/deps/v8/test/fuzzer/regexp/test20 new file mode 100644 index 0000000000..948cf947f8 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test20 @@ -0,0 +1 @@ +| diff --git a/deps/v8/test/fuzzer/regexp/test21 b/deps/v8/test/fuzzer/regexp/test21 new file mode 100644 index 0000000000..5d2207be4f --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test21 @@ -0,0 +1 @@ +(?:ab)* diff --git a/deps/v8/test/fuzzer/regexp/test22 b/deps/v8/test/fuzzer/regexp/test22 new file mode 100644 index 0000000000..2ca04990db --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test22 @@ -0,0 +1 @@ +(?:a*)? diff --git a/deps/v8/test/fuzzer/regexp/test23 b/deps/v8/test/fuzzer/regexp/test23 new file mode 100644 index 0000000000..fbe9c0cd67 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test23 @@ -0,0 +1 @@ +(?:a+){0} diff --git a/deps/v8/test/fuzzer/regexp/test24 b/deps/v8/test/fuzzer/regexp/test24 new file mode 100644 index 0000000000..bc09447441 --- /dev/null +++ b/deps/v8/test/fuzzer/regexp/test24 @@ -0,0 +1 @@ +a\Bc diff --git a/deps/v8/test/fuzzer/testcfg.py b/deps/v8/test/fuzzer/testcfg.py new file mode 100644 index 0000000000..976325a70a --- /dev/null +++ b/deps/v8/test/fuzzer/testcfg.py @@ -0,0 +1,48 @@ +# Copyright 2016 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. + +import os + +from testrunner.local import testsuite +from testrunner.objects import testcase + + +class FuzzerVariantGenerator(testsuite.VariantGenerator): + # Only run the fuzzer with standard variant. + def FilterVariantsByTest(self, testcase): + return self.standard_variant + + def GetFlagSets(self, testcase, variant): + return testsuite.FAST_VARIANT_FLAGS[variant] + + +class FuzzerTestSuite(testsuite.TestSuite): + SUB_TESTS = ( 'json', 'parser', 'regexp', ) + + def __init__(self, name, root): + super(FuzzerTestSuite, self).__init__(name, root) + + def ListTests(self, context): + tests = [] + for subtest in FuzzerTestSuite.SUB_TESTS: + shell = '%s_fuzzer' % subtest + for fname in os.listdir(os.path.join(self.root, subtest)): + if not os.path.isfile(os.path.join(self.root, subtest, fname)): + continue + test = testcase.TestCase(self, '%s/%s' % (subtest, fname), + override_shell=shell) + tests.append(test) + tests.sort() + return tests + + def GetFlagsForTestCase(self, testcase, context): + suite, name = testcase.path.split('/') + return [os.path.join(self.root, suite, name)] + + def _VariantGeneratorFactory(self): + return FuzzerVariantGenerator + + +def GetSuite(name, root): + return FuzzerTestSuite(name, root) diff --git a/deps/v8/test/ignition.isolate b/deps/v8/test/ignition.isolate index 9604a694b2..7e4e581a6b 100644 --- a/deps/v8/test/ignition.isolate +++ b/deps/v8/test/ignition.isolate @@ -2,6 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. { + 'variables': { + 'command': [ + '../tools/run-tests.py', + ], + }, 'includes': [ 'cctest/cctest.isolate', 'mjsunit/mjsunit.isolate', diff --git a/deps/v8/test/message/arrow-invalid-rest-2.js b/deps/v8/test/message/arrow-invalid-rest-2.js new file mode 100644 index 0000000000..3517803d30 --- /dev/null +++ b/deps/v8/test/message/arrow-invalid-rest-2.js @@ -0,0 +1,8 @@ +// Copyright 2016 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 f = (a, ...x = 10) => x; +f(1, 2, 3, 4, 5); diff --git a/deps/v8/test/message/arrow-invalid-rest-2.out b/deps/v8/test/message/arrow-invalid-rest-2.out new file mode 100644 index 0000000000..0196483a66 --- /dev/null +++ b/deps/v8/test/message/arrow-invalid-rest-2.out @@ -0,0 +1,4 @@ +*%(basename)s:7: SyntaxError: Rest parameter must be an identifier or destructuring pattern +var f = (a, ...x = 10) => x; + ^^^^^^^^^ +SyntaxError: Rest parameter must be an identifier or destructuring pattern diff --git a/deps/v8/test/message/arrow-invalid-rest.js b/deps/v8/test/message/arrow-invalid-rest.js new file mode 100644 index 0000000000..870dbe9f54 --- /dev/null +++ b/deps/v8/test/message/arrow-invalid-rest.js @@ -0,0 +1,8 @@ +// Copyright 2016 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 f = (...x = 10) => x; +f(1, 2, 3, 4, 5); diff --git a/deps/v8/test/message/arrow-invalid-rest.out b/deps/v8/test/message/arrow-invalid-rest.out new file mode 100644 index 0000000000..4045f14e78 --- /dev/null +++ b/deps/v8/test/message/arrow-invalid-rest.out @@ -0,0 +1,4 @@ +*%(basename)s:7: SyntaxError: Rest parameter must be an identifier or destructuring pattern +var f = (...x = 10) => x; + ^^^^^^^^^ +SyntaxError: Rest parameter must be an identifier or destructuring pattern diff --git a/deps/v8/test/message/for-loop-invalid-lhs.out b/deps/v8/test/message/for-loop-invalid-lhs.out index 1972146f87..441ba3b60c 100644 --- a/deps/v8/test/message/for-loop-invalid-lhs.out +++ b/deps/v8/test/message/for-loop-invalid-lhs.out @@ -2,3 +2,4 @@ function f() { for ("unassignable" in {}); } ^^^^^^^^^^^^^^ SyntaxError: Invalid left-hand side in for-loop + diff --git a/deps/v8/test/message/function-sent-escaped.js b/deps/v8/test/message/function-sent-escaped.js new file mode 100644 index 0000000000..aa17258f85 --- /dev/null +++ b/deps/v8/test/message/function-sent-escaped.js @@ -0,0 +1,10 @@ +// Copyright 2016 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-function-sent + +function* f() { + return function.s\u0065nt; +} +for (var i of f()) print(i); diff --git a/deps/v8/test/message/function-sent-escaped.out b/deps/v8/test/message/function-sent-escaped.out new file mode 100644 index 0000000000..d9613d8ef4 --- /dev/null +++ b/deps/v8/test/message/function-sent-escaped.out @@ -0,0 +1,4 @@ +*%(basename)s:8: SyntaxError: 'function.sent' must not contain escaped characters + return function.s\u0065nt; + ^^^^^^^^^^^^^^^^^^ +SyntaxError: 'function.sent' must not contain escaped characters diff --git a/deps/v8/test/message/let-lexical-name-in-array-prohibited.out b/deps/v8/test/message/let-lexical-name-in-array-prohibited.out index e6a53dcd17..fc8181a498 100644 --- a/deps/v8/test/message/let-lexical-name-in-array-prohibited.out +++ b/deps/v8/test/message/let-lexical-name-in-array-prohibited.out @@ -2,3 +2,4 @@ let [let]; ^^^ SyntaxError: let is disallowed as a lexically bound name + diff --git a/deps/v8/test/message/let-lexical-name-in-object-prohibited.out b/deps/v8/test/message/let-lexical-name-in-object-prohibited.out index a1458f9899..c04f6bedd2 100644 --- a/deps/v8/test/message/let-lexical-name-in-object-prohibited.out +++ b/deps/v8/test/message/let-lexical-name-in-object-prohibited.out @@ -2,3 +2,4 @@ let {let}; ^^^ SyntaxError: let is disallowed as a lexically bound name + diff --git a/deps/v8/test/message/let-lexical-name-prohibited.out b/deps/v8/test/message/let-lexical-name-prohibited.out index fe423dcd77..4b2011b297 100644 --- a/deps/v8/test/message/let-lexical-name-prohibited.out +++ b/deps/v8/test/message/let-lexical-name-prohibited.out @@ -2,3 +2,4 @@ let let; ^^^ SyntaxError: let is disallowed as a lexically bound name + diff --git a/deps/v8/test/message/new-target-escaped.js b/deps/v8/test/message/new-target-escaped.js new file mode 100644 index 0000000000..f8398bebd4 --- /dev/null +++ b/deps/v8/test/message/new-target-escaped.js @@ -0,0 +1,10 @@ +// Copyright 2016 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 new.t\u0061rget; +} +var o = new f(); diff --git a/deps/v8/test/message/new-target-escaped.out b/deps/v8/test/message/new-target-escaped.out new file mode 100644 index 0000000000..21b30e3513 --- /dev/null +++ b/deps/v8/test/message/new-target-escaped.out @@ -0,0 +1,4 @@ +*%(basename)s:8: SyntaxError: 'new.target' must not contain escaped characters + return new.t\u0061rget; + ^^^^^^^^^^^^^^^ +SyntaxError: 'new.target' must not contain escaped characters diff --git a/deps/v8/test/message/try-catch-lexical-conflict.out b/deps/v8/test/message/try-catch-lexical-conflict.out index 9dc1b54fd5..0a7a0ebc25 100644 --- a/deps/v8/test/message/try-catch-lexical-conflict.out +++ b/deps/v8/test/message/try-catch-lexical-conflict.out @@ -1,4 +1,4 @@ *%(basename)s:10: SyntaxError: Identifier 'x' has already been declared let x; - ^ + ^ SyntaxError: Identifier 'x' has already been declared diff --git a/deps/v8/test/message/try-catch-variable-conflict.out b/deps/v8/test/message/try-catch-variable-conflict.out index c7fb8de510..be4858e2fa 100644 --- a/deps/v8/test/message/try-catch-variable-conflict.out +++ b/deps/v8/test/message/try-catch-variable-conflict.out @@ -1,4 +1,4 @@ *%(basename)s:9: SyntaxError: Identifier 'x' has already been declared var x; - ^ + ^ SyntaxError: Identifier 'x' has already been declared diff --git a/deps/v8/test/mjsunit/apply.js b/deps/v8/test/mjsunit/apply.js index fdd032dab3..7ce6acccba 100644 --- a/deps/v8/test/mjsunit/apply.js +++ b/deps/v8/test/mjsunit/apply.js @@ -114,7 +114,7 @@ function al() { return arguments.length + arguments[arguments.length - 1]; } -for (var j = 1; j < 0x4000000; j <<= 1) { +for (var j = 1; j < 0x400000; j <<= 1) { try { var a = %NormalizeElements([]); a.length = j; @@ -122,7 +122,7 @@ for (var j = 1; j < 0x4000000; j <<= 1) { assertEquals(42 + j, al.apply(345, a)); } catch (e) { assertTrue(e.toString().indexOf("Maximum call stack size exceeded") != -1); - for (; j < 0x4000000; j <<= 1) { + for (; j < 0x400000; j <<= 1) { var caught = false; try { a = %NormalizeElements([]); diff --git a/deps/v8/test/mjsunit/arguments-opt.js b/deps/v8/test/mjsunit/arguments-opt.js deleted file mode 100644 index b8280b4bec..0000000000 --- a/deps/v8/test/mjsunit/arguments-opt.js +++ /dev/null @@ -1,132 +0,0 @@ -// 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: --allow-natives-syntax - -function L0() { - return %_ArgumentsLength(); -} - -function L1(a) { - return %_ArgumentsLength(); -} - -function L5(a,b,c,d,e) { - return %_ArgumentsLength(); -} - - -assertEquals(0, L0()); -assertEquals(1, L0(1)); -assertEquals(2, L0(1,2)); -assertEquals(5, L0(1,2,3,4,5)); - -assertEquals(0, L1()); -assertEquals(1, L1(1)); -assertEquals(2, L1(1,2)); -assertEquals(5, L1(1,2,3,4,5)); - -assertEquals(0, L5()); -assertEquals(1, L5(1)); -assertEquals(2, L5(1,2)); -assertEquals(5, L5(1,2,3,4,5)); - - -function A(key) { - return %_Arguments(key); -} - -// Integer access. -assertEquals(0, A(0)); -assertEquals(0, A(0,1)); -assertEquals(2, A(1,2)); -assertEquals(2, A(1,2,3,4,5)); -assertEquals(5, A(4,2,3,4,5)); -assertTrue(typeof A(1) == 'undefined'); -assertTrue(typeof A(3,2,1) == 'undefined'); - -// Out-of-bounds integer access with and without argument -// adaptor frames. -assertTrue(typeof(A(-10000)) == 'undefined'); -assertTrue(typeof(A(-10000, 0)) == 'undefined'); -assertTrue(typeof(A(-1)) == 'undefined'); -assertTrue(typeof(A(-1, 0)) == 'undefined'); -assertTrue(typeof(A(10000)) == 'undefined'); -assertTrue(typeof(A(10000, 0)) == 'undefined'); - -// String access. -assertEquals('0', A('0')); -assertEquals('0', A('0',1)); -assertEquals(2, A('1',2)); -assertEquals(2, A('1',2,3,4,5)); -assertEquals(5, A('4',2,3,4,5)); -assertEquals('undefined', typeof A('1')); -assertEquals('undefined', typeof A('3',2,1)); -assertEquals(A, A('callee')); -assertEquals(1, A('length')); -assertEquals(2, A('length',2)); -assertEquals(5, A('length',2,3,4,5)); -assertEquals({}.toString, A('toString')); -assertEquals({}.isPrototypeOf, A('isPrototypeOf')); -assertEquals('undefined', typeof A('xxx')); - -// Object access. -function O(key) { - return { toString: function() { return key; } }; -} - -var O0 = O(0); -assertSame(O0, A(O0)); -assertSame(O0, A(O0,1)); -assertEquals(2, A(O(1),2)); -assertEquals(2, A(O(1),2,3,4,5)); -assertEquals(5, A(O(4),2,3,4,5)); -assertTrue(typeof A(O(1)) == 'undefined'); -assertTrue(typeof A(O(3),2,1) == 'undefined'); - -O0 = O('0'); -assertSame(O0, A(O0)); -assertSame(O0, A(O0,1)); -assertEquals(2, A(O('1'),2)); -assertEquals(2, A(O('1'),2,3,4,5)); -assertEquals(5, A(O('4'),2,3,4,5)); -assertTrue(typeof A(O('1')) == 'undefined'); -assertTrue(typeof A(O('3'),2,1) == 'undefined'); -assertEquals(A, A(O('callee'))); -assertEquals(1, A(O('length'))); -assertEquals(2, A(O('length'),2)); -assertEquals(5, A(O('length'),2,3,4,5)); -assertEquals({}.toString, A(O('toString'))); -assertEquals({}.isPrototypeOf, A(O('isPrototypeOf'))); -assertTrue(typeof A(O('xxx')) == 'undefined'); - -// Make sure that out-of-bounds access do lookups in the -// prototype chain. -Object.prototype[5] = 42; -assertEquals(42, A(5)); -Object.prototype[-5] = 87; -assertEquals(87, A(-5)); diff --git a/deps/v8/test/mjsunit/array-sort.js b/deps/v8/test/mjsunit/array-sort.js index beb8b95b01..ae9f6efa66 100644 --- a/deps/v8/test/mjsunit/array-sort.js +++ b/deps/v8/test/mjsunit/array-sort.js @@ -466,7 +466,16 @@ function TestSortToObject() { TestSortToObject(); function TestSortOnProxy() { - var p = new Proxy([2,1,3], {}); - assertEquals([1,2,3], p.sort()); + { + var p = new Proxy([2,1,3], {}); + assertEquals([1,2,3], p.sort()); + } + + { + function f() { return arguments }; + var a = f(2,1,3); + a.__proto__ = new Proxy({}, {}); + assertEquals([1,2,3], [...(Array.prototype.sort.apply(a))]); + } } TestSortOnProxy(); diff --git a/deps/v8/test/mjsunit/compiler/debug-catch-prediction.js b/deps/v8/test/mjsunit/compiler/debug-catch-prediction.js new file mode 100644 index 0000000000..34d3afd77e --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/debug-catch-prediction.js @@ -0,0 +1,143 @@ +// Copyright 2016 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 event catch prediction for thrown exceptions. We distinguish +// between "caught" and "uncaught" based on the following assumptions: +// 1) try-catch : Will always catch the exception. +// 2) try-finally : Will always re-throw the exception. + +Debug = debug.Debug; + +var log = []; + +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Exception) { + log.push([event_data.exception(), event_data.uncaught()]); + } + } catch (e) { + %AbortJS(e + "\n" + e.stack); + } +} + +Debug.setBreakOnException(); +Debug.setListener(listener); + +(function TryCatch() { + log = []; // Clear log. + function f(a) { + try { + throw "boom" + a; + } catch(e) { + return e; + } + } + assertEquals("boom1", f(1)); + assertEquals("boom2", f(2)); + %OptimizeFunctionOnNextCall(f); + assertEquals("boom3", f(3)); + print("Collect log:", log); + assertEquals([["boom1",false], ["boom2",false], ["boom3",false]], log); +})(); + +(function TryFinally() { + log = []; // Clear log. + function f(a) { + try { + throw "baem" + a; + } finally { + return a + 10; + } + } + assertEquals(11, f(1)); + assertEquals(12, f(2)); + %OptimizeFunctionOnNextCall(f); + assertEquals(13, f(3)); + print("Collect log:", log); + assertEquals([["baem1",true], ["baem2",true], ["baem3",true]], log); +})(); + +(function TryCatchFinally() { + log = []; // Clear log. + function f(a) { + try { + throw "wosh" + a; + } catch(e) { + return e + a; + } finally { + // Nothing. + } + } + assertEquals("wosh11", f(1)); + assertEquals("wosh22", f(2)); + %OptimizeFunctionOnNextCall(f); + assertEquals("wosh33", f(3)); + print("Collect log:", log); + assertEquals([["wosh1",false], ["wosh2",false], ["wosh3",false]], log); +})(); + +(function TryCatchNestedFinally() { + log = []; // Clear log. + function f(a) { + try { + try { + throw "bang" + a; + } finally { + // Nothing. + } + } catch(e) { + return e + a; + } + } + assertEquals("bang11", f(1)); + assertEquals("bang22", f(2)); + %OptimizeFunctionOnNextCall(f); + assertEquals("bang33", f(3)); + print("Collect log:", log); + assertEquals([["bang1",false], ["bang2",false], ["bang3",false]], log); +})(); + +(function TryFinallyNestedCatch() { + log = []; // Clear log. + function f(a) { + try { + try { + throw "peng" + a; + } catch(e) { + return e + } + } finally { + return a + 10; + } + } + assertEquals(11, f(1)); + assertEquals(12, f(2)); + %OptimizeFunctionOnNextCall(f); + assertEquals(13, f(3)); + print("Collect log:", log); + assertEquals([["peng1",false], ["peng2",false], ["peng3",false]], log); +})(); + +(function TryFinallyNestedFinally() { + log = []; // Clear log. + function f(a) { + try { + try { + throw "oops" + a; + } finally { + // Nothing. + } + } finally { + return a + 10; + } + } + assertEquals(11, f(1)); + assertEquals(12, f(2)); + %OptimizeFunctionOnNextCall(f); + assertEquals(13, f(3)); + print("Collect log:", log); + assertEquals([["oops1",true], ["oops2",true], ["oops3",true]], log); +})(); diff --git a/deps/v8/test/mjsunit/regress/setvalueof-deopt.js b/deps/v8/test/mjsunit/compiler/deopt-materialize-accumulator.js index 8c42c8a20b..c80e329150 100644 --- a/deps/v8/test/mjsunit/regress/setvalueof-deopt.js +++ b/deps/v8/test/mjsunit/compiler/deopt-materialize-accumulator.js @@ -1,4 +1,4 @@ -// Copyright 2014 the V8 project authors. All rights reserved. +// Copyright 2016 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: @@ -26,17 +26,16 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Flags: --allow-natives-syntax +// +// Tests that Turbofan correctly materializes values which are in the +// interpreters accumulator during deopt. -function g(x, y) { - return y; -} - -function f(deopt) { - return g(%_SetValueOf(1, 1), deopt + 0); +var global = 3; +function f(a) { + // This will trigger a deopt since global was previously a SMI, with the + // accumulator holding an unboxed double which needs materialized. + global = %_MathSqrt(a); } - -f(0); -f(0); -f(0); %OptimizeFunctionOnNextCall(f); -assertEquals("result0", f("result")); +f(0.25); +assertEquals(0.5, global); diff --git a/deps/v8/test/mjsunit/compiler/double-array-to-global.js b/deps/v8/test/mjsunit/compiler/double-array-to-global.js new file mode 100644 index 0000000000..e221d90358 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/double-array-to-global.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: --allow-natives-syntax + +var a = [-0, 0]; +var b; +function foo(a) { + for (var i = 0; i < 2; ++i) { + b = a[i]; + } +} +foo(a); +foo(a); +%OptimizeFunctionOnNextCall(foo); +foo(a); diff --git a/deps/v8/test/mjsunit/compiler/inline-arguments.js b/deps/v8/test/mjsunit/compiler/inline-arguments.js index d52f31b5e9..1337ab237a 100644 --- a/deps/v8/test/mjsunit/compiler/inline-arguments.js +++ b/deps/v8/test/mjsunit/compiler/inline-arguments.js @@ -309,29 +309,3 @@ test_toarr(toarr2); delete forceDeopt.deopt; outer(); })(); - - -// Test inlining of functions with %_Arguments and %_ArgumentsLength intrinsic. -(function () { - function inner(len,a,b,c) { - assertSame(len, %_ArgumentsLength()); - for (var i = 1; i < len; ++i) { - var c = String.fromCharCode(96 + i); - assertSame(c, %_Arguments(i)); - } - } - - function outer() { - inner(1); - inner(2, 'a'); - inner(3, 'a', 'b'); - inner(4, 'a', 'b', 'c'); - inner(5, 'a', 'b', 'c', 'd'); - inner(6, 'a', 'b', 'c', 'd', 'e'); - } - - outer(); - outer(); - %OptimizeFunctionOnNextCall(outer); - outer(); -})(); diff --git a/deps/v8/test/mjsunit/compiler/minus-zero.js b/deps/v8/test/mjsunit/compiler/minus-zero.js index c161257d77..ac66350051 100644 --- a/deps/v8/test/mjsunit/compiler/minus-zero.js +++ b/deps/v8/test/mjsunit/compiler/minus-zero.js @@ -37,31 +37,8 @@ assertEquals(0, add(0, 0)); assertEquals(-0, add(-0, -0)); -function test(x, y) { - assertTrue(%_IsMinusZero(-0)); - assertTrue(%_IsMinusZero(1/(-Infinity))); - assertTrue(%_IsMinusZero(x)); - - assertFalse(%_IsMinusZero(0)); - assertFalse(%_IsMinusZero(1/Infinity)); - assertFalse(%_IsMinusZero(0.1)); - assertFalse(%_IsMinusZero(-0.2)); - assertFalse(%_IsMinusZero({})); - assertFalse(%_IsMinusZero("")); - assertFalse(%_IsMinusZero("-0")); - assertFalse(%_IsMinusZero(function() {})); - assertFalse(%_IsMinusZero(y)); -} - -test(-0, 1.2); -test(-0, 1.2); -%OptimizeFunctionOnNextCall(test); -test(-0, 1.2); -assertOptimized(test); - - function testsin() { - assertTrue(%_IsMinusZero(Math.sin(-0))); + assertEquals(-0, Math.sin(-0)); } testsin(); @@ -71,8 +48,7 @@ testsin(); function testfloor() { - assertTrue(%_IsMinusZero(Math.floor(-0))); - assertFalse(%_IsMinusZero(Math.floor(2))); + assertEquals(-0, Math.floor(-0)); } testfloor(); diff --git a/deps/v8/test/mjsunit/compiler/optimized-for-in.js b/deps/v8/test/mjsunit/compiler/optimized-for-in.js index f3ff6beb05..d93344ea57 100644 --- a/deps/v8/test/mjsunit/compiler/optimized-for-in.js +++ b/deps/v8/test/mjsunit/compiler/optimized-for-in.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: --optimize-for-in --allow-natives-syntax -// Flags: --no-concurrent-osr +// Flags: --allow-natives-syntax --no-concurrent-osr // Test for-in support in Crankshaft. For simplicity this tests assumes certain // fixed iteration order for properties and will have to be adjusted if V8 diff --git a/deps/v8/test/mjsunit/compiler/regress-1085.js b/deps/v8/test/mjsunit/compiler/regress-1085.js index cea587f500..533cf59c9c 100644 --- a/deps/v8/test/mjsunit/compiler/regress-1085.js +++ b/deps/v8/test/mjsunit/compiler/regress-1085.js @@ -33,6 +33,5 @@ function f(x) { return 1 / Math.min(1, x); } for (var i = 0; i < 5; ++i) f(1); %OptimizeFunctionOnNextCall(f); -%OptimizeFunctionOnNextCall(Math.min); assertEquals(-Infinity, f(-0)); diff --git a/deps/v8/test/mjsunit/compiler/regress-dead-throw-inlining.js b/deps/v8/test/mjsunit/compiler/regress-dead-throw-inlining.js new file mode 100644 index 0000000000..097a20bc41 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-dead-throw-inlining.js @@ -0,0 +1,13 @@ +// Copyright 2016 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() { if (false) throw 0; } +function f() { g(); } + +f(); +f(); +%OptimizeFunctionOnNextCall(f); +f(); diff --git a/deps/v8/test/mjsunit/compiler/regress-max.js b/deps/v8/test/mjsunit/compiler/regress-max.js index ee2fd587ec..7556f2f733 100644 --- a/deps/v8/test/mjsunit/compiler/regress-max.js +++ b/deps/v8/test/mjsunit/compiler/regress-max.js @@ -29,7 +29,6 @@ // Test Math.max with negative zero as input. for (var i = 0; i < 5; i++) Math.max(0, 0); -%OptimizeFunctionOnNextCall(Math.max); Math.max(0, 0); var r = Math.max(-0, -0); diff --git a/deps/v8/test/mjsunit/compiler/try-catch-deopt.js b/deps/v8/test/mjsunit/compiler/try-catch-deopt.js new file mode 100644 index 0000000000..2b6372cf28 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/try-catch-deopt.js @@ -0,0 +1,225 @@ +// Copyright 2016 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 LazyDeoptFromTryBlock() { + function g(dummy) { + %DeoptimizeFunction(f); + throw 42; + } + + function f() { + var a = 1; + try { + var dummy = 2; // perturb the stack height. + g(dummy); + } catch (e) { + return e + a; + } + } + + assertEquals(43, f()); + assertEquals(43, f()); + %NeverOptimizeFunction(g); + %OptimizeFunctionOnNextCall(f); + assertEquals(43, f()); +})(); + + +(function LazyDeoptDoublyNestedTryBlock() { + function g(dummy) { + %DeoptimizeFunction(f); + throw 42; + } + + function f() { + var b; + try { + var a = 1; + try { + var dummy = 2; // perturb the stack height. + g(dummy); + } catch (e) { + b = e + a; + } + } catch (e) { + return 0; + } + return b; + } + + assertEquals(43, f()); + assertEquals(43, f()); + %NeverOptimizeFunction(g); + %OptimizeFunctionOnNextCall(f); + assertEquals(43, f()); +})(); + +(function LazyDeoptInlinedTry() { + function g(dummy) { + %DeoptimizeFunction(f); + %DeoptimizeFunction(h); + throw 42; + } + + function h() { + var a = 1; + try { + var dummy = 2; // perturb the stack height. + g(dummy); + } catch (e) { + b = e + a; + } + return b; + } + + function f() { + var c = 1; + return h() + 1; + } + + assertEquals(44, f()); + assertEquals(44, f()); + %NeverOptimizeFunction(g); + %OptimizeFunctionOnNextCall(f); + assertEquals(44, f()); +})(); + +(function LazyDeoptInlinedIntoTry() { + function g(c) { + %DeoptimizeFunction(f); + %DeoptimizeFunction(h); + throw c; + } + + function h(c) { + return g(c); + } + + function f() { + var a = 1; + try { + var c = 42; // perturb the stack height. + h(c); + } catch (e) { + a += e; + } + return a; + } + + assertEquals(43, f()); + assertEquals(43, f()); + %NeverOptimizeFunction(g); + %OptimizeFunctionOnNextCall(f); + assertEquals(43, f()); +})(); + +(function LazyDeoptTryBlockContextCatch() { + var global = 0; + + function g() { + %DeoptimizeFunction(f); + throw "boom!"; + } + + function f(a) { + var x = a + 23 + try { + let y = a + 42; + function capture() { return x + y } + g(); + } catch(e) { + global = x; + } + return x; + } + assertEquals(23, f(0)); + assertEquals(24, f(1)); + %OptimizeFunctionOnNextCall(f); + assertEquals(25, f(2)); + assertEquals(25, global); +})(); + +(function LazyDeoptTryBlockFinally() { + var global = 0; + + function g() { + %DeoptimizeFunction(f); + throw "boom!"; + } + + function f(a) { + var x = a + 23 + try { + let y = a + 42; + function capture() { return x + y } + g(); + } finally { + global = x; + } + return x; + } + assertThrows(function() { f(0) }); + assertThrows(function() { f(1) }); + %OptimizeFunctionOnNextCall(f); + assertThrowsEquals(function() { f(2) }, "boom!"); + assertEquals(25, global); +})(); + +(function LazyDeoptTryCatchContextCatch() { + var global = 0; + + function g() { + %DeoptimizeFunction(f); + throw 5; + } + + function f(a) { + var x = a + 23 + try { + try { + throw 1; + } catch(e2) { + function capture() { return x + y } + g(); + } + } catch(e) { + global = x + e; + } + return x; + } + assertEquals(23, f(0)); + assertEquals(24, f(1)); + %OptimizeFunctionOnNextCall(f); + assertEquals(25, f(2)); + assertEquals(30, global); +})(); + +(function LazyDeoptTryWithContextCatch() { + var global = 0; + + function g() { + %DeoptimizeFunction(f); + throw 5; + } + + function f(a) { + var x = a + 23 + try { + with ({ y : a + 42 }) { + function capture() { return x + y } + g(); + } + } catch(e) { + global = x + e; + } + return x; + } + assertEquals(23, f(0)); + assertEquals(24, f(1)); + %OptimizeFunctionOnNextCall(f); + assertEquals(25, f(2)); + assertEquals(30, global); +})(); diff --git a/deps/v8/test/mjsunit/compiler/try-context.js b/deps/v8/test/mjsunit/compiler/try-context.js new file mode 100644 index 0000000000..4e6d9b028c --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/try-context.js @@ -0,0 +1,89 @@ +// Copyright 2016 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 TryBlockCatch() { + var global = 0; + function f(a) { + var x = a + 23 + try { + let y = a + 42; + function capture() { return x + y } + throw "boom!"; + } catch(e) { + global = x; + } + return x; + } + assertEquals(23, f(0)); + assertEquals(24, f(1)); + %OptimizeFunctionOnNextCall(f); + assertEquals(25, f(2)); + assertEquals(25, global); +})(); + +(function TryBlockFinally() { + var global = 0; + function f(a) { + var x = a + 23 + try { + let y = a + 42; + function capture() { return x + y } + throw "boom!"; + } finally { + global = x; + } + return x; + } + assertThrows(function() { f(0) }); + assertThrows(function() { f(1) }); + %OptimizeFunctionOnNextCall(f); + assertThrows(function() { f(2) }); + assertEquals(25, global); +})(); + +(function TryCatchCatch() { + var global = 0; + function f(a) { + var x = a + 23 + try { + try { + throw "boom!"; + } catch(e2) { + function capture() { return x + y } + throw "boom!"; + } + } catch(e) { + global = x; + } + return x; + } + assertEquals(23, f(0)); + assertEquals(24, f(1)); + %OptimizeFunctionOnNextCall(f); + assertEquals(25, f(2)); + assertEquals(25, global); +})(); + +(function TryWithCatch() { + var global = 0; + function f(a) { + var x = a + 23 + try { + with ({ y : a + 42 }) { + function capture() { return x + y } + throw "boom!"; + } + } catch(e) { + global = x; + } + return x; + } + assertEquals(23, f(0)); + assertEquals(24, f(1)); + %OptimizeFunctionOnNextCall(f); + assertEquals(25, f(2)); + assertEquals(25, global); +})(); diff --git a/deps/v8/test/mjsunit/compiler/try-finally-deopt.js b/deps/v8/test/mjsunit/compiler/try-finally-deopt.js new file mode 100644 index 0000000000..455bf3477f --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/try-finally-deopt.js @@ -0,0 +1,249 @@ +// Copyright 2016 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 DeoptimizeFinallyFallThrough() { + var global = 0; + function f() { + var a = 1; + try { + global = 1; + } finally { + global = 42; + %DeoptimizeNow(); + } + return global + a; + } + + f(); + f(); + %OptimizeFunctionOnNextCall(f); + assertEquals(43, f()); + assertEquals(42, global); +})(); + +(function DeoptimizeFinallyReturn() { + var global = 0; + function f() { + try { + return 10; + } finally { + global = 42; + %DeoptimizeNow(); + } + return 1; + } + + f(); + f(); + %OptimizeFunctionOnNextCall(f); + assertEquals(10, f()); + assertEquals(42, global); +})(); + +(function DeoptimizeFinallyReturnDoublyNested() { + var global = 0; + function f() { + try { + try { + return 10; + } finally { + global += 21; + %DeoptimizeNow(); + } + } finally { + global += 21; + } + return 1; + } + + f(); + f(); + %OptimizeFunctionOnNextCall(f); + global = 0; + assertEquals(10, f()); + assertEquals(42, global); +})(); + +(function DeoptimizeOuterFinallyReturnDoublyNested() { + var global = 0; + function f() { + try { + try { + return 10; + } finally { + global += 21; + } + } finally { + global += 21; + %DeoptimizeNow(); + } + return 1; + } + + f(); + f(); + %OptimizeFunctionOnNextCall(f); + global = 0; + assertEquals(10, f()); + assertEquals(42, global); +})(); + +(function DeoptimizeFinallyThrow() { + var global = 0; + function f() { + try { + global = 21; + throw 1; + global = 2; + } finally { + global += 21; + %DeoptimizeNow(); + } + global = 3; + return 1; + } + + try { f(); } catch(e) {} + try { f(); } catch(e) {} + %OptimizeFunctionOnNextCall(f); + assertThrowsEquals(f, 1); + assertEquals(42, global); +})(); + +(function DeoptimizeFinallyThrowNested() { + var global = 0; + function f() { + try { + try { + global = 10; + throw 1; + global = 2; + } finally { + global += 11; + %DeoptimizeNow(); + } + global = 4; + } finally { + global += 21; + } + global = 3; + return 1; + } + + try { f(); } catch(e) {} + try { f(); } catch(e) {} + %OptimizeFunctionOnNextCall(f); + assertThrowsEquals(f, 1); + assertEquals(42, global); +})(); + +(function DeoptimizeFinallyContinue() { + var global = 0; + function f() { + global = 0; + for (var i = 0; i < 2; i++) { + try { + if (i == 0) continue; + global += 10; + } finally { + global += 6; + %DeoptimizeNow(); + } + global += 20; + } + return 1; + } + + f(); + f(); + %OptimizeFunctionOnNextCall(f); + assertEquals(1, f()); + assertEquals(42, global); +})(); + +(function DeoptimizeFinallyContinueNestedTry() { + var global = 0; + function f() { + global = 0; + for (var i = 0; i < 2; i++) { + try { + try { + if (i == 0) continue; + global += 5; + } finally { + global += 4; + %DeoptimizeNow(); + } + global += 5; + } finally { + global += 2; + } + global += 20; + } + return 1; + } + + f(); + f(); + %OptimizeFunctionOnNextCall(f); + assertEquals(1, f()); + assertEquals(42, global); +})(); + +(function DeoptimizeFinallyBreak() { + var global = 0; + function f() { + global = 0; + for (var i = 0; i < 2; i++) { + try { + global += 20; + if (i == 0) break; + global += 5; + } finally { + global += 22; + %DeoptimizeNow(); + } + global += 5; + } + return 1; + } + + f(); + f(); + %OptimizeFunctionOnNextCall(f); + assertEquals(1, f()); + assertEquals(42, global); +})(); + +(function DeoptimizeFinallyBreakNested() { + var global = 0; + function f() { + global = 0; + for (var i = 0; i < 2; i++) { + try { + try { + global += 20; + if (i == 0) break; + global += 5; + } finally { + global += 12; + %DeoptimizeNow(); + } + global += 8; + } finally { + global += 10; + } + global += 5; + } + return 1; + } + + f(); + f(); + %OptimizeFunctionOnNextCall(f); + assertEquals(1, f()); + assertEquals(42, global); +})(); diff --git a/deps/v8/test/mjsunit/constant-fold-control-instructions.js b/deps/v8/test/mjsunit/constant-fold-control-instructions.js index eb4994591d..20900d6171 100644 --- a/deps/v8/test/mjsunit/constant-fold-control-instructions.js +++ b/deps/v8/test/mjsunit/constant-fold-control-instructions.js @@ -24,15 +24,8 @@ function test() { assertTrue(%_IsArray([1])); assertFalse(%_IsArray(function() {})); - assertTrue(%_IsFunction(function() {})); - assertFalse(%_IsFunction(null)); - assertTrue(%_IsJSReceiver(new Date())); assertFalse(%_IsJSReceiver(1)); - - assertTrue(%_IsMinusZero(-0.0)); - assertFalse(%_IsMinusZero(1)); - assertFalse(%_IsMinusZero("")); } diff --git a/deps/v8/test/mjsunit/debug-changebreakpoint.js b/deps/v8/test/mjsunit/debug-changebreakpoint.js index 897c3e3919..ad43b1749e 100644 --- a/deps/v8/test/mjsunit/debug-changebreakpoint.js +++ b/deps/v8/test/mjsunit/debug-changebreakpoint.js @@ -79,12 +79,6 @@ function listener(event, exec_state, event_data, data) { testArguments(dcp, '{' + bp_str + ',"enabled":"false"}', true); testArguments(dcp, '{' + bp_str + ',"condition":"1==2"}', true); testArguments(dcp, '{' + bp_str + ',"condition":"false"}', true); - testArguments(dcp, '{' + bp_str + ',"ignoreCount":7}', true); - testArguments(dcp, '{' + bp_str + ',"ignoreCount":0}', true); - testArguments( - dcp, - '{' + bp_str + ',"enabled":"true","condition":"false","ignoreCount":0}', - true); // Indicate that all was processed. listenerComplete = true; diff --git a/deps/v8/test/mjsunit/debug-conditional-breakpoints.js b/deps/v8/test/mjsunit/debug-conditional-breakpoints.js index 6248437300..4414897099 100644 --- a/deps/v8/test/mjsunit/debug-conditional-breakpoints.js +++ b/deps/v8/test/mjsunit/debug-conditional-breakpoints.js @@ -53,7 +53,6 @@ break_point_hit_count = 0; bp = Debug.setBreakPoint(f, 0, 0, '{{{'); f(); assertEquals(0, break_point_hit_count); -assertEquals(0, Debug.findBreakPoint(bp, false).hit_count()); Debug.clearBreakPoint(bp); // Conditional breakpoint which evaluates to false. @@ -61,7 +60,6 @@ break_point_hit_count = 0; bp = Debug.setBreakPoint(f, 0, 0, 'false'); f(); assertEquals(0, break_point_hit_count); -assertEquals(0, Debug.findBreakPoint(bp, false).hit_count()); Debug.clearBreakPoint(bp); // Conditional breakpoint which evaluates to true. @@ -69,7 +67,6 @@ break_point_hit_count = 0; bp = Debug.setBreakPoint(f, 0, 0, 'true'); f(); assertEquals(1, break_point_hit_count); -assertEquals(1, Debug.findBreakPoint(bp, false).hit_count()); Debug.clearBreakPoint(bp); // Conditional breakpoint which different types of quotes. @@ -77,13 +74,11 @@ break_point_hit_count = 0; bp = Debug.setBreakPoint(f, 0, 0, '"a" == "a"'); f(); assertEquals(1, break_point_hit_count); -assertEquals(1, Debug.findBreakPoint(bp, false).hit_count()); Debug.clearBreakPoint(bp); break_point_hit_count = 0; bp = Debug.setBreakPoint(f, 0, 0, "'a' == 'a'"); f(); assertEquals(1, break_point_hit_count); -assertEquals(1, Debug.findBreakPoint(bp, false).hit_count()); Debug.clearBreakPoint(bp); // Changing condition. @@ -91,15 +86,12 @@ break_point_hit_count = 0; bp = Debug.setBreakPoint(f, 0, 0, '"ab".indexOf("b") > 0'); f(); assertEquals(1, break_point_hit_count); -assertEquals(1, Debug.findBreakPoint(bp, false).hit_count()); Debug.changeBreakPointCondition(bp, 'Math.sin(Math.PI/2) > 1'); f(); assertEquals(1, break_point_hit_count); -assertEquals(1, Debug.findBreakPoint(bp, false).hit_count()); Debug.changeBreakPointCondition(bp, '1==1'); f(); assertEquals(2, break_point_hit_count); -assertEquals(2, Debug.findBreakPoint(bp, false).hit_count()); Debug.clearBreakPoint(bp); // Conditional breakpoint which checks global variable. @@ -107,11 +99,9 @@ break_point_hit_count = 0; bp = Debug.setBreakPoint(f, 0, 0, 'x==1'); f(); assertEquals(0, break_point_hit_count); -assertEquals(0, Debug.findBreakPoint(bp, false).hit_count()); x=1; f(); assertEquals(1, break_point_hit_count); -assertEquals(1, Debug.findBreakPoint(bp, false).hit_count()); Debug.clearBreakPoint(bp); // Conditional breakpoint which checks global variable. @@ -121,7 +111,6 @@ for (var i = 0; i < 10; i++) { g(); } assertEquals(5, break_point_hit_count); -assertEquals(5, Debug.findBreakPoint(bp, false).hit_count()); Debug.clearBreakPoint(bp); // Conditional breakpoint which checks a parameter. @@ -131,7 +120,6 @@ for (var i = 0; i < 10; i++) { g(); } assertEquals(5, break_point_hit_count); -assertEquals(5, Debug.findBreakPoint(bp, false).hit_count()); Debug.clearBreakPoint(bp); // Conditional breakpoint which checks a local variable. @@ -141,7 +129,6 @@ for (var i = 0; i < 10; i++) { g(); } assertEquals(5, break_point_hit_count); -assertEquals(5, Debug.findBreakPoint(bp, false).hit_count()); Debug.clearBreakPoint(bp); // Multiple conditional breakpoint which the same condition. @@ -152,8 +139,6 @@ for (var i = 0; i < 10; i++) { g(); } assertEquals(5, break_point_hit_count); -assertEquals(5, Debug.findBreakPoint(bp1, false).hit_count()); -assertEquals(5, Debug.findBreakPoint(bp2, false).hit_count()); Debug.clearBreakPoint(bp1); Debug.clearBreakPoint(bp2); @@ -165,7 +150,5 @@ for (var i = 0; i < 10; i++) { g(); } assertEquals(10, break_point_hit_count); -assertEquals(5, Debug.findBreakPoint(bp1, false).hit_count()); -assertEquals(5, Debug.findBreakPoint(bp2, false).hit_count()); Debug.clearBreakPoint(bp1); Debug.clearBreakPoint(bp2); diff --git a/deps/v8/test/mjsunit/debug-ignore-breakpoints.js b/deps/v8/test/mjsunit/debug-ignore-breakpoints.js deleted file mode 100644 index 3cb283bc48..0000000000 --- a/deps/v8/test/mjsunit/debug-ignore-breakpoints.js +++ /dev/null @@ -1,88 +0,0 @@ -// 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 -// Get the Debug object exposed from the debug context global object. -Debug = debug.Debug - -// Simple debug event handler which just counts the number of break points hit. -var break_point_hit_count; - -function listener(event, exec_state, event_data, data) { - if (event == Debug.DebugEvent.Break) { - break_point_hit_count++; - } -}; - -// Add the debug event listener. -Debug.setListener(listener); - -// Test function. -function f() {}; - -// This tests ignore of break points including the case with several -// break points in the same location. -break_point_hit_count = 0; - -// Set a breakpoint in f. -bp1 = Debug.setBreakPoint(f); - -// Try ignore count of 1. -Debug.changeBreakPointIgnoreCount(bp1, 1); -f(); -assertEquals(0, break_point_hit_count); -f(); -assertEquals(1, break_point_hit_count); - -// Set another breakpoint in f at the same place. -bp2 = Debug.setBreakPoint(f); -f(); -assertEquals(2, break_point_hit_count); - -// Set different ignore counts. -Debug.changeBreakPointIgnoreCount(bp1, 2); -Debug.changeBreakPointIgnoreCount(bp2, 4); -f(); -assertEquals(2, break_point_hit_count); -f(); -assertEquals(2, break_point_hit_count); -f(); -assertEquals(3, break_point_hit_count); -f(); -assertEquals(4, break_point_hit_count); - -// Set different ignore counts (opposite). -Debug.changeBreakPointIgnoreCount(bp1, 4); -Debug.changeBreakPointIgnoreCount(bp2, 2); -f(); -assertEquals(4, break_point_hit_count); -f(); -assertEquals(4, break_point_hit_count); -f(); -assertEquals(5, break_point_hit_count); -f(); -assertEquals(6, break_point_hit_count); diff --git a/deps/v8/test/mjsunit/debug-negative-break-points.js b/deps/v8/test/mjsunit/debug-negative-break-points.js new file mode 100644 index 0000000000..1eb8943a07 --- /dev/null +++ b/deps/v8/test/mjsunit/debug-negative-break-points.js @@ -0,0 +1,99 @@ +// Copyright 2016 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 + +var Debug = debug.Debug; +var break_count = 0; +var exception_count = 0; + +function assertCount(expected_breaks, expected_exceptions) { + assertEquals(expected_breaks, break_count); + assertEquals(expected_exceptions, exception_count); +} + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.Break) { + break_count++; + } else if (event == Debug.DebugEvent.Exception) { + exception_count++; + } +} + +function f(x) { + debugger; + return x + 1; +} + +function g(x) { + try { + throw x; + } catch (e) { + } +} + +function h(x) { + var a = undefined; + try { + var x = a(); + } catch (e) { + } +} + +Debug.setListener(listener); + +assertCount(0, 0); +f(0); +assertCount(1, 0); +g(0); +assertCount(1, 0); + +Debug.setBreakOnException(); +f(0); +assertCount(2, 0); +g(0); +assertCount(2, 1); + +Debug.setBreakPoint(f, 1, 0, "x == 1"); +f(1); +assertCount(3, 1); +f(2); +assertCount(3, 1); +f(1); +assertCount(4, 1); + +Debug.setBreakPoint(f, 1, 0, "x > 0"); +f(1); +assertCount(5, 1); +f(0); +assertCount(5, 1); + +Debug.setBreakPoint(g, 2, 0, "1 == 2"); +g(1); +assertCount(5, 1); + +Debug.setBreakPoint(g, 2, 0, "x == 1"); +g(1); +assertCount(6, 2); +g(2); +assertCount(6, 2); +g(1); +assertCount(7, 3); + +Debug.setBreakPoint(g, 2, 0, "x > 0"); +g(1); +assertCount(8, 4); +g(0); +assertCount(8, 4); + +h(0); +assertCount(8, 5); +Debug.setBreakPoint(h, 3, 0, "x > 0"); +h(1); +assertCount(9, 6); +h(0); +assertCount(9, 6); + +Debug.clearBreakOnException(); +Debug.setListener(null); diff --git a/deps/v8/test/mjsunit/debug-script.js b/deps/v8/test/mjsunit/debug-script.js index 8874960208..5396415087 100644 --- a/deps/v8/test/mjsunit/debug-script.js +++ b/deps/v8/test/mjsunit/debug-script.js @@ -73,8 +73,8 @@ for (i = 0; i < scripts.length; i++) { // This has to be updated if the number of native scripts change. assertEquals(%NativeScriptsCount(), named_native_count); -// Only the 'gc' extension is loaded. -assertEquals(1, extension_count); +// The 'gc' extension and one or two extras scripts are loaded. +assertTrue(extension_count == 2 || extension_count == 3); // This script and mjsunit.js has been loaded. If using d8, d8 loads // a normal script during startup too. assertTrue(normal_count == 2 || normal_count == 3); diff --git a/deps/v8/test/mjsunit/debug-setbreakpoint.js b/deps/v8/test/mjsunit/debug-setbreakpoint.js index bc23021ec7..7c996e5de0 100644 --- a/deps/v8/test/mjsunit/debug-setbreakpoint.js +++ b/deps/v8/test/mjsunit/debug-setbreakpoint.js @@ -88,7 +88,6 @@ function listener(event, exec_state, event_data, data) { testArguments(dcp, '{"type":"function","target":1}', false); testArguments(dcp, '{"type":"function","target":"f","line":-1}', false); testArguments(dcp, '{"type":"function","target":"f","column":-1}', false); - testArguments(dcp, '{"type":"function","target":"f","ignoreCount":-1}', false); testArguments(dcp, '{"type":"handle","target":"-1"}', false); mirror = debug.MakeMirror(o); testArguments(dcp, '{"type":"handle","target":' + mirror.handle() + '}', false); @@ -101,7 +100,6 @@ function listener(event, exec_state, event_data, data) { testArguments(dcp, '{"type":"function","target":"f","condition":"i == 1"}', true, false); testArguments(dcp, '{"type":"function","target":"f","enabled":true}', true, false); testArguments(dcp, '{"type":"function","target":"f","enabled":false}', true, false); - testArguments(dcp, '{"type":"function","target":"f","ignoreCount":7}', true, false); testArguments(dcp, '{"type":"script","target":"test"}', true, true); testArguments(dcp, '{"type":"script","target":"test"}', true, true); diff --git a/deps/v8/test/mjsunit/deopt-with-outer-context.js b/deps/v8/test/mjsunit/deopt-with-outer-context.js new file mode 100644 index 0000000000..42a829d853 --- /dev/null +++ b/deps/v8/test/mjsunit/deopt-with-outer-context.js @@ -0,0 +1,22 @@ +// 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 outer(y) { + function inner() { + var x = 10; + (function() { + // Access x from inner function to force it to be context allocated. + x = 20; + %DeoptimizeFunction(inner); + })(); + // Variable y should be read from the outer context. + return y; + }; + %OptimizeFunctionOnNextCall(inner); + return inner(); +} + +assertEquals(30, outer(30)); diff --git a/deps/v8/test/mjsunit/harmony/array-concat.js b/deps/v8/test/mjsunit/es6/array-concat.js index cabdf2df08..bc9e1a00cc 100644 --- a/deps/v8/test/mjsunit/harmony/array-concat.js +++ b/deps/v8/test/mjsunit/es6/array-concat.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-concat-spreadable --harmony-proxies --harmony-reflect +// Flags: --harmony-proxies --harmony-reflect (function testArrayConcatArity() { "use strict"; @@ -267,30 +267,22 @@ function testConcatTypedArray(type, elems, modulo) { } (function testConcatSmallTypedArray() { - var max = [Math.pow(2, 8), Math.pow(2, 16), Math.pow(2, 32), false, false]; - [ - Uint8Array, - Uint16Array, - Uint32Array, - Float32Array, - Float64Array - ].forEach(function(ctor, i) { - testConcatTypedArray(ctor, 1, max[i]); - }); + var length = 1; + testConcatTypedArray(Uint8Array, length, Math.pow(2, 8)); + testConcatTypedArray(Uint16Array, length, Math.pow(2, 16)); + testConcatTypedArray(Uint32Array, length, Math.pow(2, 32)); + testConcatTypedArray(Float32Array, length, false); + testConcatTypedArray(Float64Array, length, false); })(); (function testConcatLargeTypedArray() { - var max = [Math.pow(2, 8), Math.pow(2, 16), Math.pow(2, 32), false, false]; - [ - Uint8Array, - Uint16Array, - Uint32Array, - Float32Array, - Float64Array - ].forEach(function(ctor, i) { - testConcatTypedArray(ctor, 4000, max[i]); - }); + var length = 4000; + testConcatTypedArray(Uint8Array, length, Math.pow(2, 8)); + testConcatTypedArray(Uint16Array, length, Math.pow(2, 16)); + testConcatTypedArray(Uint32Array, length, Math.pow(2, 32)); + testConcatTypedArray(Float32Array, length, false); + testConcatTypedArray(Float64Array, length, false); })(); diff --git a/deps/v8/test/mjsunit/es6/array-length.js b/deps/v8/test/mjsunit/es6/array-length.js index cc3b88105c..06efe00901 100644 --- a/deps/v8/test/mjsunit/es6/array-length.js +++ b/deps/v8/test/mjsunit/es6/array-length.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-tolength - // Test array functions do not cause infinite loops when length is negative, // max_value, etc. diff --git a/deps/v8/test/mjsunit/es6/block-for.js b/deps/v8/test/mjsunit/es6/block-for.js index c7a23e8d32..d953d376f0 100644 --- a/deps/v8/test/mjsunit/es6/block-for.js +++ b/deps/v8/test/mjsunit/es6/block-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-completion - "use strict"; function props(x) { diff --git a/deps/v8/test/mjsunit/es6/classes-super.js b/deps/v8/test/mjsunit/es6/classes-super.js new file mode 100644 index 0000000000..7bdf4ba86c --- /dev/null +++ b/deps/v8/test/mjsunit/es6/classes-super.js @@ -0,0 +1,15 @@ +// Copyright 2016 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 Test { + m() { + super.length = 10; + } +} + +var array = []; +Test.prototype.m.call(array); +assertEquals(10, array.length); diff --git a/deps/v8/test/mjsunit/harmony/completion.js b/deps/v8/test/mjsunit/es6/completion.js index ceeafb2b3d..05565bfb45 100644 --- a/deps/v8/test/mjsunit/harmony/completion.js +++ b/deps/v8/test/mjsunit/es6/completion.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-completion --harmony-sloppy-let --no-legacy-const +// Flags: --harmony-sloppy-let --no-legacy-const function assertUndef(x) { diff --git a/deps/v8/test/mjsunit/es6/generators-iteration.js b/deps/v8/test/mjsunit/es6/generators-iteration.js index faeb68380f..ae4c682e7e 100644 --- a/deps/v8/test/mjsunit/es6/generators-iteration.js +++ b/deps/v8/test/mjsunit/es6/generators-iteration.js @@ -101,9 +101,9 @@ function TestGenerator(g, expected_values_for_next, testThrow(function*() { return yield* g(); }); if (g instanceof GeneratorFunction) { - testNext(function() { return new g(); }); - testSend(function() { return new g(); }); - testThrow(function() { return new g(); }); + testNext(g); + testSend(g); + testThrow(g); } } @@ -259,18 +259,6 @@ TestGenerator( [1, 2, undefined]); TestGenerator( - function g18() { - function* g() { yield this.x; yield this.y; } - var iter = new g; - iter.x = 1; - iter.y = 2; - return iter; - }, - [1, 2, undefined], - "foo", - [1, 2, undefined]); - -TestGenerator( function* g19() { var x = 1; yield x; @@ -409,39 +397,17 @@ TestGenerator( "foo", [42, undefined]); -// Test that yield* re-yields received results without re-boxing. -function TestDelegatingYield() { - function results(results) { - var i = 0; - function next() { - return results[i++]; - } - var iter = { next: next }; - var ret = {}; - ret[Symbol.iterator] = function() { return iter; }; - return ret; - } - function* yield_results(expected) { - return yield* results(expected); - } - function collect_results(iterable) { - var iter = iterable[Symbol.iterator](); - var ret = []; - var result; - do { - result = iter.next(); - ret.push(result); - } while (!result.done); - return ret; - } - // We have to put a full result for the end, because the return will re-box. - var expected = [{value: 1}, 13, "foo", {value: 34, done: true}]; - - // Sanity check. - assertEquals(expected, collect_results(results(expected))); - assertEquals(expected, collect_results(yield_results(expected))); +// Test that yield* validates iterator results. +function TestDelegatingYield(junk) { + var iterator = {next: () => junk}; + var iterable = {[Symbol.iterator]: () => iterator}; + function* g() { return yield* iterable }; + assertThrows(() => g().next(), TypeError); } TestDelegatingYield(); +TestDelegatingYield(null); +TestDelegatingYield(42); +TestDelegatingYield(true); function TestTryCatch(instantiate) { function* g() { yield 1; try { yield 2; } catch (e) { yield e; } yield 3; } @@ -693,3 +659,16 @@ function TestRecursion() { assertThrows(TestThrowRecursion, Error); } TestRecursion(); + + +// Test yield* on non-iterable objects. +function* g(junk) { return yield* junk } +var non_iterables = [ + 42, + {[Symbol.iterator]: 42}, + {[Symbol.iterator]: () => 42}, + {[Symbol.iterator]: () => ({next: 42})}, +]; +for (let junk of non_iterables) { + assertThrows(() => g(junk).next(), TypeError); +} diff --git a/deps/v8/test/mjsunit/es6/generators-objects.js b/deps/v8/test/mjsunit/es6/generators-objects.js index 9390776761..f304738841 100644 --- a/deps/v8/test/mjsunit/es6/generators-objects.js +++ b/deps/v8/test/mjsunit/es6/generators-objects.js @@ -59,18 +59,12 @@ function TestGeneratorObject() { assertEquals("[object Generator]", String(iter)); assertEquals([], Object.getOwnPropertyNames(iter)); assertTrue(iter !== g()); - - // g() is the same as new g(). - iter = new g(); - assertSame(g.prototype, Object.getPrototypeOf(iter)); - assertTrue(iter instanceof g); - assertEquals("Generator", %_ClassOf(iter)); - assertEquals("[object Generator]", String(iter)); assertEquals("[object Generator]", Object.prototype.toString.call(iter)); var gf = iter.__proto__.constructor; assertEquals("[object GeneratorFunction]", Object.prototype.toString.call(gf)); - assertEquals([], Object.getOwnPropertyNames(iter)); - assertTrue(iter !== new g()); + + // generators are not constructable. + assertThrows(()=>new g()); } TestGeneratorObject(); diff --git a/deps/v8/test/mjsunit/es6/generators-runtime.js b/deps/v8/test/mjsunit/es6/generators-runtime.js index 98015b7f7c..5c426b21fd 100644 --- a/deps/v8/test/mjsunit/es6/generators-runtime.js +++ b/deps/v8/test/mjsunit/es6/generators-runtime.js @@ -99,7 +99,7 @@ function TestGeneratorObjectPrototype() { assertSame(GeneratorObjectPrototype, Object.getPrototypeOf((function*(){yield 1}).prototype)); - var expected_property_names = ["next", "throw", "constructor"]; + var expected_property_names = ["next", "return", "throw", "constructor"]; var found_property_names = Object.getOwnPropertyNames(GeneratorObjectPrototype); diff --git a/deps/v8/test/mjsunit/es6/generators-states.js b/deps/v8/test/mjsunit/es6/generators-states.js index 0a2173a919..4e8c58029a 100644 --- a/deps/v8/test/mjsunit/es6/generators-states.js +++ b/deps/v8/test/mjsunit/es6/generators-states.js @@ -25,6 +25,7 @@ function* throwGenerator() { yield iter.throw(new Bar); } // Throw on a suspendedStart iterator. iter = nextGenerator(); assertThrows(function() { iter.throw(new Foo) }, Foo) +assertIteratorIsClosed(iter); assertThrows(function() { iter.throw(new Foo) }, Foo) assertIteratorIsClosed(iter); @@ -65,3 +66,29 @@ iter = (function* () { assertIteratorResult(3, false, iter.next()); assertIteratorResult(4, false, iter.next()); assertIteratorIsClosed(iter); + + +// A return that doesn't close. +{ + let g = function*() { try {return 42} finally {yield 43} }; + + let x = g(); + assertEquals({value: 43, done: false}, x.next()); + assertEquals({value: 42, done: true}, x.next()); +} +{ + let x; + let g = function*() { try {return 42} finally {x.throw(666)} }; + + x = g(); + assertThrows(() => x.next(), TypeError); // Still executing. +} +{ + let x; + let g = function*() { + try {return 42} finally {try {x.throw(666)} catch(e) {}} + }; + + x = g(); + assertEquals({value: 42, done: true}, x.next()); +} diff --git a/deps/v8/test/mjsunit/es6/hasinstance-symbol.js b/deps/v8/test/mjsunit/es6/hasinstance-symbol.js new file mode 100644 index 0000000000..6783d8deef --- /dev/null +++ b/deps/v8/test/mjsunit/es6/hasinstance-symbol.js @@ -0,0 +1,12 @@ +// Copyright 2016 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. + +// Verify that the hasInstance symbol is installed on function prototype. +// Test262 makes deeper tests. + +(function TestHasInstance() { + var a = Array(); + assertTrue(Array[Symbol.hasInstance](a)); + assertFalse(Function.prototype[Symbol.hasInstance].call()); +})(); diff --git a/deps/v8/test/mjsunit/es6/no-unicode-regexp-flag.js b/deps/v8/test/mjsunit/es6/no-unicode-regexp-flag.js index b56a4b56dd..035627c4d4 100644 --- a/deps/v8/test/mjsunit/es6/no-unicode-regexp-flag.js +++ b/deps/v8/test/mjsunit/es6/no-unicode-regexp-flag.js @@ -7,7 +7,7 @@ // mjsunit/es6/regexp-flags tests that the property is there when the // flag is on. -// Flags: --harmony-regexp +// Flags: --harmony-regexps --no-harmony-unicode-regexps 'use strict'; diff --git a/deps/v8/test/mjsunit/es6/object-assign.js b/deps/v8/test/mjsunit/es6/object-assign.js index d56cb0d1cf..1fec766dd1 100644 --- a/deps/v8/test/mjsunit/es6/object-assign.js +++ b/deps/v8/test/mjsunit/es6/object-assign.js @@ -138,3 +138,36 @@ assertSame(Object.assign(o, {}), o); assertThrows(function() { return Object.assign(target, source); }, ErrorB); assertEquals(log, "b"); })(); + +(function add_to_source() { + var target = {set k1(v) { source.k3 = 100; }}; + var source = {k1:10}; + Object.defineProperty(source, "k2", + {value: 20, enumerable: false, configurable: true}); + Object.assign(target, source); + assertEquals(undefined, target.k2); + assertEquals(undefined, target.k3); +})(); + +(function reconfigure_enumerable_source() { + var target = {set k1(v) { + Object.defineProperty(source, "k2", {value: 20, enumerable: true}); + }}; + var source = {k1:10}; + Object.defineProperty(source, "k2", + {value: 20, enumerable: false, configurable: true}); + Object.assign(target, source); + assertEquals(20, target.k2); +})(); + +(function propagate_assign_failure() { + var target = {set k1(v) { throw "fail" }}; + var source = {k1:10}; + assertThrows(()=>Object.assign(target, source)); +})(); + +(function propagate_read_failure() { + var target = {}; + var source = {get k1() { throw "fail" }}; + assertThrows(()=>Object.assign(target, source)); +})(); diff --git a/deps/v8/test/mjsunit/es6/object-literals-method.js b/deps/v8/test/mjsunit/es6/object-literals-method.js index e4527cb776..90bc51ec03 100644 --- a/deps/v8/test/mjsunit/es6/object-literals-method.js +++ b/deps/v8/test/mjsunit/es6/object-literals-method.js @@ -239,16 +239,14 @@ function assertIteratorResult(value, done, result) { })(); -(function TestGeneratorConstructable() { +(function TestGeneratorNotConstructable() { var object = { *method() { yield 1; } }; - var g = new object.method(); - assertIteratorResult(1, false, g.next()); - assertIteratorResult(undefined, true, g.next()); + assertThrows(()=>new object.method()); })(); diff --git a/deps/v8/test/mjsunit/es6/regexp-tolength.js b/deps/v8/test/mjsunit/es6/regexp-tolength.js index d9e967ba27..f7cfe928af 100644 --- a/deps/v8/test/mjsunit/es6/regexp-tolength.js +++ b/deps/v8/test/mjsunit/es6/regexp-tolength.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-tolength - 'use strict'; let regexp = /x/g; diff --git a/deps/v8/test/mjsunit/es6/regexp-tostring.js b/deps/v8/test/mjsunit/es6/regexp-tostring.js new file mode 100644 index 0000000000..3deeeb7ed8 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/regexp-tostring.js @@ -0,0 +1,46 @@ +// Copyright 2016 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 log = []; + +var fake = + { + get source() { + log.push("p"); + return { + toString: function() { + log.push("ps"); + return "pattern"; + } + }; + }, + get flags() { + log.push("f"); + return { + toString: function() { + log.push("fs"); + return "flags"; + } + }; + } + } + +function testThrows(x) { + try { + RegExp.prototype.toString.call(x); + } catch (e) { + assertTrue(/incompatible receiver/.test(e.message)); + return; + } + assertUnreachable(); +} + +testThrows(1); +testThrows(null); +Number.prototype.source = "a"; +Number.prototype.flags = "b"; +testThrows(1); + +assertEquals("/pattern/flags", RegExp.prototype.toString.call(fake)); +assertEquals(["p", "ps", "f", "fs"], log); diff --git a/deps/v8/test/mjsunit/es6/symbols.js b/deps/v8/test/mjsunit/es6/symbols.js index d502a83681..38338575a0 100644 --- a/deps/v8/test/mjsunit/es6/symbols.js +++ b/deps/v8/test/mjsunit/es6/symbols.js @@ -441,8 +441,9 @@ TestGetOwnPropertySymbolsWithProto() function TestWellKnown() { var symbols = [ + "hasInstance", // TODO(rossberg): reactivate once implemented. - // "hasInstance", "isConcatSpreadable", "isRegExp", + // "isConcatSpreadable", "isRegExp", "iterator", /* "toStringTag", */ "unscopables" ] diff --git a/deps/v8/test/mjsunit/es6/tail-call-megatest.js b/deps/v8/test/mjsunit/es6/tail-call-megatest.js new file mode 100644 index 0000000000..005796195a --- /dev/null +++ b/deps/v8/test/mjsunit/es6/tail-call-megatest.js @@ -0,0 +1,292 @@ +// Copyright 2016 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 --harmony-tailcalls --no-turbo-inlining + + +Error.prepareStackTrace = (error,stack) => { + error.strace = stack; + return error.message + "\n at " + stack.join("\n at "); +} + + +function CheckStackTrace(expected) { + var e = new Error(); + e.stack; // prepare stack trace + var stack = e.strace; + assertEquals("CheckStackTrace", stack[0].getFunctionName()); + for (var i = 0; i < expected.length; i++) { + assertEquals(expected[i].name, stack[i + 1].getFunctionName()); + } +} +%NeverOptimizeFunction(CheckStackTrace); + + +function CheckArguments(expected, args) { + args = Array.prototype.slice.call(args); + assertEquals(expected, args); +} +%NeverOptimizeFunction(CheckArguments); + + +var CAN_INLINE_COMMENT = "// Let it be inlined."; +var DONT_INLINE_COMMENT = (function() { + var line = "// Don't inline. Don't inline. Don't inline. Don't inline."; + for (var i = 0; i < 4; i++) { + line += "\n " + line; + } + return line; +})(); + + +function ident_source(source, ident) { + ident = " ".repeat(ident); + return ident + source.replace(/\n/gi, "\n" + ident); +} + +var global = Function('return this')(); +var the_receiver = {receiver: 1}; + +function run_tests() { + function inlinable_comment(inlinable) { + return inlinable ? CAN_INLINE_COMMENT : DONT_INLINE_COMMENT; + } + + var f_cfg_sloppy = { + func_name: 'f', + source_template: function(cfg) { + var receiver = cfg.f_receiver != undefined ? cfg.f_receiver + : "global"; + var lines = [ + `function f(a) {`, + ` ${inlinable_comment(cfg.f_inlinable)}`, + ` assertEquals(${receiver}, this);`, + ` CheckArguments([${cfg.f_args}], arguments);`, + ` CheckStackTrace([f, test]);`, + ` %DeoptimizeNow();`, + ` CheckArguments([${cfg.f_args}], arguments);`, + ` CheckStackTrace([f, test]);`, + ` return 42;`, + `}`, + ]; + return lines.join("\n"); + }, + }; + + var f_cfg_strict = { + func_name: 'f', + source_template: function(cfg) { + var receiver = cfg.f_receiver != undefined ? cfg.f_receiver + : "undefined"; + var lines = [ + `function f(a) {`, + ` "use strict";`, + ` ${inlinable_comment(cfg.f_inlinable)}`, + ` assertEquals(${receiver}, this);`, + ` CheckArguments([${cfg.f_args}], arguments);`, + ` CheckStackTrace([f, test]);`, + ` %DeoptimizeNow();`, + ` CheckArguments([${cfg.f_args}], arguments);`, + ` CheckStackTrace([f, test]);`, + ` return 42;`, + `}`, + ]; + return lines.join("\n"); + }, + }; + + var f_cfg_possibly_eval = { + func_name: 'eval', + source_template: function(cfg) { + var receiver = cfg.f_receiver != undefined ? cfg.f_receiver + : "global"; + var lines = [ + `function f(a) {`, + ` ${inlinable_comment(cfg.f_inlinable)}`, + ` assertEquals(${receiver}, this);`, + ` CheckArguments([${cfg.f_args}], arguments);`, + ` CheckStackTrace([f, test]);`, + ` %DeoptimizeNow();`, + ` CheckArguments([${cfg.f_args}], arguments);`, + ` CheckStackTrace([f, test]);`, + ` return 42;`, + `}`, + `var eval = f;`, + ]; + return lines.join("\n"); + }, + }; + + var f_cfg_bound = { + func_name: 'bound', + source_template: function(cfg) { + var lines = [ + `function f(a) {`, + ` "use strict";`, + ` ${inlinable_comment(cfg.f_inlinable)}`, + ` assertEquals(receiver, this);`, + ` CheckArguments([${cfg.f_args}], arguments);`, + ` CheckStackTrace([f, test]);`, + ` %DeoptimizeNow();`, + ` CheckArguments([${cfg.f_args}], arguments);`, + ` CheckStackTrace([f, test]);`, + ` return 42;`, + `}`, + `var receiver = {a: 153};`, + `var bound = f.bind(receiver);`, + ]; + return lines.join("\n"); + }, + }; + + var f_cfg_proxy = { + func_name: 'p', + source_template: function(cfg) { + var receiver = cfg.f_receiver != undefined ? cfg.f_receiver + : "global"; + var lines = [ + `function f(a) {`, + ` ${inlinable_comment(cfg.f_inlinable)}`, + ` assertEquals(${receiver}, this);`, + ` CheckArguments([${cfg.f_args}], arguments);`, + ` CheckStackTrace([f, test]);`, + ` %DeoptimizeNow();`, + ` CheckArguments([${cfg.f_args}], arguments);`, + ` CheckStackTrace([f, test]);`, + ` return 42;`, + `}`, + `var p = new Proxy(f, {});`, + ]; + return lines.join("\n"); + }, + }; + + var g_cfg_normal = { + receiver: undefined, + source_template: function(cfg) { + var lines = [ + `function g(a) {`, + ` "use strict";`, + ` ${inlinable_comment(cfg.g_inlinable)}`, + ` CheckArguments([${cfg.g_args}], arguments);`, + ` return ${cfg.f_name}(${cfg.f_args});`, + `}`, + ]; + return lines.join("\n"); + }, + }; + + + var g_cfg_function_apply = { + receiver: "the_receiver", + source_template: function(cfg) { + var lines = [ + `function g(a) {`, + ` "use strict";`, + ` ${inlinable_comment(cfg.g_inlinable)}`, + ` CheckArguments([${cfg.g_args}], arguments);`, + ` return ${cfg.f_name}.apply(the_receiver, [${cfg.f_args}]);`, + `}`, + ]; + return lines.join("\n"); + }, + }; + + + var g_cfg_function_call = { + receiver: "the_receiver", + source_template: function(cfg) { + var f_args = "the_receiver"; + if (cfg.f_args !== "") f_args += ", "; + f_args += cfg.f_args; + + var lines = [ + `function g(a) {`, + ` "use strict";`, + ` ${inlinable_comment(cfg.g_inlinable)}`, + ` CheckArguments([${cfg.g_args}], arguments);`, + ` return ${cfg.f_name}.call(${f_args});`, + `}`, + ]; + return lines.join("\n"); + }, + }; + + + function test_template(cfg) { + var f_source = cfg.f_source_template(cfg); + var g_source = cfg.g_source_template(cfg); + f_source = ident_source(f_source, 2); + g_source = ident_source(g_source, 2); + + var lines = [ + `(function() {`, + f_source, + g_source, + ` function test() {`, + ` "use strict";`, + ` assertEquals(42, g(${cfg.g_args}));`, + ` }`, + ` ${cfg.f_inlinable ? "%SetForceInlineFlag(f)" : ""};`, + ` ${cfg.g_inlinable ? "%SetForceInlineFlag(g)" : ""};`, + ``, + ` test();`, + ` %OptimizeFunctionOnNextCall(test);`, + ` %OptimizeFunctionOnNextCall(f);`, + ` %OptimizeFunctionOnNextCall(g);`, + ` test();`, + `})();`, + ``, + ]; + var source = lines.join("\n"); + return source; + } + + // TODO(v8:4698), TODO(ishell): support all commented cases. + var f_args_variants = ["", "1", "1, 2"]; + var g_args_variants = [/*"",*/ "10", /*"10, 20"*/]; + var f_inlinable_variants = [/*true,*/ false]; + var g_inlinable_variants = [true, false]; + var f_variants = [ + f_cfg_sloppy, + f_cfg_strict, + f_cfg_bound, + f_cfg_proxy, + f_cfg_possibly_eval, + ]; + var g_variants = [ + g_cfg_normal, + g_cfg_function_call, + g_cfg_function_apply, + ]; + + f_variants.forEach((f_cfg) => { + g_variants.forEach((g_cfg) => { + f_args_variants.forEach((f_args) => { + g_args_variants.forEach((g_args) => { + f_inlinable_variants.forEach((f_inlinable) => { + g_inlinable_variants.forEach((g_inlinable) => { + var cfg = { + f_source_template: f_cfg.source_template, + f_inlinable, + f_args, + f_name: f_cfg.func_name, + f_receiver: g_cfg.receiver, + g_source_template: g_cfg.source_template, + g_inlinable, + g_args, + }; + var source = test_template(cfg); + print("===================="); + print(source); + eval(source); + }); + }); + }); + }); + }); + }); +} + +run_tests(); diff --git a/deps/v8/test/mjsunit/es6/tail-call-proxies.js b/deps/v8/test/mjsunit/es6/tail-call-proxies.js new file mode 100644 index 0000000000..25f9fcfbe7 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/tail-call-proxies.js @@ -0,0 +1,97 @@ +// Copyright 2016 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 --harmony-tailcalls --harmony-proxies +"use strict"; + +Error.prepareStackTrace = (e,s) => s; + +function CheckStackTrace(expected) { + var stack = (new Error()).stack; + assertEquals("CheckStackTrace", stack[0].getFunctionName()); + for (var i = 0; i < expected.length; i++) { + assertEquals(expected[i].name, stack[i + 1].getFunctionName()); + } +} + + +// Tail call proxy function when caller does not have an arguments +// adaptor frame. +(function test() { + // Caller and callee have same number of arguments. + function f1(a) { + CheckStackTrace([f1, test]); + return 10 + a; + } + var p1 = new Proxy(f1, {}); + function g1(a) { return p1(2); } + assertEquals(12, g1(1)); + + // Caller has more arguments than callee. + function f2(a) { + CheckStackTrace([f2, test]); + return 10 + a; + } + var p2 = new Proxy(f2, {}); + function g2(a, b, c) { return p2(2); } + assertEquals(12, g2(1, 2, 3)); + + // Caller has less arguments than callee. + function f3(a, b, c) { + CheckStackTrace([f3, test]); + return 10 + a + b + c; + } + var p3 = new Proxy(f3, {}); + function g3(a) { return p3(2, 3, 4); } + assertEquals(19, g3(1)); + + // Callee has arguments adaptor frame. + function f4(a, b, c) { + CheckStackTrace([f4, test]); + return 10 + a; + } + var p4 = new Proxy(f4, {}); + function g4(a) { return p4(2); } + assertEquals(12, g4(1)); +})(); + + +// Tail call proxy function when caller has an arguments adaptor frame. +(function test() { + // Caller and callee have same number of arguments. + function f1(a) { + CheckStackTrace([f1, test]); + return 10 + a; + } + var p1 = new Proxy(f1, {}); + function g1(a) { return p1(2); } + assertEquals(12, g1()); + + // Caller has more arguments than callee. + function f2(a) { + CheckStackTrace([f2, test]); + return 10 + a; + } + var p2 = new Proxy(f2, {}); + function g2(a, b, c) { return p2(2); } + assertEquals(12, g2()); + + // Caller has less arguments than callee. + function f3(a, b, c) { + CheckStackTrace([f3, test]); + return 10 + a + b + c; + } + var p3 = new Proxy(f3, {}); + function g3(a) { return p3(2, 3, 4); } + assertEquals(19, g3()); + + // Callee has arguments adaptor frame. + function f4(a, b, c) { + CheckStackTrace([f4, test]); + return 10 + a; + } + var p4 = new Proxy(f4, {}); + function g4(a) { return p4(2); } + assertEquals(12, g4()); +})(); diff --git a/deps/v8/test/mjsunit/es6/tail-call-simple.js b/deps/v8/test/mjsunit/es6/tail-call-simple.js new file mode 100644 index 0000000000..d2890b0212 --- /dev/null +++ b/deps/v8/test/mjsunit/es6/tail-call-simple.js @@ -0,0 +1,107 @@ +// Copyright 2016 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 --harmony-tailcalls --stack-size=100 + +// +// Tail calls work only in strict mode. +// +(function() { + function f(n) { + if (n <= 0) { + return "foo"; + } + return f(n - 1); + } + assertThrows(()=>{ f(1e5) }); + %OptimizeFunctionOnNextCall(f); + assertThrows(()=>{ f(1e5) }); +})(); + + +// +// Tail call normal functions. +// +(function() { + "use strict"; + function f(n) { + if (n <= 0) { + return "foo"; + } + return f(n - 1); + } + assertEquals("foo", f(1e5)); + %OptimizeFunctionOnNextCall(f); + assertEquals("foo", f(1e5)); +})(); + + +(function() { + "use strict"; + function f(n){ + if (n <= 0) { + return "foo"; + } + return g(n - 1); + } + function g(n){ + if (n <= 0) { + return "bar"; + } + return f(n - 1); + } + assertEquals("foo", f(1e5)); + assertEquals("bar", f(1e5 + 1)); + %OptimizeFunctionOnNextCall(f); + assertEquals("foo", f(1e5)); + assertEquals("bar", f(1e5 + 1)); +})(); + + +// +// Tail call bound functions. +// +(function() { + "use strict"; + function f0(n) { + if (n <= 0) { + return "foo"; + } + return f_bound(n - 1); + } + var f_bound = f0.bind({}); + function f(n) { + return f_bound(n); + } + assertEquals("foo", f(1e5)); + %OptimizeFunctionOnNextCall(f); + assertEquals("foo", f(1e5)); +})(); + + +(function() { + "use strict"; + function f0(n){ + if (n <= 0) { + return "foo"; + } + return g_bound(n - 1); + } + function g0(n){ + if (n <= 0) { + return "bar"; + } + return f_bound(n - 1); + } + var f_bound = f0.bind({}); + var g_bound = g0.bind({}); + function f(n) { + return f_bound(n); + } + assertEquals("foo", f(1e5)); + assertEquals("bar", f(1e5 + 1)); + %OptimizeFunctionOnNextCall(f); + assertEquals("foo", f(1e5)); + assertEquals("bar", f(1e5 + 1)); +})(); diff --git a/deps/v8/test/mjsunit/es6/tail-call.js b/deps/v8/test/mjsunit/es6/tail-call.js new file mode 100644 index 0000000000..e9539c37ba --- /dev/null +++ b/deps/v8/test/mjsunit/es6/tail-call.js @@ -0,0 +1,386 @@ +// Copyright 2016 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 --harmony-tailcalls +"use strict"; + +Error.prepareStackTrace = (error,stack) => { + error.strace = stack; + return error.message + "\n at " + stack.join("\n at "); +} + + +function CheckStackTrace(expected) { + var e = new Error(); + e.stack; // prepare stack trace + var stack = e.strace; + assertEquals("CheckStackTrace", stack[0].getFunctionName()); + for (var i = 0; i < expected.length; i++) { + assertEquals(expected[i].name, stack[i + 1].getFunctionName()); + } +} + +function f(expected_call_stack, a, b) { + CheckStackTrace(expected_call_stack); + return a; +} + +function f_153(expected_call_stack, a) { + CheckStackTrace(expected_call_stack); + return 153; +} + + +// Tail call when caller does not have an arguments adaptor frame. +(function() { + // Caller and callee have same number of arguments. + function f1(a) { + CheckStackTrace([f1, test]); + return 10 + a; + } + function g1(a) { return f1(2); } + + // Caller has more arguments than callee. + function f2(a) { + CheckStackTrace([f2, test]); + return 10 + a; + } + function g2(a, b, c) { return f2(2); } + + // Caller has less arguments than callee. + function f3(a, b, c) { + CheckStackTrace([f3, test]); + return 10 + a + b + c; + } + function g3(a) { return f3(2, 3, 4); } + + // Callee has arguments adaptor frame. + function f4(a, b, c) { + CheckStackTrace([f4, test]); + return 10 + a; + } + function g4(a) { return f4(2); } + + function test() { + assertEquals(12, g1(1)); + assertEquals(12, g2(1, 2, 3)); + assertEquals(19, g3(1)); + assertEquals(12, g4(1)); + } + test(); + %OptimizeFunctionOnNextCall(test); + test(); +})(); + + +// Tail call when caller has an arguments adaptor frame. +(function() { + // Caller and callee have same number of arguments. + function f1(a) { + CheckStackTrace([f1, test]); + return 10 + a; + } + function g1(a) { return f1(2); } + + // Caller has more arguments than callee. + function f2(a) { + CheckStackTrace([f2, test]); + return 10 + a; + } + function g2(a, b, c) { return f2(2); } + + // Caller has less arguments than callee. + function f3(a, b, c) { + CheckStackTrace([f3, test]); + return 10 + a + b + c; + } + function g3(a) { return f3(2, 3, 4); } + + // Callee has arguments adaptor frame. + function f4(a, b, c) { + CheckStackTrace([f4, test]); + return 10 + a; + } + function g4(a) { return f4(2); } + + function test() { + assertEquals(12, g1()); + assertEquals(12, g2()); + assertEquals(19, g3()); + assertEquals(12, g4()); + } + test(); + %OptimizeFunctionOnNextCall(test); + test(); +})(); + + +// Tail call bound function when caller does not have an arguments +// adaptor frame. +(function() { + // Caller and callee have same number of arguments. + function f1(a) { + assertEquals(153, this.a); + CheckStackTrace([f1, test]); + return 10 + a; + } + var b1 = f1.bind({a: 153}); + function g1(a) { return b1(2); } + + // Caller has more arguments than callee. + function f2(a) { + assertEquals(153, this.a); + CheckStackTrace([f2, test]); + return 10 + a; + } + var b2 = f2.bind({a: 153}); + function g2(a, b, c) { return b2(2); } + + // Caller has less arguments than callee. + function f3(a, b, c) { + assertEquals(153, this.a); + CheckStackTrace([f3, test]); + return 10 + a + b + c; + } + var b3 = f3.bind({a: 153}); + function g3(a) { return b3(2, 3, 4); } + + // Callee has arguments adaptor frame. + function f4(a, b, c) { + assertEquals(153, this.a); + CheckStackTrace([f4, test]); + return 10 + a; + } + var b4 = f4.bind({a: 153}); + function g4(a) { return b4(2); } + + function test() { + assertEquals(12, g1(1)); + assertEquals(12, g2(1, 2, 3)); + assertEquals(19, g3(1)); + assertEquals(12, g4(1)); + } + test(); + %OptimizeFunctionOnNextCall(test); + test(); +})(); + + +// Tail call bound function when caller has an arguments adaptor frame. +(function() { + // Caller and callee have same number of arguments. + function f1(a) { + assertEquals(153, this.a); + CheckStackTrace([f1, test]); + return 10 + a; + } + var b1 = f1.bind({a: 153}); + function g1(a) { return b1(2); } + + // Caller has more arguments than callee. + function f2(a) { + assertEquals(153, this.a); + CheckStackTrace([f2, test]); + return 10 + a; + } + var b2 = f2.bind({a: 153}); + function g2(a, b, c) { return b2(2); } + + // Caller has less arguments than callee. + function f3(a, b, c) { + assertEquals(153, this.a); + CheckStackTrace([f3, test]); + return 10 + a + b + c; + } + var b3 = f3.bind({a: 153}); + function g3(a) { return b3(2, 3, 4); } + + // Callee has arguments adaptor frame. + function f4(a, b, c) { + assertEquals(153, this.a); + CheckStackTrace([f4, test]); + return 10 + a; + } + var b4 = f4.bind({a: 153}); + function g4(a) { return b4(2); } + + function test() { + assertEquals(12, g1()); + assertEquals(12, g2()); + assertEquals(19, g3()); + assertEquals(12, g4()); + } + test(); + %OptimizeFunctionOnNextCall(test); + test(); +})(); + + +// Tail calling via various expressions. +(function() { + function g1(a) { + return f([f, g1, test], false) || f([f, test], true); + } + + function g2(a) { + return f([f, g2, test], true) && f([f, test], true); + } + + function g3(a) { + return f([f, g3, test], 13), f([f, test], 153); + } + + function test() { + assertEquals(true, g1()); + assertEquals(true, g2()); + assertEquals(153, g3()); + } + test(); + %OptimizeFunctionOnNextCall(test); + test(); +})(); + + +// Test tail calls from try-catch constructs. +(function() { + function tc1(a) { + try { + f_153([f_153, tc1, test]); + return f_153([f_153, tc1, test]); + } catch(e) { + f_153([f_153, tc1, test]); + } + } + + function tc2(a) { + try { + f_153([f_153, tc2, test]); + throw new Error("boom"); + } catch(e) { + f_153([f_153, tc2, test]); + return f_153([f_153, test]); + } + } + + function tc3(a) { + try { + f_153([f_153, tc3, test]); + throw new Error("boom"); + } catch(e) { + f_153([f_153, tc3, test]); + } + f_153([f_153, tc3, test]); + return f_153([f_153, test]); + } + + function test() { + assertEquals(153, tc1()); + assertEquals(153, tc2()); + assertEquals(153, tc3()); + } + test(); + %OptimizeFunctionOnNextCall(test); + test(); +})(); + + +// Test tail calls from try-finally constructs. +(function() { + function tf1(a) { + try { + f_153([f_153, tf1, test]); + return f_153([f_153, tf1, test]); + } finally { + f_153([f_153, tf1, test]); + } + } + + function tf2(a) { + try { + f_153([f_153, tf2, test]); + throw new Error("boom"); + } finally { + f_153([f_153, tf2, test]); + return f_153([f_153, test]); + } + } + + function tf3(a) { + try { + f_153([f_153, tf3, test]); + } finally { + f_153([f_153, tf3, test]); + } + return f_153([f_153, test]); + } + + function test() { + assertEquals(153, tf1()); + assertEquals(153, tf2()); + assertEquals(153, tf3()); + } + test(); + %OptimizeFunctionOnNextCall(test); + test(); +})(); + + +// Test tail calls from try-catch-finally constructs. +(function() { + function tcf1(a) { + try { + f_153([f_153, tcf1, test]); + return f_153([f_153, tcf1, test]); + } catch(e) { + } finally { + f_153([f_153, tcf1, test]); + } + } + + function tcf2(a) { + try { + f_153([f_153, tcf2, test]); + throw new Error("boom"); + } catch(e) { + f_153([f_153, tcf2, test]); + return f_153([f_153, tcf2, test]); + } finally { + f_153([f_153, tcf2, test]); + } + } + + function tcf3(a) { + try { + f_153([f_153, tcf3, test]); + throw new Error("boom"); + } catch(e) { + f_153([f_153, tcf3, test]); + } finally { + f_153([f_153, tcf3, test]); + return f_153([f_153, test]); + } + } + + function tcf4(a) { + try { + f_153([f_153, tcf4, test]); + throw new Error("boom"); + } catch(e) { + f_153([f_153, tcf4, test]); + } finally { + f_153([f_153, tcf4, test]); + } + return f_153([f_153, test]); + } + + function test() { + assertEquals(153, tcf1()); + assertEquals(153, tcf2()); + assertEquals(153, tcf3()); + assertEquals(153, tcf4()); + } + test(); + %OptimizeFunctionOnNextCall(test); + test(); +})(); diff --git a/deps/v8/test/mjsunit/es6/typedarray.js b/deps/v8/test/mjsunit/es6/typedarray.js index c43ba1c4bf..e6a949ca59 100644 --- a/deps/v8/test/mjsunit/es6/typedarray.js +++ b/deps/v8/test/mjsunit/es6/typedarray.js @@ -529,6 +529,8 @@ function TestTypedArraySet() { assertThrows(function() { a.set(0); }, TypeError); assertThrows(function() { a.set(0, 1); }, TypeError); + + assertEquals(1, a.set.length); } TestTypedArraySet(); @@ -672,7 +674,6 @@ function TestDataViewConstructor() { // error cases assertThrows(function() { new DataView(ab, -1); }, RangeError); - assertThrows(function() { new DataView(ab, 1, -1); }, RangeError); assertThrows(function() { new DataView(); }, TypeError); assertThrows(function() { new DataView([]); }, TypeError); assertThrows(function() { new DataView(ab, 257); }, RangeError); @@ -693,6 +694,19 @@ function TestDataViewPropertyTypeChecks() { CheckProperty("buffer"); CheckProperty("byteOffset"); CheckProperty("byteLength"); + + function CheckGetSetLength(name) { + assertEquals(1, DataView.prototype["get" + name].length); + assertEquals(2, DataView.prototype["set" + name].length); + } + CheckGetSetLength("Int8"); + CheckGetSetLength("Uint8"); + CheckGetSetLength("Int16"); + CheckGetSetLength("Uint16"); + CheckGetSetLength("Int32"); + CheckGetSetLength("Uint32"); + CheckGetSetLength("Float32"); + CheckGetSetLength("Float64"); } diff --git a/deps/v8/test/mjsunit/for-in-opt.js b/deps/v8/test/mjsunit/for-in-opt.js index e458e1d537..8f73539382 100644 --- a/deps/v8/test/mjsunit/for-in-opt.js +++ b/deps/v8/test/mjsunit/for-in-opt.js @@ -28,13 +28,14 @@ var deopt_has = false; var deopt_enum = false; var handler = { - enumerate(target) { + ownKeys() { if (deopt_enum) { %DeoptimizeFunction(f2); deopt_enum = false; } - return keys[Symbol.iterator](); + return keys; }, + getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }}, has(target, k) { if (deopt_has) { @@ -42,7 +43,7 @@ var handler = { deopt_has = false; } has_keys.push(k); - return {value: 10, configurable: true, writable: false, enumerable: true}; + return true; } }; @@ -67,7 +68,7 @@ function check_f2() { check_f2(); check_f2(); -// Test lazy deopt after GetPropertyNamesFast +// Test lazy deopt after ForInEnumerate %OptimizeFunctionOnNextCall(f2); deopt_enum = true; check_f2(); @@ -136,14 +137,13 @@ function listener(event, exec_state, event_data, data) { } var handler3 = { - enumerate(target) { - return ["a", "b"][Symbol.iterator](); - }, + ownKeys() { return ["a", "b"] }, + getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }}, has(target, k) { if (k == "a") count++; if (x) %ScheduleBreak(); - return {value: 10, configurable: true, writable: false, enumerable: true}; + return true; } }; diff --git a/deps/v8/test/mjsunit/function-caller.js b/deps/v8/test/mjsunit/function-caller.js index a2c54bbfd3..84f3cbed2f 100644 --- a/deps/v8/test/mjsunit/function-caller.js +++ b/deps/v8/test/mjsunit/function-caller.js @@ -47,7 +47,8 @@ f(null); eval('f(null)'); // Check called from strict builtin functions. -[null, null].sort(f); +// [null, null].sort(f); // Does not work because sort tail calls. +[null].forEach(f, null); // Check called from sloppy builtin functions. "abel".replace(/b/g, function h() { diff --git a/deps/v8/test/mjsunit/function-names.js b/deps/v8/test/mjsunit/function-names.js index 5ed0b794e8..6df31b900a 100644 --- a/deps/v8/test/mjsunit/function-names.js +++ b/deps/v8/test/mjsunit/function-names.js @@ -65,10 +65,11 @@ var datePrototypeFunctions = [ "getTimezoneOffset", "setTime", "setMilliseconds", "setUTCMilliseconds", "setSeconds", "setUTCSeconds", "setMinutes", "setUTCMinutes", "setHours", "setUTCHours", "setDate", "setUTCDate", - "setMonth", "setUTCMonth", "setFullYear", "setUTCFullYear", "toGMTString", + "setMonth", "setUTCMonth", "setFullYear", "setUTCFullYear", "toUTCString", "getYear", "setYear"]; TestFunctionNames(Date.prototype, datePrototypeFunctions); +assertEquals(Date.prototype.toGMTString, Date.prototype.toUTCString); // Function.prototype functions. diff --git a/deps/v8/test/mjsunit/harmony/array-species-constructor-delete.js b/deps/v8/test/mjsunit/harmony/array-species-constructor-delete.js new file mode 100644 index 0000000000..e61d0ddebf --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/array-species-constructor-delete.js @@ -0,0 +1,28 @@ +// Copyright 2016 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-species + +// Overwriting the constructor of an instance updates the protector + +let x = []; + +assertEquals(Array, x.map(()=>{}).constructor); +assertEquals(Array, x.filter(()=>{}).constructor); +assertEquals(Array, x.slice().constructor); +assertEquals(Array, x.splice().constructor); +assertEquals(Array, x.concat([1]).constructor); +assertEquals(1, x.concat([1])[0]); + +class MyArray extends Array { } + +Object.prototype.constructor = MyArray; +delete Array.prototype.constructor; + +assertEquals(MyArray, x.map(()=>{}).constructor); +assertEquals(MyArray, x.filter(()=>{}).constructor); +assertEquals(MyArray, x.slice().constructor); +assertEquals(MyArray, x.splice().constructor); +assertEquals(MyArray, x.concat([1]).constructor); +assertEquals(1, x.concat([1])[0]); diff --git a/deps/v8/test/mjsunit/harmony/array-species-constructor.js b/deps/v8/test/mjsunit/harmony/array-species-constructor.js new file mode 100644 index 0000000000..d4eeefa010 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/array-species-constructor.js @@ -0,0 +1,27 @@ +// Copyright 2016 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-species + +// Overwriting the constructor of an instance updates the protector + +let x = []; + +assertEquals(Array, x.map(()=>{}).constructor); +assertEquals(Array, x.filter(()=>{}).constructor); +assertEquals(Array, x.slice().constructor); +assertEquals(Array, x.splice().constructor); +assertEquals(Array, x.concat([1]).constructor); +assertEquals(1, x.concat([1])[0]); + +class MyArray extends Array { } + +x.constructor = MyArray; + +assertEquals(MyArray, x.map(()=>{}).constructor); +assertEquals(MyArray, x.filter(()=>{}).constructor); +assertEquals(MyArray, x.slice().constructor); +assertEquals(MyArray, x.splice().constructor); +assertEquals(MyArray, x.concat([1]).constructor); +assertEquals(1, x.concat([1])[0]); diff --git a/deps/v8/test/mjsunit/harmony/array-species-delete.js b/deps/v8/test/mjsunit/harmony/array-species-delete.js new file mode 100644 index 0000000000..bccf3a4df9 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/array-species-delete.js @@ -0,0 +1,28 @@ +// Copyright 2016 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-species + +// Overwriting the constructor of an instance updates the protector + +let x = []; + +assertEquals(Array, x.map(()=>{}).constructor); +assertEquals(Array, x.filter(()=>{}).constructor); +assertEquals(Array, x.slice().constructor); +assertEquals(Array, x.splice().constructor); +assertEquals(Array, x.concat([1]).constructor); +assertEquals(1, x.concat([1])[0]); + +class MyArray extends Array { } + +Object.prototype[Symbol.species] = MyArray; +delete Array[Symbol.species]; + +assertEquals(MyArray, x.map(()=>{}).constructor); +assertEquals(MyArray, x.filter(()=>{}).constructor); +assertEquals(MyArray, x.slice().constructor); +assertEquals(MyArray, x.splice().constructor); +assertEquals(MyArray, x.concat([1]).constructor); +assertEquals(1, x.concat([1])[0]); diff --git a/deps/v8/test/mjsunit/harmony/array-species-modified.js b/deps/v8/test/mjsunit/harmony/array-species-modified.js new file mode 100644 index 0000000000..b5c5c16d7b --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/array-species-modified.js @@ -0,0 +1,27 @@ +// Copyright 2016 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-species + +// Overwriting Array[Symbol.species] updates the protector + +let x = []; + +assertEquals(Array, x.map(()=>{}).constructor); +assertEquals(Array, x.filter(()=>{}).constructor); +assertEquals(Array, x.slice().constructor); +assertEquals(Array, x.splice().constructor); +assertEquals(Array, x.concat([1]).constructor); +assertEquals(1, x.concat([1])[0]); + +class MyArray extends Array { } + +Object.defineProperty(Array, Symbol.species, {value: MyArray}); + +assertEquals(MyArray, x.map(()=>{}).constructor); +assertEquals(MyArray, x.filter(()=>{}).constructor); +assertEquals(MyArray, x.slice().constructor); +assertEquals(MyArray, x.splice().constructor); +assertEquals(MyArray, x.concat([1]).constructor); +assertEquals(1, x.concat([1])[0]); diff --git a/deps/v8/test/mjsunit/harmony/array-species-parent-constructor.js b/deps/v8/test/mjsunit/harmony/array-species-parent-constructor.js new file mode 100644 index 0000000000..8ea59bcfe4 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/array-species-parent-constructor.js @@ -0,0 +1,27 @@ +// Copyright 2016 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-species + +// Overwriting Array.prototype.constructor updates the protector + +let x = []; + +assertEquals(Array, x.map(()=>{}).constructor); +assertEquals(Array, x.filter(()=>{}).constructor); +assertEquals(Array, x.slice().constructor); +assertEquals(Array, x.splice().constructor); +assertEquals(Array, x.concat([1]).constructor); +assertEquals(1, x.concat([1])[0]); + +class MyArray extends Array { } + +Array.prototype.constructor = MyArray; + +assertEquals(MyArray, x.map(()=>{}).constructor); +assertEquals(MyArray, x.filter(()=>{}).constructor); +assertEquals(MyArray, x.slice().constructor); +assertEquals(MyArray, x.splice().constructor); +assertEquals(MyArray, x.concat([1]).constructor); +assertEquals(1, x.concat([1])[0]); diff --git a/deps/v8/test/mjsunit/harmony/array-species-proto.js b/deps/v8/test/mjsunit/harmony/array-species-proto.js new file mode 100644 index 0000000000..077b3f5a17 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/array-species-proto.js @@ -0,0 +1,27 @@ +// Copyright 2016 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-species + +// Overwriting an array instance's __proto__ updates the protector + +let x = []; + +assertEquals(Array, x.map(()=>{}).constructor); +assertEquals(Array, x.filter(()=>{}).constructor); +assertEquals(Array, x.slice().constructor); +assertEquals(Array, x.splice().constructor); +assertEquals(Array, x.concat([1]).constructor); +assertEquals(1, x.concat([1])[0]); + +class MyArray extends Array { } + +x.__proto__ = MyArray.prototype; + +assertEquals(MyArray, x.map(()=>{}).constructor); +assertEquals(MyArray, x.filter(()=>{}).constructor); +assertEquals(MyArray, x.slice().constructor); +assertEquals(MyArray, x.splice().constructor); +assertEquals(MyArray, x.concat([1]).constructor); +assertEquals(1, x.concat([1])[0]); diff --git a/deps/v8/test/mjsunit/harmony/array-species.js b/deps/v8/test/mjsunit/harmony/array-species.js index 75a45aaf59..3cef50cc4c 100644 --- a/deps/v8/test/mjsunit/harmony/array-species.js +++ b/deps/v8/test/mjsunit/harmony/array-species.js @@ -16,6 +16,8 @@ assertEquals(MyArray, new MyArray().map(()=>{}).constructor); assertEquals(MyArray, new MyArray().filter(()=>{}).constructor); assertEquals(MyArray, new MyArray().slice().constructor); assertEquals(MyArray, new MyArray().splice().constructor); +assertEquals(MyArray, new MyArray().concat([1]).constructor); +assertEquals(1, new MyArray().concat([1])[0]); // Subclasses can override @@species to return the another class @@ -27,6 +29,7 @@ assertEquals(MyArray, new MyOtherArray().map(()=>{}).constructor); assertEquals(MyArray, new MyOtherArray().filter(()=>{}).constructor); assertEquals(MyArray, new MyOtherArray().slice().constructor); assertEquals(MyArray, new MyOtherArray().splice().constructor); +assertEquals(MyArray, new MyOtherArray().concat().constructor); // Array methods on non-arrays return arrays @@ -44,11 +47,15 @@ assertEquals(MyObject, Array.prototype.slice.call(new MyNonArray()).constructor); assertEquals(MyObject, Array.prototype.splice.call(new MyNonArray()).constructor); +assertEquals(MyObject, + Array.prototype.concat.call(new MyNonArray()).constructor); assertEquals(undefined, Array.prototype.map.call(new MyNonArray(), ()=>{}).length); assertEquals(undefined, Array.prototype.filter.call(new MyNonArray(), ()=>{}).length); +assertEquals(undefined, + Array.prototype.concat.call(new MyNonArray(), ()=>{}).length); // slice and splice actually do explicitly define the length for some reason assertEquals(0, Array.prototype.slice.call(new MyNonArray()).length); assertEquals(0, Array.prototype.splice.call(new MyNonArray()).length); @@ -61,6 +68,9 @@ assertEquals(Array, Realm.eval(realm, "[]"), ()=>{}).constructor); assertFalse(Array === Realm.eval(realm, "[]").map(()=>{}).constructor); assertFalse(Array === Realm.eval(realm, "[].map(()=>{}).constructor")); +assertEquals(Array, + Array.prototype.concat.call( + Realm.eval(realm, "[]")).constructor); // Defaults when constructor or @@species is missing or non-constructor @@ -74,6 +84,7 @@ assertEquals(MyOtherDefaultArray, new MyOtherDefaultArray().map(()=>{}).constructor); MyOtherDefaultArray.prototype.constructor = undefined; assertEquals(Array, new MyOtherDefaultArray().map(()=>{}).constructor); +assertEquals(Array, new MyOtherDefaultArray().concat().constructor); // Exceptions propagated when getting constructor @@species throws @@ -100,6 +111,7 @@ assertThrows(() => new FrozenArray([1]).map(()=>0), TypeError); assertThrows(() => new FrozenArray([1]).filter(()=>true), TypeError); assertThrows(() => new FrozenArray([1]).slice(0, 1), TypeError); assertThrows(() => new FrozenArray([1]).splice(0, 1), TypeError); +assertThrows(() => new FrozenArray([]).concat([1]), TypeError); // Verify call counts and constructor parameters @@ -133,17 +145,22 @@ assertArrayEquals([0], params); count = 0; params = undefined; assertEquals(MyObservedArray, + new MyObservedArray().concat().constructor); +assertEquals(1, count); +assertArrayEquals([0], params); + +count = 0; +params = undefined; +assertEquals(MyObservedArray, new MyObservedArray().slice().constructor); -// TODO(littledan): Should be 1 -assertEquals(2, count); +assertEquals(1, count); assertArrayEquals([0], params); count = 0; params = undefined; assertEquals(MyObservedArray, new MyObservedArray().splice().constructor); -// TODO(littledan): Should be 1 -assertEquals(2, count); +assertEquals(1, count); assertArrayEquals([0], params); // @@species constructor can be a Proxy, and the realm access doesn't diff --git a/deps/v8/test/mjsunit/harmony/block-for-sloppy.js b/deps/v8/test/mjsunit/harmony/block-for-sloppy.js index e9e960504b..051d2b16ea 100644 --- a/deps/v8/test/mjsunit/harmony/block-for-sloppy.js +++ b/deps/v8/test/mjsunit/harmony/block-for-sloppy.js @@ -26,7 +26,6 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Flags: --no-legacy-const --harmony-sloppy --harmony-sloppy-let -// Flags: --harmony-completion function props(x) { var array = []; diff --git a/deps/v8/test/mjsunit/harmony/debug-stepin-proxies.js b/deps/v8/test/mjsunit/harmony/debug-stepin-proxies.js index 0689801a4f..8595f404f0 100644 --- a/deps/v8/test/mjsunit/harmony/debug-stepin-proxies.js +++ b/deps/v8/test/mjsunit/harmony/debug-stepin-proxies.js @@ -36,13 +36,6 @@ var handler = { set: function(target, name, value) { return false; // l }, // m - enumerate: function(target) { - function* keys() { // n - yield "foo"; // o - yield "bar"; // p - } // q - return keys(); // r - }, // s } var proxy = new Proxy(target, handler); @@ -52,9 +45,6 @@ debugger; // a var has = "step" in proxy; // b var get = proxy.step; // c proxy.step = 43; // d -for (var i in proxy) { // e - log.push(i); // f -} Debug.setListener(null); // g @@ -67,12 +57,5 @@ assertEquals([ "b0", "h4b20", "i2b20", // [[Has]] "c0", "j4c15", "k2c15", // [[Get]] "d0", "l4d11", "m2d11", // [[Set]] - "e14", "r4e14", "q4r11e14", "s2e14", // for-in [[Enumerate]] - "o6e14", "q4e14", "p6e14", "q4e14", "q4e14", // exhaust iterator - "e9", // for-in-body - "h4e9","i2e9", // [[Has]] property - "f2","foo", "e9", // for-in-body - "h4e9","i2e9", // [[Has]]property - "f2","bar", "e9", // for-in-body "g0" ], log); diff --git a/deps/v8/test/mjsunit/harmony/destructuring.js b/deps/v8/test/mjsunit/harmony/destructuring.js index 50f27857ec..b6eb6eab09 100644 --- a/deps/v8/test/mjsunit/harmony/destructuring.js +++ b/deps/v8/test/mjsunit/harmony/destructuring.js @@ -1061,8 +1061,8 @@ (function TestForInOfTDZ() { - assertThrows("'use strict'; let x = {}; for (let [x, y] of {x});", ReferenceError); - assertThrows("'use strict'; let x = {}; for (let [y, x] of {x});", ReferenceError); + assertThrows("'use strict'; let x = {}; for (let [x, y] of [x]);", ReferenceError); + assertThrows("'use strict'; let x = {}; for (let [y, x] of [x]);", ReferenceError); assertThrows("'use strict'; let x = {}; for (let [x, y] in {x});", ReferenceError); assertThrows("'use strict'; let x = {}; for (let [y, x] in {x});", ReferenceError); }()); diff --git a/deps/v8/test/mjsunit/harmony/do-expressions.js b/deps/v8/test/mjsunit/harmony/do-expressions.js index e7e513a230..3aace577d5 100644 --- a/deps/v8/test/mjsunit/harmony/do-expressions.js +++ b/deps/v8/test/mjsunit/harmony/do-expressions.js @@ -4,7 +4,6 @@ // Flags: --harmony-do-expressions --harmony-sloppy-let --allow-natives-syntax // Flags: --harmony-default-parameters --harmony-destructuring-bind -// Flags: --harmony-completion function returnValue(v) { return v; } function MyError() {} diff --git a/deps/v8/test/mjsunit/harmony/function-name.js b/deps/v8/test/mjsunit/harmony/function-name.js index 8ca5d8209a..7bb1f6ae01 100644 --- a/deps/v8/test/mjsunit/harmony/function-name.js +++ b/deps/v8/test/mjsunit/harmony/function-name.js @@ -3,6 +3,7 @@ // found in the LICENSE file. // // Flags: --harmony-function-name +// Flags: --harmony-destructuring-bind --harmony-destructuring-assignment (function testVariableDeclarationsFunction() { 'use strict'; @@ -89,36 +90,59 @@ assertEquals('set 44', descriptor.set.name); })(); -// TODO(adamk): Make computed property names work. (function testComputedProperties() { 'use strict'; var a = 'a'; + var b = 'b'; var sym1 = Symbol('1'); var sym2 = Symbol('2'); + var sym3 = Symbol('3'); + var symNoDescription = Symbol(); var obj = { [a]: function() {}, [sym1]: function() {}, [sym2]: function withName() {}, + [symNoDescription]: function() {}, + + get [sym3]() {}, + set [b](val) {}, }; - // Should be 'a' - assertEquals('', obj[a].name); - // Should be '[1]' - assertEquals('', obj[sym1].name); + assertEquals('a', obj[a].name); + assertEquals('[1]', obj[sym1].name); assertEquals('withName', obj[sym2].name); + assertEquals('', obj[symNoDescription].name); + + assertEquals('get [3]', Object.getOwnPropertyDescriptor(obj, sym3).get.name); + assertEquals('set b', Object.getOwnPropertyDescriptor(obj, 'b').set.name); + + var objMethods = { + [a]() {}, + [sym1]() {}, + [symNoDescription]: function() {}, + }; + + assertEquals('a', objMethods[a].name); + assertEquals('[1]', objMethods[sym1].name); + assertEquals('', objMethods[symNoDescription].name); class C { [a]() { } [sym1]() { } static [sym2]() { } + [symNoDescription]() { } + + get [sym3]() { } + static set [b](val) { } } - // Should be 'a' - assertEquals('', C.prototype[a].name); - // Should be '[1]' - assertEquals('', C.prototype[sym1].name); - // Should be '[2]' - assertEquals('', C[sym2].name); + assertEquals('a', C.prototype[a].name); + assertEquals('[1]', C.prototype[sym1].name); + assertEquals('[2]', C[sym2].name); + assertEquals('', C.prototype[symNoDescription].name); + + assertEquals('get [3]', Object.getOwnPropertyDescriptor(C.prototype, sym3).get.name); + assertEquals('set b', Object.getOwnPropertyDescriptor(C, 'b').set.name); })(); @@ -159,3 +183,191 @@ classLit = class { constructor() {} static get ['name']() { return true; } }; assertTrue(classLit.name); })(); + +(function testObjectBindingPattern() { + var { + a = function() {}, + b = () => {}, + x = function withName() { }, + y = class { }, + z = class ClassName { }, + q = class { static name() { return 42 } }, + foo: bar = function() {}, + inParens = (() => {}), + inManyParens = ((((() => {})))), + } = {}; + assertEquals('a', a.name); + assertEquals('b', b.name); + assertEquals('withName', x.name); + assertEquals('y', y.name); + assertEquals('ClassName', z.name); + assertEquals('function', typeof q.name); + assertEquals('bar', bar.name); + assertEquals('inParens', inParens.name) + assertEquals('inManyParens', inManyParens.name) +})(); + +(function testArrayBindingPattern() { + var [ + a = function() {}, + b = () => {}, + x = function withName() { }, + y = class { }, + z = class ClassName { }, + q = class { static name() { return 42 } }, + inParens = (() => {}), + inManyParens = ((((() => {})))), + ] = []; + assertEquals('a', a.name); + assertEquals('b', b.name); + assertEquals('withName', x.name); + assertEquals('y', y.name); + assertEquals('ClassName', z.name); + assertEquals('function', typeof q.name); + assertEquals('inParens', inParens.name) + assertEquals('inManyParens', inManyParens.name) +})(); + +(function testObjectAssignmentPattern() { + var a, b, x, y, z, q; + ({ + a = function() {}, + b = () => {}, + x = function withName() { }, + y = class { }, + z = class ClassName { }, + q = class { static name() { return 42 } }, + foo: bar = function() {}, + inParens = (() => {}), + inManyParens = ((((() => {})))), + } = {}); + assertEquals('a', a.name); + assertEquals('b', b.name); + assertEquals('withName', x.name); + assertEquals('y', y.name); + assertEquals('ClassName', z.name); + assertEquals('function', typeof q.name); + assertEquals('bar', bar.name); + assertEquals('inParens', inParens.name) + assertEquals('inManyParens', inManyParens.name) +})(); + +(function testArrayAssignmentPattern() { + var a, b, x, y, z, q; + [ + a = function() {}, + b = () => {}, + x = function withName() { }, + y = class { }, + z = class ClassName { }, + q = class { static name() { return 42 } }, + inParens = (() => {}), + inManyParens = ((((() => {})))), + ] = []; + assertEquals('a', a.name); + assertEquals('b', b.name); + assertEquals('withName', x.name); + assertEquals('y', y.name); + assertEquals('ClassName', z.name); + assertEquals('function', typeof q.name); + assertEquals('inParens', inParens.name) + assertEquals('inManyParens', inManyParens.name) +})(); + +(function testParameterDestructuring() { + (function({ a = function() {}, + b = () => {}, + x = function withName() { }, + y = class { }, + z = class ClassName { }, + q = class { static name() { return 42 } }, + foo: bar = function() {}, + inParens = (() => {}), + inManyParens = ((((() => {})))) }) { + assertEquals('a', a.name); + assertEquals('b', b.name); + assertEquals('withName', x.name); + assertEquals('y', y.name); + assertEquals('ClassName', z.name); + assertEquals('function', typeof q.name); + assertEquals('bar', bar.name); + assertEquals('inParens', inParens.name) + assertEquals('inManyParens', inManyParens.name) + })({}); + + (function([ a = function() {}, + b = () => {}, + x = function withName() { }, + y = class { }, + z = class ClassName { }, + q = class { static name() { return 42 } }, + inParens = (() => {}), + inManyParens = ((((() => {})))) ]) { + assertEquals('a', a.name); + assertEquals('b', b.name); + assertEquals('withName', x.name); + assertEquals('y', y.name); + assertEquals('ClassName', z.name); + assertEquals('function', typeof q.name); + assertEquals('inParens', inParens.name) + assertEquals('inManyParens', inManyParens.name) + })([]); +})(); + +(function testDefaultParameters() { + (function(a = function() {}, + b = () => {}, + x = function withName() { }, + y = class { }, + z = class ClassName { }, + q = class { static name() { return 42 } }, + inParens = (() => {}), + inManyParens = ((((() => {}))))) { + assertEquals('a', a.name); + assertEquals('b', b.name); + assertEquals('withName', x.name); + assertEquals('y', y.name); + assertEquals('ClassName', z.name); + assertEquals('function', typeof q.name); + assertEquals('inParens', inParens.name) + assertEquals('inManyParens', inManyParens.name) + })(); +})(); + +(function testComputedNameNotShared() { + function makeClass(propName) { + return class { + static [propName]() {} + } + } + + var sym1 = Symbol('1'); + var sym2 = Symbol('2'); + var class1 = makeClass(sym1); + assertEquals('[1]', class1[sym1].name); + var class2 = makeClass(sym2); + assertEquals('[2]', class2[sym2].name); + assertEquals('[1]', class1[sym1].name); +})(); + + +(function testComputedNamesOnlyAppliedSyntactically() { + function factory() { return () => {}; } + + var obj = { ['foo']: factory() }; + assertEquals('', obj.foo.name); +})(); + + +(function testNameNotReflectedInToString() { + var f = function() {}; + var g = function*() {}; + var obj = { + ['h']: function() {}, + i: () => {} + }; + assertEquals('function () {}', f.toString()); + assertEquals('function* () {}', g.toString()); + assertEquals('function () {}', obj.h.toString()); + assertEquals('() => {}', obj.i.toString()); +})(); diff --git a/deps/v8/test/mjsunit/harmony/function-sent.js b/deps/v8/test/mjsunit/harmony/function-sent.js new file mode 100644 index 0000000000..b3cd644dd9 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/function-sent.js @@ -0,0 +1,90 @@ +// Copyright 2016 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-function-sent + + +{ + function* g() { return function.sent } + assertEquals({value: 42, done: true}, g().next(42)); +} + + +{ + function* g() { + try { + yield function.sent; + } finally { + yield function.sent; + return function.sent; + } + } + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next(1)); + assertEquals({value: 2, done: false}, x.next(2)); + assertEquals({value: 3, done: true}, x.next(3)); + } + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next(1)); + assertEquals({value: 2, done: false}, x.throw(2)); + assertEquals({value: 3, done: true}, x.next(3)); + } + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next(1)); + assertEquals({value: 2, done: false}, x.return(2)); + assertEquals({value: 3, done: true}, x.next(3)); + } +} + + +{ + function* inner() { + try { + yield function.sent; + } finally { + return 666; + } + } + + function* g() { + yield function.sent; + yield* inner(); + return function.sent; + } + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next(1)); + assertEquals({value: undefined, done: false}, x.next(2)); + assertEquals({value: 3, done: true}, x.next(3)); + } + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next(1)); + assertEquals({value: undefined, done: false}, x.next(2)); + assertEquals({value: 42, done: true}, x.throw(42)); + } + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next(1)); + assertEquals({value: undefined, done: false}, x.next(2)); + assertEquals({value: 42, done: true}, x.return(42)); + } +} + + +assertThrows("function f() { return function.sent }", SyntaxError); +assertThrows("() => { return function.sent }", SyntaxError); +assertThrows("() => { function.sent }", SyntaxError); +assertThrows("() => function.sent", SyntaxError); +assertThrows("({*f() { function.sent }})", SyntaxError); +assertDoesNotThrow("({*f() { return function.sent }})"); diff --git a/deps/v8/test/mjsunit/harmony/generators.js b/deps/v8/test/mjsunit/harmony/generators.js new file mode 100644 index 0000000000..5b045049e9 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/generators.js @@ -0,0 +1,252 @@ +// Copyright 2016 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. + + +{ // yield in try-catch + + let g = function*() { + try {yield 1} catch (error) {assertEquals("caught", error)} + }; + + assertThrowsEquals(() => g().throw("not caught"), "not caught"); + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next()); + assertEquals({value: undefined, done: true}, x.throw("caught")); + } + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next()); + assertEquals({value: undefined, done: true}, x.next()); + assertThrowsEquals(() => x.throw("not caught"), "not caught"); + } +} + + +{ // return that doesn't close + let g = function*() { try {return 42} finally {yield 43} }; + + { + let x = g(); + assertEquals({value: 43, done: false}, x.next()); + assertEquals({value: 42, done: true}, x.next()); + } +} + + +{ // return that doesn't close + let x; + let g = function*() { try {return 42} finally {x.throw(666)} }; + + { + x = g(); + assertThrows(() => x.next(), TypeError); // still executing + } +} + + +{ // yield in try-finally, finally clause performs return + + let g = function*() { try {yield 42} finally {return 13} }; + + { // "return" closes at suspendedStart + let x = g(); + assertEquals({value: 666, done: true}, x.return(666)); + assertEquals({value: undefined, done: true}, x.next(42)); + assertThrowsEquals(() => x.throw(43), 43); + assertEquals({value: 42, done: true}, x.return(42)); + } + + { // "throw" closes at suspendedStart + let x = g(); + assertThrowsEquals(() => x.throw(666), 666); + assertEquals({value: undefined, done: true}, x.next(42)); + assertEquals({value: 43, done: true}, x.return(43)); + assertThrowsEquals(() => x.throw(44), 44); + } + + { // "next" closes at suspendedYield + let x = g(); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: 13, done: true}, x.next(666)); + assertEquals({value: undefined, done: true}, x.next(666)); + assertThrowsEquals(() => x.throw(666), 666); + } + + { // "return" closes at suspendedYield + let x = g(); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: 13, done: true}, x.return(666)); + assertEquals({value: undefined, done: true}, x.next(666)); + assertEquals({value: 666, done: true}, x.return(666)); + } + + { // "throw" closes at suspendedYield + let x = g(); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: 13, done: true}, x.throw(666)); + assertThrowsEquals(() => x.throw(666), 666); + assertEquals({value: undefined, done: true}, x.next(666)); + } +} + + +{ // yield in try-finally, finally clause doesn't perform return + + let g = function*() { try {yield 42} finally {13} }; + + { // "return" closes at suspendedStart + let x = g(); + assertEquals({value: 666, done: true}, x.return(666)); + assertEquals({value: undefined, done: true}, x.next(42)); + assertThrowsEquals(() => x.throw(43), 43); + assertEquals({value: 42, done: true}, x.return(42)); + } + + { // "throw" closes at suspendedStart + let x = g(); + assertThrowsEquals(() => x.throw(666), 666); + assertEquals({value: undefined, done: true}, x.next(42)); + assertEquals({value: 43, done: true}, x.return(43)); + assertThrowsEquals(() => x.throw(44), 44); + } + + { // "next" closes at suspendedYield + let x = g(); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: undefined, done: true}, x.next(666)); + assertEquals({value: undefined, done: true}, x.next(666)); + assertThrowsEquals(() => x.throw(666), 666); + assertEquals({value: 42, done: true}, x.return(42)); + } + + { // "return" closes at suspendedYield + let x = g(); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: 666, done: true}, x.return(666)); + assertEquals({value: undefined, done: true}, x.next(666)); + assertThrowsEquals(() => x.throw(44), 44); + assertEquals({value: 42, done: true}, x.return(42)); + } + + { // "throw" closes at suspendedYield + let x = g(); + assertEquals({value: 42, done: false}, x.next()); + assertThrowsEquals(() => x.throw(666), 666); + assertEquals({value: undefined, done: true}, x.next(666)); + assertThrowsEquals(() => x.throw(666), 666); + assertEquals({value: 42, done: true}, x.return(42)); + } +} + + +{ // yield in try-finally, finally clause yields and performs return + + let g = function*() { try {yield 42} finally {yield 43; return 13} }; + + { + let x = g(); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: 43, done: false}, x.return(666)); + assertEquals({value: 13, done: true}, x.next()); + assertEquals({value: 666, done: true}, x.return(666)); + } + + { + let x = g(); + assertEquals({value: 666, done: true}, x.return(666)); + assertEquals({value: undefined, done: true}, x.next()); + assertEquals({value: 666, done: true}, x.return(666)); + } +} + + +{ // yield in try-finally, finally clause yields and doesn't perform return + + let g = function*() { try {yield 42} finally {yield 43; 13} }; + + { + let x = g(); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: 43, done: false}, x.return(666)); + assertEquals({value: 666, done: true}, x.next()); + assertEquals({value: 5, done: true}, x.return(5)); + } + + { + let x = g(); + assertEquals({value: 666, done: true}, x.return(666)); + assertEquals({value: undefined, done: true}, x.next()); + assertEquals({value: 666, done: true}, x.return(666)); + } +} + + +{ // yield*, finally clause performs return + + let h = function*() { try {yield 42} finally {yield 43; return 13} }; + let g = function*() { yield 1; yield yield* h(); }; + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next()); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: 43, done: false}, x.next(666)); + assertEquals({value: 13, done: false}, x.next()); + assertEquals({value: undefined, done: true}, x.next()); + } + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next()); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: 43, done: false}, x.return(666)); + assertEquals({value: 13, done: false}, x.next()); + assertEquals({value: undefined, done: true}, x.next()); + } + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next()); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: 43, done: false}, x.throw(666)); + assertEquals({value: 13, done: false}, x.next()); + assertEquals({value: undefined, done: true}, x.next()); + } +} + + +{ // yield*, finally clause does not perform return + + let h = function*() { try {yield 42} finally {yield 43; 13} }; + let g = function*() { yield 1; yield yield* h(); }; + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next()); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: 43, done: false}, x.next(666)); + assertEquals({value: undefined, done: false}, x.next()); + assertEquals({value: undefined, done: true}, x.next()); + } + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next()); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: 43, done: false}, x.return(666)); + assertEquals({value: undefined, done: false}, x.next()); + assertEquals({value: undefined, done: true}, x.next()); + } + + { + let x = g(); + assertEquals({value: 1, done: false}, x.next()); + assertEquals({value: 42, done: false}, x.next()); + assertEquals({value: 43, done: false}, x.throw(666)); + assertThrowsEquals(() => x.next(), 666); + } +} diff --git a/deps/v8/test/mjsunit/harmony/instanceof-es6.js b/deps/v8/test/mjsunit/harmony/instanceof-es6.js new file mode 100644 index 0000000000..60e7ee2c39 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/instanceof-es6.js @@ -0,0 +1,50 @@ +// Copyright 2016 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-instanceof + +// Make sure it's an error if @@hasInstance isn't a function. +(function() { + var F = {}; + F[Symbol.hasInstance] = null; + assertThrows(function() { 0 instanceof F; }, TypeError); +})(); + +// Make sure the result is coerced to boolean. +(function() { + var F = {}; + F[Symbol.hasInstance] = function() { return undefined; }; + assertEquals(0 instanceof F, false); + F[Symbol.hasInstance] = function() { return null; }; + assertEquals(0 instanceof F, false); + F[Symbol.hasInstance] = function() { return true; }; + assertEquals(0 instanceof F, true); +})(); + +// Make sure if @@hasInstance throws, we catch it. +(function() { + var F = {}; + F[Symbol.hasInstance] = function() { throw new Error("always throws"); } + try { + 0 instanceof F; + } catch (e) { + assertEquals(e.message, "always throws"); + } +})(); + +// @@hasInstance works for bound functions. +(function() { + var BC = function() {}; + var bc = new BC(); + var bound = BC.bind(); + assertEquals(bound[Symbol.hasInstance](bc), true); + assertEquals(bound[Symbol.hasInstance]([]), false); +})(); + +// if OrdinaryHasInstance is passed a non-callable receiver, return false. +assertEquals(Function.prototype[Symbol.hasInstance].call(Array, []), true); +assertEquals(Function.prototype[Symbol.hasInstance].call({}, {}), false); + +// OrdinaryHasInstance passed a non-object argument returns false. +assertEquals(Function.prototype[Symbol.hasInstance].call(Array, 0), false); diff --git a/deps/v8/test/mjsunit/harmony/iterator-close.js b/deps/v8/test/mjsunit/harmony/iterator-close.js new file mode 100644 index 0000000000..94785de51f --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/iterator-close.js @@ -0,0 +1,364 @@ +// Copyright 2016 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-iterator-close + +function* g() { yield 42; return 88 }; + + +// Return method is "undefined". +{ + g.prototype.return = null; + + assertEquals(undefined, (() => { + for (let x of g()) { break; } + })()); + + assertEquals(undefined, (() => { + for (x of g()) { break; } + })()); + + assertThrowsEquals(() => { + for (let x of g()) { throw 42; } + }, 42); + + assertThrowsEquals(() => { + for (x of g()) { throw 42; } + }, 42); + + assertEquals(42, (() => { + for (let x of g()) { return 42; } + })()); + + assertEquals(42, (() => { + for (x of g()) { return 42; } + })()); + + assertEquals(42, eval('for (let x of g()) { x; }')); + + assertEquals(42, eval('for (let x of g()) { x; }')); +} + + +// Return method is not callable. +{ + g.prototype.return = 666; + + assertThrows(() => { + for (let x of g()) { break; } + }, TypeError); + + assertThrows(() => { + for (x of g()) { break; } + }, TypeError); + + assertThrows(() => { + for (let x of g()) { throw 666; } + }, TypeError); + + assertThrows(() => { + for (x of g()) { throw 666; } + }, TypeError); + + assertThrows(() => { + for (let x of g()) { return 666; } + }, TypeError); + + assertThrows(() => { + for (x of g()) { return 666; } + }, TypeError); + + assertEquals(42, eval('for (let x of g()) { x; }')); + + assertEquals(42, eval('for (let x of g()) { x; }')); +} + + +// Return method does not return an object. +{ + g.prototype.return = () => 666; + + assertThrows(() => { + for (let x of g()) { break; } + }, TypeError); + + assertThrows(() => { + for (x of g()) { break; } + }, TypeError); + + assertThrows(() => { + for (let x of g()) { throw 666; } + }, TypeError); + + assertThrows(() => { + for (x of g()) { throw 666; } + }, TypeError); + + assertThrows(() => { + for (let x of g()) { return 666; } + }, TypeError); + + assertThrows(() => { + for (x of g()) { return 666; } + }, TypeError); + + assertEquals(42, eval('for (let x of g()) { x; }')); + + assertEquals(42, eval('for (x of g()) { x; }')); +} + + +// Return method returns an object. +{ + let log = []; + g.prototype.return = (...args) => { log.push(args); return {} }; + + log = []; + for (let x of g()) { break; } + assertEquals([[]], log); + + log = []; + for (x of g()) { break; } + assertEquals([[]], log); + + log = []; + assertThrowsEquals(() => { + for (let x of g()) { throw 42; } + }, 42); + assertEquals([[]], log); + + log = []; + assertThrowsEquals(() => { + for (x of g()) { throw 42; } + }, 42); + assertEquals([[]], log); + + log = []; + assertEquals(42, (() => { + for (let x of g()) { return 42; } + })()); + assertEquals([[]], log); + + log = []; + assertEquals(42, (() => { + for (x of g()) { return 42; } + })()); + assertEquals([[]], log); + + log = []; + assertEquals(42, eval('for (let x of g()) { x; }')); + assertEquals([], log); + + log = []; + assertEquals(42, eval('for (x of g()) { x; }')); + assertEquals([], log); +} + + +// Return method throws. +{ + let log = []; + g.prototype.return = (...args) => { log.push(args); throw 23 }; + + log = []; + assertThrowsEquals(() => { + for (let x of g()) { break; } + }, 23); + assertEquals([[]], log); + + log = []; + assertThrowsEquals(() => { + for (x of g()) { break; } + }, 23); + assertEquals([[]], log); + + log = []; + assertThrowsEquals(() => { + for (let x of g()) { throw 42; } + }, 42); + assertEquals([[]], log); + + log = []; + assertThrowsEquals(() => { + for (x of g()) { throw 42; } + }, 42); + assertEquals([[]], log); + + log = []; + assertThrowsEquals(() => { + for (let x of g()) { return 42; } + }, 23); + assertEquals([[]], log); + + log = []; + assertThrowsEquals(() => { + for (x of g()) { return 42; } + }, 23); + assertEquals([[]], log); + + log = []; + assertEquals(42, eval('for (let x of g()) { x; }')); + assertEquals([], log); + + log = []; + assertEquals(42, eval('for (x of g()) { x; }')); + assertEquals([], log); +} + + +// Next method throws. +{ + g.prototype.next = () => { throw 666; }; + g.prototype.return = () => { assertUnreachable() }; + + assertThrowsEquals(() => { + for (let x of g()) {} + }, 666); + + assertThrowsEquals(() => { + for (x of g()) {} + }, 666); +} + + +// Nested loops. +{ + function* g1() { yield 1; yield 2; throw 3; } + function* g2() { yield -1; yield -2; throw -3; } + + assertDoesNotThrow(() => { + for (let x of g1()) { + for (let y of g2()) { + if (y == -2) break; + } + if (x == 2) break; + } + }, -3); + + assertThrowsEquals(() => { + for (let x of g1()) { + for (let y of g2()) { + } + } + }, -3); + + assertThrowsEquals(() => { + for (let x of g1()) { + for (let y of g2()) { + if (y == -2) break; + } + } + }, 3); + + assertDoesNotThrow(() => { + l: for (let x of g1()) { + for (let y of g2()) { + if (y == -2) break l; + } + } + }); + + assertThrowsEquals(() => { + for (let x of g1()) { + for (let y of g2()) { + throw 4; + } + } + }, 4); + + assertThrowsEquals(() => { + for (let x of g1()) { + for (let y of g2()) { + if (y == -2) throw 4; + } + } + }, 4); + + let log = []; + g1.prototype.return = () => { log.push(1); throw 5 }; + g2.prototype.return = () => { log.push(2); throw -5 }; + + log = []; + assertThrowsEquals(() => { + for (let x of g1()) { + for (let y of g2()) { + if (y == -2) break; + } + if (x == 2) break; + } + }, -5); + assertEquals([2, 1], log); + + log = []; + assertThrowsEquals(() => { + for (let x of g1()) { + for (let y of g2()) { + } + } + }, -3); + assertEquals([1], log); + + log = []; + assertThrowsEquals(() => { + for (let x of g1()) { + for (let y of g2()) { + if (y == -2) break; + } + } + }, -5); + assertEquals([2, 1], log); + + log = []; + assertThrowsEquals(() => { + l: for (let x of g1()) { + for (let y of g2()) { + if (y == -2) break l; + } + } + }, -5); + assertEquals([2, 1], log); + + log = []; + assertThrowsEquals(() => { + for (let x of g1()) { + for (let y of g2()) { + throw 4; + } + } + }, 4); + assertEquals([2, 1], log); + + log = []; + assertThrowsEquals(() => { + for (let x of g1()) { + for (let y of g2()) { + if (y == -2) throw 4; + } + } + }, 4); + assertEquals([2, 1], log); + + log = []; + assertThrowsEquals(() => { + for (let x of g1()) { + try { + for (let y of g2()) { + } + } catch (_) {} + } + }, 3); + assertEquals([], log); + + log = []; + assertThrowsEquals(() => { + for (let x of g1()) { + try { + for (let y of g2()) { + } + } catch (_) {} + if (x == 2) break; + } + }, 5); + assertEquals([1], log); +} diff --git a/deps/v8/test/mjsunit/harmony/object-entries.js b/deps/v8/test/mjsunit/harmony/object-entries.js new file mode 100644 index 0000000000..58af4d6f33 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/object-entries.js @@ -0,0 +1,249 @@ +// Copyright 2016 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-object-values-entries --harmony-proxies --harmony-reflect +// Flags: --allow-natives-syntax + +function TestMeta() { + assertEquals(1, Object.entries.length); + assertEquals(Function.prototype, Object.getPrototypeOf(Object.entries)); + assertEquals("entries", Object.entries.name); + + var descriptor = Object.getOwnPropertyDescriptor(Object, "entries"); + assertTrue(descriptor.writable); + assertFalse(descriptor.enumerable); + assertTrue(descriptor.configurable); + + assertThrows(() => new Object.entries({}), TypeError); +} +TestMeta(); + + +function TestBasic() { + var x = 16; + var O = { + d: 1, + c: 3, + [Symbol.iterator]: void 0, + 0: 123, + 1000: 456, + [x * x]: "ducks", + [`0x${(x * x).toString(16)}`]: "quack" + }; + O.a = 2; + O.b = 4; + Object.defineProperty(O, "HIDDEN", { enumerable: false, value: NaN }); + assertEquals([ + ["0", 123], + ["256", "ducks"], + ["1000", 456], + ["d", 1], + ["c", 3], + ["0x100", "quack"], + ["a", 2], + ["b", 4] + ], Object.entries(O)); + assertEquals(Object.entries(O), Object.keys(O).map(key => [key, O[key]])); + + assertTrue(Array.isArray(Object.entries({}))); + assertEquals(0, Object.entries({}).length); +} +TestBasic(); + + +function TestToObject() { + assertThrows(function() { Object.entries(); }, TypeError); + assertThrows(function() { Object.entries(null); }, TypeError); + assertThrows(function() { Object.entries(void 0); }, TypeError); +} +TestToObject(); + + +function TestOrder() { + var O = { + a: 1, + [Symbol.iterator]: null + }; + O[456] = 123; + Object.defineProperty(O, "HIDDEN", { enumerable: false, value: NaN }); + var priv = %CreatePrivateSymbol("Secret"); + O[priv] = 56; + + var log = []; + var P = new Proxy(O, { + ownKeys(target) { + log.push("[[OwnPropertyKeys]]"); + return Reflect.ownKeys(target); + }, + get(target, name) { + log.push(`[[Get]](${JSON.stringify(name)})`); + return Reflect.get(target, name); + }, + getOwnPropertyDescriptor(target, name) { + log.push(`[[GetOwnProperty]](${JSON.stringify(name)})`); + return Reflect.getOwnPropertyDescriptor(target, name); + }, + set(target, name, value) { + assertUnreachable(); + } + }); + + assertEquals([["456", 123], ["a", 1]], Object.entries(P)); + assertEquals([ + "[[OwnPropertyKeys]]", + "[[GetOwnProperty]](\"456\")", + "[[Get]](\"456\")", + "[[GetOwnProperty]](\"a\")", + "[[Get]](\"a\")", + "[[GetOwnProperty]](\"HIDDEN\")" + ], log); +} +TestOrder(); + + +function TestOrderWithDuplicates() { + var O = { + a: 1, + [Symbol.iterator]: null + }; + O[456] = 123; + Object.defineProperty(O, "HIDDEN", { enumerable: false, value: NaN }); + var priv = %CreatePrivateSymbol("Secret"); + O[priv] = 56; + + var log = []; + var P = new Proxy(O, { + ownKeys(target) { + log.push("[[OwnPropertyKeys]]"); + return ["a", Symbol.iterator, "a", "456", "HIDDEN", "HIDDEN", "456"]; + }, + get(target, name) { + log.push(`[[Get]](${JSON.stringify(name)})`); + return Reflect.get(target, name); + }, + getOwnPropertyDescriptor(target, name) { + log.push(`[[GetOwnProperty]](${JSON.stringify(name)})`); + return Reflect.getOwnPropertyDescriptor(target, name); + }, + set(target, name, value) { + assertUnreachable(); + } + }); + + assertEquals([ + ["a", 1], + ["a", 1], + ["456", 123], + ["456", 123] + ], Object.entries(P)); + assertEquals([ + "[[OwnPropertyKeys]]", + "[[GetOwnProperty]](\"a\")", + "[[Get]](\"a\")", + "[[GetOwnProperty]](\"a\")", + "[[Get]](\"a\")", + "[[GetOwnProperty]](\"456\")", + "[[Get]](\"456\")", + "[[GetOwnProperty]](\"HIDDEN\")", + "[[GetOwnProperty]](\"HIDDEN\")", + "[[GetOwnProperty]](\"456\")", + "[[Get]](\"456\")" + ], log); +} +TestOrderWithDuplicates(); + + +function TestPropertyFilter() { + var object = { prop3: 30 }; + object[2] = 40; + object["prop4"] = 50; + Object.defineProperty(object, "prop5", { value: 60, enumerable: true }); + Object.defineProperty(object, "prop6", { value: 70, enumerable: false }); + Object.defineProperty(object, "prop7", { + enumerable: true, get() { return 80; }}); + var sym = Symbol("prop8"); + object[sym] = 90; + + values = Object.entries(object); + assertEquals(5, values.length); + assertEquals([ + [ "2", 40 ], + [ "prop3", 30 ], + [ "prop4", 50 ], + [ "prop5", 60 ], + [ "prop7", 80 ] + ], values); +} +TestPropertyFilter(); + + +function TestWithProxy() { + var obj1 = {prop1:10}; + var proxy1 = new Proxy(obj1, { }); + assertEquals([ [ "prop1", 10 ] ], Object.entries(proxy1)); + + var obj2 = {}; + Object.defineProperty(obj2, "prop2", { value: 20, enumerable: true }); + Object.defineProperty(obj2, "prop3", { + get() { return 30; }, enumerable: true }); + var proxy2 = new Proxy(obj2, { + getOwnPropertyDescriptor(target, name) { + return Reflect.getOwnPropertyDescriptor(target, name); + } + }); + assertEquals([ [ "prop2", 20 ], [ "prop3", 30 ] ], Object.entries(proxy2)); + + var obj3 = {}; + var count = 0; + var proxy3 = new Proxy(obj3, { + get(target, property, receiver) { + return count++ * 5; + }, + getOwnPropertyDescriptor(target, property) { + return { configurable: true, enumerable: true }; + }, + ownKeys(target) { + return [ "prop0", "prop1", Symbol("prop2"), Symbol("prop5") ]; + } + }); + assertEquals([ [ "prop0", 0 ], [ "prop1", 5 ] ], Object.entries(proxy3)); +} +TestWithProxy(); + + +function TestMutateDuringEnumeration() { + var aDeletesB = { + get a() { + delete this.b; + return 1; + }, + b: 2 + }; + assertEquals([ [ "a", 1 ] ], Object.entries(aDeletesB)); + + var aRemovesB = { + get a() { + Object.defineProperty(this, "b", { enumerable: false }); + return 1; + }, + b: 2 + }; + assertEquals([ [ "a", 1 ] ], Object.entries(aRemovesB)); + + var aAddsB = { get a() { this.b = 2; return 1; } }; + assertEquals([ [ "a", 1 ] ], Object.entries(aAddsB)); + + var aMakesBEnumerable = {}; + Object.defineProperty(aMakesBEnumerable, "a", { + get() { + Object.defineProperty(this, "b", { enumerable: true }); + return 1; + }, + enumerable: true + }); + Object.defineProperty(aMakesBEnumerable, "b", { + value: 2, configurable:true, enumerable: false }); + assertEquals([ [ "a", 1 ], [ "b", 2 ] ], Object.entries(aMakesBEnumerable)); +} +TestMutateDuringEnumeration(); diff --git a/deps/v8/test/mjsunit/harmony/object-get-own-property-descriptors.js b/deps/v8/test/mjsunit/harmony/object-get-own-property-descriptors.js new file mode 100644 index 0000000000..b23e7d6e02 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/object-get-own-property-descriptors.js @@ -0,0 +1,206 @@ +// Copyright 2016 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-object-own-property-descriptors +// Flags: --harmony-proxies --harmony-reflect --allow-natives-syntax + +function DataDescriptor(value) { + return { "enumerable": true, "configurable": true, "writable": true, value }; +} + + +function TestMeta() { + assertEquals(1, Object.getOwnPropertyDescriptors.length); + assertEquals(Function.prototype, + Object.getPrototypeOf(Object.getOwnPropertyDescriptors)); + assertEquals( + 'getOwnPropertyDescriptors', Object.getOwnPropertyDescriptors.name); + var desc = Reflect.getOwnPropertyDescriptor( + Object, 'getOwnPropertyDescriptors'); + assertFalse(desc.enumerable); + assertTrue(desc.writable); + assertTrue(desc.configurable); +} +TestMeta(); + + +function TestToObject() { + assertThrows(function() { + Object.getOwnPropertyDescriptors(null); + }, TypeError); + + assertThrows(function() { + Object.getOwnPropertyDescriptors(undefined); + }, TypeError); + + assertThrows(function() { + Object.getOwnPropertyDescriptors(); + }, TypeError); +} +TestToObject(); + + +function TestPrototypeProperties() { + function F() {}; + F.prototype.a = "A"; + F.prototype.b = "B"; + + var F2 = new F(); + Object.defineProperties(F2, { + "b": { + enumerable: false, + configurable: true, + writable: false, + value: "Shadowed 'B'" + }, + "c": { + enumerable: false, + configurable: true, + writable: false, + value: "C" + } + }); + + assertEquals({ + "b": { + enumerable: false, + configurable: true, + writable: false, + value: "Shadowed 'B'" + }, + "c": { + enumerable: false, + configurable: true, + writable: false, + value: "C" + } + }, Object.getOwnPropertyDescriptors(F2)); +} +TestPrototypeProperties(); + + +function TestPrototypeProperties() { + function F() {}; + F.prototype.a = "A"; + F.prototype.b = "B"; + + var F2 = new F(); + Object.defineProperties(F2, { + "b": { + enumerable: false, + configurable: true, + writable: false, + value: "Shadowed 'B'" + }, + "c": { + enumerable: false, + configurable: true, + writable: false, + value: "C" + } + }); + + assertEquals({ + "b": { + enumerable: false, + configurable: true, + writable: false, + value: "Shadowed 'B'" + }, + "c": { + enumerable: false, + configurable: true, + writable: false, + value: "C" + } + }, Object.getOwnPropertyDescriptors(F2)); +} +TestPrototypeProperties(); + + +function TestTypeFilteringAndOrder() { + var log = []; + var sym = Symbol("foo"); + var psym = %CreatePrivateSymbol("private"); + var O = { + 0: 0, + [sym]: 3, + "a": 2, + [psym]: 4, + 1: 1, + }; + var P = new Proxy(O, { + ownKeys(target) { + log.push("ownKeys()"); + return Reflect.ownKeys(target); + }, + getOwnPropertyDescriptor(target, name) { + log.push(`getOwnPropertyDescriptor(${String(name)})`); + return Reflect.getOwnPropertyDescriptor(target, name); + }, + get(target, name) { assertUnreachable(); }, + set(target, name, value) { assertUnreachable(); }, + deleteProperty(target, name) { assertUnreachable(); }, + defineProperty(target, name, desc) { assertUnreachable(); } + }); + + var result1 = Object.getOwnPropertyDescriptors(O); + assertEquals({ + 0: DataDescriptor(0), + 1: DataDescriptor(1), + "a": DataDescriptor(2), + [sym]: DataDescriptor(3) + }, result1); + + var result2 = Object.getOwnPropertyDescriptors(P); + assertEquals([ + "ownKeys()", + "getOwnPropertyDescriptor(0)", + "getOwnPropertyDescriptor(1)", + "getOwnPropertyDescriptor(a)", + "getOwnPropertyDescriptor(Symbol(foo))" + ], log); + assertEquals({ + 0: DataDescriptor(0), + 1: DataDescriptor(1), + "a": DataDescriptor(2), + [sym]: DataDescriptor(3) + }, result2); +} +TestTypeFilteringAndOrder(); + + +function TestDuplicateKeys() { + var i = 0; + var log = []; + var P = new Proxy({}, { + ownKeys() { + log.push(`ownKeys()`); + return ["A", "A"]; + }, + getOwnPropertyDescriptor(t, name) { + log.push(`getOwnPropertyDescriptor(${name})`); + if (i++) return; + return { + configurable: true, + writable: false, + value: "VALUE" + }; + }, + get(target, name) { assertUnreachable(); }, + set(target, name, value) { assertUnreachable(); }, + deleteProperty(target, name) { assertUnreachable(); }, + defineProperty(target, name, desc) { assertUnreachable(); } + }); + + var result = Object.getOwnPropertyDescriptors(P); + assertEquals({ "A": undefined }, result); + assertTrue(result.hasOwnProperty("A")); + assertEquals([ + "ownKeys()", + "getOwnPropertyDescriptor(A)", + "getOwnPropertyDescriptor(A)" + ], log); +} +TestDuplicateKeys(); diff --git a/deps/v8/test/mjsunit/harmony/object-values.js b/deps/v8/test/mjsunit/harmony/object-values.js new file mode 100644 index 0000000000..f56fe8a7b3 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/object-values.js @@ -0,0 +1,229 @@ +// Copyright 2016 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-object-values-entries --harmony-proxies --harmony-reflect +// Flags: --allow-natives-syntax + +function TestMeta() { + assertEquals(1, Object.values.length); + assertEquals(Function.prototype, Object.getPrototypeOf(Object.values)); + assertEquals("values", Object.values.name); + + var descriptor = Object.getOwnPropertyDescriptor(Object, "values"); + assertTrue(descriptor.writable); + assertFalse(descriptor.enumerable); + assertTrue(descriptor.configurable); + + assertThrows(() => new Object.values({}), TypeError); +} +TestMeta(); + + +function TestBasic() { + var x = 16; + var O = { + d: 1, + c: 3, + [Symbol.iterator]: void 0, + 0: 123, + 1000: 456, + [x * x]: "ducks", + [`0x${(x * x).toString(16)}`]: "quack" + }; + O.a = 2; + O.b = 4; + Object.defineProperty(O, "HIDDEN", { enumerable: false, value: NaN }); + assertEquals([123, "ducks", 456, 1, 3, "quack", 2, 4], Object.values(O)); + assertEquals(Object.values(O), Object.keys(O).map(key => O[key])); + + assertTrue(Array.isArray(Object.values({}))); + assertEquals(0, Object.values({}).length); +} +TestBasic(); + + +function TestToObject() { + assertThrows(function() { Object.values(); }, TypeError); + assertThrows(function() { Object.values(null); }, TypeError); + assertThrows(function() { Object.values(void 0); }, TypeError); +} +TestToObject(); + + +function TestOrder() { + var O = { + a: 1, + [Symbol.iterator]: null + }; + O[456] = 123; + Object.defineProperty(O, "HIDDEN", { enumerable: false, value: NaN }); + var priv = %CreatePrivateSymbol("Secret"); + O[priv] = 56; + + var log = []; + var P = new Proxy(O, { + ownKeys(target) { + log.push("[[OwnPropertyKeys]]"); + return Reflect.ownKeys(target); + }, + get(target, name) { + log.push(`[[Get]](${JSON.stringify(name)})`); + return Reflect.get(target, name); + }, + getOwnPropertyDescriptor(target, name) { + log.push(`[[GetOwnProperty]](${JSON.stringify(name)})`); + return Reflect.getOwnPropertyDescriptor(target, name); + }, + set(target, name, value) { + assertUnreachable(); + } + }); + + assertEquals([123, 1], Object.values(P)); + assertEquals([ + "[[OwnPropertyKeys]]", + "[[GetOwnProperty]](\"456\")", + "[[Get]](\"456\")", + "[[GetOwnProperty]](\"a\")", + "[[Get]](\"a\")", + "[[GetOwnProperty]](\"HIDDEN\")" + ], log); +} +TestOrder(); + + +function TestOrderWithDuplicates() { + var O = { + a: 1, + [Symbol.iterator]: null + }; + O[456] = 123; + Object.defineProperty(O, "HIDDEN", { enumerable: false, value: NaN }); + O[priv] = 56; + var priv = %CreatePrivateSymbol("private"); + + var log = []; + var P = new Proxy(O, { + ownKeys(target) { + log.push("[[OwnPropertyKeys]]"); + return [ "a", Symbol.iterator, "a", "456", "HIDDEN", "HIDDEN", "456" ]; + }, + get(target, name) { + log.push(`[[Get]](${JSON.stringify(name)})`); + return Reflect.get(target, name); + }, + getOwnPropertyDescriptor(target, name) { + log.push(`[[GetOwnProperty]](${JSON.stringify(name)})`); + return Reflect.getOwnPropertyDescriptor(target, name); + }, + set(target, name, value) { + assertUnreachable(); + } + }); + + assertEquals([1, 1, 123, 123], Object.values(P)); + assertEquals([ + "[[OwnPropertyKeys]]", + "[[GetOwnProperty]](\"a\")", + "[[Get]](\"a\")", + "[[GetOwnProperty]](\"a\")", + "[[Get]](\"a\")", + "[[GetOwnProperty]](\"456\")", + "[[Get]](\"456\")", + "[[GetOwnProperty]](\"HIDDEN\")", + "[[GetOwnProperty]](\"HIDDEN\")", + "[[GetOwnProperty]](\"456\")", + "[[Get]](\"456\")", + ], log); +} +TestOrderWithDuplicates(); + + +function TestPropertyFilter() { + var object = { prop3: 30 }; + object[2] = 40; + object["prop4"] = 50; + Object.defineProperty(object, "prop5", { value: 60, enumerable: true }); + Object.defineProperty(object, "prop6", { value: 70, enumerable: false }); + Object.defineProperty(object, "prop7", { + enumerable: true, get() { return 80; }}); + var sym = Symbol("prop8"); + object[sym] = 90; + + values = Object.values(object); + assertEquals(5, values.length); + assertEquals([40,30,50,60,80], values); +} +TestPropertyFilter(); + + +function TestWithProxy() { + var obj1 = {prop1:10}; + var proxy1 = new Proxy(obj1, { }); + assertEquals([10], Object.values(proxy1)); + + var obj2 = {}; + Object.defineProperty(obj2, "prop2", { value: 20, enumerable: true }); + Object.defineProperty(obj2, "prop3", { + get() { return 30; }, enumerable: true }); + var proxy2 = new Proxy(obj2, { + getOwnPropertyDescriptor(target, name) { + return Reflect.getOwnPropertyDescriptor(target, name); + } + }); + assertEquals([20, 30], Object.values(proxy2)); + + var obj3 = {}; + var count = 0; + var proxy3 = new Proxy(obj3, { + get(target, property, receiver) { + return count++ * 5; + }, + getOwnPropertyDescriptor(target, property) { + return { configurable: true, enumerable: true }; + }, + ownKeys(target) { + return [ "prop0", "prop1", Symbol("prop2"), Symbol("prop5") ]; + } + }); + assertEquals([0, 5], Object.values(proxy3)); +} +TestWithProxy(); + + +function TestMutateDuringEnumeration() { + var aDeletesB = { + get a() { + delete this.b; + return 1; + }, + b: 2 + }; + assertEquals([1], Object.values(aDeletesB)); + + var aRemovesB = { + get a() { + Object.defineProperty(this, "b", { enumerable: false }); + return 1; + }, + b: 2 + }; + assertEquals([1], Object.values(aRemovesB)); + + var aAddsB = { get a() { this.b = 2; return 1; } }; + assertEquals([1], Object.values(aAddsB)); + + var aMakesBEnumerable = {}; + Object.defineProperty(aMakesBEnumerable, "a", { + get() { + Object.defineProperty(this, "b", { enumerable: true }); + return 1; + }, + enumerable: true + }); + Object.defineProperty(aMakesBEnumerable, "b", { + value: 2, configurable:true, enumerable: false }); + assertEquals([1, 2], Object.values(aMakesBEnumerable)); +} +TestMutateDuringEnumeration(); diff --git a/deps/v8/test/mjsunit/harmony/private-symbols.js b/deps/v8/test/mjsunit/harmony/private-symbols.js index 369c222897..18a2e4cf07 100644 --- a/deps/v8/test/mjsunit/harmony/private-symbols.js +++ b/deps/v8/test/mjsunit/harmony/private-symbols.js @@ -16,7 +16,6 @@ for (var key of Object.keys(object)) assertUnreachable(); for (var key of Object.getOwnPropertySymbols(object)) assertUnreachable(); for (var key of Object.getOwnPropertyNames(object)) assertUnreachable(); for (var key of Reflect.ownKeys(object)) assertUnreachable(); -for (var key of Reflect.enumerate(object)) assertUnreachable(); for (var key in object) assertUnreachable(); var object2 = {__proto__: object}; @@ -24,7 +23,6 @@ for (var key of Object.keys(object2)) assertUnreachable(); for (var key of Object.getOwnPropertySymbols(object2)) assertUnreachable(); for (var key of Object.getOwnPropertyNames(object2)) assertUnreachable(); for (var key of Reflect.ownKeys(object2)) assertUnreachable(); -for (var key of Reflect.enumerate(object2)) assertUnreachable(); for (var key in object2) assertUnreachable(); diff --git a/deps/v8/test/mjsunit/harmony/proxies-apply.js b/deps/v8/test/mjsunit/harmony/proxies-apply.js index 4ddffe73b8..dae362ac61 100644 --- a/deps/v8/test/mjsunit/harmony/proxies-apply.js +++ b/deps/v8/test/mjsunit/harmony/proxies-apply.js @@ -87,3 +87,36 @@ assertTrue(called_target); assertTrue(called_handler); })(); + + +(function testCallProxyNonCallableTarget() { + var values = [NaN, 1.5, 100, /RegExp/, "string", {}, [], Symbol(), + new Map(), new Set(), new WeakMap(), new WeakSet()]; + values.forEach(target => { + target = Object(target); + var proxy = new Proxy(target, { apply() { assertUnreachable(); } }); + assertThrows(() => { proxy(); }, TypeError); + assertThrows(() => { ({ proxy }).proxy(); }, TypeError); + assertThrows(() => { Reflect.apply(proxy, null, []); }, TypeError); + assertThrows(() => { Reflect.apply(proxy, { proxy }, []); }, TypeError); + assertThrows(() => { + Function.prototype.call.apply(proxy, [null]); + }, TypeError); + assertThrows(() => { + Function.prototype.apply.apply(proxy, [null, []]); + }, TypeError); + + var proxy_to_proxy = new Proxy(proxy, { apply() { assertUnreachable(); } }); + assertThrows(() => { proxy_to_proxy(); }, TypeError); + assertThrows(() => { ({ proxy_to_proxy }).proxy_to_proxy(); }, TypeError); + assertThrows(() => { Reflect.apply(proxy_to_proxy, null, []); }, TypeError); + assertThrows(() => { Reflect.apply(proxy_to_proxy, { proxy }, []); }, + TypeError); + assertThrows(() => { + Function.prototype.call.apply(proxy_to_proxy, [null]); + }, TypeError); + assertThrows(() => { + Function.prototype.apply.apply(proxy_to_proxy, [null, []]); + }, TypeError); + }); +})(); diff --git a/deps/v8/test/mjsunit/harmony/proxies-enumerate.js b/deps/v8/test/mjsunit/harmony/proxies-enumerate.js deleted file mode 100644 index 82464d0c7f..0000000000 --- a/deps/v8/test/mjsunit/harmony/proxies-enumerate.js +++ /dev/null @@ -1,109 +0,0 @@ -// 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 target = { - "target_one": 1 -}; -target.__proto__ = { - "target_two": 2 -}; -var handler = { - enumerate: function(target) { - function* keys() { - yield "foo"; - yield "bar"; - } - return keys(); - }, - // For-in calls "has" on every iteration, so for TestForIn() below to - // detect all results of the "enumerate" trap, "has" must return true. - has: function(target, name) { - return true; - } -} - -var proxy = new Proxy(target, handler); - -function TestForIn(receiver, expected) { - var result = []; - for (var k in receiver) { - result.push(k); - } - assertEquals(expected, result); -} - -TestForIn(proxy, ["foo", "bar"]); - -// Test revoked proxy. -var pair = Proxy.revocable(target, handler); -TestForIn(pair.proxy, ["foo", "bar"]); -pair.revoke(); -assertThrows(()=>{ TestForIn(pair.proxy, ["foo", "bar"]) }, TypeError); - -// Properly call traps on proxies on the prototype chain. -var receiver = { - "receiver_one": 1 -}; -receiver.__proto__ = proxy; -TestForIn(receiver, ["receiver_one", "foo", "bar"]); - -// Fall through to default behavior when trap is undefined. -handler.enumerate = undefined; -TestForIn(proxy, ["target_one", "target_two"]); -delete handler.enumerate; -TestForIn(proxy, ["target_one", "target_two"]); - -// Non-string keys must be filtered. -function TestNonStringKey(key) { - handler.enumerate = function(target) { - function* keys() { yield key; } - return keys(); - } - assertThrows("for (var k in proxy) {}", TypeError); -} - -TestNonStringKey(1); -TestNonStringKey(3.14); -TestNonStringKey(Symbol("foo")); -TestNonStringKey({bad: "value"}); -TestNonStringKey(null); -TestNonStringKey(undefined); -TestNonStringKey(true); - -(function testProtoProxyEnumerate() { - var keys = ['a', 'b', 'c', 'd']; - var handler = { - enumerate() { return keys[Symbol.iterator]() }, - has(target, key) { return false } - }; - var proxy = new Proxy({}, handler); - var seen_keys = []; - for (var i in proxy) { - seen_keys.push(i); - } - assertEquals([], seen_keys); - - handler.has = function(target, key) { return true }; - for (var i in proxy) { - seen_keys.push(i); - } - assertEquals(keys, seen_keys); - - o = {__proto__:proxy}; - handler.has = function(target, key) { return false }; - seen_keys = []; - for (var i in o) { - seen_keys.push(i); - } - assertEquals([], seen_keys); - - handler.has = function(target, key) { return true }; - seen_keys = []; - for (var i in o) { - seen_keys.push(i); - } - assertEquals(keys, seen_keys); -})(); diff --git a/deps/v8/test/mjsunit/harmony/proxies-for.js b/deps/v8/test/mjsunit/harmony/proxies-for.js index aea9bd6c21..e52ee43031 100644 --- a/deps/v8/test/mjsunit/harmony/proxies-for.js +++ b/deps/v8/test/mjsunit/harmony/proxies-for.js @@ -27,21 +27,15 @@ // Flags: --harmony-proxies - // Helper. function TestWithProxies(test, x, y, z) { test(function(h){ return new Proxy({}, h) }, x, y, z) - test(function(h) { - return new Proxy(function() {}, h) - }, x, y, z) } // Iterate over a proxy. -Array.prototype.values = function() { return this[Symbol.iterator]() } - function TestForIn(properties, handler) { TestWithProxies(TestForIn2, properties, handler) } @@ -54,23 +48,18 @@ function TestForIn2(create, properties, handler) { } TestForIn(["0", "a"], { - enumerate() { return ["0", "a"].values() }, - has(target, property) { return true } + ownKeys() { return ["0", "a"] }, + has(target, property) { return true }, + getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }} }) TestForIn(["null", "a"], { - enumerate() { return this.enumerate2() }, - enumerate2() { return ["null", "a"].values() }, - has(target, property) { return true } + ownKeys() { return this.enumerate() }, + enumerate() { return ["null", "a"] }, + has(target, property) { return true }, + getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }} }) -TestForIn(["b", "a", "0", "c"], new Proxy({}, { - get: function(pr, pk) { - return function() { return ["b", "a", "0", "c"].values() } - } -})) - - // Iterate over an object with a proxy prototype. @@ -94,19 +83,21 @@ function TestForInDerived2(create, properties, handler) { } TestForInDerived(["0", "a"], { - enumerate: function() { return ["0", "a"].values() }, - has: function(t, k) { return k == "0" || k == "a" } + ownKeys: function() { return ["0", "a"] }, + has: function(t, k) { return k == "0" || k == "a" }, + getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }} }) TestForInDerived(["null", "a"], { - enumerate: function() { return this.enumerate2() }, - enumerate2: function() { return ["null", "a"].values() }, - has: function(t, k) { return k == "null" || k == "a" } + ownKeys: function() { return this.enumerate() }, + enumerate: function() { return ["null", "a"] }, + has: function(t, k) { return k == "null" || k == "a" }, + getOwnPropertyDescriptor() { return { enumerable: true, configurable: true }} }) -// Throw exception in enumerate trap. +// Throw exception in ownKeys trap. function TestForInThrow(handler) { TestWithProxies(TestForInThrow2, handler) @@ -120,12 +111,12 @@ function TestForInThrow2(create, handler) { } TestForInThrow({ - enumerate: function() { throw "myexn" } + ownKeys: function() { throw "myexn" } }) TestForInThrow({ - enumerate: function() { return this.enumerate2() }, - enumerate2: function() { throw "myexn" } + ownKeys: function() { return this.enumerate() }, + enumerate: function() { throw "myexn" } }) TestForInThrow(new Proxy({}, { @@ -135,7 +126,7 @@ TestForInThrow(new Proxy({}, { })); (function() { - var p = new Proxy({}, {enumerate:function() { return ["0"].values(); }}); + var p = new Proxy({}, {ownKeys:function() { return ["0"]; }}); var o = [0]; o.__proto__ = p; var keys = []; diff --git a/deps/v8/test/mjsunit/harmony/proxies-ownkeys.js b/deps/v8/test/mjsunit/harmony/proxies-ownkeys.js index 6a7ae64d78..88350cca02 100644 --- a/deps/v8/test/mjsunit/harmony/proxies-ownkeys.js +++ b/deps/v8/test/mjsunit/harmony/proxies-ownkeys.js @@ -56,6 +56,10 @@ assertEquals(["a", "b", "c"], Reflect.ownKeys(proxy)); keys.length = Math.pow(2, 33); assertThrows("Reflect.ownKeys(proxy)", RangeError); +// Check that we allow duplicated keys. +keys = ['a', 'a', 'a'] +assertEquals(keys, Reflect.ownKeys(proxy)); + // Non-Name results throw. keys = [1]; assertThrows("Reflect.ownKeys(proxy)", TypeError); @@ -73,6 +77,10 @@ assertThrows("Reflect.ownKeys(proxy)", TypeError); keys = ["nonconf"]; assertEquals(keys, Reflect.ownKeys(proxy)); +// Check that we allow duplicated keys. +keys = ['nonconf', 'nonconf', 'nonconf'] +assertEquals(keys, Reflect.ownKeys(proxy)); + // Step 19a: The trap result must all keys of a non-extensible target. Object.preventExtensions(target); assertThrows("Reflect.ownKeys(proxy)", TypeError); @@ -82,3 +90,7 @@ assertEquals(keys, Reflect.ownKeys(proxy)); // Step 20: The trap result must not add keys to a non-extensible target. keys = ["nonconf", "target_one", "fantasy"]; assertThrows("Reflect.ownKeys(proxy)", TypeError); + +// Check that we allow duplicated keys. +keys = ['nonconf', 'target_one', 'nonconf', 'nonconf', 'target_one',] +assertEquals(keys, Reflect.ownKeys(proxy)); diff --git a/deps/v8/test/mjsunit/harmony/proxies-set-prototype-of.js b/deps/v8/test/mjsunit/harmony/proxies-set-prototype-of.js index bc60ff492c..810c219533 100644 --- a/deps/v8/test/mjsunit/harmony/proxies-set-prototype-of.js +++ b/deps/v8/test/mjsunit/harmony/proxies-set-prototype-of.js @@ -120,3 +120,11 @@ assertEquals({a:5}, seen_prototype); prototype = [5]; assertThrows(() => {Reflect.setPrototypeOf(proxy2, prototype)}, TypeError); })(); + +(function testProxyTrapReturnsFalse() { + var handler = {}; + handler.setPrototypeOf = () => false; + var target = new Proxy({}, {isExtensible: () => assertUnreachable()}); + var object = new Proxy(target, handler); + assertFalse(Reflect.setPrototypeOf(object, {})); +})(); diff --git a/deps/v8/test/mjsunit/harmony/reflect-construct.js b/deps/v8/test/mjsunit/harmony/reflect-construct.js index f2dfc15366..c136957df0 100644 --- a/deps/v8/test/mjsunit/harmony/reflect-construct.js +++ b/deps/v8/test/mjsunit/harmony/reflect-construct.js @@ -279,10 +279,7 @@ (function() { function* f() { yield 1; yield 2; } function* g() { yield 3; yield 4; } - var o = Reflect.construct(f, [], g); - assertEquals([1, 2], [...o]); - assertTrue(o.__proto__ === g.prototype); - assertTrue(o.__proto__ !== f.prototype); + assertThrows(()=>Reflect.construct(f, [], g)); })(); (function () { diff --git a/deps/v8/test/mjsunit/harmony/reflect-enumerate-delete.js b/deps/v8/test/mjsunit/harmony/reflect-enumerate-delete.js deleted file mode 100644 index 1137d8a0a4..0000000000 --- a/deps/v8/test/mjsunit/harmony/reflect-enumerate-delete.js +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2010-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. - -// Test that properties deleted during an enumeration do not show up in -// the enumeration. This is adapted from mjsunit/for-in-delete.js. - -// Flags: --harmony-reflect - - -function f(o, expected, del) { - var index = 0; - for (p of Reflect.enumerate(o)) { - if (del) delete o[del]; - assertEquals(expected[index], p); - index++; - } - assertEquals(expected.length, index); -} - -var o = {} -o.a = 1; -o.b = 2; -o.c = 3; -o.d = 3; - -f(o, ['a', 'b', 'c', 'd']); -f(o, ['a', 'b', 'c', 'd']); -f(o, ['a', 'c', 'd'], 'b'); -f(o, ['a', 'c'], 'd'); diff --git a/deps/v8/test/mjsunit/harmony/reflect-enumerate-opt.js b/deps/v8/test/mjsunit/harmony/reflect-enumerate-opt.js deleted file mode 100644 index ccd1845c78..0000000000 --- a/deps/v8/test/mjsunit/harmony/reflect-enumerate-opt.js +++ /dev/null @@ -1,78 +0,0 @@ -// 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. - -// This is adapted from mjsunit/for-in-opt.js. - -// Flags: --harmony-proxies --harmony-reflect --allow-natives-syntax - - -"use strict"; - -function f(o) { - var result = []; - for (var i of Reflect.enumerate(Object(o))) { - result.push(i); - } - return result; -} - -assertEquals(["0"], f("a")); -assertEquals(["0"], f("a")); -%OptimizeFunctionOnNextCall(f); -assertEquals(["0","1","2"], f("bla")); - -// Test the lazy deopt points. -var keys = ["a", "b", "c", "d"]; -var has_keys = []; -var deopt_has = false; -var deopt_enum = false; - -var handler = { - enumerate: function(target) { - if (deopt_enum) { - %DeoptimizeFunction(f2); - deopt_enum = false; - } - return keys; - }, - - getPropertyDescriptor: function(k) { - if (deopt_has) { - %DeoptimizeFunction(f2); - deopt_has = false; - } - has_keys.push(k); - return {value: 10, configurable: true, writable: false, enumerable: true}; - } -}; - -// TODO(neis,cbruni): Enable once the enumerate proxy trap is properly -// implemented. -// var proxy = new Proxy({}, handler); -// var o = {__proto__: proxy}; -// -// function f2(o) { -// var result = []; -// for (var i of Reflect.enumerate(o)) { -// result.push(i); -// } -// return result; -// } -// -// function check_f2() { -// assertEquals(keys, f2(o)); -// assertEquals(keys, has_keys); -// has_keys.length = 0; -// } -// -// check_f2(); -// check_f2(); -// Test lazy deopt after GetPropertyNamesFast -// %OptimizeFunctionOnNextCall(f2); -// deopt_enum = true; -// check_f2(); -// Test lazy deopt after FILTER_KEY -// %OptimizeFunctionOnNextCall(f2); -// deopt_has = true; -// check_f2(); diff --git a/deps/v8/test/mjsunit/harmony/reflect-enumerate-special-cases.js b/deps/v8/test/mjsunit/harmony/reflect-enumerate-special-cases.js deleted file mode 100644 index 234a3e3e0d..0000000000 --- a/deps/v8/test/mjsunit/harmony/reflect-enumerate-special-cases.js +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2008-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. - -// This is adapted from mjsunit/for-in-special-cases.js. - -// Flags: --harmony-reflect - - -function Accumulate(x) { - var accumulator = ""; - for (var i of Reflect.enumerate(Object(x))) { - accumulator += i; - } - return accumulator; -} - -for (var i = 0; i < 3; ++i) { - var elements = Accumulate("abcd"); - // We do not assume that enumerate enumerates elements in order. - assertTrue(-1 != elements.indexOf("0")); - assertTrue(-1 != elements.indexOf("1")); - assertTrue(-1 != elements.indexOf("2")); - assertTrue(-1 != elements.indexOf("3")); - assertEquals(4, elements.length); -} - -function for_in_string_prototype() { - - var x = new String("abc"); - x.foo = 19; - function B() { - this.bar = 5; - this[7] = 4; - } - B.prototype = x; - - var y = new B(); - y.gub = 13; - - var elements = Accumulate(y); - var elements1 = Accumulate(y); - // If enumerate returns elements in a different order on multiple calls, this - // assert will fail. If that happens, consider if that behavior is OK. - assertEquals(elements, elements1, "Enumeration not the same both times."); - // We do not assume that enumerate enumerates elements in order. - assertTrue(-1 != elements.indexOf("0")); - assertTrue(-1 != elements.indexOf("1")); - assertTrue(-1 != elements.indexOf("2")); - assertTrue(-1 != elements.indexOf("7")); - assertTrue(-1 != elements.indexOf("foo")); - assertTrue(-1 != elements.indexOf("bar")); - assertTrue(-1 != elements.indexOf("gub")); - assertEquals(13, elements.length); - - elements = Accumulate(x); - assertTrue(-1 != elements.indexOf("0")); - assertTrue(-1 != elements.indexOf("1")); - assertTrue(-1 != elements.indexOf("2")); - assertTrue(-1 != elements.indexOf("foo")); - assertEquals(6, elements.length); -} - -for_in_string_prototype(); -for_in_string_prototype(); diff --git a/deps/v8/test/mjsunit/harmony/reflect-enumerate.js b/deps/v8/test/mjsunit/harmony/reflect-enumerate.js deleted file mode 100644 index bbc364e7b9..0000000000 --- a/deps/v8/test/mjsunit/harmony/reflect-enumerate.js +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2008-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. - -// This is adapted from mjsunit/for-in.js. - -// Flags: --harmony-reflect - - -function props(x) { - var array = []; - for (var p of Reflect.enumerate(x)) array.push(p); - return array.sort(); -} - -assertEquals(0, props({}).length, "olen0"); -assertEquals(1, props({x:1}).length, "olen1"); -assertEquals(2, props({x:1, y:2}).length, "olen2"); - -assertArrayEquals(["x"], props({x:1}), "x"); -assertArrayEquals(["x", "y"], props({x:1, y:2}), "xy"); -assertArrayEquals(["x", "y", "zoom"], props({x:1, y:2, zoom:3}), "xyzoom"); - -assertEquals(0, props([]).length, "alen0"); -assertEquals(1, props([1]).length, "alen1"); -assertEquals(2, props([1,2]).length, "alen2"); - -assertArrayEquals(["0"], props([1]), "0"); -assertArrayEquals(["0", "1"], props([1,2]), "01"); -assertArrayEquals(["0", "1", "2"], props([1,2,3]), "012"); - -var o = {}; -var a = []; -for (var i = 0x0020; i < 0x01ff; i+=2) { - var s = 'char:' + String.fromCharCode(i); - a.push(s); - o[s] = i; -} -assertArrayEquals(a, props(o), "charcodes"); - -var a = []; -assertEquals(0, props(a).length, "proplen0"); -a[Math.pow(2,30)-1] = 0; -assertEquals(1, props(a).length, "proplen1"); -a[Math.pow(2,31)-1] = 0; -assertEquals(2, props(a).length, "proplen2"); -a[1] = 0; -assertEquals(3, props(a).length, "proplen3"); - -var result = ''; -for (var p of Reflect.enumerate({a : [0], b : 1})) { result += p; } -assertEquals('ab', result, "ab"); - -var result = ''; -for (var p of Reflect.enumerate({a : {v:1}, b : 1})) { result += p; } -assertEquals('ab', result, "ab-nodeep"); - -var result = ''; -for (var p of Reflect.enumerate({ get a() {}, b : 1})) { result += p; } -assertEquals('ab', result, "abget"); - -var result = ''; -for (var p of Reflect.enumerate({ get a() {}, set a(x) {}, b : 1})) { - result += p; -} -assertEquals('ab', result, "abgetset"); - -(function() { - var large_key = 2147483650; - var o = {__proto__: {}}; - o[large_key] = 1; - o.__proto__[large_key] = 1; - var keys = []; - for (var k of Reflect.enumerate(o)) { - keys.push(k); - } - assertEquals(["2147483650"], keys); -})(); diff --git a/deps/v8/test/mjsunit/harmony/reflect.js b/deps/v8/test/mjsunit/harmony/reflect.js index 8ee1227a44..6449eb8259 100644 --- a/deps/v8/test/mjsunit/harmony/reflect.js +++ b/deps/v8/test/mjsunit/harmony/reflect.js @@ -486,27 +486,6 @@ function prepare(target) { })(); - -//////////////////////////////////////////////////////////////////////////////// -// Reflect.enumerate - - -(function testReflectEnumerateArity() { - assertEquals(1, Reflect.enumerate.length); -})(); - - -(function testReflectEnumerateOnNonObject() { - assertThrows(function() { Reflect.enumerate(); }, TypeError); - assertThrows(function() { Reflect.enumerate(42); }, TypeError); - assertThrows(function() { Reflect.enumerate(null); }, TypeError); -})(); - - -// See reflect-enumerate*.js for further tests. - - - //////////////////////////////////////////////////////////////////////////////// // Reflect.getOwnPropertyDescriptor diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-4696.js b/deps/v8/test/mjsunit/harmony/regress/regress-4696.js new file mode 100644 index 0000000000..82969f9fbe --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/regress/regress-4696.js @@ -0,0 +1,29 @@ +// Copyright 2016 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 testSpreadIndex() { + var result = [...[17, 42]][1]; + assertEquals(result, 42); +})(); + +(function testSpreadProperty() { + var result = [...[17, 42]].length; + assertEquals(result, 2); +})(); + +(function testSpreadMethodCall() { + var result = [...[17, 42]].join("+"); + assertEquals(result, "17+42"); +})(); + +(function testSpreadSavedMethodCall() { + var x = [...[17, 42]]; + var method = x.join; + var result = method.call(x, "+"); + assertEquals(result, "17+42"); +})(); + +(function testSpreadAsTemplateTag() { + assertThrows(function() { [...[17, 42]] `foo`; }, TypeError) +})(); diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-4755.js b/deps/v8/test/mjsunit/harmony/regress/regress-4755.js new file mode 100644 index 0000000000..2a0df9dba4 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/regress/regress-4755.js @@ -0,0 +1,45 @@ +// Copyright 2016 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 --harmony-do-expressions + +(function DoTryCatchInsideBinop() { + function f(a, b) { + return a + do { try { throw "boom" } catch(e) { b } } + } + assertEquals(3, f(1, 2)); + assertEquals(3, f(1, 2)); + %OptimizeFunctionOnNextCall(f); + assertEquals(3, f(1, 2)); +})(); + +(function DoTryCatchInsideCall() { + function f(a, b) { + return Math.max(a, do { try { throw a } catch(e) { e + b } }) + } + assertEquals(3, f(1, 2)); + assertEquals(3, f(1, 2)); + %OptimizeFunctionOnNextCall(f); + assertEquals(3, f(1, 2)); +})(); + +(function DoTryCatchInsideTry() { + function f(a, b) { + try { return do { try { throw a } catch(e) { e + b } } } catch(e) {} + } + assertEquals(3, f(1, 2)); + assertEquals(3, f(1, 2)); + %OptimizeFunctionOnNextCall(f); + assertEquals(3, f(1, 2)); +})(); + +(function DoTryCatchInsideFinally() { + function f(a, b) { + try {} finally { return do { try { throw a } catch(e) { e + b } } } + } + assertEquals(3, f(1, 2)); + assertEquals(3, f(1, 2)); + %OptimizeFunctionOnNextCall(f); + assertEquals(3, f(1, 2)); +})(); diff --git a/deps/v8/test/mjsunit/harmony/regress/regress-crbug-578038.js b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-578038.js new file mode 100644 index 0000000000..42774b84ed --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/regress/regress-crbug-578038.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-do-expressions + +(function testWithoutOtherLiteral() { + var result = ((x = [...[42]]) => x)(); + assertEquals(result, [42]); +})(); + +(function testWithSomeOtherLiteral() { + []; // important: an array literal before the arrow function + var result = ((x = [...[42]]) => x)(); // will core dump, if not fixed. + assertEquals(result, [42]); +})(); diff --git a/deps/v8/test/mjsunit/harmony/simd.js b/deps/v8/test/mjsunit/harmony/simd.js index 6330ac8338..ff81506afe 100644 --- a/deps/v8/test/mjsunit/harmony/simd.js +++ b/deps/v8/test/mjsunit/harmony/simd.js @@ -407,7 +407,7 @@ function TestSameValue(type, lanes) { var simdFn = SIMD[type]; var instance = createInstance(type); var sameValue = Object.is - var sameValueZero = natives.ImportNow("SameValueZero"); + var sameValueZero = function(x, y) { return %SameValueZero(x, y); } // SIMD values should not be the same as instances of different types. checkTypeMatrix(type, function(other) { diff --git a/deps/v8/test/mjsunit/harmony/string-replace.js b/deps/v8/test/mjsunit/harmony/string-replace.js new file mode 100644 index 0000000000..208c483fd0 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/string-replace.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: --harmony-regexp-subclass + +var pattern = { + [Symbol.replace]: (string, newValue) => string + newValue +}; +// Check object coercible fails. +assertThrows(() => String.prototype.replace.call(null, pattern, "x"), + TypeError); +// Override is called. +assertEquals("abcdex", "abcde".replace(pattern, "x")); +// Non-callable override. +pattern[Symbol.replace] = "dumdidum"; +assertThrows(() => "abcde".replace(pattern, "x"), TypeError); + +assertEquals("[Symbol.replace]", RegExp.prototype[Symbol.replace].name); diff --git a/deps/v8/test/mjsunit/harmony/unicode-character-ranges.js b/deps/v8/test/mjsunit/harmony/unicode-character-ranges.js new file mode 100644 index 0000000000..e4f5247c15 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/unicode-character-ranges.js @@ -0,0 +1,158 @@ +// Copyright 2016 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-unicode-regexps --harmony-regexp-lookbehind + +function execl(expectation, regexp, subject) { + if (regexp instanceof String) regexp = new RegExp(regexp, "u"); + assertEquals(expectation, regexp.exec(subject)); +} + +function execs(expectation, regexp_source, subject) { + execl(expectation, new RegExp(regexp_source, "u"), subject); +} + +// Character ranges. +execl(["A"], /[A-D]/u, "A"); +execs(["A"], "[A-D]", "A"); +execl(["ABCD"], /[A-D]+/u, "ZABCDEF"); +execs(["ABCD"], "[A-D]+", "ZABCDEF"); + +execl(["\u{12345}"], /[\u1234-\u{12345}]/u, "\u{12345}"); +execs(["\u{12345}"], "[\u1234-\u{12345}]", "\u{12345}"); +execl(null, /[^\u1234-\u{12345}]/u, "\u{12345}"); +execs(null, "[^\u1234-\u{12345}]", "\u{12345}"); + +execl(["\u{1234}"], /[\u1234-\u{12345}]/u, "\u{1234}"); +execs(["\u{1234}"], "[\u1234-\u{12345}]", "\u{1234}"); +execl(null, /[^\u1234-\u{12345}]/u, "\u{1234}"); +execs(null, "[^\u1234-\u{12345}]", "\u{1234}"); + +execl(null, /[\u1234-\u{12345}]/u, "\u{1233}"); +execs(null, "[\u1234-\u{12345}]", "\u{1233}"); +execl(["\u{1233}"], /[^\u1234-\u{12345}]/u, "\u{1233}"); +execs(["\u{1233}"], "[^\u1234-\u{12345}]", "\u{1233}"); + +execl(["\u{12346}"], /[^\u1234-\u{12345}]/u, "\u{12346}"); +execs(["\u{12346}"], "[^\u1234-\u{12345}]", "\u{12346}"); +execl(null, /[\u1234-\u{12345}]/u, "\u{12346}"); +execs(null, "[\u1234-\u{12345}]", "\u{12346}"); + +execl(["\u{12342}"], /[\u{12340}-\u{12345}]/u, "\u{12342}"); +execs(["\u{12342}"], "[\u{12340}-\u{12345}]", "\u{12342}"); +execl(["\u{12342}"], /[\ud808\udf40-\ud808\udf45]/u, "\u{12342}"); +execs(["\u{12342}"], "[\ud808\udf40-\ud808\udf45]", "\u{12342}"); +execl(null, /[^\u{12340}-\u{12345}]/u, "\u{12342}"); +execs(null, "[^\u{12340}-\u{12345}]", "\u{12342}"); +execl(null, /[^\ud808\udf40-\ud808\udf45]/u, "\u{12342}"); +execs(null, "[^\ud808\udf40-\ud808\udf45]", "\u{12342}"); + +execl(["\u{ffff}"], /[\u{ff80}-\u{12345}]/u, "\u{ffff}"); +execs(["\u{ffff}"], "[\u{ff80}-\u{12345}]", "\u{ffff}"); +execl(["\u{ffff}"], /[\u{ff80}-\ud808\udf45]/u, "\u{ffff}"); +execs(["\u{ffff}"], "[\u{ff80}-\ud808\udf45]", "\u{ffff}"); +execl(null, /[^\u{ff80}-\u{12345}]/u, "\u{ffff}"); +execs(null, "[^\u{ff80}-\u{12345}]", "\u{ffff}"); +execl(null, /[^\u{ff80}-\ud808\udf45]/u, "\u{ffff}"); +execs(null, "[^\u{ff80}-\ud808\udf45]", "\u{ffff}"); + +// Lone surrogate +execl(["\ud800"], /[^\u{ff80}-\u{12345}]/u, "\uff99\u{d800}A"); +execs(["\udc00"], "[^\u{ff80}-\u{12345}]", "\uff99\u{dc00}A"); +execl(["\udc01"], /[\u0100-\u{10ffff}]/u, "A\udc01"); +execl(["\udc03"], /[\udc01-\udc03]/u, "\ud801\udc02\udc03"); +execl(["\ud801"], /[\ud801-\ud803]/u, "\ud802\udc01\ud801"); + +// Paired sorrogate. +execl(null, /[^\u{ff80}-\u{12345}]/u, "\u{d800}\u{dc00}"); +execs(null, "[^\u{ff80}-\u{12345}]", "\u{d800}\u{dc00}"); +execl(["\ud800\udc00"], /[\u{ff80}-\u{12345}]/u, "\u{d800}\u{dc00}"); +execs(["\ud800\udc00"], "[\u{ff80}-\u{12345}]", "\u{d800}\u{dc00}"); +execl(["foo\u{10e6d}bar"], /foo\ud803\ude6dbar/u, "foo\u{10e6d}bar"); + +// Lone surrogates +execl(["\ud801\ud801"], /\ud801+/u, "\ud801\udc01\ud801\ud801"); +execl(["\udc01\udc01"], /\udc01+/u, "\ud801\ud801\udc01\udc01\udc01"); + +execl(["\udc02\udc03A"], /\W\WA/u, "\ud801\udc01A\udc02\udc03A"); +execl(["\ud801\ud802"], /\ud801./u, "\ud801\udc01\ud801\ud802"); +execl(["\udc02\udc03A"], /[\ud800-\udfff][\ud800-\udfff]A/u, + "\ud801\udc01A\udc02\udc03A"); + +// Character classes +execl(null, /\w/u, "\ud801\udc01"); +execl(["\ud801"], /[^\w]/, "\ud801\udc01"); +execl(["\ud801\udc01"], /[^\w]/u, "\ud801\udc01"); +execl(["\ud801"], /\W/, "\ud801\udc01"); +execl(["\ud801\udc01"], /\W/u, "\ud801\udc01"); + +execl(["\ud800X"], /.X/u, "\ud800XaX"); +execl(["aX"], /.(?<!\ud800)X/u, "\ud800XaX"); +execl(["aX"], /.(?<![\ud800-\ud900])X/u, "\ud800XaX"); + +execl(null, /[]/u, "\u1234"); +execl(["0abc"], /[^]abc/u, "0abc"); +execl(["\u1234abc"], /[^]abc/u, "\u1234abc"); +execl(["\u{12345}abc"], /[^]abc/u, "\u{12345}abc"); + +execl(null, /[\u{0}-\u{1F444}]/u, "\ud83d\udfff"); + +// Backward matches of lone surrogates. +execl(["B", "\ud803A"], /(?<=([\ud800-\ud900]A))B/u, + "\ud801\udc00AB\udc00AB\ud802\ud803AB"); +execl(["B", "\udc00A"], /(?<=([\ud800-\u{10300}]A))B/u, + "\ud801\udc00AB\udc00AB\ud802\ud803AB"); +execl(["B", "\udc11A"], /(?<=([\udc00-\udd00]A))B/u, + "\ud801\udc00AB\udc11AB\ud802\ud803AB"); +execl(["X", "\ud800C"], /(?<=(\ud800\w))X/u, + "\ud800\udc00AX\udc11BX\ud800\ud800CX"); +execl(["C", "\ud800\ud800"], /(?<=(\ud800.))\w/u, + "\ud800\udc00AX\udc11BX\ud800\ud800CX"); +execl(["X", "\udc01C"], /(?<=(\udc01\w))X/u, + "\ud800\udc01AX\udc11BX\udc01\udc01CX"); +execl(["C", "\udc01\udc01"], /(?<=(\udc01.))./u, + "\ud800\udc01AX\udc11BX\udc01\udc01CX"); + +var L = "\ud800"; +var T = "\udc00"; +var X = "X"; + +// Test string contains only match. +function testw(expect, src, subject) { + var re = new RegExp("^" + src + "$", "u"); + assertEquals(expect, re.test(subject)); +} + +// Test string starts with match. +function tests(expect, src, subject) { + var re = new RegExp("^" + src, "u"); + assertEquals(expect, re.test(subject)); +} + +testw(true, X, X); +testw(true, L, L); +testw(true, T, T); +testw(true, L + T, L + T); +testw(true, T + L, T + L); +testw(false, T, L + T); +testw(false, L, L + T); +testw(true, ".(?<=" + L + ")", L); +testw(true, ".(?<=" + T + ")", T); +testw(true, ".(?<=" + L + T + ")", L + T); +testw(true, ".(?<=" + L + T + ")", L + T); +tests(true, ".(?<=" + T + ")", T + L); +tests(false, ".(?<=" + L + ")", L + T); +tests(false, ".(?<=" + T + ")", L + T); +tests(true, "..(?<=" + T + ")", T + T + L); +tests(true, "..(?<=" + T + ")", X + T + L); +tests(true, "...(?<=" + L + ")", X + T + L); +tests(false, "...(?<=" + T + ")", X + L + T) +tests(true, "..(?<=" + L + T + ")", X + L + T) +tests(true, "..(?<=" + L + T + "(?<=" + L + T + "))", X + L + T); +tests(false, "..(?<=" + L + "(" + T + "))", X + L + T); +tests(false, ".*" + L, X + L + T); +tests(true, ".*" + L, X + L + L + T); +tests(false, ".*" + L, X + L + T + L + T); +tests(false, ".*" + T, X + L + T + L + T); +tests(true, ".*" + T, X + L + T + T + L + T); diff --git a/deps/v8/test/mjsunit/harmony/unicode-escapes-in-regexps.js b/deps/v8/test/mjsunit/harmony/unicode-escapes-in-regexps.js index f591dac930..895e0c6722 100644 --- a/deps/v8/test/mjsunit/harmony/unicode-escapes-in-regexps.js +++ b/deps/v8/test/mjsunit/harmony/unicode-escapes-in-regexps.js @@ -252,6 +252,36 @@ assertFalse(/(\u{12345}|\u{23456}).\1/u.test("\u{12345}b\u{23456}")); assertTrue(new RegExp("\u{12345}{3}", "u").test("\u{12345}\u{12345}\u{12345}")); assertTrue(/\u{12345}{3}/u.test("\u{12345}\u{12345}\u{12345}")); assertTrue(new RegExp("\u{12345}{3}").test("\u{12345}\udf45\udf45")); -assertTrue(/\ud808\udf45{3}/u.test("\u{12345}\udf45\udf45")); +assertFalse(/\ud808\udf45{3}/u.test("\u{12345}\udf45\udf45")); +assertTrue(/\ud808\udf45{3}/u.test("\u{12345}\u{12345}\u{12345}")); assertFalse(new RegExp("\u{12345}{3}", "u").test("\u{12345}\udf45\udf45")); assertFalse(/\u{12345}{3}/u.test("\u{12345}\udf45\udf45")); + +// Literal surrogates. +assertEquals(["\u{10000}\u{10000}"], + new RegExp("\ud800\udc00+", "u").exec("\u{10000}\u{10000}")); +assertEquals(["\u{10000}\u{10000}"], + new RegExp("\\ud800\\udc00+", "u").exec("\u{10000}\u{10000}")); + +assertEquals(["\u{10003}\u{50001}"], + new RegExp("[\\ud800\\udc03-\\ud900\\udc01\]+", "u").exec( + "\u{10003}\u{50001}")); +assertEquals(["\u{10003}\u{50001}"], + new RegExp("[\ud800\udc03-\u{50001}\]+", "u").exec( + "\u{10003}\u{50001}")); + +// Unicode escape sequences to represent a non-BMP character cannot have +// mixed notation, and must follow the rules for RegExpUnicodeEscapeSequence. +assertThrows(() => new RegExp("[\\ud800\udc03-\ud900\\udc01\]+", "u")); +assertThrows(() => new RegExp("[\\ud800\udc03-\ud900\\udc01\]+", "u")); +assertNull(new RegExp("\\ud800\udc00+", "u").exec("\u{10000}\u{10000}")); +assertNull(new RegExp("\ud800\\udc00+", "u").exec("\u{10000}\u{10000}")); + +assertNull(new RegExp("[\\ud800\udc00]", "u").exec("\u{10000}")); +assertNull(new RegExp("[\\{ud800}\udc00]", "u").exec("\u{10000}")); +assertNull(new RegExp("[\ud800\\udc00]", "u").exec("\u{10000}")); +assertNull(new RegExp("[\ud800\\{udc00}]", "u").exec("\u{10000}")); + +assertNull(/\u{d800}\u{dc00}+/u.exec("\ud800\udc00\udc00")); +assertNull(/\ud800\u{dc00}+/u.exec("\ud800\udc00\udc00")); +assertNull(/\u{d800}\udc00+/u.exec("\ud800\udc00\udc00")); diff --git a/deps/v8/test/mjsunit/harmony/unicode-regexp-backrefs.js b/deps/v8/test/mjsunit/harmony/unicode-regexp-backrefs.js new file mode 100644 index 0000000000..e02301be1e --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/unicode-regexp-backrefs.js @@ -0,0 +1,53 @@ +// Copyright 2016 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-unicode-regexps --harmony-regexp-lookbehind + +// Back reference does not end in the middle of a surrogate pair. +function replace(string) { + return string.replace(/L/g, "\ud800") + .replace(/l/g, "\ud801") + .replace(/T/g, "\udc00") + .replace(/\./g, "[^]"); +} + +function test(expectation, regexp_source, subject) { + if (expectation !== null) expectation = expectation.map(replace); + subject = replace(subject); + regexp_source = replace(regexp_source); + assertEquals(expectation, new RegExp(regexp_source, "u").exec(subject)); +} + +// Back reference does not end in the middle of a surrogate pair. +test(null, "(L)\\1", "LLT"); +test(["LLTLl", "L", "l"], "(L).*\\1(.)", "LLTLl"); +test(null, "(aL).*\\1", "aLaLT"); +test(["aLaLTaLl", "aL", "l"], "(aL).*\\1(.)", "aLaLTaLl"); + +var s = "TabcLxLTabcLxTabcLTyTabcLz"; +test([s, "TabcL", "z"], "([^x]+).*\\1(.)", s); + +// Back reference does not start in the middle of a surrogate pair. +test(["TLTabTc", "T", "c"], "(T).*\\1(.)", "TLTabTc"); + +// Lookbehinds. +test(null, "(?<=\\1(T)x)", "LTTx"); +test(["", "b", "T"], "(?<=(.)\\2.*(T)x)", "bTaLTTx"); +test(null, "(?<=\\1.*(L)x)", "LTLx"); +test(["", "b", "L"], "(?<=(.)\\2.*(L)x)", "bLaLTLx"); + + +test(null, "([^x]+)x*\\1", "LxLT"); +test(null, "([^x]+)x*\\1", "TxLT"); +test(null, "([^x]+)x*\\1", "LTxL"); +test(null, "([^x]+)x*\\1", "LTxT"); +test(null, "([^x]+)x*\\1", "xLxLT"); +test(null, "([^x]+)x*\\1", "xTxLT"); +test(null, "([^x]+)x*\\1", "xLTxL"); +test(null, "([^x]+)x*\\1", "xLTxT"); +test(null, "([^x]+)x*\\1", "xxxLxxLTxx"); +test(null, "([^x]+)x*\\1", "xxxTxxLTxx"); +test(null, "([^x]+)x*\\1", "xxxLTxxLxx"); +test(null, "([^x]+)x*\\1", "xxxLTxxTxx"); +test(["LTTxxLTT", "LTT"], "([^x]+)x*\\1", "xxxLTTxxLTTxx"); diff --git a/deps/v8/test/mjsunit/harmony/unicode-regexp-ignore-case-noi18n.js b/deps/v8/test/mjsunit/harmony/unicode-regexp-ignore-case-noi18n.js new file mode 100644 index 0000000000..a4cb9dc337 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/unicode-regexp-ignore-case-noi18n.js @@ -0,0 +1,59 @@ +// Copyright 2016 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-unicode-regexps + +// Non-unicode use toUpperCase mappings. +assertFalse(/[\u00e5]/i.test("\u212b")); +assertFalse(/[\u212b]/i.test("\u00e5\u1234")); +assertFalse(/[\u212b]/i.test("\u00e5")); + +assertTrue("\u212b".toLowerCase() == "\u00e5"); +assertTrue("\u00c5".toLowerCase() == "\u00e5"); +assertTrue("\u00e5".toUpperCase() == "\u00c5"); + +// Unicode uses case folding mappings. +assertFalse(/\u00e5/ui.test("\u212b")); +assertTrue(/\u00e5/ui.test("\u00c5")); +assertTrue(/\u00e5/ui.test("\u00e5")); +assertFalse(/\u00e5/ui.test("\u212b")); +assertTrue(/\u00c5/ui.test("\u00e5")); +assertFalse(/\u00c5/ui.test("\u212b")); +assertTrue(/\u00c5/ui.test("\u00c5")); +assertFalse(/\u212b/ui.test("\u00c5")); +assertFalse(/\u212b/ui.test("\u00e5")); +assertTrue(/\u212b/ui.test("\u212b")); + +// Non-BMP. +assertFalse(/\u{10400}/i.test("\u{10428}")); +assertFalse(/\u{10400}/ui.test("\u{10428}")); +assertFalse(/\ud801\udc00/ui.test("\u{10428}")); +assertFalse(/[\u{10428}]/ui.test("\u{10400}")); +assertFalse(/[\ud801\udc28]/ui.test("\u{10400}")); +assertEquals(["\uff21\u{10400}"], + /[\uff40-\u{10428}]+/ui.exec("\uff21\u{10400}abc")); +assertEquals(["abc"], /[^\uff40-\u{10428}]+/ui.exec("\uff21\u{10400}abc\uff23")); +assertEquals(["\uff53\u24bb"], + /[\u24d5-\uff33]+/ui.exec("\uff54\uff53\u24bb\u24ba")); + +// Full mappings are ignored. +assertFalse(/\u00df/ui.test("SS")); +assertFalse(/\u1f8d/ui.test("\u1f05\u03b9")); + +// Simple mappings. +assertFalse(/\u1f8d/ui.test("\u1f85")); + +// Common mappings. +assertTrue(/\u1f6b/ui.test("\u1f63")); + +// Back references. +assertNull(/(.)\1\1/ui.exec("\u00e5\u212b\u00c5")); +assertNull(/(.)\1/ui.exec("\u{118aa}\u{118ca}")); + + +// Non-Latin1 maps to Latin1. +assertNull(/^\u017F/ui.exec("s")); +assertNull(/^\u017F/ui.exec("s\u1234")); +assertNull(/^a[\u017F]/ui.exec("as")); +assertNull(/^a[\u017F]/ui.exec("as\u1234")); diff --git a/deps/v8/test/mjsunit/harmony/unicode-regexp-ignore-case.js b/deps/v8/test/mjsunit/harmony/unicode-regexp-ignore-case.js new file mode 100644 index 0000000000..291b8662ff --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/unicode-regexp-ignore-case.js @@ -0,0 +1,64 @@ +// Copyright 2016 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-unicode-regexps + +// Non-unicode use toUpperCase mappings. +assertFalse(/[\u00e5]/i.test("\u212b")); +assertFalse(/[\u212b]/i.test("\u00e5\u1234")); +assertFalse(/[\u212b]/i.test("\u00e5")); + +assertTrue("\u212b".toLowerCase() == "\u00e5"); +assertTrue("\u00c5".toLowerCase() == "\u00e5"); +assertTrue("\u00e5".toUpperCase() == "\u00c5"); + +// Unicode uses case folding mappings. +assertTrue(/\u00e5/ui.test("\u212b")); +assertTrue(/\u00e5/ui.test("\u00c5")); +assertTrue(/\u00e5/ui.test("\u00e5")); +assertTrue(/\u00e5/ui.test("\u212b")); +assertTrue(/\u00c5/ui.test("\u00e5")); +assertTrue(/\u00c5/ui.test("\u212b")); +assertTrue(/\u00c5/ui.test("\u00c5")); +assertTrue(/\u212b/ui.test("\u00c5")); +assertTrue(/\u212b/ui.test("\u00e5")); +assertTrue(/\u212b/ui.test("\u212b")); + +// Non-BMP. +assertFalse(/\u{10400}/i.test("\u{10428}")); +assertTrue(/\u{10400}/ui.test("\u{10428}")); +assertTrue(/\ud801\udc00/ui.test("\u{10428}")); +assertTrue(/[\u{10428}]/ui.test("\u{10400}")); +assertTrue(/[\ud801\udc28]/ui.test("\u{10400}")); +assertEquals(["\uff21\u{10400}"], + /[\uff40-\u{10428}]+/ui.exec("\uff21\u{10400}abc")); +assertEquals(["abc"], /[^\uff40-\u{10428}]+/ui.exec("\uff21\u{10400}abc\uff23")); +assertEquals(["\uff53\u24bb"], + /[\u24d5-\uff33]+/ui.exec("\uff54\uff53\u24bb\u24ba")); + +// Full mappings are ignored. +assertFalse(/\u00df/ui.test("SS")); +assertFalse(/\u1f8d/ui.test("\u1f05\u03b9")); + +// Simple mappings work. +assertTrue(/\u1f8d/ui.test("\u1f85")); + +// Common mappings work. +assertTrue(/\u1f6b/ui.test("\u1f63")); + +// Back references. +assertEquals(["\u00e5\u212b\u00c5", "\u00e5"], + /(.)\1\1/ui.exec("\u00e5\u212b\u00c5")); +assertEquals(["\u{118aa}\u{118ca}", "\u{118aa}"], + /(.)\1/ui.exec("\u{118aa}\u{118ca}")); + +// Misc. +assertTrue(/\u00e5\u00e5\u00e5/ui.test("\u212b\u00e5\u00c5")); +assertTrue(/AB\u{10400}/ui.test("ab\u{10428}")); + +// Non-Latin1 maps to Latin1. +assertEquals(["s"], /^\u017F/ui.exec("s")); +assertEquals(["s"], /^\u017F/ui.exec("s\u1234")); +assertEquals(["as"], /^a[\u017F]/ui.exec("as")); +assertEquals(["as"], /^a[\u017F]/ui.exec("as\u1234")); diff --git a/deps/v8/test/mjsunit/harmony/unicode-regexp-last-index.js b/deps/v8/test/mjsunit/harmony/unicode-regexp-last-index.js new file mode 100644 index 0000000000..4a075d4380 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/unicode-regexp-last-index.js @@ -0,0 +1,104 @@ +// Copyright 2016 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-unicode-regexps --harmony-regexp-lookbehind + +var r = /./ug; +assertEquals(["\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(2, r.lastIndex); +r.lastIndex = 1; +assertEquals(["\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(2, r.lastIndex); +assertEquals(["\ud801\udc01"], r.exec("\ud800\udc00\ud801\udc01")); +r.lastIndex = 3; +assertEquals(["\ud801\udc01"], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(4, r.lastIndex); +r.lastIndex = 4; +assertNull(r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(0, r.lastIndex); +r.lastIndex = 5; +assertNull(r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(0, r.lastIndex); + +r.lastIndex = 3; +assertEquals(["\ud802"], r.exec("\ud800\udc00\ud801\ud802")); +r.lastIndex = 4; +assertNull(r.exec("\ud800\udc00\ud801\ud802")); + +r = /./g; +assertEquals(["\ud800"], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(1, r.lastIndex); +assertEquals(["\udc00"], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(2, r.lastIndex); +assertEquals(["\ud801"], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(3, r.lastIndex); +assertEquals(["\udc01"], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(4, r.lastIndex); +assertNull(r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(0, r.lastIndex); +r.lastIndex = 1; +assertEquals(["\udc00"], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(2, r.lastIndex); + +// ------------------------ + +r = /^./ug; +assertEquals(["\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(2, r.lastIndex); +r.lastIndex = 1; +assertEquals(["\ud800\udc00"], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(2, r.lastIndex); +assertNull(r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(0, r.lastIndex); +r.lastIndex = 3; +assertNull(r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(0, r.lastIndex); +r.lastIndex = 4; +assertNull(r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(0, r.lastIndex); +r.lastIndex = 5; +assertNull(r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(0, r.lastIndex); + +r = /^./g; +assertEquals(["\ud800"], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(1, r.lastIndex); +assertNull(r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(0, r.lastIndex); +r.lastIndex = 3; +assertNull(r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(0, r.lastIndex); + +//------------------------ + +r = /(?:(^.)|.)/ug; +assertEquals(["\ud800\udc00", "\ud800\udc00"], + r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(2, r.lastIndex); +r.lastIndex = 1; +assertEquals(["\ud800\udc00", "\ud800\udc00"], + r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(2, r.lastIndex); +assertEquals(["\ud801\udc01", undefined], r.exec("\ud800\udc00\ud801\udc01")); +r.lastIndex = 3; +assertEquals(["\ud801\udc01", undefined], r.exec("\ud800\udc00\ud801\udc01")); +r.lastIndex = 4; +assertNull(r.exec("\ud800\udc00\ud801\udc01")); +r.lastIndex = 5; +assertNull(r.exec("\ud800\udc00\ud801\udc01")); + +r.lastIndex = 3; +assertEquals(["\ud802", undefined], r.exec("\ud800\udc00\ud801\ud802")); +r.lastIndex = 4; +assertNull(r.exec("\ud800\udc00\ud801\ud802")); + +r = /(?:(^.)|.)/g; +assertEquals(["\ud800", "\ud800"], + r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(1, r.lastIndex); +assertEquals(["\udc00", undefined], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(2, r.lastIndex); +r.lastIndex = 3; +assertEquals(["\udc01", undefined], r.exec("\ud800\udc00\ud801\udc01")); +assertEquals(4, r.lastIndex); diff --git a/deps/v8/test/mjsunit/harmony/unicode-regexp-property-class.js b/deps/v8/test/mjsunit/harmony/unicode-regexp-property-class.js new file mode 100644 index 0000000000..323873ab7f --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/unicode-regexp-property-class.js @@ -0,0 +1,64 @@ +// Copyright 2016 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-regexp-property --harmony-unicode-regexps + +assertThrows("/\\p/u"); +assertThrows("/\\p{garbage}/u"); +assertThrows("/\\p{}/u"); +assertThrows("/\\p{/u"); +assertThrows("/\\p}/u"); +assertThrows("/\p{Math}/u"); +assertThrows("/\p{Bidi_M}/u"); +assertThrows("/\p{Hex}/u"); + +assertTrue(/\p{Ll}/u.test("a")); +assertFalse(/\P{Ll}/u.test("a")); +assertTrue(/\P{Ll}/u.test("A")); +assertFalse(/\p{Ll}/u.test("A")); +assertTrue(/\p{Ll}/u.test("\u{1D7BE}")); +assertFalse(/\P{Ll}/u.test("\u{1D7BE}")); +assertFalse(/\p{Ll}/u.test("\u{1D5E3}")); +assertTrue(/\P{Ll}/u.test("\u{1D5E3}")); + +assertTrue(/\p{Ll}/iu.test("a")); +assertTrue(/\p{Ll}/iu.test("\u{118D4}")); +assertTrue(/\p{Ll}/iu.test("A")); +assertTrue(/\p{Ll}/iu.test("\u{118B4}")); +assertFalse(/\P{Ll}/iu.test("a")); +assertFalse(/\P{Ll}/iu.test("\u{118D4}")); +assertFalse(/\P{Ll}/iu.test("A")); +assertFalse(/\P{Ll}/iu.test("\u{118B4}")); + +assertTrue(/\p{Lu}/u.test("A")); +assertFalse(/\P{Lu}/u.test("A")); +assertTrue(/\P{Lu}/u.test("a")); +assertFalse(/\p{Lu}/u.test("a")); +assertTrue(/\p{Lu}/u.test("\u{1D5E3}")); +assertFalse(/\P{Lu}/u.test("\u{1D5E3}")); +assertFalse(/\p{Lu}/u.test("\u{1D7BE}")); +assertTrue(/\P{Lu}/u.test("\u{1D7BE}")); + +assertTrue(/\p{Lu}/iu.test("a")); +assertTrue(/\p{Lu}/iu.test("\u{118D4}")); +assertTrue(/\p{Lu}/iu.test("A")); +assertTrue(/\p{Lu}/iu.test("\u{118B4}")); +assertFalse(/\P{Lu}/iu.test("a")); +assertFalse(/\P{Lu}/iu.test("\u{118D4}")); +assertFalse(/\P{Lu}/iu.test("A")); +assertFalse(/\P{Lu}/iu.test("\u{118B4}")); + +assertTrue(/\p{Sm}/u.test("+")); +assertFalse(/\P{Sm}/u.test("+")); +assertTrue(/\p{Sm}/u.test("\u{1D6C1}")); +assertFalse(/\P{Sm}/u.test("\u{1D6C1}")); + +assertTrue(/\pL/u.test("a")); +assertFalse(/\PL/u.test("a")); +assertFalse(/\pL/u.test("1")); +assertTrue(/\PL/u.test("1")); +assertTrue(/\pL/u.test("\u1FAB")); +assertFalse(/\PL/u.test("\u1FAB")); +assertFalse(/\p{L}/u.test("\uA6EE")); +assertTrue(/\P{L}/u.test("\uA6EE")); diff --git a/deps/v8/test/mjsunit/harmony/unicode-regexp-restricted-syntax.js b/deps/v8/test/mjsunit/harmony/unicode-regexp-restricted-syntax.js new file mode 100644 index 0000000000..d129cc340e --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/unicode-regexp-restricted-syntax.js @@ -0,0 +1,44 @@ +// Copyright 2016 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-unicode-regexps + +// test262/data/test/language/literals/regexp/u-dec-esc +assertThrows("/\\1/u", SyntaxError); +// test262/language/literals/regexp/u-invalid-char-range-a +assertThrows("/[\\w-a]/u", SyntaxError); +// test262/language/literals/regexp/u-invalid-char-range-b +assertThrows("/[a-\\w]/u", SyntaxError); +// test262/language/literals/regexp/u-invalid-char-esc +assertThrows("/\\c/u", SyntaxError); +assertThrows("/\\c0/u", SyntaxError); +// test262/built-ins/RegExp/unicode_restricted_quantifiable_assertion +assertThrows("/(?=.)*/u", SyntaxError); +// test262/built-ins/RegExp/unicode_restricted_octal_escape +assertThrows("/[\\1]/u", SyntaxError); +assertThrows("/\\00/u", SyntaxError); +assertThrows("/\\09/u", SyntaxError); +// test262/built-ins/RegExp/unicode_restricted_identity_escape_alpha +assertThrows("/[\\c]/u", SyntaxError); +// test262/built-ins/RegExp/unicode_restricted_identity_escape_c +assertThrows("/[\\c0]/u", SyntaxError); +// test262/built-ins/RegExp/unicode_restricted_incomple_quantifier +assertThrows("/a{/u", SyntaxError); +assertThrows("/a{1,/u", SyntaxError); +assertThrows("/{/u", SyntaxError); +assertThrows("/}/u", SyntaxError); +// test262/data/test/built-ins/RegExp/unicode_restricted_brackets +assertThrows("/]/u", SyntaxError); +// test262/built-ins/RegExp/unicode_identity_escape +/\//u; + +// escaped \0 is allowed inside a character class. +assertEquals(["\0"], /[\0]/u.exec("\0")); +// unless it is followed by another digit. +assertThrows("/[\\00]/u", SyntaxError); +assertThrows("/[\\01]/u", SyntaxError); +assertThrows("/[\\09]/u", SyntaxError); +assertEquals(["\u{0}1\u{0}a\u{0}"], /[1\0a]+/u.exec("b\u{0}1\u{0}a\u{0}2")); +// escaped \- is allowed inside a character class. +assertEquals(["-"], /[a\-z]/u.exec("12-34")); diff --git a/deps/v8/test/mjsunit/harmony/unicode-regexp-unanchored-advance.js b/deps/v8/test/mjsunit/harmony/unicode-regexp-unanchored-advance.js new file mode 100644 index 0000000000..97960e1cd3 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/unicode-regexp-unanchored-advance.js @@ -0,0 +1,8 @@ +// Copyright 2013 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-unicode-regexps + +var s = "a".repeat(1E7) + "\u1234"; +assertEquals(["\u1234", "\u1234"], /(\u1234)/u.exec(s)); diff --git a/deps/v8/test/mjsunit/harmony/unicode-regexp-zero-length.js b/deps/v8/test/mjsunit/harmony/unicode-regexp-zero-length.js new file mode 100644 index 0000000000..bbc17dc2d5 --- /dev/null +++ b/deps/v8/test/mjsunit/harmony/unicode-regexp-zero-length.js @@ -0,0 +1,58 @@ +// Copyright 2016 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-unicode-regexps + +var L = "\ud800"; +var T = "\udc00"; +var x = "x"; + +var r = /()/g; // Global, but not unicode. +// Zero-length matches do not advance lastIndex. +assertEquals(["", ""], r.exec(L + T + L + T)); +assertEquals(0, r.lastIndex); +r.lastIndex = 1; +assertEquals(["", ""], r.exec(L + T + L + T)); +assertEquals(1, r.lastIndex); + +var u = /()/ug; // Global and unicode. +// Zero-length matches do not advance lastIndex. +assertEquals(["", ""], u.exec(L + T + L + T)); +assertEquals(0, u.lastIndex); +u.lastIndex = 1; +assertEquals(["", ""], u.exec(L + T + L + T)); +assertEquals(0, u.lastIndex); + +// However, with repeating matches, lastIndex does not matter. +// We do advance from match to match. +r.lastIndex = 2; +assertEquals(x + L + x + T + x + L + x + T + x, + (L + T + L + T).replace(r, "x")); + +// With unicode flag, we advance code point by code point. +u.lastIndex = 3; +assertEquals(x + L + T + x + L + T + x, + (L + T + L + T).replace(u, "x")); + +// Test that exhausting the global match cache is fine. +assertEquals((x + L + T).repeat(1000) + x, + (L + T).repeat(1000).replace(u, "x")); + +// Same thing for RegExp.prototype.match. +r.lastIndex = 1; +assertEquals(["","","","",""], (L + T + L + T).match(r)); +r.lastIndex = 2; +assertEquals(["","","","",""], (L + T + L + T).match(r)); + +u.lastIndex = 1; +assertEquals(["","",""], (L + T + L + T).match(u)); +u.lastIndex = 2; +assertEquals(["","",""], (L + T + L + T).match(u)); + +var expected = []; +for (var i = 0; i <= 1000; i++) expected.push(""); +assertEquals(expected, (L + T).repeat(1000).match(u)); + +// Also test RegExp.prototype.@@split. +assertEquals(["\u{12345}"], "\u{12345}".split(/(?:)/u)); diff --git a/deps/v8/test/mjsunit/ignition/dead-code-source-position.js b/deps/v8/test/mjsunit/ignition/dead-code-source-position.js new file mode 100644 index 0000000000..95bb9183b8 --- /dev/null +++ b/deps/v8/test/mjsunit/ignition/dead-code-source-position.js @@ -0,0 +1,9 @@ +// Copyright 2016 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() { + for (f(x) in []) { f(new f()) } +} + +f(); diff --git a/deps/v8/test/mjsunit/ignition/debug-break-on-stack.js b/deps/v8/test/mjsunit/ignition/debug-break-on-stack.js new file mode 100644 index 0000000000..d2577b38de --- /dev/null +++ b/deps/v8/test/mjsunit/ignition/debug-break-on-stack.js @@ -0,0 +1,48 @@ +// Copyright 2016 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 + +var Debug = debug.Debug; + +var break_count = 0; +var exception = null; + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + break_count++; + var line = exec_state.frame(0).sourceLineText(); + print(line); + assertTrue(line.indexOf(`B${break_count}`) > 0); + } catch (e) { + exception = e; + } +} + + +function g() { + setbreaks(); + throw 1; // B1 +} + +function f() { + try { + g(); + } catch (e) {} + return 2; // B2 +} + +function setbreaks() { + Debug.setListener(listener); + Debug.setBreakPoint(g, 2, 0); + Debug.setBreakPoint(f, 4, 0); +} + +f(); + +assertEquals(2, break_count); +assertNull(exception); + +Debug.setListener(null); diff --git a/deps/v8/test/mjsunit/ignition/debug-break.js b/deps/v8/test/mjsunit/ignition/debug-break.js new file mode 100644 index 0000000000..8237d4a552 --- /dev/null +++ b/deps/v8/test/mjsunit/ignition/debug-break.js @@ -0,0 +1,46 @@ +// Copyright 2016 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 + +var Debug = debug.Debug; + +var break_count = 0; +var exception = null; + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + break_count++; + var line = exec_state.frame(0).sourceLineText(); + assertTrue(line.indexOf(`B${break_count}`) > 0); + } catch (e) { + exception = e; + } +} + +Debug.setListener(listener); + +function g() { + throw 1; +} + +function f() { + try { + g(); // B1 + } catch (e) {} + assertEquals(2, break_count); // B2 + return 1; // B3 +} + +Debug.setBreakPoint(f, 2, 0); +Debug.setBreakPoint(f, 4, 1); +Debug.setBreakPoint(f, 5, 1); + +f(); + +assertEquals(3, break_count); +assertNull(exception); + +Debug.setListener(null); diff --git a/deps/v8/test/mjsunit/ignition/debugger-statement.js b/deps/v8/test/mjsunit/ignition/debugger-statement.js new file mode 100644 index 0000000000..9c2204e4d2 --- /dev/null +++ b/deps/v8/test/mjsunit/ignition/debugger-statement.js @@ -0,0 +1,31 @@ +// Copyright 2016 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: --ignition-filter=f --expose-debug-as debug + +var Debug = debug.Debug; + +var break_count = 0; + +function f() { + debugger; +} + +function listener(event, exec_data) { + if (event != Debug.DebugEvent.Break) return; + break_count++; +} + +f(); +assertEquals(0, break_count); + +Debug.setListener(listener); + +f(); +assertEquals(1, break_count); + +Debug.setListener(null); + +f(); +assertEquals(1, break_count); diff --git a/deps/v8/test/mjsunit/ignition/stack-trace-source-position.js b/deps/v8/test/mjsunit/ignition/stack-trace-source-position.js new file mode 100644 index 0000000000..ce236c398c --- /dev/null +++ b/deps/v8/test/mjsunit/ignition/stack-trace-source-position.js @@ -0,0 +1,21 @@ +// Copyright 2016 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: --ignition-filter=f +// Flags: --no-turbo + +// TODO(yangguo): fix for turbofan + +function f(x) { + if (x == 0) { + return new Error().stack; + } + return f(x - 1); +} + +var stack_lines = f(2).split("\n"); + +assertTrue(/at f \(.*?:12:12\)/.test(stack_lines[1])); +assertTrue(/at f \(.*?:14:10\)/.test(stack_lines[2])); +assertTrue(/at f \(.*?:14:10\)/.test(stack_lines[3])); diff --git a/deps/v8/test/mjsunit/messages.js b/deps/v8/test/mjsunit/messages.js index 8da7e6bd7b..7deef02615 100644 --- a/deps/v8/test/mjsunit/messages.js +++ b/deps/v8/test/mjsunit/messages.js @@ -3,7 +3,7 @@ // found in the LICENSE file. // Flags: --stack-size=100 --harmony --harmony-reflect --harmony-regexps -// Flags: --harmony-simd --strong-mode +// Flags: --harmony-simd function test(f, expected, type) { try { @@ -150,7 +150,7 @@ TypeError); // kInstanceofFunctionExpected test(function() { 1 instanceof 1; -}, "Expecting a function in instanceof check, but got 1", TypeError); +}, "Expecting an object in instanceof check", TypeError); // kInstanceofNonobjectProto test(function() { @@ -305,12 +305,6 @@ test(function() { (1).a = 1; }, "Cannot create property 'a' on number '1'", TypeError); -// kStrongImplicitCast -test(function() { - "use strong"; - "a" + 1; -}, "In strong mode, implicit conversions are deprecated", TypeError); - // kSymbolToString test(function() { "" + Symbol(); @@ -345,36 +339,35 @@ test(function() { eval("/a/x.test(\"a\");"); }, "Invalid regular expression flags", SyntaxError); -// kMalformedRegExp -test(function() { - /(/.test("a"); -}, "Invalid regular expression: /(/: Unterminated group", SyntaxError); - -// kParenthesisInArgString -test(function() { - new Function(")", ""); -}, "Function arg string contains parenthesis", SyntaxError); - -// kUnexpectedEOS +//kJsonParseUnexpectedEOS test(function() { JSON.parse("{") -}, "Unexpected end of input", SyntaxError); +}, "Unexpected end of JSON input", SyntaxError); -// kUnexpectedToken +// kJsonParseUnexpectedTokenAt test(function() { JSON.parse("/") -}, "Unexpected token /", SyntaxError); +}, "Unexpected token / in JSON at position 0", SyntaxError); -// kUnexpectedTokenNumber +// kJsonParseUnexpectedTokenNumberAt test(function() { JSON.parse("{ 1") -}, "Unexpected number", SyntaxError); +}, "Unexpected number in JSON at position 2", SyntaxError); -// kUnexpectedTokenString +// kJsonParseUnexpectedTokenStringAt test(function() { JSON.parse('"""') -}, "Unexpected string", SyntaxError); +}, "Unexpected string in JSON at position 2", SyntaxError); + +// kMalformedRegExp +test(function() { + /(/.test("a"); +}, "Invalid regular expression: /(/: Unterminated group", SyntaxError); +// kParenthesisInArgString +test(function() { + new Function(")", ""); +}, "Function arg string contains parenthesis", SyntaxError); // === ReferenceError === diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status index 95e8da1cb2..e638f5645b 100644 --- a/deps/v8/test/mjsunit/mjsunit.status +++ b/deps/v8/test/mjsunit/mjsunit.status @@ -43,6 +43,9 @@ # This test non-deterministically runs out of memory on Windows ia32. 'regress/regress-crbug-160010': [SKIP], + # Issue 4698: not fully supported by Turbofan yet + 'es6/tail-call': [PASS, NO_VARIANTS], + # Issue 3389: deopt_every_n_garbage_collections is unsafe 'regress/regress-2653': [SKIP], @@ -118,7 +121,18 @@ 'debug-listbreakpoints': [PASS, NO_VARIANTS], # arm64 nosnap with turbofan 'debug-enable-disable-breakpoints': [PASS, NO_VARIANTS], #arm64 nosnap with turbofan. - # TODO(rossberg) + # Issue 3956: Strong mode is deprecating. The expectations inside the + # following tests should be updated once deprecation is complete. + 'strong/destructuring': [SKIP], + 'strong/implicit-conversions': [SKIP], + 'strong/implicit-conversions-count': [SKIP], + 'strong/implicit-conversions-inlining': [SKIP], + 'strong/load-builtins': [SKIP], + 'strong/load-element': [SKIP], + 'strong/load-element-mutate-backing-store': [SKIP], + 'strong/load-property': [SKIP], + 'strong/load-property-mutate-backing-store': [SKIP], + 'strong/load-super': [SKIP], 'strong/literals': [SKIP], # Rest arguments do not respect strongness in Turbofan. # Issue 4035: unexpected frame->context() in debugger @@ -193,7 +207,8 @@ 'regress/regress-crbug-491062': [PASS, NO_VARIANTS], # Issue 488: this test sometimes times out. - 'array-constructor': [PASS, TIMEOUT], + # TODO(arm): This seems to flush out a bug on arm with simulator. + 'array-constructor': [PASS, TIMEOUT, ['arch == arm and simulator == True', SKIP]], # Issue 4413: this test sometimes times out with TSAN because we trigger # the slow path in C++ with holey arrays in Function.prototype.apply. @@ -281,11 +296,16 @@ 'readonly': [PASS, SLOW], 'regress/regress-1200351': [PASS, ['mode == debug', SLOW]], 'regress/regress-crbug-474297': [PASS, ['mode == debug', SLOW]], - 'strong/implicit-conversions': [PASS, SLOW], - 'strong/load-element-mutate-backing-store': [PASS, SLOW], - # TODO(bradnelson): Enable tests in a separate change. - 'wasm/*': [SKIP], + # TODO(titzer): correct WASM adapter frame alignment on arm64 + 'wasm/*': [PASS, ['arch == arm64', SKIP]], + 'wasm/asm-wasm': [PASS, ['arch == arm or arch == arm64', SKIP]], + + # case-insensitive unicode regexp relies on case mapping provided by ICU. + 'harmony/unicode-regexp-ignore-case': [PASS, ['no_i18n == True', FAIL]], + 'harmony/unicode-regexp-ignore-case-noi18n': [FAIL, ['no_i18n == True', PASS]], + # desugaring regexp property class relies on ICU. + 'harmony/unicode-regexp-property-class': [PASS, ['no_i18n == True', FAIL]], }], # ALWAYS ['novfp3 == True', { @@ -362,6 +382,9 @@ # BUG(v8:3097) 'debug-references': [SKIP], + + # BUG(v8:4754). + 'debug-referenced-by': [PASS, NO_VARIANTS], }], # 'gc_stress == True' ############################################################################## @@ -376,6 +399,8 @@ 'asm/embenchen/*': [SKIP], 'asm/poppler/*': [SKIP], 'asm/sqlite3/*': [SKIP], + # TODO(mips-team): Fix Wasm for big-endian. + 'wasm/*': [SKIP], }], # 'byteorder == big' ############################################################################## @@ -578,6 +603,7 @@ ['arch == x87', { # Turbofan will hit the known issue that x87 changes sNaN to qNaN by default. 'regress/regress-undefined-nan': [SKIP], + 'regress/regress-crbug-242924': [SKIP], }], # 'arch == x87' ############################################################################## @@ -727,6 +753,7 @@ # Skip tests that are known to be non-deterministic. 'd8-worker-sharedarraybuffer': [SKIP], + 'd8-os': [SKIP], }], # 'predictable == True' ############################################################################## @@ -737,377 +764,150 @@ }], # 'arch == ppc and simulator_run == True' ['ignition == True', { - 'const*': [SKIP], - 'debug-*': [SKIP], - 'es6/*': [SKIP], - 'es7/*': [SKIP], + # Skip strong mode tests since strong mode is unsupported on ignition. 'strong/*': [SKIP], - 'harmony/*': [SKIP], + + # TODO(yangguo,4690): Requires debugger support. + 'es6/debug*': [SKIP], + 'harmony/debug*': [SKIP], 'regress/debug*': [SKIP], 'regress/regress-debug*': [SKIP], - # TODO(bradnelson): Figure out why these tests fail with ignition. - 'wasm/*': [SKIP], - - 'allocation-folding': [SKIP], - 'api-call-after-bypassed-exception': [SKIP], - 'apply-arguments-gc-safepoint': [SKIP], - 'arguments-load-across-eval': [SKIP], - 'arguments-read-and-assignment': [SKIP], - 'array-bounds-check-removal': [SKIP], - 'array-elements-from-array-prototype-chain': [SKIP], - 'array-functions-prototype-misc': [SKIP], - 'array-join': [SKIP], - 'array-literal-feedback': [SKIP], + # TODO(yangguo,4690): assertion failures in debugger tests. + 'debug-allscopes-on-debugger': [FAIL], + 'debug-liveedit-restart-frame': [FAIL], + 'debug-return-value': [FAIL], + 'debug-liveedit-literals': [FAIL], + 'debug-liveedit-3': [FAIL], + 'debug-liveedit-1': [FAIL], + 'debug-step-into-json': [FAIL], + 'debug-liveedit-patch-positions-replace': [FAIL], + 'debug-step-into-valueof': [FAIL], + 'debug-liveedit-patch-positions': [FAIL], + 'debug-liveedit-stepin': [FAIL], + 'debug-step-4': [FAIL], + 'debug-liveedit-newsource': [FAIL], + 'debug-liveedit-stack-padding': [FAIL], + 'debug-stepframe': [FAIL], + 'debug-negative-break-points': [FAIL], + 'debug-stepin-accessor': [FAIL], + 'debug-step-stub-callfunction': [FAIL], + 'debug-liveedit-breakpoints': [FAIL], + 'debug-stepin-accessor-ic': [FAIL], + 'debug-stepin-builtin': [FAIL], + 'debug-stepin-foreach': [FAIL], + 'debug-stepnext-do-while': [FAIL], + 'debug-stepin-builtin-callback-opt': [FAIL], + 'debug-stepin-function-call': [FAIL], + + # TODO(yangguo,4690): Check failure in debug.cc BreakLocation::SetBreakPoint + # DCHECK(IsDebugBreak() || IsDebuggerStatement()); + 'regress/regress-1523': [FAIL], + 'regress/regress-102153': [FAIL], + 'regress/regress-2825': [FAIL], + 'regress/regress-crbug-119800': [FAIL], + 'regress/regress-crbug-467180': [FAIL], + 'regress/regress-opt-after-debug-deopt': [FAIL], + + # TODO(rmcilroy,4681): Requires support for generators. + 'messages': [FAIL], + 'es6/array-from': [FAIL], + 'regress-3225': [FAIL], + 'es6/classes-subclass-builtins': [FAIL], + 'es6/computed-property-names-classes': [FAIL], + 'es6/computed-property-names-object-literals-methods': [FAIL], + 'es6/function-length-configurable': [FAIL], + 'es6/generators-poisoned-properties': [FAIL], + 'es6/generators-runtime': [FAIL], + 'es6/generators-objects': [FAIL], + 'es6/generators-parsing': [FAIL], + 'es6/generators-iteration': [FAIL], + 'es6/generators-states': [FAIL], + 'es6/iteration-semantics': [FAIL], + 'es6/iterator-prototype': [FAIL], + 'es6/generators-mirror': [FAIL], + 'es6/object-literals-method': [FAIL], + 'es6/object-literals-super': [FAIL], + 'es6/generators-relocation': [FAIL], + 'es6/spread-array': [FAIL], + 'es6/generators-debug-liveedit': [FAIL], + 'es6/spread-call': [FAIL], + 'es6/typedarray-from': [FAIL], + 'es6/typedarray': [FAIL], + 'es6/regress/regress-2681': [FAIL], + 'es6/regress/regress-2691': [FAIL], + 'es6/regress/regress-3280': [FAIL], + 'harmony/destructuring-assignment': [FAIL], + 'harmony/function-sent': [FAIL], + 'harmony/reflect-enumerate-delete': [FAIL], + 'harmony/reflect-enumerate-special-cases': [FAIL], + 'harmony/proxies-enumerate': [FAIL], + 'harmony/reflect-enumerate-opt': [FAIL], + 'harmony/reflect-enumerate': [FAIL], + 'harmony/destructuring': [FAIL], + 'harmony/regress/regress-4482': [FAIL], + 'harmony/generators': [FAIL], + 'harmony/iterator-close': [FAIL], + 'harmony/reflect-construct': [FAIL], + 'es6/promises': [FAIL], + + # TODO(rmcilroy,4680): Check failed in + # BytecodeGenerator::VisitFunctionLiteral - !shared_info.is_null(). + 'regress/regress-crbug-429159': [FAIL], + + # TODO(rmcilroy,4680): Pass on debug, fail on release. + 'compiler/regress-stacktrace-methods': [PASS, ['mode == release', FAIL]], + + # TODO(rmcilroy,4680): Test assert failures. + 'array-literal-feedback': [FAIL], + 'undetectable-compare': [FAIL], + 'debug-liveedit-2': [FAIL], + 'compiler/deopt-tonumber-compare': [FAIL], + 'es6/string-search': [FAIL], + 'es6/mirror-collections': [FAIL], + 'es6/regress/regress-468661': [FAIL], + 'harmony/string-replace': [FAIL], + 'harmony/string-match': [FAIL], + 'harmony/string-split': [FAIL], + 'regress/regress-2618': [FAIL], + 'regress/regress-4121': [FAIL], + 'regress/regress-4266': [FAIL], + 'harmony/simd': [FAIL], + 'regress/regress-crbug-109362': [FAIL], + 'regress/regress-crbug-568477-2': [FAIL], + 'regress/regress-crbug-568477-3': [FAIL], + 'regress/regress-crbug-568477-1': [FAIL], + 'regress/regress-2318': [FAIL], + + # TODO(rmcilroy, 4680): new ES6 instanceof support + 'harmony/instanceof-es6': [SKIP], + + # TODO(rmcilroy,4680): Test timeouts. 'array-literal-transitions': [SKIP], - 'array-tostring': [SKIP], - 'break': [SKIP], - 'call-runtime-tail': [SKIP], - 'compiler/compare-map-elim2': [SKIP], - 'compiler/deopt-inlined-smi': [SKIP], - 'compiler/deopt-tonumber-compare': [SKIP], - 'compiler/escape-analysis-arguments': [SKIP], - 'compiler/escape-analysis': [SKIP], - 'compiler/expression-trees': [SKIP], - 'compiler/inline-arguments': [SKIP], - 'compiler/inline-arity-mismatch': [SKIP], - 'compiler/inline-construct': [SKIP], - 'compiler/lazy-deopt-in-literal': [SKIP], - 'compiler/manual-concurrent-recompile': [SKIP], - 'compiler/optimized-for-in': [SKIP], - 'compiler/optimized-function-calls': [SKIP], - 'compiler/optimize_max': [SKIP], - 'compiler/optimize_min': [SKIP], - 'compiler/opt-next-call-turbo': [SKIP], - 'compiler/osr-forof': [SKIP], - 'compiler/property-refs': [SKIP], - 'compiler/regress-3786': [SKIP], - 'compiler/regress-446647': [SKIP], - 'compiler/regress-447567': [SKIP], - 'compiler/regress-469089': [SKIP], - 'compiler/regress-96989': [SKIP], - 'compiler/regress-const': [SKIP], - 'compiler/regress-funarguments': [SKIP], - 'compiler/regress-stacktrace-methods': [SKIP], - 'compiler/regress-variable-liveness': [SKIP], - 'compiler/rotate': [SKIP], - 'compiler/safepoint': [SKIP], - 'compiler/try-deopt': [SKIP], - 'compiler/try-osr': [SKIP], - 'compiler/uint32': [SKIP], - 'compiler/variables': [SKIP], - 'context-calls-maintained': [SKIP], - 'contextual-calls': [SKIP], - 'cross-realm-filtering': [SKIP], - 'cyclic-array-to-string': [SKIP], - 'd8-worker-sharedarraybuffer': [SKIP], - 'delete-in-with': [SKIP], - 'deopt-minus-zero': [SKIP], - 'deserialize-optimize-inner': [SKIP], - 'double-equals': [SKIP], - 'eval-enclosing-function-name': [SKIP], - 'eval-stack-trace': [SKIP], - 'fast-prototype': [SKIP], - 'field-type-tracking': [SKIP], - 'for-in-opt': [SKIP], - 'for-in-special-cases': [SKIP], - 'function-call': [SKIP], - 'get-caller-js-function': [SKIP], - 'get-prototype-of': [SKIP], - 'getter-in-prototype': [SKIP], - 'global-hash': [SKIP], - 'global-load-from-eval-in-with': [SKIP], - 'global-vars-with': [SKIP], - 'instanceof-2': [SKIP], - 'json-replacer-number-wrapper-tostring': [SKIP], - 'json-replacer-order': [SKIP], - 'json': [SKIP], - 'keyed-load-with-symbol-key': [SKIP], - 'local-load-from-eval': [SKIP], - 'math-min-max': [SKIP], - 'messages': [SKIP], - 'mirror-object': [SKIP], - 'object-literal-gc': [SKIP], - 'osr-elements-kind': [SKIP], - 'property-load-across-eval': [SKIP], - 'proto-accessor': [SKIP], - 'readonly': [SKIP], - 'receiver-in-with-calls': [SKIP], - 'regress-3225': [SKIP], - 'regress/clear-keyed-call': [SKIP], - 'regress/poly_count_operation': [SKIP], - 'regress/regress-102153': [SKIP], - 'regress/regress-1030466': [SKIP], - 'regress/regress-1079': [SKIP], - 'regress/regress-109195': [SKIP], - 'regress/regress-1114040': [SKIP], - 'regress/regress-1125': [SKIP], - 'regress/regress-1129': [SKIP], - 'regress/regress-1170187': [SKIP], - 'regress/regress-117409': [SKIP], - 'regress/regress-1177809': [SKIP], - 'regress/regress-119609': [SKIP], - 'regress/regress-123919': [SKIP], - 'regress/regress-124594': [SKIP], - 'regress/regress-125515': [SKIP], - 'regress/regress-128018': [SKIP], - 'regress/regress-131994': [SKIP], - 'regress/regress-133211b': [SKIP], - 'regress/regress-1365': [SKIP], - 'regress/regress-1369': [SKIP], - 'regress/regress-1403': [SKIP], - 'regress/regress-1412': [SKIP], - 'regress/regress-1436': [SKIP], - 'regress/regress-1493017': [SKIP], - 'regress/regress-1523': [SKIP], - 'regress/regress-1560': [SKIP], - 'regress/regress-1586': [SKIP], - 'regress/regress-1639-2': [SKIP], - 'regress/regress-1639': [SKIP], - 'regress/regress-166553': [SKIP], - 'regress/regress-1708': [SKIP], - 'regress/regress-1757': [SKIP], - 'regress/regress-1790': [SKIP], - 'regress/regress-1853': [SKIP], - 'regress/regress-1980': [SKIP], - 'regress/regress-2054': [SKIP], - 'regress/regress-2071': [SKIP], - 'regress/regress-2163': [SKIP], - 'regress/regress-220': [SKIP], - 'regress/regress-2318': [SKIP], - 'regress/regress-2339': [SKIP], - 'regress/regress-2374': [SKIP], - 'regress/regress-2593': [SKIP], - 'regress/regress-2618': [SKIP], - 'regress/regress-263': [SKIP], - 'regress/regress-265': [SKIP], - 'regress/regress-269': [SKIP], - 'regress/regress-2790': [SKIP], - 'regress/regress-2825': [SKIP], - 'regress/regress-3135': [SKIP], - 'regress/regress-3138': [SKIP], - 'regress/regress-318420': [SKIP], - 'regress/regress-320532': [SKIP], - 'regress/regress-3281': [SKIP], - 'regress/regress-331444': [SKIP], - 'regress/regress-343609': [SKIP], - 'regress/regress-347530': [SKIP], - 'regress/regress-347914': [SKIP], - 'regress/regress-351261': [SKIP], - 'regress/regress-352982': [SKIP], - 'regress/regress-353551': [SKIP], - 'regress/regress-354357': [SKIP], - 'regress/regress-356053': [SKIP], - 'regress/regress-357105': [SKIP], - 'regress/regress-359441': [SKIP], - 'regress/regress-361025': [SKIP], - 'regress/regress-3621': [SKIP], - 'regress/regress-365172-3': [SKIP], - 'regress/regress-370827': [SKIP], - 'regress/regress-377290': [SKIP], - 'regress/regress-3859': [SKIP], - 'regress/regress-3884': [SKIP], - 'regress/regress-3926': [SKIP], - 'regress/regress-3960': [SKIP], - 'regress/regress-3969': [SKIP], - 'regress/regress-3985': [SKIP], - 'regress/regress-4023': [SKIP], - 'regress/regress-4027': [SKIP], - 'regress/regress-403292': [SKIP], - 'regress/regress-410912': [SKIP], - 'regress/regress-4121': [SKIP], - 'regress/regress-419663': [SKIP], - 'regress/regress-4255-4': [SKIP], - 'regress/regress-430201b': [SKIP], - 'regress/regress-430201': [SKIP], - 'regress/regress-4309-3': [SKIP], - 'regress/regress-4320': [SKIP], - 'regress/regress-4325': [SKIP], - 'regress/regress-436893': [SKIP], - 'regress/regress-4374': [SKIP], - 'regress/regress-4388': [SKIP], - 'regress/regress-444805': [SKIP], - 'regress/regress-446389': [SKIP], - 'regress/regress-447756': [SKIP], - 'regress/regress-4515': [SKIP], - 'regress/regress-4521': [SKIP], - 'regress/regress-4525': [SKIP], - 'regress/regress-453481': [SKIP], - 'regress/regress-4534': [SKIP], - 'regress/regress-454725': [SKIP], - 'regress/regress-457935': [SKIP], - 'regress/regress-470804': [SKIP], - 'regress/regress-476488': [SKIP], - 'regress/regress-503565': [SKIP], - 'regress/regress-514362': [SKIP], - 'regress/regress-520029': [SKIP], - 'regress/regress-542100': [SKIP], - 'regress/regress-544991': [SKIP], - 'regress/regress-568765': [SKIP], - 'regress/regress-572589': [SKIP], - 'regress/regress-580': [SKIP], - 'regress/regress-618': [SKIP], - 'regress/regress-69': [SKIP], - 'regress/regress-70066': [SKIP], - 'regress/regress-747': [SKIP], - 'regress/regress-753': [SKIP], - 'regress/regress-799761': [SKIP], - 'regress/regress-806473': [SKIP], - 'regress/regress-842017': [SKIP], - 'regress/regress-84234': [SKIP], - 'regress/regress-88858': [SKIP], - 'regress/regress-94425': [SKIP], - 'regress/regress-94873': [SKIP], - 'regress/regress-95485': [SKIP], - 'regress/regress-97116b': [SKIP], - 'regress/regress-97116': [SKIP], - 'regress/regress-974': [SKIP], - 'regress/regress-99167': [SKIP], - 'regress/regress-998565': [SKIP], - 'regress/regress-arg-materialize-store': [SKIP], - 'regress/regress-arguments-gc': [SKIP], - 'regress/regress-assignment-in-test-context': [SKIP], - 'regress/regress-bce-underflow': [SKIP], - 'regress/regress-cnlt-elements': [SKIP], - 'regress/regress-cnlt-enum-indices': [SKIP], - 'regress/regress-cntl-descriptors-enum': [SKIP], - 'regress/regress-conditional-position': [SKIP], - 'regress/regress-convert-enum': [SKIP], - 'regress/regress-crbug-109362': [SKIP], - 'regress/regress-crbug-119800': [SKIP], - 'regress/regress-crbug-163530': [SKIP], - 'regress/regress-crbug-229923': [SKIP], - 'regress/regress-crbug-242502': [SKIP], - 'regress/regress-crbug-242924': [SKIP], - 'regress/regress-crbug-245480': [SKIP], - 'regress/regress-crbug-350864': [SKIP], - 'regress/regress-crbug-351262': [SKIP], - 'regress/regress-crbug-352058': [SKIP], - 'regress/regress-crbug-357137': [SKIP], - 'regress/regress-crbug-385002': [SKIP], - 'regress/regress-crbug-387599': [SKIP], - 'regress/regress-crbug-405517': [SKIP], - 'regress/regress-crbug-405922': [SKIP], - 'regress/regress-crbug-409614': [SKIP], - 'regress/regress-crbug-410033': [SKIP], - 'regress/regress-crbug-412208': [SKIP], - 'regress/regress-crbug-416558': [SKIP], - 'regress/regress-crbug-424142': [SKIP], - 'regress/regress-crbug-429159': [SKIP], - 'regress/regress-crbug-431602': [SKIP], - 'regress/regress-crbug-432493': [SKIP], - 'regress/regress-crbug-450642': [SKIP], - 'regress/regress-crbug-455644': [SKIP], - 'regress/regress-crbug-465298': [SKIP], - 'regress/regress-crbug-467180': [SKIP], - 'regress/regress-crbug-467531': [SKIP], - 'regress/regress-crbug-474297': [SKIP], - 'regress/regress-crbug-480819': [SKIP], - 'regress/regress-crbug-481896': [SKIP], - 'regress/regress-crbug-485548-1': [SKIP], - 'regress/regress-crbug-485548-2': [SKIP], - 'regress/regress-crbug-487289': [SKIP], - 'regress/regress-crbug-489293': [SKIP], - 'regress/regress-crbug-489597': [SKIP], - 'regress/regress-crbug-498142': [SKIP], - 'regress/regress-crbug-501809': [SKIP], - 'regress/regress-crbug-506443': [SKIP], - 'regress/regress-crbug-507070': [SKIP], 'regress/regress-crbug-517592': [SKIP], - 'regress/regress-crbug-522895': [SKIP], - 'regress/regress-crbug-527364': [SKIP], - 'regress/regress-crbug-546968': [SKIP], - 'regress/regress-crbug-568477-1': [SKIP], - 'regress/regress-crbug-568477-2': [SKIP], - 'regress/regress-crbug-568477-3': [SKIP], 'regress/regress-crbug-568477-4': [SKIP], - 'regress/regress-crbug-572590': [SKIP], - 'regress/regress-crbug-573857': [SKIP], - 'regress/regress-crbug-575080': [SKIP], - 'regress/regress-deopt-gcb': [SKIP], - 'regress/regress-deopt-gc': [SKIP], - 'regress/regress-deopt-in-array-literal-spread': [SKIP], - 'regress/regress-embedded-cons-string': [SKIP], - 'regress/regress-existing-shared-function-info': [SKIP], - 'regress/regress-fast-literal-transition': [SKIP], - 'regress/regress-function-constructor-receiver': [SKIP], - 'regress/regress-handle-illegal-redeclaration': [SKIP], - 'regress/regress-inline-class-constructor': [SKIP], - 'regress/regress-inlining-function-literal-context': [SKIP], - 'regress/regress-latin-1': [SKIP], - 'regress/regress-lazy-deopt-reloc': [SKIP], - 'regress/regress-opt-after-debug-deopt': [SKIP], - 'regress/regress-osr-in-case-label': [SKIP], - 'regress/regress-osr-in-literal': [SKIP], - 'regress/regress-prepare-break-while-recompile': [SKIP], - 'regress/regress-put-prototype-transition': [SKIP], - 'regress/regress-sliced-external-cons-regexp': [SKIP], - 'regress/regress-store-heapobject': [SKIP], - 'regress/regress-transcendental': [SKIP], - 'regress/regress-typedarray-length': [SKIP], - 'regress/splice-missing-wb': [SKIP], - 'setter-on-constructor-prototype': [SKIP], - 'shift-for-integer-div': [SKIP], - 'simple-constructor': [SKIP], - 'sparse-array-reverse': [SKIP], - 'stack-traces': [SKIP], - 'strict-mode': [SKIP], - 'string-case': [SKIP], - 'string-external-cached': [SKIP], - 'string-externalize': [SKIP], - 'string-natives': [SKIP], - 'string-replace-with-empty': [SKIP], - 'string-slices': [SKIP], - 'tools/profile': [SKIP], - 'tools/profviz': [SKIP], - 'try-finally-continue': [SKIP], - 'try': [SKIP], - 'undetectable-compare': [SKIP], - 'unused-context-in-with': [SKIP], - 'value-wrapper': [SKIP], - 'with-function-expression': [SKIP], - 'with-parameter-access': [SKIP], - 'with-prototype': [SKIP], - 'with-readonly': [SKIP], - 'with-value': [SKIP], - 'regress/regress-builtinbust-7': [SKIP], - 'regress/regress-crbug-451770': [SKIP], - 'regress/regress-crbug-503968': [SKIP], - 'regress/regress-crbug-504729': [SKIP], + 'regress/regress-crbug-409614': [SKIP], + 'regress/regress-crbug-42414': [SKIP], + 'regress/regress-1853': [SKIP], + 'regress/regress-crbug-424142': [SKIP], }], # ignition == True +['ignition == True and arch == arm64', { + # TODO(rmcilroy,4680): Fails on Arm64 due to expecting to take less than 3 + # seconds. + 'regress/regress-165637': [FAIL], +}], # ignition == True and arch == arm64 + ['ignition == True and (arch == arm or arch == arm64)', { - 'array-constructor': [SKIP], - 'array-sort': [SKIP], - 'array-store-and-grow': [SKIP], - 'compiler/division-by-constant': [SKIP], - 'compiler/osr-big': [SKIP], + # TODO(rmcilroy,4680): Arm / Arm64 specific timeouts. + 'asm/construct-double': [SKIP], 'compiler/osr-nested': [SKIP], 'compiler/osr-one': [SKIP], 'compiler/osr-two': [SKIP], - 'mul-exhaustive-part*': [SKIP], 'regress/regress-1257': [SKIP], 'regress/regress-165637': [SKIP], - 'regress/regress-319722-ArrayBuffer': [SKIP], - 'regress/regress-411210': [SKIP], + 'regress/regress-2185': [SKIP], 'regress/regress-91008': [SKIP], - 'regress/regress-crbug-347903': [SKIP], - 'regress/regress-crbug-500497': [SKIP], - 'regress/regress-crbug-505007-1': [SKIP], - 'regress/regress-crbug-505007-2': [SKIP], - 'regress/regress-2193': [SKIP], - 'regress/regress-3158': [SKIP], - 'regress/regress-347904': [SKIP], - 'regress/regress-380092': [SKIP], - 'regress/regress-4173': [SKIP], - 'regress/regress-copy-hole-to-field': [SKIP], - 'regress/regress-crbug-315252': [SKIP], - 'regress/regress-crbug-412215': [SKIP], - 'regress/regress-crbug-513507': [SKIP], - 'regress/regress-deep-proto': [SKIP], - 'regress/regress-deopt-store-effect': [SKIP], - 'regress/regress-undefined-store-keyed-fast-element': [SKIP], - 'stack-traces-overflow': [SKIP], 'unicodelctest': [SKIP], 'unicodelctest-no-optimization': [SKIP], }], # ignition == True and (arch == arm or arch == arm64) @@ -1118,6 +918,9 @@ 'array-functions-prototype-misc': [SKIP], 'strong/implicit-conversions': [SKIP], 'strong/load-element-mutate-backing-store': [SKIP], + + # Stack overflow. + 'big-array-literal': [SKIP], }], # 'gcov_coverage' ] diff --git a/deps/v8/test/mjsunit/random-bit-correlations.js b/deps/v8/test/mjsunit/random-bit-correlations.js index 8322cfac4c..2ac84c54a7 100644 --- a/deps/v8/test/mjsunit/random-bit-correlations.js +++ b/deps/v8/test/mjsunit/random-bit-correlations.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: --random-seed=12 --nostress-opt --noalways-opt --predictable +// Flags: --random-seed=20 --nostress-opt --noalways-opt --predictable (function() { var kHistory = 2; diff --git a/deps/v8/test/mjsunit/regexp-compile.js b/deps/v8/test/mjsunit/regexp-compile.js index 6a24325e16..92c3f7b3dd 100644 --- a/deps/v8/test/mjsunit/regexp-compile.js +++ b/deps/v8/test/mjsunit/regexp-compile.js @@ -40,3 +40,5 @@ assertEquals(["x", "x"], re.exec("axyb")); re.compile("(y)"); assertEquals(["y", "y"], re.exec("axyb")); + +assertEquals(2, re.compile.length); diff --git a/deps/v8/test/mjsunit/regexp.js b/deps/v8/test/mjsunit/regexp.js index b6f019ea26..1a5de2addf 100644 --- a/deps/v8/test/mjsunit/regexp.js +++ b/deps/v8/test/mjsunit/regexp.js @@ -719,9 +719,6 @@ assertThrows("RegExp.prototype.toString.call(0)", TypeError); assertThrows("RegExp.prototype.toString.call('')", TypeError); assertThrows("RegExp.prototype.toString.call(false)", TypeError); assertThrows("RegExp.prototype.toString.call(true)", TypeError); -assertThrows("RegExp.prototype.toString.call([])", TypeError); -assertThrows("RegExp.prototype.toString.call({})", TypeError); -assertThrows("RegExp.prototype.toString.call(function(){})", TypeError); // Test mutually recursive capture and backreferences. assertEquals(["b", "", ""], /(\2)b(\1)/.exec("aba")); diff --git a/deps/v8/test/mjsunit/regress-587004.js b/deps/v8/test/mjsunit/regress-587004.js new file mode 100644 index 0000000000..9dc6052c43 --- /dev/null +++ b/deps/v8/test/mjsunit/regress-587004.js @@ -0,0 +1,31 @@ +// Copyright 2016 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 --min-semi-space-size=32 + +// We need to set --min-semi-space-size to enable allocation site pretenuring. + +function foo(i) { + with({}) {}; + x = {}; + x.a = 0.23; + x.b = 0.3; + return x; +} + +var all = []; +function step() { + for (var i = 0; i < 100; i++) { + var z = foo(i); + // Write unboxed double in object slack. + z.c = 0.1 + z.b + all.push(z); + } + gc(1); + gc(1); +} + +step(); +// Now foo will allocate objects in old space. +step(); diff --git a/deps/v8/test/mjsunit/regress/math-min.js b/deps/v8/test/mjsunit/regress/math-min.js new file mode 100644 index 0000000000..942e9d0b7d --- /dev/null +++ b/deps/v8/test/mjsunit/regress/math-min.js @@ -0,0 +1,66 @@ +// Copyright 2016 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 a = new Float64Array(4); +a[2] *= -1; +a[3] *= -1; +assertEquals(0, a[0]); +assertEquals(0, a[1]); +assertEquals(-0, a[2]); +assertEquals(-0, a[3]); + +function f1() { + var z = a[0]; + // Same register. + assertEquals(0, Math.min(z, z)); +} + +function f2() { + // Different registers. + assertEquals(0, Math.min(a[0], a[1])); +} + +function f3() { + // Zero and minus zero. + assertEquals(-0, Math.min(a[1], a[2])); +} + +function f4() { + // Zero and minus zero, reversed order. + assertEquals(-0, Math.min(a[2], a[1])); +} + +function f5() { + // Minus zero, same register. + var m_z = a[2]; + assertEquals(-0, Math.min(m_z, m_z)); +} + +function f6() { + // Minus zero, different registers. + assertEquals(-0, Math.min(a[2], a[3])); +} + +for (var i = 0; i < 3; i++) { + f1(); + f2(); + f3(); + f4(); + f5(); + f6(); +} +%OptimizeFunctionOnNextCall(f1); +%OptimizeFunctionOnNextCall(f2); +%OptimizeFunctionOnNextCall(f3); +%OptimizeFunctionOnNextCall(f4); +%OptimizeFunctionOnNextCall(f5); +%OptimizeFunctionOnNextCall(f6); +f1(); +f2(); +f3(); +f4(); +f5(); +f6(); diff --git a/deps/v8/test/mjsunit/regress/regress-3650-1.js b/deps/v8/test/mjsunit/regress/regress-3650-1.js new file mode 100644 index 0000000000..db91ec2d4e --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-3650-1.js @@ -0,0 +1,22 @@ +// Copyright 2016 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 --deopt-every-n-times=55 +// Flags: --nodead-code-elimination + +function f(t) { + var result = []; + for (var i in t) { + for (var j in t) { + result.push(i + j + t[i] + t[j]); + continue; + } + } + return result.join(''); +} + +var t = {a: "1", b: "2"}; +assertEquals("aa11ab12ba21bb22", f(t)); +%OptimizeFunctionOnNextCall(f); +assertEquals("aa11ab12ba21bb22", f(t)); diff --git a/deps/v8/test/mjsunit/regress/regress-3650-2.js b/deps/v8/test/mjsunit/regress/regress-3650-2.js new file mode 100644 index 0000000000..aaa6d55b68 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-3650-2.js @@ -0,0 +1,23 @@ +// Copyright 2016 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 a = {} +var b = {} +a.x = 1; +a.y = 1; +b.x = 1; + +function foo(c) { + var s = 0; + for (var p in c) { s++; } + return s; +} + +assertEquals(2, foo(a)); +assertEquals(1, foo(b)); +%OptimizeFunctionOnNextCall(foo); +assertEquals(2, foo(a)); +assertEquals(1, foo(b)); diff --git a/deps/v8/test/mjsunit/regress/regress-3650-3.js b/deps/v8/test/mjsunit/regress/regress-3650-3.js new file mode 100644 index 0000000000..013e4df283 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-3650-3.js @@ -0,0 +1,17 @@ +// Copyright 2016 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 foo(a) { + for (var d in a) { + delete a[1]; + } +} + +foo([1,2,3]); +foo([2,3,4]); +%OptimizeFunctionOnNextCall(foo); +foo([1,2,3]); +assertOptimized(foo); diff --git a/deps/v8/test/mjsunit/regress/regress-4267.js b/deps/v8/test/mjsunit/regress/regress-4267.js new file mode 100644 index 0000000000..f8cf746723 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-4267.js @@ -0,0 +1,16 @@ +// Copyright 2016 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 strict"; + +var a = []; +Object.defineProperty(a, "0", {configurable: false, value: 10}); +assertEquals(1, a.length); +var setter = ()=>{ a.length = 0; }; +assertThrows(setter); +assertThrows(setter); +%OptimizeFunctionOnNextCall(setter); +assertThrows(setter); diff --git a/deps/v8/test/mjsunit/regress/regress-4509-Class-constructor-typeerror-realm.js b/deps/v8/test/mjsunit/regress/regress-4509-Class-constructor-typeerror-realm.js new file mode 100644 index 0000000000..bc83a11802 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-4509-Class-constructor-typeerror-realm.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. + +"use strict"; +var realm = Realm.create(); +var OtherTypeError = Realm.eval(realm, 'TypeError'); + +class Derived extends Object { + constructor() { + return null; + } +} + +assertThrows(() => { new Derived() }, TypeError); + +var OtherDerived = Realm.eval(realm, + "'use strict';" + + "class Derived extends Object {" + + "constructor() {" + + "return null;" + + "}};"); + +// Before throwing the TypeError we have to switch to the caller context. +assertThrows(() => { new OtherDerived() }, TypeError); diff --git a/deps/v8/test/mjsunit/regress/regress-4654.js b/deps/v8/test/mjsunit/regress/regress-4654.js new file mode 100644 index 0000000000..eb08b1126e --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-4654.js @@ -0,0 +1,5 @@ +// Copyright 2016 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. + +assertEquals('hello\u0000foobar', 'hello\u0000foobar'.normalize('NFC')); diff --git a/deps/v8/test/mjsunit/regress/regress-4659.js b/deps/v8/test/mjsunit/regress/regress-4659.js new file mode 100644 index 0000000000..ff436bec1b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-4659.js @@ -0,0 +1,12 @@ +// Copyright 2016 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-function-name + +var obj = { + get longerName(){ + return 42; + } +}; +assertEquals(42, obj.longerName); diff --git a/deps/v8/test/mjsunit/regress/regress-4665-2.js b/deps/v8/test/mjsunit/regress/regress-4665-2.js new file mode 100644 index 0000000000..b94301eea8 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-4665-2.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: --harmony-species + +// First test case + +function FirstBuffer () {} +FirstBuffer.prototype.__proto__ = Uint8Array.prototype +FirstBuffer.__proto__ = Uint8Array + +var buf = new Uint8Array(10) +buf.__proto__ = FirstBuffer.prototype + +var buf2 = buf.subarray(2) +assertEquals(8, buf2.length); + +// Second test case + +function SecondBuffer (arg) { + var arr = new Uint8Array(arg) + arr.__proto__ = SecondBuffer.prototype + return arr +} +SecondBuffer.prototype.__proto__ = Uint8Array.prototype +SecondBuffer.__proto__ = Uint8Array + +var buf3 = new SecondBuffer(10) + +var buf4 = buf3.subarray(2) + +assertEquals(8, buf4.length); diff --git a/deps/v8/test/mjsunit/regress/regress-4693.js b/deps/v8/test/mjsunit/regress/regress-4693.js index ed832e65da..6145964607 100644 --- a/deps/v8/test/mjsunit/regress/regress-4693.js +++ b/deps/v8/test/mjsunit/regress/regress-4693.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-sloppy-function +// Flags: --harmony-sloppy-function --nolegacy-const // In sloppy mode we allow function redeclarations within blocks for webcompat. (function() { @@ -27,3 +27,54 @@ assertThrows(` } })(); `, SyntaxError); + +// Conflicts between let and function still throw +assertThrows(` + (function() { + if (true) { + let f; + function f() { return 2 } + } + })(); +`, SyntaxError); + +assertThrows(` + (function() { + if (true) { + function f() { return 2 } + let f; + } + })(); +`, SyntaxError); + +// Conflicts between const and function still throw +assertThrows(` + (function() { + if (true) { + const f; + function f() { return 2 } + } + })(); +`, SyntaxError); + +assertThrows(` + (function() { + if (true) { + function f() { return 2 } + const f; + } + })(); +`, SyntaxError); + +// Annex B redefinition semantics still apply with more blocks +(function() { + assertEquals(undefined, f); // Annex B + if (true) { + assertEquals(undefined, f); + { function f() { return 1 } } + assertEquals(1, f()); + { function f() { return 2 } } + assertEquals(2, f()); + } + assertEquals(2, f()); // Annex B +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-4715.js b/deps/v8/test/mjsunit/regress/regress-4715.js new file mode 100644 index 0000000000..0e38cdc27d --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-4715.js @@ -0,0 +1,48 @@ +// Copyright 2016 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 --dead-code-elimination --expose-gc + +var training = {}; +training.a = "nop"; +training.slow = "nop"; +delete training.slow; // Dictionary-mode properties => slow-mode for-in. + +var keepalive = {}; +keepalive.a = "nop"; // Keep a map early in the transition chain alive. + +function GetReal() { + var r = {}; + r.a = "nop"; + r.b = "nop"; + r.c = "dictionarize", + r.d = "gc"; + r.e = "result"; + return r; +}; + +function SideEffect(object, action) { + if (action === "dictionarize") { + delete object.a; + } else if (action === "gc") { + gc(); + } +} + +function foo(object) { + for (var key in object) { + SideEffect(object, object[key]); + } + return key; +} + +// Collect type feedback for slow-mode for-in. +foo(training); +SideEffect({a: 0}, "dictionarize"); +SideEffect({}, "gc"); + +// Compile for slow-mode objects... +%OptimizeFunctionOnNextCall(foo); +// ...and pass in a fast-mode object. +assertEquals("e", foo(GetReal())); diff --git a/deps/v8/test/mjsunit/regress/regress-575364.js b/deps/v8/test/mjsunit/regress/regress-575364.js index f1dc49e073..73136c5538 100644 --- a/deps/v8/test/mjsunit/regress/regress-575364.js +++ b/deps/v8/test/mjsunit/regress/regress-575364.js @@ -9,4 +9,4 @@ function f() { } assertFalse(_WASMEXP_ == undefined); -assertThrows(function() { _WASMEXP_.asmCompileRun(f.toString()); }); +assertThrows(function() { _WASMEXP_.instantiateModuleFromAsm(f.toString()); }); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-516775.js b/deps/v8/test/mjsunit/regress/regress-crbug-516775.js index 25d4d0103d..df190c149b 100644 --- a/deps/v8/test/mjsunit/regress/regress-crbug-516775.js +++ b/deps/v8/test/mjsunit/regress/regress-crbug-516775.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-concat-spreadable +// Flags: --allow-natives-syntax function arguments_with_length_getter(f) { arguments.__defineGetter__('length', f); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-577112.js b/deps/v8/test/mjsunit/regress/regress-crbug-577112.js new file mode 100644 index 0000000000..504f921a33 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-577112.js @@ -0,0 +1,15 @@ +// Copyright 2016 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 + +Array.prototype.__proto__ = null; +var prototype = Array.prototype; +function f() { + prototype.lastIndexOf({}); +} +f(); +f(); +%OptimizeFunctionOnNextCall(f); +f(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-580506.js b/deps/v8/test/mjsunit/regress/regress-crbug-580506.js new file mode 100644 index 0000000000..fb036982cf --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-580506.js @@ -0,0 +1,22 @@ +// Copyright 2016 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() { + 'use strict'; + class A extends Function { + constructor(...args) { + super(...args); + this.a = 42; + } + } + var v1 = new A("'use strict';"); + function f(func) { + func.__defineSetter__('a', function() { }); + } + var v2 = new A(); + f(v2); + f(v1); +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-580584.js b/deps/v8/test/mjsunit/regress/regress-crbug-580584.js new file mode 100644 index 0000000000..cb6776f54c --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-580584.js @@ -0,0 +1,19 @@ +// Copyright 2016 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 arguments } + +// Reconfiguring function.name should update both the attributes and the value. +Object.defineProperty(f, "name", { + writable: true, configurable: true, value: 10}); +assertEquals({value: 10, writable: true, enumerable: false, configurable: true}, + Object.getOwnPropertyDescriptor(f, "name")); + +var args = f(); + +// Setting a value for arguments[Symbol.iterator] should not affect the +// attributes. +args[Symbol.iterator] = 10; +assertEquals({value: 10, writable: true, configurable: true, enumerable: false}, + Object.getOwnPropertyDescriptor(args, Symbol.iterator)); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-581577.js b/deps/v8/test/mjsunit/regress/regress-crbug-581577.js new file mode 100644 index 0000000000..d95ada5f5a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-581577.js @@ -0,0 +1,5 @@ +// 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. + +assertEquals("", RegExp.prototype.flags); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-582051.js b/deps/v8/test/mjsunit/regress/regress-crbug-582051.js new file mode 100644 index 0000000000..93f4e70dfb --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-582051.js @@ -0,0 +1,44 @@ +// Copyright 2016 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 + +var test_y = false; + +function foo(a = 1) { + var x = 2; + debugger; + eval("var y = 3"); + test_y = true; + debugger; +} + +var exception = null; +var break_count = 0; +var Debug = debug.Debug; +var ScopeType = debug.ScopeType; + +function listener(event, exec_state) { + if (event != Debug.DebugEvent.Break) return; + try { + var scopes = exec_state.frame(0).allScopes(); + var expectation = [ ScopeType.Block, + ScopeType.Local, + ScopeType.Script, + ScopeType.Global ]; + assertEquals(expectation, scopes.map(x => x.scopeType())); + assertEquals(2, scopes[0].scopeObject().value().x); + if (test_y) assertEquals(3, scopes[0].scopeObject().value().y); + assertEquals(1, scopes[1].scopeObject().value().a); + break_count++; + } catch (e) { + print(e); + exception = e; + } +} +Debug.setListener(listener); +foo(); + +assertNull(exception); +assertEquals(2, break_count); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-582703.js b/deps/v8/test/mjsunit/regress/regress-crbug-582703.js new file mode 100644 index 0000000000..792266f54c --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-582703.js @@ -0,0 +1,8 @@ +// Copyright 2016 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 + +%FunctionGetScript({}); +%FunctionGetSourceCode({}); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-583257.js b/deps/v8/test/mjsunit/regress/regress-crbug-583257.js new file mode 100644 index 0000000000..85a08c7c81 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-583257.js @@ -0,0 +1,27 @@ +// 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. + +Object.defineProperty(String.prototype, "0", { __v_1: 1}); +Object.defineProperty(String.prototype, "3", { __v_1: 1}); + +(function () { + var s = new String(); + function set(object, index, value) { object[index] = value; } + set(s, 10, "value"); + set(s, 1073741823, "value"); +})(); + +function __f_11() { + Object.preventExtensions(new String()); +} +__f_11(); +__f_11(); + +(function() { + var i = 10; + var a = new String("foo"); + for (var j = 0; j < i; j++) { + a[j] = {}; + } +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-584188.js b/deps/v8/test/mjsunit/regress/regress-crbug-584188.js new file mode 100644 index 0000000000..f54e5593b7 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-584188.js @@ -0,0 +1,10 @@ +// Copyright 2016 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 x = {}; +try { +Object.defineProperty(String.prototype, "3", { x: function() { x = v; }}); +string = "bla"; +} catch(e) {; } +assertThrows("Array.prototype.sort.call(string);", TypeError); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-590989-1.js b/deps/v8/test/mjsunit/regress/regress-crbug-590989-1.js new file mode 100644 index 0000000000..73118eb20e --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-590989-1.js @@ -0,0 +1,18 @@ +// Copyright 2016 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 = {} +var p = {foo: 1.5} + +function g(x) { return x.foo === +x.foo; } + +assertEquals(false, g(o)); +assertEquals(false, g(o)); +%OptimizeFunctionOnNextCall(g); +assertEquals(false, g(o)); // Still fine here. +assertEquals(true, g(p)); +%OptimizeFunctionOnNextCall(g); +assertEquals(false, g(o)); // Confused by type feedback. diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-590989-2.js b/deps/v8/test/mjsunit/regress/regress-crbug-590989-2.js new file mode 100644 index 0000000000..cae1d9db5b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-590989-2.js @@ -0,0 +1,12 @@ +// Copyright 2016 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(x) { return x === +x; } + +assertEquals(false, f(undefined)); +assertEquals(false, f(undefined)); +%OptimizeFunctionOnNextCall(f); +assertEquals(false, f(undefined)); // Interestingly this fails right away. diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-592343.js b/deps/v8/test/mjsunit/regress/regress-crbug-592343.js new file mode 100644 index 0000000000..c98e921b00 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-592343.js @@ -0,0 +1,12 @@ +// Copyright 2016 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 r = /[^\u{1}-\u{1000}\u{1002}-\u{2000}]/u; +assertTrue(r.test("\u{0}")); +assertFalse(r.test("\u{1}")); +assertFalse(r.test("\u{1000}")); +assertTrue(r.test("\u{1001}")); +assertFalse(r.test("\u{1002}")); +assertFalse(r.test("\u{2000}")); +assertTrue(r.test("\u{2001}")); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-593282.js b/deps/v8/test/mjsunit/regress/regress-crbug-593282.js new file mode 100644 index 0000000000..85c4e10a12 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-593282.js @@ -0,0 +1,38 @@ +// Copyright 2016 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 --stack-size=120 + +var __v_11 = {}; +function __f_2(depth) { + try { + __f_5(depth, __v_11); + return true; + } catch (e) { + gc(); + } +} +function __f_5(n, __v_4) { + if (--n == 0) { + __f_1(__v_4); + return; + } + __f_5(n, __v_4); +} +function __f_1(__v_4) { + var __v_5 = new RegExp(__v_4); +} +function __f_4() { + var __v_1 = 100; + var __v_8 = 100000; + while (__v_1 < __v_8 - 1) { + var __v_3 = Math.floor((__v_1 + __v_8) / 2); + if (__f_2(__v_3)) { + __v_1 = __v_3; + } else { + __v_8 = __v_3; + } + } +} +__f_4(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-595657.js b/deps/v8/test/mjsunit/regress/regress-crbug-595657.js new file mode 100644 index 0000000000..653259781b --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-595657.js @@ -0,0 +1,15 @@ +// Copyright 2016 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 test() { + try { + test(); + } catch(e) { + /(\2)(a)/.test(""); + } +} + +test(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-599003.js b/deps/v8/test/mjsunit/regress/regress-crbug-599003.js new file mode 100644 index 0000000000..da29455661 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-599003.js @@ -0,0 +1,39 @@ +// Copyright 2016 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 --verify-heap + +function A() {} + +function g1() { + var obj = new A(); + obj.v0 = 0; + obj.v1 = 0; + obj.v2 = 0; + obj.v3 = 0; + obj.v4 = 0; + obj.v5 = 0; + obj.v6 = 0; + obj.v7 = 0; + obj.v8 = 0; + obj.v9 = 0; + return obj; +} + +function g2() { + return new A(); +} + +var o = g1(); +%OptimizeFunctionOnNextCall(g2); +g2(); +o = null; +gc(); + +for (var i = 0; i < 20; i++) { + var o = new A(); +} +g2(); + +gc(); // Boom! diff --git a/deps/v8/test/mjsunit/regress/regress-integer-indexed-element.js b/deps/v8/test/mjsunit/regress/regress-integer-indexed-element.js new file mode 100644 index 0000000000..1bae2d06f5 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-integer-indexed-element.js @@ -0,0 +1,12 @@ +// Copyright 2016 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 o = {__proto__:new Int32Array(100)}; +Object.prototype[1.3] = 10; +assertEquals(undefined, o[1.3]); + +var o = new Int32Array(100); +var o2 = new Int32Array(200); +o.__proto__ = o2; +assertEquals(undefined, Reflect.get(o, 1.3, o2)); diff --git a/deps/v8/test/mjsunit/regress/regress-seqstrsetchar-ex1.js b/deps/v8/test/mjsunit/regress/regress-seqstrsetchar-ex1.js index 1fd8d810b3..444fe4beb4 100644 --- a/deps/v8/test/mjsunit/regress/regress-seqstrsetchar-ex1.js +++ b/deps/v8/test/mjsunit/regress/regress-seqstrsetchar-ex1.js @@ -35,18 +35,18 @@ function ToNumber(x) { // Reduced version of String.fromCharCode; // does not actually do the same calculation but exhibits untagging bug. function StringFromCharCode(code) { - var n = %_ArgumentsLength(); + var n = arguments.length; var one_byte = %NewString(n, true); var i; for (i = 0; i < n; i++) { - var code = %_Arguments(i); + var code = arguments[i]; if (!%_IsSmi(code)) code = ToNumber(code) & 0xffff; if (code > 0xff) break; } var two_byte = %NewString(n - i, false); for (var j = 0; i < n; i++, j++) { - var code = %_Arguments(i); + var code = arguments[i]; %_TwoByteSeqStringSetChar(j, code, two_byte); } return one_byte + two_byte; diff --git a/deps/v8/test/mjsunit/regress/regress-v8-4839.js b/deps/v8/test/mjsunit/regress/regress-v8-4839.js new file mode 100644 index 0000000000..120685b1de --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-v8-4839.js @@ -0,0 +1,62 @@ +// Copyright 2016 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 dummy() { } + +(function InlinedFunctionTestContext() { + var f = function() { } + + function g() { + var s = "hey"; + dummy(); // Force a deopt point. + if (f()) return s; + } + + g(); + g(); + g(); + %OptimizeFunctionOnNextCall(g); + f = function() { return true; } + assertEquals("hey", g()); +})(); + +(function InlinedConstructorReturnTestContext() { + function c() { return 1; } + + var f = function() { return !(new c()); } + + function g() { + var s = "hey"; + dummy(); // Force a deopt point. + if (f()) return s; + } + + g(); + g(); + g(); + %OptimizeFunctionOnNextCall(g); + f = function() { return true; } + assertEquals("hey", g()); +})(); + +(function InlinedConstructorNoReturnTestContext() { + function c() { } + + var f = function() { return !(new c()); } + + function g() { + var s = "hey"; + dummy(); // Force a deopt point. + if (f()) return s; + } + + g(); + g(); + g(); + %OptimizeFunctionOnNextCall(g); + f = function() { return true; } + assertEquals("hey", g()); +})(); diff --git a/deps/v8/test/mjsunit/samevalue.js b/deps/v8/test/mjsunit/samevalue.js index 038fd68eb9..356e888016 100644 --- a/deps/v8/test/mjsunit/samevalue.js +++ b/deps/v8/test/mjsunit/samevalue.js @@ -26,14 +26,14 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --expose-natives-as natives +// Flags: --expose-natives-as natives --allow-natives-syntax // Test the SameValue and SameValueZero internal methods. var obj1 = {x: 10, y: 11, z: "test"}; var obj2 = {x: 10, y: 11, z: "test"}; var sameValue = Object.is; -var sameValueZero = natives.ImportNow("SameValueZero"); +var sameValueZero = function(x, y) { return %SameValueZero(x, y); } // Calls SameValue and SameValueZero and checks that their results match. function sameValueBoth(a, b) { diff --git a/deps/v8/test/mjsunit/strict-mode.js b/deps/v8/test/mjsunit/strict-mode.js index 6beb9c667a..63dc9d0bda 100644 --- a/deps/v8/test/mjsunit/strict-mode.js +++ b/deps/v8/test/mjsunit/strict-mode.js @@ -1149,7 +1149,9 @@ function CheckArgumentsPillDescriptor(func, name) { function strict() { "use strict"; - return return_my_caller(); + // Returning result via local variable to avoid tail call optimization. + var res = return_my_caller(); + return res; } assertSame(null, strict()); @@ -1163,7 +1165,9 @@ function CheckArgumentsPillDescriptor(func, name) { (function TestNonStrictFunctionCallerPill() { function strict(n) { "use strict"; - return non_strict(n); + // Returning result via local variable to avoid tail call optimization. + var res = non_strict(n); + return res; } function recurse(n, then) { @@ -1191,7 +1195,9 @@ function CheckArgumentsPillDescriptor(func, name) { (function TestNonStrictFunctionCallerDescriptorPill() { function strict(n) { "use strict"; - return non_strict(n); + // Returning result via local variable to avoid tail call optimization. + var res = non_strict(n); + return res; } function recurse(n, then) { diff --git a/deps/v8/test/mjsunit/strong/declaration-after-use.js b/deps/v8/test/mjsunit/strong/declaration-after-use.js deleted file mode 100644 index 3530105f2b..0000000000 --- a/deps/v8/test/mjsunit/strong/declaration-after-use.js +++ /dev/null @@ -1,255 +0,0 @@ -// 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 - -// 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;"); - - assertThrowsHelper("x; const x = 0;"); - assertThrowsHelper("function f() { x; const x = 0; }"); - assertThrowsHelper("function f() { x; } const 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" + - "})()"); - - // 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() { - // Referring to a variable declared later - assertThrowsHelper("class C { m() { x; } } let x = 0;"); - assertThrowsHelper("class C { static m() { x; } } let x = 0;"); - assertThrowsHelper("class C { [x]() { } } let x = 0;"); - - assertThrowsHelper("class C { m() { x; } } const x = 0;"); - assertThrowsHelper("class C { static m() { x; } } const x = 0;"); - assertThrowsHelper("class C { [x]() { } } const x = 0;"); - - // Referring to the class name. - 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; - } - - 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; } - // TODO(arv): The arity checking is not correct with rest parameters. - func4(1, 2); - - let func5 = (p1, p2) => { p1; p2; }; - func5(1, 2); - - let func5b = p1 => p1; - func5b(1); - - function func6() { - var1, var2a, var2b, var2c; - } - - 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/for-in.js b/deps/v8/test/mjsunit/strong/for-in.js index 8fa9010202..641248c408 100644 --- a/deps/v8/test/mjsunit/strong/for-in.js +++ b/deps/v8/test/mjsunit/strong/for-in.js @@ -9,9 +9,3 @@ assertThrows("'use strong'; for (let x in []) {}", SyntaxError); assertThrows("'use strong'; for (const x in []) {}", SyntaxError); })(); - -(function ForOfStatement() { - assertTrue(eval("'use strong'; for (x of []) {} true")); - assertTrue(eval("'use strong'; for (let x of []) {} true")); - assertTrue(eval("'use strong'; for (const x of []) {} true")); -})(); diff --git a/deps/v8/test/mjsunit/strong/mutually-recursive-classes.js b/deps/v8/test/mjsunit/strong/mutually-recursive-classes.js deleted file mode 100644 index 204c3964de..0000000000 --- a/deps/v8/test/mjsunit/strong/mutually-recursive-classes.js +++ /dev/null @@ -1,229 +0,0 @@ -// 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 -"use strict" - -let prologue_dead = "(function outer() { if (false) { "; -let epilogue_dead = " } })();"; - -let prologue_live = "(function outer() { "; -let epilogue_live = "})();"; - -// For code which already throws a run-time error in non-strong mode; we assert -// that we now get the error already compilation time. -function assertLateErrorsBecomeEarly(code) { - assertThrows("'use strong'; " + prologue_dead + code + epilogue_dead, - ReferenceError); - - // Make sure the error happens only in strong mode (note that we need strict - // mode here because of let). - assertDoesNotThrow("'use strict'; " + prologue_dead + code + epilogue_dead); - - // But if we don't put the references inside a dead code, it throws a run-time - // error (also in strict mode). - assertThrows("'use strong'; " + prologue_live + code + epilogue_live, - ReferenceError); - assertThrows("'use strict'; " + prologue_live + code + epilogue_live, - ReferenceError); -} - -// For code which doesn't throw an error at all in non-strong mode. -function assertNonErrorsBecomeEarly(code) { - assertThrows("'use strong'; " + prologue_dead + code + epilogue_dead, - ReferenceError); - assertDoesNotThrow("'use strict'; " + prologue_dead + code + epilogue_dead); - - assertThrows("'use strong'; " + prologue_live + code + epilogue_live, - ReferenceError); - assertDoesNotThrow("'use strict'; " + prologue_live + code + epilogue_live, - ReferenceError); -} - -(function InitTimeReferenceForward() { - // It's never OK to have an init time reference to a class which hasn't been - // declared. - assertLateErrorsBecomeEarly( - `class A extends B { } - class B {}`); - - assertLateErrorsBecomeEarly( - `class A { - [B.sm()]() { } - } - class B { - static sm() { return 0; } - }`); -})(); - -(function InitTimeReferenceBackward() { - // Backwards is of course fine. - "use strong"; - class A { - static sm() { return 0; } - } - let i = "making these classes non-consecutive"; - class B extends A {}; - "by inserting statements and declarations in between"; - class C { - [A.sm()]() { } - }; -})(); - -(function BasicMutualRecursion() { - "use strong"; - class A { - m() { B; } - static sm() { B; } - } - // No statements or declarations between the classes. - class B { - m() { A; } - static sm() { A; } - } -})(); - -(function MutualRecursionWithMoreClasses() { - "use strong"; - class A { - m() { B; C; } - static sm() { B; C; } - } - class B { - m() { A; C; } - static sm() { A; C; } - } - class C { - m() { A; B; } - static sm() { A; B; } - } -})(); - -(function ReferringForwardInDeeperScopes() { - "use strong"; - - function foo() { - class A1 { - m() { B1; } - } - class B1 { } - } - - class Outer { - m() { - class A2 { - m() { B2; } - } - class B2 { } - } - } - - for (let i = 0; i < 1; ++i) { - class A3 { - m() { B3; } - } - class B3 { } - } - - (a, b) => { - class A4 { - m() { B4; } - } - class B4 { } - } -})(); - -(function ReferringForwardButClassesNotConsecutive() { - assertNonErrorsBecomeEarly( - `class A { - m() { B; } - } - ; - class B {}`); - - assertNonErrorsBecomeEarly( - `let A = class { - m() { B; } - } - class B {}`); - - assertNonErrorsBecomeEarly( - `class A { - m() { B1; } // Just a normal use-before-declaration. - } - let B1 = class B2 {}`); - - assertNonErrorsBecomeEarly( - `class A { - m() { B; } - } - let i = 0; - class B {}`); - - assertNonErrorsBecomeEarly( - `class A { - m() { B; } - } - function foo() {} - class B {}`); - - assertNonErrorsBecomeEarly( - `function foo() { - class A { - m() { B; } - } - } - class B {}`); - - assertNonErrorsBecomeEarly( - `class A extends class B { m() { C; } } { - } - class C { }`); - - assertLateErrorsBecomeEarly( - `class A extends class B { [C.sm()]() { } } { - } - class C { static sm() { return 'a';} }`); - - assertLateErrorsBecomeEarly( - `class A extends class B extends C { } { - } - class C { }`); -})(); - - -(function RegressionForClassResolution() { - assertNonErrorsBecomeEarly( - `let A = class B { - m() { C; } - } - ;;;; - class C {} - class B {}`); -})(); - - -(function TestMultipleMethodScopes() { - "use strong"; - - // Test cases where the reference is inside multiple method scopes. - class A1 { - m() { - class C1 { - m() { B1; } - } - } - } - class B1 { } - - ; - - class A2 { - m() { - class C2 extends B2 { - } - } - } - class B2 { } -})(); diff --git a/deps/v8/test/mjsunit/to_number_order.js b/deps/v8/test/mjsunit/to_number_order.js index 50e4bc762e..c20ec5e147 100644 --- a/deps/v8/test/mjsunit/to_number_order.js +++ b/deps/v8/test/mjsunit/to_number_order.js @@ -56,6 +56,13 @@ x = ""; assertEquals(1, Math.pow(v, w)); assertEquals("hestfisk", x, "pow"); +x = ""; +var a = {valueOf: function() { x += "hest"; return 1/0; }}; +var b = {valueOf: function() { x += "fisk"; return 1}}; +assertEquals(1/0, Math.hypot(a, b)); +assertEquals("hestfisk", x, "hypot"); + + var year = { valueOf: function() { x += 1; return 2007; } }; var month = { valueOf: function() { x += 2; return 2; } }; var date = { valueOf: function() { x += 3; return 4; } }; diff --git a/deps/v8/test/mjsunit/typeof.js b/deps/v8/test/mjsunit/typeof.js index 8aa0ab1c3d..864f1cfdb6 100644 --- a/deps/v8/test/mjsunit/typeof.js +++ b/deps/v8/test/mjsunit/typeof.js @@ -35,3 +35,5 @@ assertFalse(typeof r == 'function'); function test(x, y) { return x == y; } assertTrue(test('object', typeof r)); + +assertFalse(typeof null == "undefined"); diff --git a/deps/v8/test/mjsunit/wasm/asm-wasm.js b/deps/v8/test/mjsunit/wasm/asm-wasm.js index 8dfe85aee1..3f936f5f21 100644 --- a/deps/v8/test/mjsunit/wasm/asm-wasm.js +++ b/deps/v8/test/mjsunit/wasm/asm-wasm.js @@ -15,7 +15,9 @@ function EmptyTest() { return {caller: caller}; } -assertEquals(11, _WASMEXP_.asmCompileRun(EmptyTest.toString())); +assertEquals(11, _WASMEXP_.instantiateModuleFromAsm( + EmptyTest.toString()).caller()); + function IntTest() { "use asm"; @@ -24,7 +26,7 @@ function IntTest() { b = b|0; var c = (b + 1)|0 var d = 3.0; - var e = d | 0; // double conversion + var e = ~~d; // double conversion return (a + c + 1)|0; } @@ -35,7 +37,9 @@ function IntTest() { return {caller: caller}; } -assertEquals(101, _WASMEXP_.asmCompileRun(IntTest.toString())); +assertEquals(101, _WASMEXP_.instantiateModuleFromAsm( + IntTest.toString()).caller()); + function Float64Test() { "use asm"; @@ -59,7 +63,9 @@ function Float64Test() { return {caller: caller}; } -assertEquals(1, _WASMEXP_.asmCompileRun(Float64Test.toString())); +assertEquals(1, _WASMEXP_.instantiateModuleFromAsm( + Float64Test.toString()).caller()); + function BadModule() { "use asm"; @@ -78,9 +84,10 @@ function BadModule() { } assertThrows(function() { - _WASMEXP_.asmCompileRun(BadModule.toString()) + _WASMEXP_.instantiateModuleFromAsm(BadModule.toString()).caller(); }); + function TestReturnInBlock() { "use asm"; @@ -98,7 +105,9 @@ function TestReturnInBlock() { return {caller: caller}; } -assertEquals(1, _WASMEXP_.asmCompileRun(TestReturnInBlock.toString())); +assertEquals(1, _WASMEXP_.instantiateModuleFromAsm( + TestReturnInBlock.toString()).caller()); + function TestWhileSimple() { "use asm"; @@ -114,7 +123,9 @@ function TestWhileSimple() { return {caller: caller}; } -assertEquals(5, _WASMEXP_.asmCompileRun(TestWhileSimple.toString())); +assertEquals(5, _WASMEXP_.instantiateModuleFromAsm( + TestWhileSimple.toString()).caller()); + function TestWhileWithoutBraces() { "use asm"; @@ -129,7 +140,9 @@ function TestWhileWithoutBraces() { return {caller: caller}; } -assertEquals(4, _WASMEXP_.asmCompileRun(TestWhileWithoutBraces.toString())); +assertEquals(4, _WASMEXP_.instantiateModuleFromAsm( + TestWhileWithoutBraces.toString()).caller()); + function TestReturnInWhile() { "use asm"; @@ -146,7 +159,9 @@ function TestReturnInWhile() { return {caller: caller}; } -assertEquals(6, _WASMEXP_.asmCompileRun(TestReturnInWhile.toString())); +assertEquals(6, _WASMEXP_.instantiateModuleFromAsm( + TestReturnInWhile.toString()).caller()); + function TestReturnInWhileWithoutBraces() { "use asm"; @@ -161,7 +176,10 @@ function TestReturnInWhileWithoutBraces() { return {caller: caller}; } -assertEquals(7, _WASMEXP_.asmCompileRun(TestReturnInWhileWithoutBraces.toString())); +assertEquals( + 7, _WASMEXP_.instantiateModuleFromAsm( + TestReturnInWhileWithoutBraces.toString()).caller()); + function TestBreakInWhile() { "use asm"; @@ -176,7 +194,9 @@ function TestBreakInWhile() { return {caller: caller}; } -assertEquals(8, _WASMEXP_.asmCompileRun(TestBreakInWhile.toString())); +assertEquals(8, _WASMEXP_.instantiateModuleFromAsm( + TestBreakInWhile.toString()).caller()); + function TestBreakInNestedWhile() { "use asm"; @@ -198,7 +218,9 @@ function TestBreakInNestedWhile() { return {caller: caller}; } -assertEquals(9, _WASMEXP_.asmCompileRun(TestBreakInNestedWhile.toString())); +assertEquals(9, _WASMEXP_.instantiateModuleFromAsm( + TestBreakInNestedWhile.toString()).caller()); + function TestBreakInBlock() { "use asm"; @@ -218,7 +240,9 @@ function TestBreakInBlock() { return {caller: caller}; } -assertEquals(10, _WASMEXP_.asmCompileRun(TestBreakInBlock.toString())); +assertEquals(10, _WASMEXP_.instantiateModuleFromAsm( + TestBreakInBlock.toString()).caller()); + function TestBreakInNamedWhile() { "use asm"; @@ -237,7 +261,9 @@ function TestBreakInNamedWhile() { return {caller: caller}; } -assertEquals(11, _WASMEXP_.asmCompileRun(TestBreakInNamedWhile.toString())); +assertEquals(11, _WASMEXP_.instantiateModuleFromAsm( + TestBreakInNamedWhile.toString()).caller()); + function TestContinue() { "use asm"; @@ -258,7 +284,9 @@ function TestContinue() { return {caller: caller}; } -assertEquals(-5, _WASMEXP_.asmCompileRun(TestContinue.toString())); +assertEquals(-5, _WASMEXP_.instantiateModuleFromAsm( + TestContinue.toString()).caller()); + function TestContinueInNamedWhile() { "use asm"; @@ -284,7 +312,9 @@ function TestContinueInNamedWhile() { return {caller: caller}; } -assertEquals(20, _WASMEXP_.asmCompileRun(TestContinueInNamedWhile.toString())); +assertEquals(20, _WASMEXP_.instantiateModuleFromAsm( + TestContinueInNamedWhile.toString()).caller()); + function TestNot() { "use asm"; @@ -297,7 +327,9 @@ function TestNot() { return {caller:caller}; } -assertEquals(1, _WASMEXP_.asmCompileRun(TestNot.toString())); +assertEquals(1, _WASMEXP_.instantiateModuleFromAsm( + TestNot.toString()).caller()); + function TestNotEquals() { "use asm"; @@ -313,7 +345,9 @@ function TestNotEquals() { return {caller:caller}; } -assertEquals(21, _WASMEXP_.asmCompileRun(TestNotEquals.toString())); +assertEquals(21, _WASMEXP_.instantiateModuleFromAsm( + TestNotEquals.toString()).caller()); + function TestUnsignedComparison() { "use asm"; @@ -329,7 +363,9 @@ function TestUnsignedComparison() { return {caller:caller}; } -assertEquals(22, _WASMEXP_.asmCompileRun(TestUnsignedComparison.toString())); +assertEquals(22, _WASMEXP_.instantiateModuleFromAsm( + TestUnsignedComparison.toString()).caller()); + function TestMixedAdd() { "use asm"; @@ -350,7 +386,9 @@ function TestMixedAdd() { return {caller:caller}; } -assertEquals(23, _WASMEXP_.asmCompileRun(TestMixedAdd.toString())); +assertEquals(23, _WASMEXP_.instantiateModuleFromAsm( + TestMixedAdd.toString()).caller()); + function TestInt32HeapAccess(stdlib, foreign, buffer) { "use asm"; @@ -368,27 +406,49 @@ function TestInt32HeapAccess(stdlib, foreign, buffer) { return {caller: caller}; } -assertEquals(7, _WASMEXP_.asmCompileRun(TestInt32HeapAccess.toString())); +assertEquals(7, _WASMEXP_.instantiateModuleFromAsm( + TestInt32HeapAccess.toString()).caller()); + + +function TestInt32HeapAccessExternal() { + var memory = new ArrayBuffer(1024); + var memory_int32 = new Int32Array(memory); + var module = _WASMEXP_.instantiateModuleFromAsm( + TestInt32HeapAccess.toString(), null, memory); + module.__init__(); + assertEquals(7, module.caller()); + assertEquals(7, memory_int32[2]); +} + +TestInt32HeapAccessExternal(); + function TestHeapAccessIntTypes() { var types = [ - ['Int8Array', '>> 0'], - ['Uint8Array', '>> 0'], - ['Int16Array', '>> 1'], - ['Uint16Array', '>> 1'], - ['Int32Array', '>> 2'], - ['Uint32Array', '>> 2'], + [Int8Array, 'Int8Array', '>> 0'], + [Uint8Array, 'Uint8Array', '>> 0'], + [Int16Array, 'Int16Array', '>> 1'], + [Uint16Array, 'Uint16Array', '>> 1'], + [Int32Array, 'Int32Array', '>> 2'], + [Uint32Array, 'Uint32Array', '>> 2'], ]; for (var i = 0; i < types.length; i++) { var code = TestInt32HeapAccess.toString(); - code = code.replace('Int32Array', types[i][0]); - code = code.replace(/>> 2/g, types[i][1]); - assertEquals(7, _WASMEXP_.asmCompileRun(code)); + code = code.replace('Int32Array', types[i][1]); + code = code.replace(/>> 2/g, types[i][2]); + var memory = new ArrayBuffer(1024); + var memory_view = new types[i][0](memory); + var module = _WASMEXP_.instantiateModuleFromAsm(code, null, memory); + module.__init__(); + assertEquals(7, module.caller()); + assertEquals(7, memory_view[2]); + assertEquals(7, _WASMEXP_.instantiateModuleFromAsm(code).caller()); } } TestHeapAccessIntTypes(); + function TestFloatHeapAccess(stdlib, foreign, buffer) { "use asm"; @@ -411,7 +471,22 @@ function TestFloatHeapAccess(stdlib, foreign, buffer) { return {caller: caller}; } -assertEquals(1, _WASMEXP_.asmCompileRun(TestFloatHeapAccess.toString())); +assertEquals(1, _WASMEXP_.instantiateModuleFromAsm( + TestFloatHeapAccess.toString()).caller()); + + +function TestFloatHeapAccessExternal() { + var memory = new ArrayBuffer(1024); + var memory_float64 = new Float64Array(memory); + var module = _WASMEXP_.instantiateModuleFromAsm( + TestFloatHeapAccess.toString(), null, memory); + module.__init__(); + assertEquals(1, module.caller()); + assertEquals(9.0, memory_float64[1]); +} + +TestFloatHeapAccessExternal(); + function TestConvertI32() { "use asm"; @@ -427,7 +502,9 @@ function TestConvertI32() { return {caller:caller}; } -assertEquals(24, _WASMEXP_.asmCompileRun(TestConvertI32.toString())); +assertEquals(24, _WASMEXP_.instantiateModuleFromAsm( + TestConvertI32.toString()).caller()); + function TestConvertF64FromInt() { "use asm"; @@ -443,7 +520,9 @@ function TestConvertF64FromInt() { return {caller:caller}; } -assertEquals(25, _WASMEXP_.asmCompileRun(TestConvertF64FromInt.toString())); +assertEquals(25, _WASMEXP_.instantiateModuleFromAsm( + TestConvertF64FromInt.toString()).caller()); + function TestConvertF64FromUnsigned() { "use asm"; @@ -461,7 +540,9 @@ function TestConvertF64FromUnsigned() { return {caller:caller}; } -assertEquals(26, _WASMEXP_.asmCompileRun(TestConvertF64FromUnsigned.toString())); +assertEquals(26, _WASMEXP_.instantiateModuleFromAsm( + TestConvertF64FromUnsigned.toString()).caller()); + function TestModInt() { "use asm"; @@ -475,7 +556,9 @@ function TestModInt() { return {caller:caller}; } -assertEquals(-27, _WASMEXP_.asmCompileRun(TestModInt.toString())); +assertEquals(-27, _WASMEXP_.instantiateModuleFromAsm( + TestModInt.toString()).caller()); + function TestModUnsignedInt() { "use asm"; @@ -489,7 +572,9 @@ function TestModUnsignedInt() { return {caller:caller}; } -assertEquals(8, _WASMEXP_.asmCompileRun(TestModUnsignedInt.toString())); +assertEquals(8, _WASMEXP_.instantiateModuleFromAsm( + TestModUnsignedInt.toString()).caller()); + function TestModDouble() { "use asm"; @@ -506,7 +591,9 @@ function TestModDouble() { return {caller:caller}; } -assertEquals(28, _WASMEXP_.asmCompileRun(TestModDouble.toString())); +assertEquals(28, _WASMEXP_.instantiateModuleFromAsm( + TestModDouble.toString()).caller()); + /* TODO: Fix parsing of negative doubles @@ -526,9 +613,11 @@ function TestModDoubleNegative() { return {caller:caller}; } -assertEquals(28, _WASMEXP_.asmCompileRun(TestModDoubleNegative.toString())); +assertEquals(28, _WASMEXP_.instantiateModuleFromAsm( + TestModDoubleNegative.toString()).caller()); */ + function TestNamedFunctions() { "use asm"; @@ -552,6 +641,7 @@ var module = _WASMEXP_.instantiateModuleFromAsm(TestNamedFunctions.toString()); module.init(); assertEquals(77.5, module.add()); + function TestGlobalsWithInit() { "use asm"; @@ -569,6 +659,7 @@ var module = _WASMEXP_.instantiateModuleFromAsm(TestGlobalsWithInit.toString()); module.__init__(); assertEquals(77.5, module.add()); + function TestForLoop() { "use asm" @@ -584,7 +675,9 @@ function TestForLoop() { return {caller:caller}; } -assertEquals(54, _WASMEXP_.asmCompileRun(TestForLoop.toString())); +assertEquals(54, _WASMEXP_.instantiateModuleFromAsm( + TestForLoop.toString()).caller()); + function TestForLoopWithoutInit() { "use asm" @@ -601,7 +694,9 @@ function TestForLoopWithoutInit() { return {caller:caller}; } -assertEquals(100, _WASMEXP_.asmCompileRun(TestForLoopWithoutInit.toString())); +assertEquals(100, _WASMEXP_.instantiateModuleFromAsm( + TestForLoopWithoutInit.toString()).caller()); + function TestForLoopWithoutCondition() { "use asm" @@ -621,7 +716,9 @@ function TestForLoopWithoutCondition() { return {caller:caller}; } -assertEquals(66, _WASMEXP_.asmCompileRun(TestForLoopWithoutCondition.toString())); +assertEquals(66, _WASMEXP_.instantiateModuleFromAsm( + TestForLoopWithoutCondition.toString()).caller()); + function TestForLoopWithoutNext() { "use asm" @@ -637,7 +734,9 @@ function TestForLoopWithoutNext() { return {caller:caller}; } -assertEquals(41, _WASMEXP_.asmCompileRun(TestForLoopWithoutNext.toString())); +assertEquals(41, _WASMEXP_.instantiateModuleFromAsm( + TestForLoopWithoutNext.toString()).caller()); + function TestForLoopWithoutBody() { "use asm" @@ -652,7 +751,9 @@ function TestForLoopWithoutBody() { return {caller:caller}; } -assertEquals(45, _WASMEXP_.asmCompileRun(TestForLoopWithoutBody.toString())); +assertEquals(45, _WASMEXP_.instantiateModuleFromAsm( + TestForLoopWithoutBody.toString()).caller()); + function TestDoWhile() { "use asm" @@ -670,7 +771,9 @@ function TestDoWhile() { return {caller:caller}; } -assertEquals(84, _WASMEXP_.asmCompileRun(TestDoWhile.toString())); +assertEquals(84, _WASMEXP_.instantiateModuleFromAsm( + TestDoWhile.toString()).caller()); + function TestConditional() { "use asm" @@ -683,7 +786,9 @@ function TestConditional() { return {caller:caller}; } -assertEquals(41, _WASMEXP_.asmCompileRun(TestConditional.toString())); +assertEquals(41, _WASMEXP_.instantiateModuleFromAsm( + TestConditional.toString()).caller()); + function TestSwitch() { "use asm" @@ -710,7 +815,9 @@ function TestSwitch() { return {caller:caller}; } -assertEquals(23, _WASMEXP_.asmCompileRun(TestSwitch.toString())); +assertEquals(23, _WASMEXP_.instantiateModuleFromAsm( + TestSwitch.toString()).caller()); + function TestSwitchFallthrough() { "use asm" @@ -731,7 +838,9 @@ function TestSwitchFallthrough() { return {caller:caller}; } -assertEquals(42, _WASMEXP_.asmCompileRun(TestSwitchFallthrough.toString())); +assertEquals(42, _WASMEXP_.instantiateModuleFromAsm( + TestSwitchFallthrough.toString()).caller()); + function TestNestedSwitch() { "use asm" @@ -756,7 +865,9 @@ function TestNestedSwitch() { return {caller:caller}; } -assertEquals(43, _WASMEXP_.asmCompileRun(TestNestedSwitch.toString())); +assertEquals(43, _WASMEXP_.instantiateModuleFromAsm( + TestNestedSwitch.toString()).caller()); + function TestInitFunctionWithNoGlobals() { "use asm"; @@ -771,6 +882,7 @@ var module = _WASMEXP_.instantiateModuleFromAsm( module.__init__(); assertEquals(51, module.caller()); + function TestExportNameDifferentFromFunctionName() { "use asm"; function caller() { @@ -783,3 +895,458 @@ var module = _WASMEXP_.instantiateModuleFromAsm( TestExportNameDifferentFromFunctionName.toString()); module.__init__(); assertEquals(55, module.alt_caller()); + + +function TestFunctionTableSingleFunction() { + "use asm"; + + function dummy() { + return 71; + } + + function caller() { + return function_table[0&0]() | 0; + } + + var function_table = [dummy] + + return {caller:caller}; +} + +assertEquals(71, _WASMEXP_.instantiateModuleFromAsm( + TestFunctionTableSingleFunction.toString()).caller()); + + +function TestFunctionTableMultipleFunctions() { + "use asm"; + + function inc1(x) { + x = x|0; + return (x+1)|0; + } + + function inc2(x) { + x = x|0; + return (x+2)|0; + } + + function caller() { + if (function_table[0&1](50) == 51) { + if (function_table[1&1](60) == 62) { + return 73; + } + } + return 0; + } + + var function_table = [inc1, inc2] + + return {caller:caller}; +} + +assertEquals(73, _WASMEXP_.instantiateModuleFromAsm( + TestFunctionTableMultipleFunctions.toString()).caller()); + + +function TestFunctionTable() { + "use asm"; + + function add(a, b) { + a = a|0; + b = b|0; + return (a+b)|0; + } + + function sub(a, b) { + a = a|0; + b = b|0; + return (a-b)|0; + } + + function inc(a) { + a = a|0; + return (a+1)|0; + } + + function caller(table_id, fun_id, arg1, arg2) { + table_id = table_id|0; + fun_id = fun_id|0; + arg1 = arg1|0; + arg2 = arg2|0; + if (table_id == 0) { + return funBin[fun_id&3](arg1, arg2)|0; + } else if (table_id == 1) { + return fun[fun_id&0](arg1)|0; + } + return 0; + } + + var funBin = [add, sub, sub, add]; + var fun = [inc]; + + return {caller:caller}; +} + +var module = _WASMEXP_.instantiateModuleFromAsm(TestFunctionTable.toString()); +module.__init__(); +assertEquals(55, module.caller(0, 0, 33, 22)); +assertEquals(11, module.caller(0, 1, 33, 22)); +assertEquals(9, module.caller(0, 2, 54, 45)); +assertEquals(99, module.caller(0, 3, 54, 45)); +assertEquals(23, module.caller(0, 4, 12, 11)); +assertEquals(31, module.caller(1, 0, 30, 11)); + + +function TestForeignFunctions() { + function AsmModule(stdlib, foreign, buffer) { + "use asm"; + + var setVal = foreign.setVal; + var getVal = foreign.getVal; + + function caller(initial_value, new_value) { + initial_value = initial_value|0; + new_value = new_value|0; + if ((getVal()|0) == (initial_value|0)) { + setVal(new_value|0); + return getVal()|0; + } + return 0; + } + + return {caller:caller}; + } + + function ffi(initial_val) { + var val = initial_val; + + function getVal() { + return val; + } + + function setVal(new_val) { + val = new_val; + } + + return {getVal:getVal, setVal:setVal}; + } + + var foreign = new ffi(23); + + var module = _WASMEXP_.instantiateModuleFromAsm(AsmModule.toString(), + foreign, null); + + module.__init__(); + assertEquals(103, module.caller(23, 103)); +} + +TestForeignFunctions(); + + +function TestForeignFunctionMultipleUse() { + function AsmModule(stdlib, foreign, buffer) { + "use asm"; + + var getVal = foreign.getVal; + + function caller(int_val, double_val) { + int_val = int_val|0; + double_val = +double_val; + if ((getVal()|0) == (int_val|0)) { + if ((+getVal()) == (+double_val)) { + return 89; + } + } + return 0; + } + + return {caller:caller}; + } + + function ffi() { + function getVal() { + return 83.25; + } + + return {getVal:getVal}; + } + + var foreign = new ffi(); + + var module = _WASMEXP_.instantiateModuleFromAsm(AsmModule.toString(), + foreign, null); + + module.__init__(); + assertEquals(89, module.caller(83, 83.25)); +} + +TestForeignFunctionMultipleUse(); + + +function TestForeignVariables() { + function AsmModule(stdlib, foreign, buffer) { + "use asm"; + + var i1 = foreign.foo | 0; + var f1 = +foreign.bar; + var i2 = foreign.baz | 0; + var f2 = +foreign.baz; + + function geti1() { + return i1|0; + } + + function getf1() { + return +f1; + } + + function geti2() { + return i2|0; + } + + function getf2() { + return +f2; + } + + return {geti1:geti1, getf1:getf1, geti2:geti2, getf2:getf2}; + } + + function TestCase(env, i1, f1, i2, f2) { + var module = _WASMEXP_.instantiateModuleFromAsm( + AsmModule.toString(), env); + module.__init__(); + assertEquals(i1, module.geti1()); + assertEquals(f1, module.getf1()); + assertEquals(i2, module.geti2()); + assertEquals(f2, module.getf2()); + } + + // Check normal operation. + TestCase({foo: 123, bar: 234.5, baz: 345.7}, 123, 234.5, 345, 345.7); + // Check partial operation. + TestCase({baz: 345.7}, 0, NaN, 345, 345.7); + // Check that undefined values are converted to proper defaults. + TestCase({qux: 999}, 0, NaN, 0, NaN); + // Check that an undefined ffi is ok. + TestCase(undefined, 0, NaN, 0, NaN); + // Check that true values are converted properly. + TestCase({foo: true, bar: true, baz: true}, 1, 1.0, 1, 1.0); + // Check that false values are converted properly. + TestCase({foo: false, bar: false, baz: false}, 0, 0, 0, 0); + // Check that null values are converted properly. + TestCase({foo: null, bar: null, baz: null}, 0, 0, 0, 0); + // Check that string values are converted properly. + TestCase({foo: 'hi', bar: 'there', baz: 'dude'}, 0, NaN, 0, NaN); + TestCase({foo: '0xff', bar: '234', baz: '456.1'}, 255, 234, 456, 456.1, 456); + // Check that Date values are converted properly. + TestCase({foo: new Date(123), bar: new Date(456), + baz: new Date(789)}, 123, 456, 789, 789); + // Check that list values are converted properly. + TestCase({foo: [], bar: [], baz: []}, 0, 0, 0, 0); + // Check that object values are converted properly. + TestCase({foo: {}, bar: {}, baz: {}}, 0, NaN, 0, NaN); + // Check that getter object values are converted properly. + var o = { + get foo() { + return 123.4; + } + }; + TestCase({foo: o.foo, bar: o.foo, baz: o.foo}, 123, 123.4, 123, 123.4); + // Check that getter object values are converted properly. + var o = { + get baz() { + return 123.4; + } + }; + TestCase(o, 0, NaN, 123, 123.4); + // Check that objects with valueOf are converted properly. + var o = { + valueOf: function() { return 99; } + }; + TestCase({foo: o, bar: o, baz: o}, 99, 99, 99, 99); + // Check that function values are converted properly. + TestCase({foo: TestCase, bar: TestCase, qux: TestCase}, 0, NaN, 0, NaN); + // Check that a missing ffi object is safe. + TestCase(undefined, 0, NaN, 0, NaN); +} + +TestForeignVariables(); + + +(function() { + function TestByteHeapAccessCompat(stdlib, foreign, buffer) { + "use asm"; + + var HEAP8 = new stdlib.Uint8Array(buffer); + var HEAP32 = new stdlib.Int32Array(buffer); + + function store(i, v) { + i = i | 0; + v = v | 0; + HEAP32[i >> 2] = v; + } + + function storeb(i, v) { + i = i | 0; + v = v | 0; + HEAP8[i | 0] = v; + } + + function load(i) { + i = i | 0; + return HEAP8[i] | 0; + } + + function iload(i) { + i = i | 0; + return HEAP8[HEAP32[i >> 2] | 0] | 0; + } + + return {load: load, iload: iload, store: store, storeb: storeb}; + } + + var m = _WASMEXP_.instantiateModuleFromAsm( + TestByteHeapAccessCompat.toString()); + m.store(0, 20); + m.store(4, 21); + m.store(8, 22); + m.storeb(20, 123); + m.storeb(21, 42); + m.storeb(22, 77); + assertEquals(123, m.load(20)); + assertEquals(42, m.load(21)); + assertEquals(77, m.load(22)); + assertEquals(123, m.iload(0)); + assertEquals(42, m.iload(4)); + assertEquals(77, m.iload(8)); +})(); + + +(function TestGlobalBlock() { + function Module(stdlib, foreign, buffer) { + "use asm"; + + var x = foreign.x | 0, y = foreign.y | 0; + + function test() { + return (x + y) | 0; + } + + return {test: test}; + } + + var m = _WASMEXP_.instantiateModuleFromAsm( + Module.toString(), { x: 4, y: 11 }); + m.__init__(); + assertEquals(15, m.test()); +})(); + + +(function TestComma() { + function CommaModule() { + "use asm"; + + function ifunc(a, b) { + a = +a; + b = b | 0; + return (a, b) | 0; + } + + function dfunc(a, b) { + a = a | 0; + b = +b; + return +(a, b); + } + + return {ifunc: ifunc, dfunc: dfunc}; + } + + var m = _WASMEXP_.instantiateModuleFromAsm(CommaModule.toString()); + assertEquals(123, m.ifunc(456.7, 123)); + assertEquals(123.4, m.dfunc(456, 123.4)); +})(); + + +(function TestOr() { + function Module() { + "use asm"; + function func() { + var x = 1; + var y = 2; + return (x | y) | 0; + } + return {func: func}; + } + + var m = _WASMEXP_.instantiateModuleFromAsm(Module.toString()); + assertEquals(3, m.func()); +})(); + + +(function TestAnd() { + function Module() { + "use asm"; + function func() { + var x = 3; + var y = 2; + return (x & y) | 0; + } + return {func: func}; + } + + var m = _WASMEXP_.instantiateModuleFromAsm(Module.toString()); + assertEquals(2, m.func()); +})(); + + +(function TestXor() { + function Module() { + "use asm"; + function func() { + var x = 3; + var y = 2; + return (x ^ y) | 0; + } + return {func: func}; + } + + var m = _WASMEXP_.instantiateModuleFromAsm(Module.toString()); + assertEquals(1, m.func()); +})(); + + +(function TestIntishAssignment() { + function Module(stdlib, foreign, heap) { + "use asm"; + var HEAP32 = new stdlib.Int32Array(heap); + function func() { + var a = 1; + var b = 2; + HEAP32[0] = a + b; + return HEAP32[0] | 0; + } + return {func: func}; + } + + var m = _WASMEXP_.instantiateModuleFromAsm(Module.toString()); + assertEquals(3, m.func()); +})(); + + +(function TestFloatishAssignment() { + function Module(stdlib, foreign, heap) { + "use asm"; + var HEAPF32 = new stdlib.Float32Array(heap); + var fround = stdlib.Math.fround; + function func() { + var a = fround(1.0); + var b = fround(2.0); + HEAPF32[0] = a + b; + return +HEAPF32[0]; + } + return {func: func}; + } + + var m = _WASMEXP_.instantiateModuleFromAsm(Module.toString()); + assertEquals(3, m.func()); +}) // TODO(bradnelson): Enable when Math.fround implementation lands. diff --git a/deps/v8/test/mjsunit/wasm/import-table.js b/deps/v8/test/mjsunit/wasm/import-table.js new file mode 100644 index 0000000000..33d1c3551c --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/import-table.js @@ -0,0 +1,387 @@ +// 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-wasm + +load("test/mjsunit/wasm/wasm-constants.js"); + +function testCallImport(func, check) { + var kBodySize = 6; + var kNameFunOffset = 29 + kBodySize + 1; + var kNameMainOffset = kNameFunOffset + 4; + + var ffi = new Object(); + ffi.fun = func; + + var data = bytes( + // signatures + kDeclSignatures, 1, + 2, kAstI32, kAstF64, kAstF64, // (f64,f64) -> int + // -- main function + kDeclFunctions, + 1, + kDeclFunctionName | kDeclFunctionExport, + 0, 0, + kNameMainOffset, 0, 0, 0, // name offset + kBodySize, 0, + // main body + kExprCallImport, 0, // -- + kExprGetLocal, 0, // -- + kExprGetLocal, 1, // -- + // imports + kDeclImportTable, + 1, + 0, 0, // sig index + 0, 0, 0, 0, // module name offset + kNameFunOffset, 0, 0, 0, // function name offset + // names + kDeclEnd, + 'f', 'u', 'n', 0, // -- + 'm', 'a', 'i', 'n', 0 // -- + ); + + var module = _WASMEXP_.instantiateModule(data, ffi); + + assertEquals("function", typeof module.main); + + for (var i = 0; i < 100000; i += 10003) { + var a = 22.5 + i, b = 10.5 + i; + var r = module.main(a, b); + check(r, a, b); + } +} + +var global = (function() { return this; })(); +var params = [-99, -99, -99, -99]; +var was_called = false; +var length = -1; + +function FOREIGN_SUB(a, b) { + print("FOREIGN_SUB(" + a + ", " + b + ")"); + was_called = true; + params[0] = this; + params[1] = a; + params[2] = b; + return (a - b) | 0; +} + +function check_FOREIGN_SUB(r, a, b) { + assertEquals(a - b | 0, r); + assertTrue(was_called); +// assertEquals(global, params[0]); // sloppy mode + assertEquals(a, params[1]); + assertEquals(b, params[2]); + was_called = false; +} + +testCallImport(FOREIGN_SUB, check_FOREIGN_SUB); + + +function FOREIGN_ABCD(a, b, c, d) { + print("FOREIGN_ABCD(" + a + ", " + b + ", " + c + ", " + d + ")"); + was_called = true; + params[0] = this; + params[1] = a; + params[2] = b; + params[3] = c; + params[4] = d; + return (a * b * 6) | 0; +} + +function check_FOREIGN_ABCD(r, a, b) { + assertEquals((a * b * 6) | 0, r); + assertTrue(was_called); +// assertEquals(global, params[0]); // sloppy mode. + assertEquals(a, params[1]); + assertEquals(b, params[2]); + assertEquals(undefined, params[3]); + assertEquals(undefined, params[4]); + was_called = false; +} + +testCallImport(FOREIGN_ABCD, check_FOREIGN_ABCD); + +function FOREIGN_ARGUMENTS0() { + print("FOREIGN_ARGUMENTS0"); + was_called = true; + length = arguments.length; + for (var i = 0; i < arguments.length; i++) { + params[i] = arguments[i]; + } + return (arguments[0] * arguments[1] * 7) | 0; +} + +function FOREIGN_ARGUMENTS1(a) { + print("FOREIGN_ARGUMENTS1", a); + was_called = true; + length = arguments.length; + for (var i = 0; i < arguments.length; i++) { + params[i] = arguments[i]; + } + return (arguments[0] * arguments[1] * 7) | 0; +} + +function FOREIGN_ARGUMENTS2(a, b) { + print("FOREIGN_ARGUMENTS2", a, b); + was_called = true; + length = arguments.length; + for (var i = 0; i < arguments.length; i++) { + params[i] = arguments[i]; + } + return (a * b * 7) | 0; +} + +function FOREIGN_ARGUMENTS3(a, b, c) { + print("FOREIGN_ARGUMENTS3", a, b, c); + was_called = true; + length = arguments.length; + for (var i = 0; i < arguments.length; i++) { + params[i] = arguments[i]; + } + return (a * b * 7) | 0; +} + +function FOREIGN_ARGUMENTS4(a, b, c, d) { + print("FOREIGN_ARGUMENTS4", a, b, c, d); + was_called = true; + length = arguments.length; + for (var i = 0; i < arguments.length; i++) { + params[i] = arguments[i]; + } + return (a * b * 7) | 0; +} + +function check_FOREIGN_ARGUMENTS(r, a, b) { + assertEquals((a * b * 7) | 0, r); + assertTrue(was_called); + assertEquals(2, length); + assertEquals(a, params[0]); + assertEquals(b, params[1]); + was_called = false; +} + +// Check a bunch of uses of the arguments object. +testCallImport(FOREIGN_ARGUMENTS0, check_FOREIGN_ARGUMENTS); +testCallImport(FOREIGN_ARGUMENTS1, check_FOREIGN_ARGUMENTS); +testCallImport(FOREIGN_ARGUMENTS2, check_FOREIGN_ARGUMENTS); +testCallImport(FOREIGN_ARGUMENTS3, check_FOREIGN_ARGUMENTS); +testCallImport(FOREIGN_ARGUMENTS4, check_FOREIGN_ARGUMENTS); + +function returnValue(val) { + return function(a, b) { + print("RETURN_VALUE ", val); + return val; + } +} + + +function checkReturn(expected) { + return function(r, a, b) { assertEquals(expected, r); } +} + +// Check that returning weird values doesn't crash +testCallImport(returnValue(undefined), checkReturn(0)); +testCallImport(returnValue(null), checkReturn(0)); +testCallImport(returnValue("0"), checkReturn(0)); +testCallImport(returnValue("-77"), checkReturn(-77)); + +var objWithValueOf = {valueOf: function() { return 198; }} + +testCallImport(returnValue(objWithValueOf), checkReturn(198)); + + +function testCallBinopVoid(type, func, check) { + var kBodySize = 10; + var kNameFunOffset = 28 + kBodySize + 1; + var kNameMainOffset = kNameFunOffset + 4; + + var ffi = new Object(); + + var passed_length = -1; + var passed_a = -1; + var passed_b = -1; + var args_a = -1; + var args_b = -1; + + ffi.fun = function(a, b) { + passed_length = arguments.length; + passed_a = a; + passed_b = b; + args_a = arguments[0]; + args_b = arguments[1]; + } + + var data = bytes( + // -- signatures + kDeclSignatures, 2, + 2, kAstStmt, type, type, // (type,type)->void + 2, kAstI32, type, type, // (type,type)->int + // -- foreign function + kDeclFunctions, 2, + kDeclFunctionName | kDeclFunctionImport, + 0, 0, // signature index + kNameFunOffset, 0, 0, 0, // name offset + // -- main function + kDeclFunctionName | kDeclFunctionExport, + 1, 0, // signature index + kNameMainOffset, 0, 0, 0, // name offset + kBodySize, 0, // body size + // main body + kExprBlock, 2, // -- + kExprCallFunction, 0, // -- + kExprGetLocal, 0, // -- + kExprGetLocal, 1, // -- + kExprI8Const, 99, // -- + // names + kDeclEnd, + 'f', 'u', 'n', 0, // -- + 'm', 'a', 'i', 'n', 0 // -- + ); + + var module = _WASMEXP_.instantiateModule(data, ffi); + + assertEquals("function", typeof module.main); + + print("testCallBinopVoid", type); + + for (var i = 0; i < 100000; i += 10003.1) { + var a = 22.5 + i, b = 10.5 + i; + var r = module.main(a, b); + assertEquals(99, r); + assertEquals(2, passed_length); + var expected_a, expected_b; + switch (type) { + case kAstI32: { + expected_a = a | 0; + expected_b = b | 0; + break; + } + case kAstF32: { + expected_a = Math.fround(a); + expected_b = Math.fround(b); + break; + } + case kAstF64: { + expected_a = a; + expected_b = b; + break; + } + } + + assertEquals(expected_a, args_a); + assertEquals(expected_b, args_b); + assertEquals(expected_a, passed_a); + assertEquals(expected_b, passed_b); + } +} + + +testCallBinopVoid(kAstI32); +// TODO testCallBinopVoid(kAstI64); +testCallBinopVoid(kAstF32); +testCallBinopVoid(kAstF64); + + + +function testCallPrint() { + var kBodySize = 10; + var kNamePrintOffset = 10 + 7 + 7 + 9 + kBodySize + 1; + var kNameMainOffset = kNamePrintOffset + 6; + + var ffi = new Object(); + ffi.print = print; + + var data = bytes( + // -- signatures + kDeclSignatures, 2, + 1, kAstStmt, kAstI32, // i32->void + 1, kAstStmt, kAstF64, // f64->int + kDeclFunctions, 3, + // -- import print i32 + kDeclFunctionName | kDeclFunctionImport, + 0, 0, // signature index + kNamePrintOffset, 0, 0, 0, // name offset + // -- import print f64 + kDeclFunctionName | kDeclFunctionImport, + 1, 0, // signature index + kNamePrintOffset, 0, 0, 0, // name offset + // -- decl main + kDeclFunctionName | kDeclFunctionExport, + 1, 0, // signature index + kNameMainOffset, 0, 0, 0, // name offset + kBodySize, 0, // body size + // main body + kExprBlock, 2, // -- + kExprCallFunction, 0, // -- + kExprI8Const, 97, // -- + kExprCallFunction, 1, // -- + kExprGetLocal, 0, // -- + // names + kDeclEnd, + 'p', 'r', 'i', 'n', 't', 0, // -- + 'm', 'a', 'i', 'n', 0 // -- + ); + + var module = _WASMEXP_.instantiateModule(data, ffi); + + assertEquals("function", typeof module.main); + + for (var i = -9; i < 900; i += 6.125) { + module.main(i); + } +} + +testCallPrint(); +testCallPrint(); + + +function testCallImport2(foo, bar, expected) { + var kBodySize = 5; + var kNameFooOffset = 37 + kBodySize + 1; + var kNameBarOffset = kNameFooOffset + 4; + var kNameMainOffset = kNameBarOffset + 4; + + var ffi = new Object(); + ffi.foo = foo; + ffi.bar = bar; + + var data = bytes( + // signatures + kDeclSignatures, 1, + 0, kAstI32, // void -> i32 + // -- main function + kDeclFunctions, + 1, + kDeclFunctionName | kDeclFunctionExport, + 0, 0, + kNameMainOffset, 0, 0, 0, // name offset + kBodySize, 0, + // main body + kExprI32Add, // -- + kExprCallImport, 0, // -- + kExprCallImport, 1, // -- + // imports + kDeclImportTable, + 2, + 0, 0, // sig index + 0, 0, 0, 0, // module name offset + kNameFooOffset, 0, 0, 0, // function name offset + 0, 0, // sig index + 0, 0, 0, 0, // module name offset + kNameBarOffset, 0, 0, 0, // function name offset + // names + kDeclEnd, + 'f', 'o', 'o', 0, // -- + 'b', 'a', 'r', 0, // -- + 'm', 'a', 'i', 'n', 0 // -- + ); + + var module = _WASMEXP_.instantiateModule(data, ffi); + + assertEquals("function", typeof module.main); + + assertEquals(expected, module.main()); +} + +testCallImport2(function() { return 33; }, function () { return 44; }, 77); diff --git a/deps/v8/test/mjsunit/wasm/compile-run-basic.js b/deps/v8/test/mjsunit/wasm/instantiate-run-basic.js index dbc624a2fb..b103e8f439 100644 --- a/deps/v8/test/mjsunit/wasm/compile-run-basic.js +++ b/deps/v8/test/mjsunit/wasm/instantiate-run-basic.js @@ -28,4 +28,4 @@ var data = bytes( 'm', 'a', 'i', 'n', 0 // name ); -assertEquals(kReturnValue, _WASMEXP_.compileRun(data)); +assertEquals(kReturnValue, _WASMEXP_.instantiateModule(data).main()); diff --git a/deps/v8/test/mjsunit/wasm/stack.js b/deps/v8/test/mjsunit/wasm/stack.js new file mode 100644 index 0000000000..d4b72c0085 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/stack.js @@ -0,0 +1,69 @@ +// Copyright 2016 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-wasm + +load("test/mjsunit/wasm/wasm-constants.js"); + +function testStack(func, check) { + var kBodySize = 2; + var kNameFunOffset = 22 + kBodySize + 1; + var kNameMainOffset = kNameFunOffset + 4; + + var ffi = new Object(); + ffi.fun = func; + + var data = bytes( + // signatures + kDeclSignatures, 1, // -- + 0, kAstStmt, // () -> void + // -- foreign function + kDeclFunctions, 2, // -- + kDeclFunctionName | kDeclFunctionImport, // -- + 0, 0, // -- + kNameFunOffset, 0, 0, 0, // name offset + // -- main function + kDeclFunctionName | kDeclFunctionExport, // -- + 0, 0, // -- + kNameMainOffset, 0, 0, 0, // name offset + kBodySize, 0, + // main body + kExprCallFunction, 0, // -- + // names + kDeclEnd, // -- + 'f', 'u', 'n', 0, // -- + 'm', 'a', 'i', 'n', 0 // -- + ); + + var module = _WASMEXP_.instantiateModule(data, ffi); + + assertEquals("function", typeof module.main); + + module.main(); + check(); +} + +// The stack trace contains file path, only keep "stack.js". +function stripPath(s) { + return s.replace(/[^ (]*stack\.js/g, "stack.js"); +} + +var stack; +function STACK() { + var e = new Error(); + stack = e.stack; +} + +function check_STACK() { + assertEquals(expected, stripPath(stack)); +} + +var expected = "Error\n" + + // The line numbers below will change as this test gains / loses lines.. + " at STACK (stack.js:54:11)\n" + // -- + " at testStack (stack.js:43:10)\n" + + // TODO(jfb) Add WebAssembly stack here. + " at stack.js:69:1"; + +testStack(STACK, check_STACK); diff --git a/deps/v8/test/mjsunit/wasm/start-function.js b/deps/v8/test/mjsunit/wasm/start-function.js new file mode 100644 index 0000000000..4008efa563 --- /dev/null +++ b/deps/v8/test/mjsunit/wasm/start-function.js @@ -0,0 +1,172 @@ +// Copyright 2016 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-wasm + +load("test/mjsunit/wasm/wasm-constants.js"); + +function instantiate(sig, body) { + var module = new Array(); + module = module.concat([ + // -- signatures + kDeclSignatures, 1, + ]); + module = module.concat(sig); + module = module.concat([ + // -- functions + kDeclFunctions, 1, + 0, // decl flags + 0, 0, // signature + body.length, 0, // body size + ]); + module = module.concat(body); + module = module.concat([ + // -- declare start function + kDeclStartFunction, + 0 + ]); + + var data = bytes.apply(this, module); + print(module); + print(data instanceof ArrayBuffer); + print(data.byteLength); + return _WASMEXP_.instantiateModule(data); +} + +function assertFails(sig, body) { + try { + var module = instantiate(sig, body); + print("expected failure, but passes"); + assertFalse(true); + } catch (expected) { + print("ok: " + expected); + } +} + +function assertVerifies(sig, body) { + var module = instantiate(sig, body); + assertFalse(module === undefined); + assertFalse(module === null); + assertFalse(module === 0); + assertEquals("object", typeof module); + return module; +} + +assertVerifies([0, kAstStmt], [kExprNop]); +assertVerifies([0, kAstI32], [kExprI8Const, 0]); + +// Arguments aren't allow to start functions. +assertFails([1, kAstI32, kAstI32], [kExprGetLocal, 0]); +assertFails([2, kAstI32, kAstI32, kAstF32], [kExprGetLocal, 0]); +assertFails([3, kAstI32, kAstI32, kAstF32, kAstF64], [kExprGetLocal, 0]); + +(function testInvalidIndex() { + var kBodySize = 1; + var data = bytes( + // -- signatures + kDeclSignatures, 1, + 0, kAstStmt, + // -- functions + kDeclFunctions, 1, + 0, // decl flags + 0, 0, // signature + kBodySize, 0, // body size + kExprNop, // body + // -- declare start function + kDeclStartFunction, + 1 + ); + + assertThrows(function() { _WASMEXP_.instantiateModule(data); }); +})(); + + +(function testTwoStartFuncs() { + var kBodySize = 1; + var data = bytes( + // -- signatures + kDeclSignatures, 1, + 0, kAstStmt, + // -- functions + kDeclFunctions, 1, + 0, // decl flags + 0, 0, // signature + kBodySize, 0, // body size + kExprNop, // body + // -- declare start function + kDeclStartFunction, + 0, + // -- declare start function + kDeclStartFunction, + 0 + ); + + assertThrows(function() { _WASMEXP_.instantiateModule(data); }); +})(); + + +(function testRun() { + var kBodySize = 6; + + var data = bytes( + kDeclMemory, + 12, 12, 1, // memory + // -- signatures + kDeclSignatures, 1, + 0, kAstStmt, + // -- start function + kDeclFunctions, 1, + 0, // decl flags + 0, 0, // signature + kBodySize, 0, // code size + // -- start body + kExprI32StoreMem, 0, kExprI8Const, 0, kExprI8Const, 77, + // -- declare start function + kDeclStartFunction, + 0 + ); + + var module = _WASMEXP_.instantiateModule(data); + var memory = module.memory; + var view = new Int8Array(memory); + assertEquals(77, view[0]); +})(); + +(function testStartFFI() { + var kBodySize = 2; + var kNameOffset = 4 + 9 + 7 + 3; + + var data = bytes( + // -- signatures + kDeclSignatures, 1, + 0, kAstStmt, + // -- imported function + kDeclFunctions, 2, + kDeclFunctionImport | kDeclFunctionName, // decl flags + 0, 0, // signature + kNameOffset, 0, 0, 0, + // -- start function + 0, // decl flags + 0, 0, // signature + kBodySize, 0, // code size + // -- start body + kExprCallFunction, 0, + // -- declare start function + kDeclStartFunction, + 1, + kDeclEnd, + 'f', 'o', 'o', 0 + ); + + var ranned = false; + var ffi = new Object(); + ffi.foo = function() { + print("we ranned at stert!"); + ranned = true; + } + var module = _WASMEXP_.instantiateModule(data, ffi); + var memory = module.memory; + var view = new Int8Array(memory); + assertTrue(ranned); +})(); diff --git a/deps/v8/test/mjsunit/wasm/wasm-constants.js b/deps/v8/test/mjsunit/wasm/wasm-constants.js index 4b710f1037..458b51ad07 100644 --- a/deps/v8/test/mjsunit/wasm/wasm-constants.js +++ b/deps/v8/test/mjsunit/wasm/wasm-constants.js @@ -22,6 +22,8 @@ var kDeclFunctions = 0x02; var kDeclGlobals = 0x03; var kDeclDataSegments = 0x04; var kDeclFunctionTable = 0x05; +var kDeclStartFunction = 0x07; +var kDeclImportTable = 0x08; var kDeclEnd = 0x06; // Function declaration flags @@ -61,6 +63,7 @@ var kExprLoadGlobal = 0x10; var kExprStoreGlobal = 0x11; var kExprCallFunction = 0x12; var kExprCallIndirect = 0x13; +var kExprCallImport = 0x1F; var kExprI32LoadMem8S = 0x20; var kExprI32LoadMem8U = 0x21; diff --git a/deps/v8/test/mjsunit/wasm/wasm-object-api.js b/deps/v8/test/mjsunit/wasm/wasm-object-api.js index 1dfbb6522e..8912271c23 100644 --- a/deps/v8/test/mjsunit/wasm/wasm-object-api.js +++ b/deps/v8/test/mjsunit/wasm/wasm-object-api.js @@ -8,4 +8,5 @@ assertFalse(undefined === _WASMEXP_); assertFalse(undefined == _WASMEXP_); assertEquals("function", typeof _WASMEXP_.verifyModule); assertEquals("function", typeof _WASMEXP_.verifyFunction); -assertEquals("function", typeof _WASMEXP_.compileRun); +assertEquals("function", typeof _WASMEXP_.instantiateModule); +assertEquals("function", typeof _WASMEXP_.instantiateModuleFromAsm); diff --git a/deps/v8/test/optimize_for_size.isolate b/deps/v8/test/optimize_for_size.isolate index aa7f57036e..16b93157d3 100644 --- a/deps/v8/test/optimize_for_size.isolate +++ b/deps/v8/test/optimize_for_size.isolate @@ -2,6 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. { + 'variables': { + 'command': [ + '../tools/run-tests.py', + ], + }, 'includes': [ 'cctest/cctest.isolate', 'intl/intl.isolate', diff --git a/deps/v8/test/perf.gyp b/deps/v8/test/perf.gyp new file mode 100644 index 0000000000..ff846068f4 --- /dev/null +++ b/deps/v8/test/perf.gyp @@ -0,0 +1,27 @@ +# Copyright 2016 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. + +{ + 'conditions': [ + ['test_isolation_mode != "noop"', { + 'targets': [ + { + 'target_name': 'perf_run', + 'type': 'none', + 'dependencies': [ + 'cctest/cctest.gyp:cctest_exe_run', + '../src/d8.gyp:d8_run', + ], + 'includes': [ + '../build/features.gypi', + '../build/isolate.gypi', + ], + 'sources': [ + 'perf.isolate', + ], + }, + ], + }], + ], +} diff --git a/deps/v8/test/perf.isolate b/deps/v8/test/perf.isolate new file mode 100644 index 0000000000..77f66cc67c --- /dev/null +++ b/deps/v8/test/perf.isolate @@ -0,0 +1,23 @@ +# Copyright 2016 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. +{ + 'variables': { + 'command': [ + '../tools/run_perf.py', + ], + 'files': [ + '../tools/run_perf.py', + # This is often used to trigger performance bots. We include it in the + # isolate to not get these builds deduped. + '../tools/whitespace.txt', + 'js-perf-test/', + 'memory/', + 'simdjs/', + ], + }, + 'includes': [ + 'cctest/cctest_exe.isolate', + '../src/d8.isolate', + ], +} diff --git a/deps/v8/test/test262/archive.py b/deps/v8/test/test262/archive.py new file mode 100755 index 0000000000..8398e51716 --- /dev/null +++ b/deps/v8/test/test262/archive.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# Copyright 2016 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. + +import os +import tarfile + +os.chdir(os.path.dirname(os.path.abspath(__file__))) + +def filter_git(tar_info): + if tar_info.name.startswith(os.path.join('data', '.git')): + return None + else: + return tar_info + +with tarfile.open('data.tar', 'w') as tar: + tar.add('data', filter=filter_git) diff --git a/deps/v8/test/test262/list.py b/deps/v8/test/test262/list.py new file mode 100755 index 0000000000..69ca62cf20 --- /dev/null +++ b/deps/v8/test/test262/list.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +# Copyright 2016 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. + +import os +import tarfile + +os.chdir(os.path.dirname(os.path.abspath(__file__))) + +for root, dirs, files in os.walk("data"): + dirs[:] = [d for d in dirs if not d.endswith('.git')] + for name in files: + # These names are for gyp, which expects slashes on all platforms. + print('/'.join(root.split(os.sep) + [name])) diff --git a/deps/v8/test/test262/test262.gyp b/deps/v8/test/test262/test262.gyp index 45e6bc7271..5d79adda35 100644 --- a/deps/v8/test/test262/test262.gyp +++ b/deps/v8/test/test262/test262.gyp @@ -19,6 +19,14 @@ 'sources': [ 'test262.isolate', ], + 'actions': [ + { + 'action_name': 'archive_test262', + 'inputs': ['archive.py', '<!@(python list.py)'], + 'outputs': ['data.tar'], + 'action': ['python', 'archive.py'], + }, + ], }, ], }], diff --git a/deps/v8/test/test262/test262.isolate b/deps/v8/test/test262/test262.isolate index dbeca5e55c..0ac045af17 100644 --- a/deps/v8/test/test262/test262.isolate +++ b/deps/v8/test/test262/test262.isolate @@ -4,11 +4,14 @@ { 'variables': { 'files': [ - './', + 'data.tar', + 'harness-adapt.js', + 'test262.status', + 'testcfg.py', ], }, 'includes': [ '../../src/d8.isolate', '../../tools/testrunner/testrunner.isolate', ], -}
\ No newline at end of file +} diff --git a/deps/v8/test/test262/test262.status b/deps/v8/test/test262/test262.status index a7f76a4e27..a926bcc92d 100644 --- a/deps/v8/test/test262/test262.status +++ b/deps/v8/test/test262/test262.status @@ -33,9 +33,6 @@ 'intl402/11.2.3_b': [FAIL], 'intl402/12.2.3_b': [FAIL], - # Unicode canonicalization is not available with i18n turned off. - 'built-ins/String/prototype/localeCompare/15.5.4.9_CE': [['no_i18n', SKIP]], - ###################### NEEDS INVESTIGATION ####################### # Possibly same cause as S8.5_A2.1, below: floating-point tests. @@ -50,43 +47,10 @@ ###################### MISSING ES6 FEATURES ####################### - # It's unclear what the right behavior for [[Enumerate]] is; we're awaiting - # clarification in the spec. Currently, our for-in implementation for - # Proxies checks all trap result values for being strings... - 'built-ins/Proxy/enumerate/return-trap-result': [FAIL], - # ...and our Reflect.enumerate implementation is built on for-in by wrapping - # the iteration's results in a new generator; this postpones exceptions. - 'built-ins/Reflect/enumerate/return-abrupt-from-result': [FAIL], - - # https://code.google.com/p/v8/issues/detail?id=4093 - 'built-ins/Array/symbol-species': [FAIL], - 'built-ins/Array/symbol-species-name': [FAIL], - 'built-ins/ArrayBuffer/symbol-species': [FAIL], - 'built-ins/ArrayBuffer/symbol-species-name': [FAIL], - 'built-ins/ArrayBuffer/prototype/slice/species-constructor-is-not-object': [FAIL], - 'built-ins/ArrayBuffer/prototype/slice/species-returns-smaller-arraybuffer': [FAIL], - 'built-ins/ArrayBuffer/prototype/slice/species-is-not-object': [FAIL], - 'built-ins/ArrayBuffer/prototype/slice/species-is-not-constructor': [FAIL], - 'built-ins/ArrayBuffer/prototype/slice/species-returns-larger-arraybuffer': [FAIL], - 'built-ins/ArrayBuffer/prototype/slice/species-returns-not-arraybuffer': [FAIL], - 'built-ins/ArrayBuffer/prototype/slice/species-returns-same-arraybuffer': [FAIL], - 'built-ins/ArrayBuffer/prototype/slice/species': [FAIL], - 'built-ins/Map/symbol-species': [FAIL], - 'built-ins/Map/symbol-species-name': [FAIL], - 'built-ins/Promise/Symbol.species/prop-desc': [FAIL], - 'built-ins/Promise/Symbol.species/return-value': [FAIL], - 'built-ins/Promise/all/species-get-error': [PASS, FAIL], - 'built-ins/Promise/prototype/then/ctor-custom': [FAIL], - 'built-ins/Promise/race/species-get-error': [PASS, FAIL], - 'built-ins/Promise/symbol-species': [FAIL], - 'built-ins/Promise/symbol-species-name': [FAIL], - 'built-ins/RegExp/symbol-species': [FAIL], - 'built-ins/RegExp/symbol-species-name': [FAIL], - 'built-ins/Set/symbol-species': [FAIL], - 'built-ins/Set/symbol-species-name': [FAIL], - 'built-ins/Symbol/species/basic': [FAIL], - 'built-ins/Symbol/species/builtin-getter-name': [FAIL], - 'built-ins/Symbol/species/subclassing': [FAIL], + # https://bugs.chromium.org/p/v8/issues/detail?id=4768 + # The Reflect.enumerate trap is removed + 'built-ins/Reflect/enumerate/*': [SKIP], + 'built-ins/Proxy/enumerate/*': [SKIP], # https://code.google.com/p/v8/issues/detail?id=4163 'built-ins/GeneratorPrototype/next/context-constructor-invocation': [FAIL], @@ -99,6 +63,7 @@ 'built-ins/Map/iterator-item-second-entry-returns-abrupt': [FAIL], 'built-ins/Map/iterator-items-are-not-object-close-iterator': [FAIL], 'built-ins/Promise/all/iter-close': [FAIL], + 'built-ins/Promise/race/iter-close': [PASS, FAIL], 'built-ins/Set/set-iterator-close-after-add-failure': [FAIL], 'built-ins/WeakMap/iterator-close-after-set-failure': [FAIL], 'built-ins/WeakMap/iterator-item-first-entry-returns-abrupt': [FAIL], @@ -106,15 +71,6 @@ 'built-ins/WeakMap/iterator-items-are-not-object-close-iterator': [FAIL], 'built-ins/WeakSet/iterator-close-after-add-failure': [FAIL], - # https://code.google.com/p/v8/issues/detail?id=4119 - 'built-ins/RegExp/call_with_non_regexp_same_constructor': [FAIL], - 'built-ins/RegExp/from-regexp-like-short-circuit': [FAIL], - 'built-ins/RegExp/from-regexp-like': [FAIL], - 'built-ins/RegExp/from-regexp-like-flag-override': [FAIL], - 'built-ins/RegExp/from-regexp-like-get-source-err': [FAIL], - 'built-ins/RegExp/from-regexp-like-get-flags-err': [FAIL], - 'built-ins/RegExp/from-regexp-like-get-ctor-err': [FAIL], - # https://code.google.com/p/v8/issues/detail?id=4348 'built-ins/String/prototype/Symbol.iterator/this-val-non-obj-coercible': [FAIL], @@ -148,24 +104,6 @@ 'built-ins/Array/prototype/values/iteration-mutable': [FAIL], 'built-ins/Array/prototype/Symbol.unscopables/value': [FAIL], - # https://code.google.com/p/v8/issues/detail?id=3566 - 'built-ins/GeneratorPrototype/return/from-state-completed': [FAIL], - 'built-ins/GeneratorPrototype/return/from-state-suspended-start': [FAIL], - 'built-ins/GeneratorPrototype/return/property-descriptor': [FAIL], - 'built-ins/GeneratorPrototype/return/try-catch-before-try': [FAIL], - 'built-ins/GeneratorPrototype/return/try-catch-following-catch': [FAIL], - 'built-ins/GeneratorPrototype/return/try-catch-within-catch': [FAIL], - 'built-ins/GeneratorPrototype/return/try-catch-within-try': [FAIL], - 'built-ins/GeneratorPrototype/return/try-finally-before-try': [FAIL], - 'built-ins/GeneratorPrototype/return/try-finally-following-finally': [FAIL], - 'built-ins/GeneratorPrototype/return/try-finally-nested-try-catch-within-catch': [FAIL], - 'built-ins/GeneratorPrototype/return/try-finally-nested-try-catch-within-finally': [FAIL], - 'built-ins/GeneratorPrototype/return/try-finally-nested-try-catch-within-inner-try': [FAIL], - 'built-ins/GeneratorPrototype/return/try-finally-nested-try-catch-within-outer-try-after-nested': [FAIL], - 'built-ins/GeneratorPrototype/return/try-finally-nested-try-catch-within-outer-try-before-nested': [FAIL], - 'built-ins/GeneratorPrototype/return/try-finally-within-finally': [FAIL], - 'built-ins/GeneratorPrototype/return/try-finally-within-try': [FAIL], - # https://code.google.com/p/v8/issues/detail?id=4248 'language/expressions/compound-assignment/S11.13.2_A5.*': [FAIL], 'language/expressions/compound-assignment/S11.13.2_A6.*': [FAIL], @@ -194,71 +132,13 @@ 'language/expressions/assignment/S11.13.1_A5*': [FAIL], 'language/expressions/assignment/S11.13.1_A6*': [FAIL], - # https://code.google.com/p/v8/issues/detail?id=3699 + # https://bugs.chromium.org/p/v8/issues/detail?id=4709 'built-ins/Proxy/revocable/revocation-function-name': [FAIL], - 'language/expressions/assignment/destructuring/array-elem-init-fn-name-arrow': [FAIL], - 'language/expressions/assignment/destructuring/array-elem-init-fn-name-class': [FAIL], - 'language/expressions/assignment/destructuring/array-elem-init-fn-name-cover': [FAIL], - 'language/expressions/assignment/destructuring/array-elem-init-fn-name-fn': [FAIL], - 'language/expressions/assignment/destructuring/array-elem-init-fn-name-gen': [FAIL], - 'language/expressions/assignment/destructuring/obj-id-init-fn-name-arrow': [FAIL], - 'language/expressions/assignment/destructuring/obj-id-init-fn-name-class': [FAIL], - 'language/expressions/assignment/destructuring/obj-id-init-fn-name-cover': [FAIL], - 'language/expressions/assignment/destructuring/obj-id-init-fn-name-fn': [FAIL], - 'language/expressions/assignment/destructuring/obj-id-init-fn-name-gen': [FAIL], - 'language/expressions/assignment/destructuring/obj-prop-elem-init-fn-name-arrow': [FAIL], - 'language/expressions/assignment/destructuring/obj-prop-elem-init-fn-name-class': [FAIL], - 'language/expressions/assignment/destructuring/obj-prop-elem-init-fn-name-cover': [FAIL], - 'language/expressions/assignment/destructuring/obj-prop-elem-init-fn-name-fn': [FAIL], - 'language/expressions/assignment/destructuring/obj-prop-elem-init-fn-name-gen': [FAIL], - 'language/expressions/assignment/fn-name-arrow': [FAIL], - 'language/expressions/assignment/fn-name-class': [FAIL], - 'language/expressions/assignment/fn-name-cover': [FAIL], - 'language/expressions/assignment/fn-name-fn': [FAIL], - 'language/expressions/assignment/fn-name-gen': [FAIL], 'language/expressions/assignment/fn-name-lhs-cover': [FAIL], 'language/expressions/assignment/fn-name-lhs-member': [FAIL], 'language/expressions/class/name': [FAIL], 'language/expressions/function/name': [FAIL], - 'language/expressions/generators/implicit-name': [FAIL], 'language/expressions/generators/name': [FAIL], - 'language/expressions/generators/name-property-descriptor': [FAIL], - 'language/expressions/object/fn-name-accessor-get': [FAIL], - 'language/expressions/object/fn-name-accessor-set': [FAIL], - 'language/expressions/object/fn-name-arrow': [FAIL], - 'language/expressions/object/fn-name-class': [FAIL], - 'language/expressions/object/fn-name-cover': [FAIL], - 'language/expressions/object/fn-name-fn': [FAIL], - 'language/expressions/object/fn-name-gen': [FAIL], - 'language/expressions/object/fn-name-lhs-cover': [FAIL], - 'language/expressions/object/fn-name-lhs-member': [FAIL], - 'language/expressions/object/method-definition/fn-name-accessor-get': [FAIL], - 'language/expressions/object/method-definition/fn-name-accessor-set': [FAIL], - 'language/expressions/object/method-definition/fn-name-arrow': [FAIL], - 'language/expressions/object/method-definition/fn-name-class': [FAIL], - 'language/expressions/object/method-definition/fn-name-cover': [FAIL], - 'language/expressions/object/method-definition/fn-name-fn': [FAIL], - 'language/expressions/object/method-definition/fn-name-gen': [FAIL], - 'language/statements/class/definition/basics': [FAIL], - 'language/statements/class/definition/fn-name-accessor-get': [FAIL], - 'language/statements/class/definition/fn-name-accessor-set': [FAIL], - 'language/statements/class/definition/fn-name-gen-method': [FAIL], - 'language/statements/class/definition/fn-name-method': [FAIL], - 'language/statements/const/fn-name-arrow': [FAIL], - 'language/statements/const/fn-name-class': [FAIL], - 'language/statements/const/fn-name-cover': [FAIL], - 'language/statements/const/fn-name-fn': [FAIL], - 'language/statements/const/fn-name-gen': [FAIL], - 'language/statements/let/fn-name-arrow': [FAIL], - 'language/statements/let/fn-name-class': [FAIL], - 'language/statements/let/fn-name-cover': [FAIL], - 'language/statements/let/fn-name-fn': [FAIL], - 'language/statements/let/fn-name-gen': [FAIL], - 'language/statements/variable/fn-name-arrow': [FAIL], - 'language/statements/variable/fn-name-class': [FAIL], - 'language/statements/variable/fn-name-cover': [FAIL], - 'language/statements/variable/fn-name-fn': [FAIL], - 'language/statements/variable/fn-name-gen': [FAIL], # https://code.google.com/p/v8/issues/detail?id=4251 'language/expressions/postfix-increment/S11.3.1_A5_T1': [FAIL], @@ -273,30 +153,6 @@ # https://code.google.com/p/v8/issues/detail?id=4253 'language/asi/S7.9_A5.7_T1': [PASS, FAIL_OK], - # https://code.google.com/p/v8/issues/detail?id=3761 - 'language/expressions/object/method-definition/generator-name-prop-symbol': [FAIL], - 'language/expressions/object/method-definition/name-name-prop-symbol': [FAIL], - - # https://code.google.com/p/v8/issues/detail?id=2952 - 'built-ins/RegExp/prototype/exec/u-lastindex-adv': [FAIL], - 'built-ins/RegExp/prototype/exec/u-captured-value': [FAIL], - 'built-ins/RegExp/prototype/exec/u-lastindex-value': [FAIL], - 'built-ins/RegExp/prototype/test/u-captured-value': [FAIL], - 'built-ins/RegExp/prototype/test/u-lastindex-adv': [FAIL], - 'built-ins/RegExp/prototype/test/u-lastindex-value': [FAIL], - 'built-ins/RegExp/prototype/unicode/this-regexp': [FAIL], - 'built-ins/RegExp/unicode_identity_escape': [FAIL], - 'language/literals/regexp/u-unicode-esc': [FAIL], - 'language/literals/regexp/u-surrogate-pairs': [FAIL], - 'language/literals/regexp/u-case-mapping': [FAIL], - 'language/literals/regexp/u-astral': [FAIL], - 'built-ins/RegExp/valid-flags-y': [FAIL], - 'built-ins/RegExp/prototype/unicode/length': [FAIL], - 'built-ins/RegExp/prototype/unicode/name': [FAIL], - 'built-ins/RegExp/prototype/unicode/prop-desc': [FAIL], - 'built-ins/RegExp/prototype/unicode/this-invald-obj': [FAIL], - 'built-ins/RegExp/prototype/unicode/this-non-obj': [FAIL], - # https://code.google.com/p/v8/issues/detail?id=4602 'built-ins/RegExp/prototype/exec/get-sticky-coerce': [FAIL], 'built-ins/RegExp/prototype/exec/get-sticky-err': [FAIL], @@ -311,36 +167,19 @@ # happens to be thrown for some other reason (e.g, # built-ins/RegExp/prototype/Symbol.match/builtin-failure-set-lastindex-err) 'built-ins/RegExp/prototype/Symbol.match/*': [SKIP], - 'built-ins/Symbol/match/prop-desc': [FAIL], 'built-ins/String/prototype/endsWith/return-abrupt-from-searchstring-regexp-test': [FAIL], 'built-ins/String/prototype/includes/return-abrupt-from-searchstring-regexp-test': [FAIL], 'built-ins/String/prototype/startsWith/return-abrupt-from-searchstring-regexp-test': [FAIL], - 'built-ins/String/prototype/match/cstm-matcher-get-err': [FAIL], 'built-ins/String/prototype/match/invoke-builtin-match': [FAIL], - 'built-ins/String/prototype/match/cstm-matcher-invocation': [FAIL], # https://code.google.com/p/v8/issues/detail?id=4343 'built-ins/RegExp/prototype/Symbol.replace/*': [SKIP], - 'built-ins/Symbol/replace/prop-desc': [FAIL], - 'built-ins/String/prototype/replace/cstm-replace-get-err': [FAIL], - 'built-ins/String/prototype/replace/cstm-replace-invocation': [FAIL], # https://code.google.com/p/v8/issues/detail?id=4344 'built-ins/RegExp/prototype/Symbol.search/*': [SKIP], - 'built-ins/Symbol/search/prop-desc': [FAIL], - 'built-ins/String/prototype/search/cstm-search-get-err': [FAIL], - 'built-ins/String/prototype/search/invoke-builtin-search-searcher-undef': [FAIL], - 'built-ins/String/prototype/search/cstm-search-invocation': [FAIL], - 'built-ins/String/prototype/search/invoke-builtin-search': [FAIL], # https://code.google.com/p/v8/issues/detail?id=4345 'built-ins/RegExp/prototype/Symbol.split/*': [SKIP], - 'built-ins/Symbol/split/prop-desc': [FAIL], - 'built-ins/String/prototype/split/cstm-split-invocation': [FAIL], - 'built-ins/String/prototype/split/cstm-split-get-err': [FAIL], - - # https://code.google.com/p/v8/issues/detail?id=4346 - 'built-ins/RegExp/prototype/flags/u': [FAIL], # https://code.google.com/p/v8/issues/detail?id=4360 'intl402/Collator/10.1.1_1': [FAIL], @@ -350,13 +189,6 @@ # https://code.google.com/p/v8/issues/detail?id=4361 'intl402/Collator/10.1.1_a': [FAIL], - # https://code.google.com/p/v8/issues/detail?id=4447 - 'built-ins/Function/prototype/Symbol.hasInstance/*': [SKIP], - 'built-ins/Symbol/hasInstance/prop-desc': [FAIL], - 'language/expressions/instanceof/symbol-hasinstance-get-err': [FAIL], - 'language/expressions/instanceof/symbol-hasinstance-invocation': [FAIL], - 'language/expressions/instanceof/symbol-hasinstance-to-boolean': [FAIL], - # https://code.google.com/p/v8/issues/detail?id=4476 'built-ins/String/prototype/toLocaleLowerCase/special_casing_conditional': [FAIL], 'built-ins/String/prototype/toLocaleLowerCase/supplementary_plane': [FAIL], @@ -381,11 +213,7 @@ 'built-ins/ArrayBuffer/length-is-absent': [FAIL], 'built-ins/ArrayBuffer/length-is-not-number': [FAIL], 'built-ins/ArrayBuffer/positive-integer-length': [FAIL], - - # https://bugs.chromium.org/p/v8/issues/detail?id=4630 - 'language/statements/generators/invoke-as-constructor': [FAIL], - 'language/expressions/generators/invoke-as-constructor': [FAIL], - 'language/expressions/object/method-definition/generator-invoke-ctor': [FAIL], + 'language/statements/class/subclass/builtin-objects/ArrayBuffer/regular-subclassing': [FAIL], # https://bugs.chromium.org/p/v8/issues/detail?id=4633 'built-ins/Promise/reject-function-name': [FAIL], @@ -409,8 +237,20 @@ 'built-ins/DataView/prototype/setUint8/index-check-before-value-conversion': [FAIL], 'built-ins/DataView/prototype/setInt8/index-check-before-value-conversion': [FAIL], - # https://bugs.chromium.org/p/v8/issues/detail?id=4639 - 'built-ins/ArrayBuffer/allocation-limit': [SKIP], + # https://bugs.chromium.org/p/v8/issues/detail?id=4706 + 'language/statements/class/subclass/builtin-objects/NativeError/EvalError-message': [FAIL], + 'language/statements/class/subclass/builtin-objects/NativeError/RangeError-message': [FAIL], + 'language/statements/class/subclass/builtin-objects/NativeError/ReferenceError-message': [FAIL], + 'language/statements/class/subclass/builtin-objects/NativeError/SyntaxError-message': [FAIL], + 'language/statements/class/subclass/builtin-objects/NativeError/TypeError-message': [FAIL], + 'language/statements/class/subclass/builtin-objects/NativeError/URIError-message': [FAIL], + 'language/statements/class/subclass/builtin-objects/Error/message-property-assignment': [FAIL], + + # https://bugs.chromium.org/p/v8/issues/detail?id=4663 + 'built-ins/object/entries/*': [SKIP], + 'built-ins/object/values/*': [SKIP], + 'built-ins/Object/entries/*': [SKIP], + 'built-ins/Object/values/*': [SKIP], # https://code.google.com/p/chromium/issues/detail?id=581577 'built-ins/RegExp/prototype/source/15.10.7.1-1': [FAIL], @@ -496,8 +336,9 @@ 'built-ins/Array/prototype/indexOf/15.4.4.14-5-9': [FAIL], 'built-ins/Array/prototype/lastIndexOf/15.4.4.15-5-9': [FAIL], - # https://github.com/tc39/test262/issues/436 - 'built-ins/RegExp/call_with_regexp_match_falsy': [FAIL], + # https://github.com/tc39/test262/issues/489 + # Test will pass in 0 or -GMT, but fail in +GMT + 'language/statements/class/subclass/builtin-objects/Date/regular-subclassing': [PASS, FAIL_OK], ############################ SKIPPED TESTS ############################# @@ -544,12 +385,18 @@ 'intl402/NumberFormat/prototype/format/11.3.2_TRP': [SKIP], }], # system == macos -['no_i18n == True and mode == debug', { +['no_i18n == True', { + # Unicode canonicalization is not available with i18n turned off. + 'built-ins/String/prototype/localeCompare/15.5.4.9_CE': [SKIP], + + # Unicode regexp case mapping is not available with i18n turned off. + 'language/literals/regexp/u-case-mapping': [SKIP], + # BUG(v8:4437). 'built-ins/String/prototype/normalize/return-normalized-string': [SKIP], 'built-ins/String/prototype/normalize/return-normalized-string-from-coerced-form': [SKIP], 'built-ins/String/prototype/normalize/return-normalized-string-using-default-parameter': [SKIP], -}], # no_i18n == True and mode == debug +}], # no_i18n == True ['arch == arm or arch == mipsel or arch == mips or arch == arm64 or arch == mips64 or arch == mips64el', { @@ -571,7 +418,13 @@ # BUG(v8:4653): Test262 tests which rely on quit() are not compatible with # asan's --omit-quit flag. 'built-ins/Promise/prototype/then/deferred-is-resolved-value': [SKIP], -}], +}], # asan == True + +['asan == True or msan == True or tsan == True', { + # https://bugs.chromium.org/p/v8/issues/detail?id=4639 + # The failed allocation causes an asan/msan/tsan error + 'built-ins/ArrayBuffer/allocation-limit': [SKIP], +}], # asan == True or msan == True or tsan == True ['ignition == True', { 'annexB/B.2.3.*': [SKIP], @@ -579,48 +432,37 @@ 'built-ins/Array/prototype/reduceRight/*': [SKIP], 'built-ins/GeneratorFunction/*': [SKIP], 'built-ins/GeneratorPrototype/*': [SKIP], - 'built-ins/Map/*': [SKIP], - 'built-ins/MapIteratorPrototype/*': [SKIP], - 'built-ins/Promise/prototype/then/capability-executor-called-twice': [SKIP], 'built-ins/Promise/prototype/then/capability-executor-not-callable': [SKIP], - 'built-ins/Promise/prototype/then/deferred-is-resolved-value': [SKIP], - 'built-ins/Proxy/has/*': [SKIP], 'built-ins/Reflect/enumerate/*': [SKIP], - 'built-ins/Set/*': [SKIP], - 'built-ins/SetIteratorPrototype/*': [SKIP], - 'built-ins/WeakMap/*': [SKIP], - 'built-ins/WeakSet/*': [SKIP], 'language/computed-property-names/class/*': [SKIP], 'language/computed-property-names/to-name-side-effects/*': [SKIP], 'language/directive-prologue/*': [SKIP], 'language/expressions/arrow-function/*': [SKIP], 'language/expressions/assignment/destructuring/*': [SKIP], - 'language/expressions/class/*': [SKIP], + 'language/expressions/class/subclass/builtin-objects/GeneratorFunction/*': [SKIP], 'language/expressions/generators/*': [SKIP], + 'language/expressions/instanceof/primitive-prototype-with-object': [SKIP], + 'language/expressions/instanceof/prototype-getter-with-object-throws': [SKIP], + 'language/expressions/instanceof/prototype-getter-with-object': [SKIP], 'language/expressions/object/method-definition/yield*': [SKIP], 'language/expressions/object/method-definition/generator*': [SKIP], - 'language/expressions/object/prop-def-id-eval-error-2': [SKIP], 'language/expressions/yield/*': [SKIP], - 'language/function-code/*': [SKIP], - 'language/statements/class/*': [SKIP], - 'language/statements/const/*': [SKIP], - 'language/statements/for-in/const*': [SKIP], - 'language/statements/for-in/let*': [SKIP], - 'language/statements/for-of/*': [SKIP], + 'language/statements/class/definition/methods-gen-no-yield': [SKIP], + 'language/statements/class/definition/methods-gen-return': [SKIP], + 'language/statements/class/definition/methods-gen-yield-as-expression-with-rhs': [SKIP], + 'language/statements/class/definition/methods-gen-yield-as-generator-method-binding-identifier': [SKIP], + 'language/statements/class/definition/methods-gen-yield-as-literal-property-name': [SKIP], + 'language/statements/class/definition/methods-gen-yield-as-property-name': [SKIP], + 'language/statements/class/definition/methods-gen-yield-as-statement': [SKIP], + 'language/statements/class/definition/methods-gen-yield-as-expression-without-rhs': [SKIP], + 'language/statements/class/definition/methods-gen-yield-as-yield-operand': [SKIP], + 'language/statements/class/definition/methods-gen-yield-newline': [SKIP], + 'language/statements/class/definition/methods-gen-yield-star-before-newline': [SKIP], + 'language/statements/class/subclass/builtin-objects/GeneratorFunction/*': [SKIP], 'language/statements/generators/*': [SKIP], - 'language/statements/try/*': [SKIP], - 'language/statements/with/*': [SKIP], 'built-ins/Array/prototype/concat/Array.prototype.concat_non-array': [SKIP], - 'built-ins/Array/prototype/join/S15.4.4.5_A3.1_T1': [SKIP], - 'built-ins/Array/prototype/join/S15.4.4.5_A3.1_T2': [SKIP], - 'built-ins/Array/prototype/toString/S15.4.4.2_A1_T2': [SKIP], - 'built-ins/Array/prototype/toString/S15.4.4.2_A1_T3': [SKIP], - 'built-ins/Array/prototype/toString/S15.4.4.2_A1_T4': [SKIP], - 'built-ins/Date/15.9.1.15-1': [SKIP], 'built-ins/Date/prototype/toISOString/15.9.5.43-0-13': [SKIP], - 'built-ins/JSON/stringify/*': [SKIP], - 'built-ins/Object/defineProperty/15.2.3.6-4-625gs': [SKIP], 'built-ins/Object/prototype/hasOwnProperty/S15.2.4.5_A12': [SKIP], 'built-ins/Object/prototype/isPrototypeOf/S15.2.4.6_A12': [SKIP], 'built-ins/Object/prototype/propertyIsEnumerable/S15.2.4.7_A12': [SKIP], @@ -631,10 +473,8 @@ 'built-ins/Object/prototype/valueOf/S15.2.4.4_A12': [SKIP], 'built-ins/Object/prototype/valueOf/S15.2.4.4_A14': [SKIP], 'built-ins/Object/prototype/valueOf/S15.2.4.4_A15': [SKIP], - 'built-ins/Promise/all/ctx-ctor': [SKIP], - 'built-ins/Promise/race/ctx-ctor': [SKIP], - 'built-ins/Promise/reject/ctx-ctor': [SKIP], - 'built-ins/Promise/resolve/ctx-ctor': [SKIP], + 'built-ins/Promise/all/S25.4.4.1_A4.1_T1': [SKIP], + 'built-ins/Promise/prototype/then/on-rejected-throw': [SKIP], 'built-ins/Promise/reject/S25.4.4.4_A3.1_T1': [SKIP], 'built-ins/String/prototype/codePointAt/this-is-undefined-throws': [SKIP], 'built-ins/String/prototype/concat/S15.5.4.6_A2': [SKIP], @@ -643,84 +483,138 @@ 'built-ins/String/prototype/repeat/this-is-undefined-throws': [SKIP], 'built-ins/String/prototype/startsWith/this-is-undefined-throws': [SKIP], 'built-ins/String/prototype/trim/15.5.4.20-1-1': [SKIP], - 'built-ins/String/S15.5.5.1_A4_T1': [SKIP], 'language/block-scope/leave/nested-block-let-declaration-only-shadows-outer-parameter-value-1': [SKIP], 'language/block-scope/leave/nested-block-let-declaration-only-shadows-outer-parameter-value-2': [SKIP], 'language/block-scope/leave/verify-context-in-labelled-block': [SKIP], 'language/block-scope/leave/x-after-break-to-label': [SKIP], - 'language/computed-property-names/object/accessor/getter-super': [SKIP], - 'language/computed-property-names/object/accessor/setter-super': [SKIP], - 'language/computed-property-names/object/method/super': [SKIP], 'language/default-parameters/class-definitions': [SKIP], 'language/default-parameters/generators': [SKIP], - 'language/default-parameters/param-ref-uninitialized': [SKIP], - 'language/expressions/delete/11.4.1-4.a-5': [SKIP], - 'language/expressions/delete/11.4.1-4.a-6': [SKIP], 'language/expressions/object/method-definition/name-prop-name-yield-expr': [SKIP], - 'language/expressions/object/method-definition/name-super-prop-param': [SKIP], - 'language/expressions/object/method-definition/name-super-prop-body': [SKIP], - 'language/expressions/object/prop-def-id-eval-error': [SKIP], 'language/expressions/tagged-template/call-expression-context-no-strict': [SKIP], 'language/expressions/tagged-template/call-expression-context-strict': [SKIP], 'language/expressions/template-literal/evaluation-order': [SKIP], - 'language/expressions/this/11.1.1-1gs': [SKIP], - 'language/identifier-resolution/S10.2.2_A1_T5': [SKIP], - 'language/identifier-resolution/S10.2.2_A1_T6': [SKIP], - 'language/identifier-resolution/S10.2.2_A1_T7': [SKIP], - 'language/identifier-resolution/S10.2.2_A1_T8': [SKIP], - 'language/identifier-resolution/S10.2.2_A1_T9': [SKIP], + 'language/statements/for-of/body-dstr-assign': [SKIP], + 'language/statements/for-of/break': [SKIP], + 'language/statements/for-of/break-from-catch': [SKIP], + 'language/statements/for-of/break-from-finally': [SKIP], + 'language/statements/for-of/break-from-try': [SKIP], + 'language/statements/for-of/break-label': [SKIP], + 'language/statements/for-of/break-label-from-catch': [SKIP], + 'language/statements/for-of/break-label-from-finally': [SKIP], + 'language/statements/for-of/break-label-from-try': [SKIP], + 'language/statements/for-of/continue': [SKIP], + 'language/statements/for-of/continue-from-catch': [SKIP], + 'language/statements/for-of/continue-from-finally': [SKIP], + 'language/statements/for-of/continue-from-try': [SKIP], + 'language/statements/for-of/continue-label': [SKIP], + 'language/statements/for-of/continue-label-from-catch': [SKIP], + 'language/statements/for-of/continue-label-from-finally': [SKIP], + 'language/statements/for-of/continue-label-from-try': [SKIP], + 'language/statements/for-of/generator': [SKIP], + 'language/statements/for-of/generator-next-error': [SKIP], + 'language/statements/for-of/nested': [SKIP], + 'language/statements/for-of/return': [SKIP], + 'language/statements/for-of/return-from-catch': [SKIP], + 'language/statements/for-of/return-from-finally': [SKIP], + 'language/statements/for-of/return-from-try': [SKIP], + 'language/statements/for-of/throw': [SKIP], + 'language/statements/for-of/throw-from-catch': [SKIP], + 'language/statements/for-of/throw-from-finally': [SKIP], + 'language/statements/for-of/yield': [SKIP], + 'language/statements/for-of/yield-from-catch': [SKIP], + 'language/statements/for-of/yield-from-finally': [SKIP], + 'language/statements/for-of/yield-from-try': [SKIP], + 'language/statements/for-of/yield-star': [SKIP], + 'language/statements/for-of/yield-star-from-catch': [SKIP], + 'language/statements/for-of/yield-star-from-finally': [SKIP], + 'language/statements/for-of/yield-star-from-try': [SKIP], 'language/object-literal/concise-generator': [SKIP], - 'language/object-literal/getter': [SKIP], - 'language/object-literal/method': [SKIP], - 'language/object-literal/setter': [SKIP], - 'language/rest-parameters/arrow-function': [SKIP], - 'language/rest-parameters/expected-argument-count': [SKIP], - 'language/rest-parameters/no-alias-arguments': [SKIP], - 'language/rest-parameters/rest-index': [SKIP], - 'language/rest-parameters/rest-parameters-apply': [SKIP], - 'language/rest-parameters/rest-parameters-call': [SKIP], - 'language/rest-parameters/rest-parameters-produce-an-array': [SKIP], - 'language/rest-parameters/with-new-target': [SKIP], 'language/statements/do-while/S12.6.1_A4_T5': [SKIP], - 'language/statements/function/S13.2.2_A18_T2': [SKIP], - 'language/statements/function/S13.2.2_A19_T1': [SKIP], - 'language/statements/function/S13.2.2_A19_T2': [SKIP], - 'language/statements/function/S13.2.2_A19_T3': [SKIP], - 'language/statements/function/S13.2.2_A19_T4': [SKIP], - 'language/statements/function/S13.2.2_A19_T5': [SKIP], - 'language/statements/function/S13.2.2_A19_T6': [SKIP], - 'language/statements/function/S13.2.2_A19_T7': [SKIP], - 'language/statements/function/S13.2.2_A19_T8': [SKIP], - 'language/statements/function/S13.2.2_A18_T1': [SKIP], - 'language/statements/function/S13.2.2_A17_T2': [SKIP], - 'language/statements/function/S13.2.2_A17_T3': [SKIP], - 'language/statements/let/block-local-closure-get-before-initialization': [SKIP], - 'language/statements/let/block-local-closure-set-before-initialization': [SKIP], - 'language/statements/let/block-local-use-before-initialization-in-declaration-statement': [SKIP], - 'language/statements/let/block-local-use-before-initialization-in-prior-statement': [SKIP], - 'language/statements/let/function-local-closure-get-before-initialization': [SKIP], - 'language/statements/let/function-local-closure-set-before-initialization': [SKIP], - 'language/statements/let/function-local-use-before-initialization-in-declaration-statement': [SKIP], - 'language/statements/let/function-local-use-before-initialization-in-prior-statement': [SKIP], - 'language/statements/let/global-closure-get-before-initialization': [SKIP], - 'language/statements/let/global-closure-set-before-initialization': [SKIP], - 'language/statements/let/global-use-before-initialization-in-declaration-statement': [SKIP], - 'language/statements/let/global-use-before-initialization-in-prior-statement': [SKIP], 'language/statements/while/S12.6.2_A4_T5': [SKIP], + 'language/expressions/instanceof/symbol-hasinstance-not-callable': [SKIP], }], # ignition == True ['ignition == True and (arch == arm or arch == arm64)', { + 'built-ins/Promise/all/ctx-ctor': [SKIP], + 'built-ins/Promise/race/ctx-ctor': [SKIP], 'built-ins/decodeURI/S15.1.3.1_A1.12_T3': [SKIP], 'built-ins/decodeURIComponent/S15.1.3.2_A1.10_T1': [SKIP], 'built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2': [SKIP], 'built-ins/decodeURIComponent/S15.1.3.2_A1.12_T2': [SKIP], 'built-ins/decodeURIComponent/S15.1.3.2_A1.12_T3': [SKIP], 'intl402/9.2.2': [SKIP], + 'language/statements/class/arguments/default-constructor': [SKIP], + 'language/statements/class/definition/constructor-strict-by-default': [SKIP], + 'language/statements/class/definition/fn-name-accessor-get': [SKIP], + 'language/statements/class/definition/fn-name-accessor-set': [SKIP], + 'language/statements/class/definition/fn-name-gen-method': [SKIP], + 'language/statements/class/definition/fn-name-method': [SKIP], + 'language/statements/class/definition/methods-restricted-properties': [SKIP], + 'language/statements/class/definition/prototype-getter': [SKIP], + 'language/statements/class/definition/prototype-wiring': [SKIP], + 'language/statements/class/definition/this-access-restriction': [SKIP], + 'language/statements/class/definition/this-access-restriction-2': [SKIP], + 'language/statements/class/definition/this-check-ordering': [SKIP], + 'language/statements/class/name': [SKIP], + 'language/statements/class/restricted-properties': [SKIP], + 'language/statements/class/subclass/binding': [SKIP], + 'language/statements/class/subclass/builtin-objects/Array/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/ArrayBuffer/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/Boolean/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/DataView/regular-subclassing': [SKIP], + 'language/statements/class/subclass/builtin-objects/DataView/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/Date/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/Error/regular-subclassing': [SKIP], + 'language/statements/class/subclass/builtin-objects/Error/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/Function/instance-length': [SKIP], + 'language/statements/class/subclass/builtin-objects/Function/instance-name': [SKIP], + 'language/statements/class/subclass/builtin-objects/Function/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/Map/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/NativeError/EvalError-name': [SKIP], + 'language/statements/class/subclass/builtin-objects/NativeError/EvalError-super': [SKIP], + 'language/statements/class/subclass/builtin-objects/NativeError/RangeError-name': [SKIP], + 'language/statements/class/subclass/builtin-objects/NativeError/RangeError-super': [SKIP], + 'language/statements/class/subclass/builtin-objects/NativeError/ReferenceError-name': [SKIP], + 'language/statements/class/subclass/builtin-objects/NativeError/ReferenceError-super': [SKIP], + 'language/statements/class/subclass/builtin-objects/NativeError/SyntaxError-name': [SKIP], + 'language/statements/class/subclass/builtin-objects/NativeError/SyntaxError-super': [SKIP], + 'language/statements/class/subclass/builtin-objects/NativeError/TypeError-name': [SKIP], + 'language/statements/class/subclass/builtin-objects/NativeError/TypeError-super': [SKIP], + 'language/statements/class/subclass/builtin-objects/NativeError/URIError-name': [SKIP], + 'language/statements/class/subclass/builtin-objects/NativeError/URIError-super': [SKIP], + 'language/statements/class/subclass/builtin-objects/Number/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/Object/constructor-return-undefined-throws': [SKIP], + 'language/statements/class/subclass/builtin-objects/Object/constructor-returns-non-object': [SKIP], + 'language/statements/class/subclass/builtin-objects/Promise/regular-subclassing': [SKIP], + 'language/statements/class/subclass/builtin-objects/Promise/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/RegExp/lastIndex': [SKIP], + 'language/statements/class/subclass/builtin-objects/RegExp/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/Set/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/String/length': [SKIP], + 'language/statements/class/subclass/builtin-objects/String/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/Symbol/new-symbol-with-super-throws': [SKIP], + 'language/statements/class/subclass/builtin-objects/WeakMap/super-must-be-called': [SKIP], + 'language/statements/class/subclass/builtin-objects/WeakSet/super-must-be-called': [SKIP], + 'language/statements/class/subclass/class-definition-null-proto-missing-return-override': [SKIP], + 'language/statements/class/subclass/default-constructor': [SKIP], + 'language/statements/class/subclass/default-constructor-2': [SKIP], + 'language/statements/class/subclass/derived-class-return-override-with-boolean': [SKIP], + 'language/statements/class/subclass/derived-class-return-override-with-null': [SKIP], + 'language/statements/class/subclass/derived-class-return-override-with-number': [SKIP], + 'language/statements/class/subclass/derived-class-return-override-with-string': [SKIP], + 'language/statements/class/subclass/derived-class-return-override-with-symbol': [SKIP], + 'language/statements/const/fn-name-arrow': [SKIP], + 'language/statements/const/fn-name-class': [SKIP], + 'language/statements/const/fn-name-cover': [SKIP], + 'language/statements/const/fn-name-fn': [SKIP], + 'language/statements/const/fn-name-gen': [SKIP], 'language/statements/let/fn-name-arrow': [SKIP], + 'language/statements/let/fn-name-class': [SKIP], 'language/statements/let/fn-name-cover': [SKIP], 'language/statements/let/fn-name-fn': [SKIP], 'language/statements/let/fn-name-gen': [SKIP], + 'test-api/Regress470113': [SKIP], }], # ignition == True and (arch == arm or arch == arm64) ] diff --git a/deps/v8/test/test262/testcfg.py b/deps/v8/test/test262/testcfg.py index f222e1e37d..b5ad30949d 100644 --- a/deps/v8/test/test262/testcfg.py +++ b/deps/v8/test/test262/testcfg.py @@ -39,6 +39,8 @@ from testrunner.local import testsuite from testrunner.local import utils from testrunner.objects import testcase +ARCHIVE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data.tar") + TEST_262_HARNESS_FILES = ["sta.js", "assert.js"] TEST_262_SUITE_PATH = ["data", "test"] @@ -199,6 +201,11 @@ class Test262TestSuite(testsuite.TestSuite): for f in archive_files: os.remove(os.path.join(self.root, f)) + print "Extracting archive..." + tar = tarfile.open(ARCHIVE) + tar.extractall(path=os.path.dirname(ARCHIVE)) + tar.close() + def GetSuite(name, root): return Test262TestSuite(name, root) 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 62abeda1b5..72cfc51d58 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 @@ -1584,7 +1584,7 @@ TEST_P(InstructionSelectorF32ComparisonTest, NegatedWithParameters) { StreamBuilder m(this, MachineType::Int32(), MachineType::Float32(), MachineType::Float32()); m.Return( - m.WordBinaryNot((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)))); + m.Word32BinaryNot((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)))); Stream const s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArmVcmpF32, s[0]->arch_opcode()); @@ -1667,7 +1667,7 @@ TEST_P(InstructionSelectorF64ComparisonTest, NegatedWithParameters) { StreamBuilder m(this, MachineType::Int32(), MachineType::Float64(), MachineType::Float64()); m.Return( - m.WordBinaryNot((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)))); + m.Word32BinaryNot((m.*cmp.constructor)(m.Parameter(0), m.Parameter(1)))); Stream const s = m.Build(); ASSERT_EQ(1U, s.size()); EXPECT_EQ(kArmVcmpF64, s[0]->arch_opcode()); @@ -2544,8 +2544,28 @@ TEST_F(InstructionSelectorTest, Uint32ModWithParametersForSUDIVAndMLS) { } +TEST_F(InstructionSelectorTest, Word32ShlWord32SarForSbfx) { + TRACED_FORRANGE(int32_t, shl, 1, 31) { + TRACED_FORRANGE(int32_t, sar, shl, 31) { + if ((shl == sar) && (sar == 16)) continue; // Sxth. + if ((shl == sar) && (sar == 24)) continue; // Sxtb. + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + m.Return(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(shl)), + m.Int32Constant(sar))); + Stream s = m.Build(ARMv7); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmSbfx, s[0]->arch_opcode()); + ASSERT_EQ(3U, s[0]->InputCount()); + EXPECT_EQ(sar - shl, s.ToInt32(s[0]->InputAt(1))); + EXPECT_EQ(32 - sar, s.ToInt32(s[0]->InputAt(2))); + } + } +} + + TEST_F(InstructionSelectorTest, Word32AndWithUbfxImmediateForARMv7) { - TRACED_FORRANGE(int32_t, width, 1, 32) { + TRACED_FORRANGE(int32_t, width, 9, 23) { + if (width == 16) continue; // Uxth. StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32And(m.Parameter(0), m.Int32Constant(0xffffffffu >> (32 - width)))); @@ -2556,7 +2576,8 @@ TEST_F(InstructionSelectorTest, Word32AndWithUbfxImmediateForARMv7) { EXPECT_EQ(0, s.ToInt32(s[0]->InputAt(1))); EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); } - TRACED_FORRANGE(int32_t, width, 1, 32) { + TRACED_FORRANGE(int32_t, width, 9, 23) { + if (width == 16) continue; // Uxth. StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)), m.Parameter(0))); @@ -2572,7 +2593,7 @@ TEST_F(InstructionSelectorTest, Word32AndWithUbfxImmediateForARMv7) { TEST_F(InstructionSelectorTest, Word32AndWithBfcImmediateForARMv7) { TRACED_FORRANGE(int32_t, lsb, 0, 31) { - TRACED_FORRANGE(int32_t, width, 9, (32 - lsb) - 1) { + TRACED_FORRANGE(int32_t, width, 9, (24 - lsb) - 1) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32And( m.Parameter(0), @@ -2589,7 +2610,7 @@ TEST_F(InstructionSelectorTest, Word32AndWithBfcImmediateForARMv7) { } } TRACED_FORRANGE(int32_t, lsb, 0, 31) { - TRACED_FORRANGE(int32_t, width, 9, (32 - lsb) - 1) { + TRACED_FORRANGE(int32_t, width, 9, (24 - lsb) - 1) { StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return( m.Word32And(m.Int32Constant(~((0xffffffffu >> (32 - width)) << lsb)), @@ -2828,8 +2849,11 @@ TEST_F(InstructionSelectorTest, Word32NotWithParameter) { TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) { - TRACED_FORRANGE(int32_t, lsb, 0, 31) { + TRACED_FORRANGE(int32_t, lsb, 1, 31) { TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { + if (((width == 8) || (width == 16)) && + ((lsb == 8) || (lsb == 16) || (lsb == 24))) + continue; // Uxtb/h ror. StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32And(m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)), m.Int32Constant(0xffffffffu >> (32 - width)))); @@ -2841,8 +2865,11 @@ TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) { EXPECT_EQ(width, s.ToInt32(s[0]->InputAt(2))); } } - TRACED_FORRANGE(int32_t, lsb, 0, 31) { + TRACED_FORRANGE(int32_t, lsb, 1, 31) { TRACED_FORRANGE(int32_t, width, 1, 32 - lsb) { + if (((width == 8) || (width == 16)) && + ((lsb == 8) || (lsb == 16) || (lsb == 24))) + continue; // Uxtb/h ror. StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); m.Return(m.Word32And(m.Int32Constant(0xffffffffu >> (32 - width)), m.Word32Shr(m.Parameter(0), m.Int32Constant(lsb)))); @@ -2857,6 +2884,62 @@ TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrWithImmediateForARMv7) { } +TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrAnd0xff) { + TRACED_FORRANGE(int32_t, shr, 1, 3) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = m.Word32And(m.Word32Shr(p0, m.Int32Constant(shr * 8)), + m.Int32Constant(0xff)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUxtb, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(shr * 8, s.ToInt32(s[0]->InputAt(1))); + } + TRACED_FORRANGE(int32_t, shr, 1, 3) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = m.Word32And(m.Int32Constant(0xff), + m.Word32Shr(p0, m.Int32Constant(shr * 8))); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUxtb, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(shr * 8, s.ToInt32(s[0]->InputAt(1))); + } +} + + +TEST_F(InstructionSelectorTest, Word32AndWithWord32ShrAnd0xffff) { + TRACED_FORRANGE(int32_t, shr, 1, 3) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = m.Word32And(m.Word32Shr(p0, m.Int32Constant(shr * 8)), + m.Int32Constant(0xffff)); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUxth, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(shr * 8, s.ToInt32(s[0]->InputAt(1))); + } + TRACED_FORRANGE(int32_t, shr, 1, 3) { + StreamBuilder m(this, MachineType::Int32(), MachineType::Int32()); + Node* const p0 = m.Parameter(0); + Node* const r = m.Word32And(m.Int32Constant(0xffff), + m.Word32Shr(p0, m.Int32Constant(shr * 8))); + m.Return(r); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArmUxth, s[0]->arch_opcode()); + ASSERT_EQ(2U, s[0]->InputCount()); + EXPECT_EQ(shr * 8, s.ToInt32(s[0]->InputAt(1))); + } +} + + TEST_F(InstructionSelectorTest, Word32Clz) { StreamBuilder m(this, MachineType::Uint32(), MachineType::Uint32()); Node* const p0 = m.Parameter(0); diff --git a/deps/v8/test/unittests/compiler/escape-analysis-unittest.cc b/deps/v8/test/unittests/compiler/escape-analysis-unittest.cc index b088367a58..d5e12ba0db 100644 --- a/deps/v8/test/unittests/compiler/escape-analysis-unittest.cc +++ b/deps/v8/test/unittests/compiler/escape-analysis-unittest.cc @@ -9,7 +9,7 @@ #include "src/compiler/js-graph.h" #include "src/compiler/node-properties.h" #include "src/compiler/simplified-operator.h" -#include "src/types-inl.h" +#include "src/types.h" #include "src/zone-containers.h" #include "test/unittests/compiler/graph-unittest.h" @@ -85,6 +85,20 @@ class EscapeAnalysisTest : public GraphTest { allocation, value, effect, control); } + Node* StoreElement(const ElementAccess& access, Node* allocation, Node* index, + Node* value, Node* effect = nullptr, + Node* control = nullptr) { + if (!effect) { + effect = effect_; + } + if (!control) { + control = control_; + } + return effect_ = + graph()->NewNode(simplified()->StoreElement(access), allocation, + index, value, effect, control); + } + Node* Load(const FieldAccess& access, Node* from, Node* effect = nullptr, Node* control = nullptr) { if (!effect) { @@ -131,12 +145,18 @@ class EscapeAnalysisTest : public GraphTest { return control_ = graph()->NewNode(common()->Merge(2), control1, control2); } - FieldAccess AccessAtIndex(int offset) { + FieldAccess FieldAccessAtIndex(int offset) { FieldAccess access = {kTaggedBase, offset, MaybeHandle<Name>(), Type::Any(), MachineType::AnyTagged()}; return access; } + ElementAccess MakeElementAccess(int header_size) { + ElementAccess access = {kTaggedBase, header_size, Type::Any(), + MachineType::AnyTagged()}; + return access; + } + // ---------------------------------Assertion Helper-------------------------- void ExpectReplacement(Node* node, Node* rep) { @@ -166,6 +186,7 @@ class EscapeAnalysisTest : public GraphTest { SimplifiedOperatorBuilder* simplified() { return &simplified_; } Node* effect() { return effect_; } + Node* control() { return control_; } private: SimplifiedOperatorBuilder simplified_; @@ -185,9 +206,9 @@ TEST_F(EscapeAnalysisTest, StraightNonEscape) { Node* object1 = Constant(1); BeginRegion(); Node* allocation = Allocate(Constant(kPointerSize)); - Store(AccessAtIndex(0), allocation, object1); + Store(FieldAccessAtIndex(0), allocation, object1); Node* finish = FinishRegion(allocation); - Node* load = Load(AccessAtIndex(0), finish); + Node* load = Load(FieldAccessAtIndex(0), finish); Node* result = Return(load); EndGraph(); @@ -202,13 +223,39 @@ TEST_F(EscapeAnalysisTest, StraightNonEscape) { } +TEST_F(EscapeAnalysisTest, StraightNonEscapeNonConstStore) { + Node* object1 = Constant(1); + Node* object2 = Constant(2); + BeginRegion(); + Node* allocation = Allocate(Constant(kPointerSize)); + Store(FieldAccessAtIndex(0), allocation, object1); + Node* index = + graph()->NewNode(common()->Select(MachineRepresentation::kTagged), + object1, object2, control()); + StoreElement(MakeElementAccess(0), allocation, index, object1); + Node* finish = FinishRegion(allocation); + Node* load = Load(FieldAccessAtIndex(0), finish); + Node* result = Return(load); + EndGraph(); + + Analysis(); + + ExpectEscaped(allocation); + ExpectReplacement(load, nullptr); + + Transformation(); + + ASSERT_EQ(load, NodeProperties::GetValueInput(result, 0)); +} + + TEST_F(EscapeAnalysisTest, StraightEscape) { Node* object1 = Constant(1); BeginRegion(); Node* allocation = Allocate(Constant(kPointerSize)); - Store(AccessAtIndex(0), allocation, object1); + Store(FieldAccessAtIndex(0), allocation, object1); Node* finish = FinishRegion(allocation); - Node* load = Load(AccessAtIndex(0), finish); + Node* load = Load(FieldAccessAtIndex(0), finish); Node* result = Return(allocation); EndGraph(); graph()->end()->AppendInput(zone(), load); @@ -229,15 +276,15 @@ TEST_F(EscapeAnalysisTest, StoreLoadEscape) { BeginRegion(); Node* allocation1 = Allocate(Constant(kPointerSize)); - Store(AccessAtIndex(0), allocation1, object1); + Store(FieldAccessAtIndex(0), allocation1, object1); Node* finish1 = FinishRegion(allocation1); BeginRegion(); Node* allocation2 = Allocate(Constant(kPointerSize)); - Store(AccessAtIndex(0), allocation2, finish1); + Store(FieldAccessAtIndex(0), allocation2, finish1); Node* finish2 = FinishRegion(allocation2); - Node* load = Load(AccessAtIndex(0), finish2); + Node* load = Load(FieldAccessAtIndex(0), finish2); Node* result = Return(load); EndGraph(); Analysis(); @@ -257,16 +304,18 @@ TEST_F(EscapeAnalysisTest, BranchNonEscape) { Node* object2 = Constant(2); BeginRegion(); Node* allocation = Allocate(Constant(kPointerSize)); - Store(AccessAtIndex(0), allocation, object1); + Store(FieldAccessAtIndex(0), allocation, object1); Node* finish = FinishRegion(allocation); Branch(); Node* ifFalse = IfFalse(); Node* ifTrue = IfTrue(); - Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish, ifFalse); - Node* effect2 = Store(AccessAtIndex(0), allocation, object2, finish, ifTrue); + Node* effect1 = + Store(FieldAccessAtIndex(0), allocation, object1, finish, ifFalse); + Node* effect2 = + Store(FieldAccessAtIndex(0), allocation, object2, finish, ifTrue); Node* merge = Merge2(ifFalse, ifTrue); Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge); - Node* load = Load(AccessAtIndex(0), finish, phi, merge); + Node* load = Load(FieldAccessAtIndex(0), finish, phi, merge); Node* result = Return(load, phi); EndGraph(); graph()->end()->AppendInput(zone(), result); @@ -283,14 +332,81 @@ TEST_F(EscapeAnalysisTest, BranchNonEscape) { } +TEST_F(EscapeAnalysisTest, BranchEscapeOne) { + Node* object1 = Constant(1); + Node* object2 = Constant(2); + Node* index = graph()->NewNode(common()->Parameter(0), start()); + BeginRegion(); + Node* allocation = Allocate(Constant(kPointerSize)); + Store(FieldAccessAtIndex(0), allocation, object1); + Node* finish = FinishRegion(allocation); + Branch(); + Node* ifFalse = IfFalse(); + Node* ifTrue = IfTrue(); + Node* effect1 = + Store(FieldAccessAtIndex(0), allocation, object1, finish, ifFalse); + Node* effect2 = StoreElement(MakeElementAccess(0), allocation, index, object2, + finish, ifTrue); + Node* merge = Merge2(ifFalse, ifTrue); + Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge); + Node* load = Load(FieldAccessAtIndex(0), finish, phi, merge); + Node* result = Return(load, phi); + EndGraph(); + + Analysis(); + + ExpectEscaped(allocation); + ExpectReplacement(load, nullptr); + + Transformation(); + + ASSERT_EQ(load, NodeProperties::GetValueInput(result, 0)); +} + + +TEST_F(EscapeAnalysisTest, BranchEscapeThroughStore) { + Node* object1 = Constant(1); + Node* object2 = Constant(2); + BeginRegion(); + Node* allocation = Allocate(Constant(kPointerSize)); + Store(FieldAccessAtIndex(0), allocation, object1); + FinishRegion(allocation); + BeginRegion(); + Node* allocation2 = Allocate(Constant(kPointerSize)); + Store(FieldAccessAtIndex(0), allocation, object2); + Node* finish2 = FinishRegion(allocation2); + Branch(); + Node* ifFalse = IfFalse(); + Node* ifTrue = IfTrue(); + Node* effect1 = + Store(FieldAccessAtIndex(0), allocation, allocation2, finish2, ifFalse); + Node* merge = Merge2(ifFalse, ifTrue); + Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, finish2, merge); + Node* load = Load(FieldAccessAtIndex(0), finish2, phi, merge); + Node* result = Return(allocation, phi); + EndGraph(); + graph()->end()->AppendInput(zone(), load); + + Analysis(); + + ExpectEscaped(allocation); + ExpectEscaped(allocation2); + ExpectReplacement(load, nullptr); + + Transformation(); + + ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0)); +} + + TEST_F(EscapeAnalysisTest, DanglingLoadOrder) { Node* object1 = Constant(1); Node* object2 = Constant(2); Node* allocation = Allocate(Constant(kPointerSize)); - Node* store1 = Store(AccessAtIndex(0), allocation, object1); - Node* load1 = Load(AccessAtIndex(0), allocation); - Node* store2 = Store(AccessAtIndex(0), allocation, object2); - Node* load2 = Load(AccessAtIndex(0), allocation, store1); + Node* store1 = Store(FieldAccessAtIndex(0), allocation, object1); + Node* load1 = Load(FieldAccessAtIndex(0), allocation); + Node* store2 = Store(FieldAccessAtIndex(0), allocation, object2); + Node* load2 = Load(FieldAccessAtIndex(0), allocation, store1); Node* result = Return(load2); EndGraph(); graph()->end()->AppendInput(zone(), store2); @@ -312,9 +428,9 @@ TEST_F(EscapeAnalysisTest, DeoptReplacement) { Node* object1 = Constant(1); BeginRegion(); Node* allocation = Allocate(Constant(kPointerSize)); - Store(AccessAtIndex(0), allocation, object1); + Store(FieldAccessAtIndex(0), allocation, object1); Node* finish = FinishRegion(allocation); - Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish); + Node* effect1 = Store(FieldAccessAtIndex(0), allocation, object1, finish); Branch(); Node* ifFalse = IfFalse(); Node* state_values1 = graph()->NewNode(common()->StateValues(1), finish); @@ -328,7 +444,7 @@ TEST_F(EscapeAnalysisTest, DeoptReplacement) { Node* deopt = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager), frame_state, effect1, ifFalse); Node* ifTrue = IfTrue(); - Node* load = Load(AccessAtIndex(0), finish, effect1, ifTrue); + Node* load = Load(FieldAccessAtIndex(0), finish, effect1, ifTrue); Node* result = Return(load, effect1, ifTrue); EndGraph(); graph()->end()->AppendInput(zone(), deopt); @@ -351,10 +467,10 @@ TEST_F(EscapeAnalysisTest, DeoptReplacementIdentity) { Node* object1 = Constant(1); BeginRegion(); Node* allocation = Allocate(Constant(kPointerSize * 2)); - Store(AccessAtIndex(0), allocation, object1); - Store(AccessAtIndex(kPointerSize), allocation, allocation); + Store(FieldAccessAtIndex(0), allocation, object1); + Store(FieldAccessAtIndex(kPointerSize), allocation, allocation); Node* finish = FinishRegion(allocation); - Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish); + Node* effect1 = Store(FieldAccessAtIndex(0), allocation, object1, finish); Branch(); Node* ifFalse = IfFalse(); Node* state_values1 = graph()->NewNode(common()->StateValues(1), finish); @@ -368,7 +484,7 @@ TEST_F(EscapeAnalysisTest, DeoptReplacementIdentity) { Node* deopt = graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager), frame_state, effect1, ifFalse); Node* ifTrue = IfTrue(); - Node* load = Load(AccessAtIndex(0), finish, effect1, ifTrue); + Node* load = Load(FieldAccessAtIndex(0), finish, effect1, ifTrue); Node* result = Return(load, effect1, ifTrue); EndGraph(); graph()->end()->AppendInput(zone(), deopt); diff --git a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc b/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc index 89c0a654e9..16030f80d7 100644 --- a/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc +++ b/deps/v8/test/unittests/compiler/instruction-selector-unittest.cc @@ -40,7 +40,7 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build( instruction_blocks); SourcePositionTable source_position_table(graph()); InstructionSelector selector(test_->zone(), node_count, &linkage, &sequence, - schedule, &source_position_table, + schedule, &source_position_table, nullptr, source_position_mode, features); selector.SelectInstructions(); if (FLAG_trace_turbo) { @@ -148,7 +148,7 @@ InstructionSelectorTest::StreamBuilder::GetFrameStateFunctionInfo( int parameter_count, int local_count) { return common()->CreateFrameStateFunctionInfo( FrameStateType::kJavaScriptFunction, parameter_count, local_count, - Handle<SharedFunctionInfo>(), CALL_MAINTAINS_NATIVE_CONTEXT); + Handle<SharedFunctionInfo>()); } diff --git a/deps/v8/test/unittests/compiler/instruction-selector-unittest.h b/deps/v8/test/unittests/compiler/instruction-selector-unittest.h index fc7c144939..f1397faa06 100644 --- a/deps/v8/test/unittests/compiler/instruction-selector-unittest.h +++ b/deps/v8/test/unittests/compiler/instruction-selector-unittest.h @@ -92,7 +92,7 @@ class InstructionSelectorTest : public TestWithContext, CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type) { MachineSignature::Builder builder(zone, 1, 0); builder.AddReturn(return_type); - return Linkage::GetSimplifiedCDescriptor(zone, builder.Build()); + return MakeSimpleCallDescriptor(zone, builder.Build()); } CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type, @@ -100,7 +100,7 @@ class InstructionSelectorTest : public TestWithContext, MachineSignature::Builder builder(zone, 1, 1); builder.AddReturn(return_type); builder.AddParam(parameter0_type); - return Linkage::GetSimplifiedCDescriptor(zone, builder.Build()); + return MakeSimpleCallDescriptor(zone, builder.Build()); } CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type, @@ -110,7 +110,7 @@ class InstructionSelectorTest : public TestWithContext, builder.AddReturn(return_type); builder.AddParam(parameter0_type); builder.AddParam(parameter1_type); - return Linkage::GetSimplifiedCDescriptor(zone, builder.Build()); + return MakeSimpleCallDescriptor(zone, builder.Build()); } CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type, @@ -122,11 +122,48 @@ class InstructionSelectorTest : public TestWithContext, builder.AddParam(parameter0_type); builder.AddParam(parameter1_type); builder.AddParam(parameter2_type); - return Linkage::GetSimplifiedCDescriptor(zone, builder.Build()); + return MakeSimpleCallDescriptor(zone, builder.Build()); } private: InstructionSelectorTest* test_; + + // Create a simple call descriptor for testing. + CallDescriptor* MakeSimpleCallDescriptor(Zone* zone, + MachineSignature* msig) { + LocationSignature::Builder locations(zone, msig->return_count(), + msig->parameter_count()); + + // Add return location(s). + const int return_count = static_cast<int>(msig->return_count()); + for (int i = 0; i < return_count; i++) { + locations.AddReturn(LinkageLocation::ForCallerFrameSlot(-1 - i)); + } + + // Just put all parameters on the stack. + const int parameter_count = static_cast<int>(msig->parameter_count()); + for (int i = 0; i < parameter_count; i++) { + locations.AddParam(LinkageLocation::ForCallerFrameSlot(-1 - i)); + } + + const RegList kCalleeSaveRegisters = 0; + const RegList kCalleeSaveFPRegisters = 0; + + MachineType target_type = MachineType::Pointer(); + LinkageLocation target_loc = LinkageLocation::ForAnyRegister(); + return new (zone) CallDescriptor( // -- + CallDescriptor::kCallAddress, // kind + target_type, // target MachineType + target_loc, // target location + msig, // machine_sig + locations.Build(), // location_sig + 0, // stack_parameter_count + Operator::kNoProperties, // properties + kCalleeSaveRegisters, // callee-saved registers + kCalleeSaveFPRegisters, // callee-saved fp regs + CallDescriptor::kNoFlags, // flags + "iselect-test-call"); + } }; class Stream final { diff --git a/deps/v8/test/unittests/compiler/int64-lowering-unittest.cc b/deps/v8/test/unittests/compiler/int64-lowering-unittest.cc new file mode 100644 index 0000000000..eff6d4a931 --- /dev/null +++ b/deps/v8/test/unittests/compiler/int64-lowering-unittest.cc @@ -0,0 +1,299 @@ +// Copyright 2016 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/int64-lowering.h" +#include "src/compiler/common-operator.h" +#include "src/compiler/linkage.h" +#include "src/compiler/machine-operator.h" +#include "src/compiler/node.h" + +#include "src/compiler/node-properties.h" + +#include "src/signature.h" + +#include "src/wasm/wasm-module.h" + +#include "test/unittests/compiler/graph-unittest.h" +#include "test/unittests/compiler/node-test-utils.h" +#include "testing/gmock-support.h" + +using testing::AllOf; +using testing::Capture; +using testing::CaptureEq; + +namespace v8 { +namespace internal { +namespace compiler { + +class Int64LoweringTest : public GraphTest { + public: + Int64LoweringTest() : GraphTest(), machine_(zone()) { + value_[0] = 0x1234567890abcdef; + value_[1] = 0x1edcba098765432f; + value_[2] = 0x1133557799886644; + } + + MachineOperatorBuilder* machine() { return &machine_; } + + void LowerGraph(Node* node, Signature<MachineRepresentation>* signature) { + Node* ret = graph()->NewNode(common()->Return(), node, graph()->start(), + graph()->start()); + NodeProperties::MergeControlToEnd(graph(), common(), ret); + + Int64Lowering lowering(graph(), machine(), common(), zone(), signature); + lowering.LowerGraph(); + } + + void LowerGraph(Node* node, MachineRepresentation return_type, + MachineRepresentation rep = MachineRepresentation::kWord32, + int num_params = 0) { + Signature<MachineRepresentation>::Builder sig_builder(zone(), 1, + num_params); + sig_builder.AddReturn(return_type); + for (int i = 0; i < num_params; i++) { + sig_builder.AddParam(rep); + } + LowerGraph(node, sig_builder.Build()); + } + + void CompareCallDescriptors(const CallDescriptor* lhs, + const CallDescriptor* rhs) { + EXPECT_THAT(lhs->CalleeSavedFPRegisters(), rhs->CalleeSavedFPRegisters()); + EXPECT_THAT(lhs->CalleeSavedRegisters(), rhs->CalleeSavedRegisters()); + EXPECT_THAT(lhs->FrameStateCount(), rhs->FrameStateCount()); + EXPECT_THAT(lhs->InputCount(), rhs->InputCount()); + for (size_t i = 0; i < lhs->InputCount(); i++) { + EXPECT_THAT(lhs->GetInputLocation(i), rhs->GetInputLocation(i)); + EXPECT_THAT(lhs->GetInputType(i), rhs->GetInputType(i)); + } + EXPECT_THAT(lhs->ReturnCount(), rhs->ReturnCount()); + for (size_t i = 0; i < lhs->ReturnCount(); i++) { + EXPECT_THAT(lhs->GetReturnLocation(i), rhs->GetReturnLocation(i)); + EXPECT_THAT(lhs->GetReturnType(i), rhs->GetReturnType(i)); + } + EXPECT_THAT(lhs->flags(), rhs->flags()); + EXPECT_THAT(lhs->kind(), rhs->kind()); + } + + int64_t value(int i) { return value_[i]; } + + int32_t low_word_value(int i) { + return static_cast<int32_t>(value_[i] & 0xffffffff); + } + + int32_t high_word_value(int i) { + return static_cast<int32_t>(value_[i] >> 32); + } + + private: + MachineOperatorBuilder machine_; + int64_t value_[3]; +}; + +TEST_F(Int64LoweringTest, Int64Constant) { + if (4 != kPointerSize) return; + + LowerGraph(Int64Constant(value(0)), MachineRepresentation::kWord64); + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn2(IsInt32Constant(low_word_value(0)), + IsInt32Constant(high_word_value(0)), start(), start())); +} + +TEST_F(Int64LoweringTest, Int64Load) { + if (4 != kPointerSize) return; + + int32_t base = 0x1234; + int32_t index = 0x5678; + + LowerGraph(graph()->NewNode(machine()->Load(MachineType::Int64()), + Int32Constant(base), Int32Constant(index), + start(), start()), + MachineRepresentation::kWord64); + + Capture<Node*> high_word_load; + Matcher<Node*> high_word_load_matcher = + IsLoad(MachineType::Int32(), IsInt32Constant(base), + IsInt32Add(IsInt32Constant(index), IsInt32Constant(0x4)), start(), + start()); + + EXPECT_THAT( + graph()->end()->InputAt(1), + IsReturn2(IsLoad(MachineType::Int32(), IsInt32Constant(base), + IsInt32Constant(index), AllOf(CaptureEq(&high_word_load), + high_word_load_matcher), + start()), + AllOf(CaptureEq(&high_word_load), high_word_load_matcher), + start(), start())); +} + +TEST_F(Int64LoweringTest, Int64Store) { + if (4 != kPointerSize) return; + + // We have to build the TF graph explicitly here because Store does not return + // a value. + + int32_t base = 1111; + int32_t index = 2222; + int32_t return_value = 0x5555; + + Signature<MachineRepresentation>::Builder sig_builder(zone(), 1, 0); + sig_builder.AddReturn(MachineRepresentation::kWord32); + + Node* store = graph()->NewNode( + machine()->Store(StoreRepresentation(MachineRepresentation::kWord64, + WriteBarrierKind::kNoWriteBarrier)), + Int32Constant(base), Int32Constant(index), Int64Constant(value(0)), + start(), start()); + + Node* ret = graph()->NewNode(common()->Return(), Int32Constant(return_value), + store, start()); + + NodeProperties::MergeControlToEnd(graph(), common(), ret); + + Int64Lowering lowering(graph(), machine(), common(), zone(), + sig_builder.Build()); + lowering.LowerGraph(); + + const StoreRepresentation rep(MachineRepresentation::kWord32, + kNoWriteBarrier); + + EXPECT_THAT( + graph()->end()->InputAt(1), + IsReturn( + IsInt32Constant(return_value), + IsStore( + rep, IsInt32Constant(base), IsInt32Constant(index), + IsInt32Constant(low_word_value(0)), + IsStore(rep, IsInt32Constant(base), + IsInt32Add(IsInt32Constant(index), IsInt32Constant(4)), + IsInt32Constant(high_word_value(0)), start(), start()), + start()), + start())); +} + +TEST_F(Int64LoweringTest, Int64And) { + if (4 != kPointerSize) return; + + LowerGraph(graph()->NewNode(machine()->Word64And(), Int64Constant(value(0)), + Int64Constant(value(1))), + MachineRepresentation::kWord64); + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn2(IsWord32And(IsInt32Constant(low_word_value(0)), + IsInt32Constant(low_word_value(1))), + IsWord32And(IsInt32Constant(high_word_value(0)), + IsInt32Constant(high_word_value(1))), + start(), start())); +} + +TEST_F(Int64LoweringTest, TruncateInt64ToInt32) { + if (4 != kPointerSize) return; + + LowerGraph(graph()->NewNode(machine()->TruncateInt64ToInt32(), + Int64Constant(value(0))), + MachineRepresentation::kWord32); + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn(IsInt32Constant(low_word_value(0)), start(), start())); +} + +TEST_F(Int64LoweringTest, Parameter) { + if (4 != kPointerSize) return; + + LowerGraph(Parameter(0), MachineRepresentation::kWord64, + MachineRepresentation::kWord64, 1); + + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn2(IsParameter(0), IsParameter(1), start(), start())); +} + +TEST_F(Int64LoweringTest, Parameter2) { + if (4 != kPointerSize) return; + + Signature<MachineRepresentation>::Builder sig_builder(zone(), 1, 5); + sig_builder.AddReturn(MachineRepresentation::kWord32); + + sig_builder.AddParam(MachineRepresentation::kWord32); + sig_builder.AddParam(MachineRepresentation::kWord64); + sig_builder.AddParam(MachineRepresentation::kFloat64); + sig_builder.AddParam(MachineRepresentation::kWord64); + sig_builder.AddParam(MachineRepresentation::kWord32); + + int start_parameter = start()->op()->ValueOutputCount(); + LowerGraph(Parameter(4), sig_builder.Build()); + + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn(IsParameter(6), start(), start())); + // The parameter of the start node should increase by 2, because we lowered + // two parameter nodes. + EXPECT_THAT(start()->op()->ValueOutputCount(), start_parameter + 2); +} + +TEST_F(Int64LoweringTest, CallI64Return) { + if (4 != kPointerSize) return; + + int32_t function = 0x9999; + + Signature<MachineRepresentation>::Builder sig_builder(zone(), 1, 0); + sig_builder.AddReturn(MachineRepresentation::kWord64); + + compiler::CallDescriptor* desc = + wasm::ModuleEnv::GetWasmCallDescriptor(zone(), sig_builder.Build()); + + LowerGraph(graph()->NewNode(common()->Call(desc), Int32Constant(function), + start(), start()), + MachineRepresentation::kWord64); + + Capture<Node*> call; + Matcher<Node*> call_matcher = + IsCall(testing::_, IsInt32Constant(function), start(), start()); + + EXPECT_THAT(graph()->end()->InputAt(1), + IsReturn2(IsProjection(0, AllOf(CaptureEq(&call), call_matcher)), + IsProjection(1, AllOf(CaptureEq(&call), call_matcher)), + start(), start())); + + CompareCallDescriptors( + OpParameter<const CallDescriptor*>( + graph()->end()->InputAt(1)->InputAt(0)->InputAt(0)), + wasm::ModuleEnv::GetI32WasmCallDescriptor(zone(), desc)); +} + +TEST_F(Int64LoweringTest, CallI64Parameter) { + if (4 != kPointerSize) return; + + int32_t function = 0x9999; + + Signature<MachineRepresentation>::Builder sig_builder(zone(), 1, 3); + sig_builder.AddReturn(MachineRepresentation::kWord32); + sig_builder.AddParam(MachineRepresentation::kWord64); + sig_builder.AddParam(MachineRepresentation::kWord32); + sig_builder.AddParam(MachineRepresentation::kWord64); + + compiler::CallDescriptor* desc = + wasm::ModuleEnv::GetWasmCallDescriptor(zone(), sig_builder.Build()); + + LowerGraph(graph()->NewNode(common()->Call(desc), Int32Constant(function), + Int64Constant(value(0)), + Int32Constant(low_word_value(1)), + Int64Constant(value(2)), start(), start()), + MachineRepresentation::kWord32); + + EXPECT_THAT( + graph()->end()->InputAt(1), + IsReturn(IsCall(testing::_, IsInt32Constant(function), + IsInt32Constant(low_word_value(0)), + IsInt32Constant(high_word_value(0)), + IsInt32Constant(low_word_value(1)), + IsInt32Constant(low_word_value(2)), + IsInt32Constant(high_word_value(2)), start(), start()), + start(), start())); + + CompareCallDescriptors( + OpParameter<const CallDescriptor*>( + graph()->end()->InputAt(1)->InputAt(0)), + wasm::ModuleEnv::GetI32WasmCallDescriptor(zone(), desc)); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.h b/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.h deleted file mode 100644 index 15fa38b1be..0000000000 --- a/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.h +++ /dev/null @@ -1,57 +0,0 @@ -// 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. - -#ifndef V8_UNITTESTS_COMPILER_INTERPRETER_ASSEMBLER_UNITTEST_H_ -#define V8_UNITTESTS_COMPILER_INTERPRETER_ASSEMBLER_UNITTEST_H_ - -#include "src/compiler/interpreter-assembler.h" -#include "src/compiler/linkage.h" -#include "src/compiler/machine-operator.h" -#include "test/unittests/test-utils.h" -#include "testing/gmock-support.h" - -namespace v8 { -namespace internal { -namespace compiler { - -using ::testing::Matcher; - -class InterpreterAssemblerTest : public TestWithIsolateAndZone { - public: - InterpreterAssemblerTest() {} - ~InterpreterAssemblerTest() override {} - - class InterpreterAssemblerForTest final : public InterpreterAssembler { - public: - InterpreterAssemblerForTest(InterpreterAssemblerTest* test, - interpreter::Bytecode bytecode) - : InterpreterAssembler(test->isolate(), test->zone(), bytecode) {} - ~InterpreterAssemblerForTest() override {} - - Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher, - const Matcher<Node*>& base_matcher, - const Matcher<Node*>& index_matcher); - Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher, - const Matcher<Node*>& base_matcher, - const Matcher<Node*>& index_matcher, - const Matcher<Node*>& value_matcher); - - Matcher<Node*> IsBytecodeOperand(int offset); - Matcher<Node*> IsBytecodeOperandSignExtended(int offset); - Matcher<Node*> IsBytecodeOperandShort(int offset); - Matcher<Node*> IsBytecodeOperandShortSignExtended(int offset); - - using InterpreterAssembler::call_descriptor; - using InterpreterAssembler::graph; - - private: - DISALLOW_COPY_AND_ASSIGN(InterpreterAssemblerForTest); - }; -}; - -} // namespace compiler -} // namespace internal -} // namespace v8 - -#endif // V8_UNITTESTS_COMPILER_INTERPRETER_ASSEMBLER_UNITTEST_H_ 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 78e9253a17..9e14cda7fb 100644 --- a/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-builtin-reducer-unittest.cc @@ -64,10 +64,6 @@ Type* const kIntegral32Types[] = {Type::UnsignedSmall(), Type::Negative32(), Type::Integral32()}; -const LanguageMode kLanguageModes[] = {SLOPPY, STRICT, STRONG}; - - -// TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering. Type* const kNumberTypes[] = { Type::UnsignedSmall(), Type::Negative32(), Type::Unsigned31(), Type::SignedSmall(), Type::Signed32(), Type::Unsigned32(), @@ -88,15 +84,13 @@ TEST_F(JSBuiltinReducerTest, MathMax0) { Node* control = graph()->start(); Node* context = UndefinedConstant(); Node* frame_state = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Node* call = graph()->NewNode(javascript()->CallFunction(2, language_mode), - function, UndefinedConstant(), context, - frame_state, frame_state, effect, control); - Reduction r = Reduce(call); + Node* call = graph()->NewNode(javascript()->CallFunction(2), function, + UndefinedConstant(), context, frame_state, + frame_state, effect, control); + Reduction r = Reduce(call); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY)); - } + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY)); } @@ -107,18 +101,15 @@ TEST_F(JSBuiltinReducerTest, MathMax1) { Node* control = graph()->start(); Node* context = UndefinedConstant(); Node* frame_state = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - TRACED_FOREACH(Type*, t0, kNumberTypes) { - Node* p0 = Parameter(t0, 0); - Node* call = - graph()->NewNode(javascript()->CallFunction(3, language_mode), - function, UndefinedConstant(), p0, context, - frame_state, frame_state, effect, control); - Reduction r = Reduce(call); + TRACED_FOREACH(Type*, t0, kNumberTypes) { + Node* p0 = Parameter(t0, 0); + Node* call = graph()->NewNode(javascript()->CallFunction(3), function, + UndefinedConstant(), p0, context, frame_state, + frame_state, effect, control); + Reduction r = Reduce(call); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), p0); - } + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), p0); } } @@ -130,22 +121,18 @@ TEST_F(JSBuiltinReducerTest, MathMax2) { Node* control = graph()->start(); Node* context = UndefinedConstant(); Node* frame_state = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - TRACED_FOREACH(Type*, t0, kIntegral32Types) { - TRACED_FOREACH(Type*, t1, kIntegral32Types) { - Node* p0 = Parameter(t0, 0); - Node* p1 = Parameter(t1, 1); - Node* call = - graph()->NewNode(javascript()->CallFunction(4, language_mode), - function, UndefinedConstant(), p0, p1, context, - frame_state, frame_state, effect, control); - Reduction r = Reduce(call); - - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsSelect(MachineRepresentation::kNone, - IsNumberLessThan(p1, p0), p0, p1)); - } + TRACED_FOREACH(Type*, t0, kIntegral32Types) { + TRACED_FOREACH(Type*, t1, kIntegral32Types) { + Node* p0 = Parameter(t0, 0); + Node* p1 = Parameter(t1, 1); + Node* call = graph()->NewNode(javascript()->CallFunction(4), function, + UndefinedConstant(), p0, p1, context, + frame_state, frame_state, effect, control); + Reduction r = Reduce(call); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsSelect(MachineRepresentation::kNone, + IsNumberLessThan(p1, p0), p0, p1)); } } } @@ -162,20 +149,17 @@ TEST_F(JSBuiltinReducerTest, MathImul) { Node* control = graph()->start(); Node* context = UndefinedConstant(); Node* frame_state = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - TRACED_FOREACH(Type*, t0, kIntegral32Types) { - TRACED_FOREACH(Type*, t1, kIntegral32Types) { - Node* p0 = Parameter(t0, 0); - Node* p1 = Parameter(t1, 1); - Node* call = - graph()->NewNode(javascript()->CallFunction(4, language_mode), - function, UndefinedConstant(), p0, p1, context, - frame_state, frame_state, effect, control); - Reduction r = Reduce(call); - - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1)); - } + TRACED_FOREACH(Type*, t0, kIntegral32Types) { + TRACED_FOREACH(Type*, t1, kIntegral32Types) { + Node* p0 = Parameter(t0, 0); + Node* p1 = Parameter(t1, 1); + Node* call = graph()->NewNode(javascript()->CallFunction(4), function, + UndefinedConstant(), p0, p1, context, + frame_state, frame_state, effect, control); + Reduction r = Reduce(call); + + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1)); } } } @@ -192,18 +176,15 @@ TEST_F(JSBuiltinReducerTest, MathFround) { Node* control = graph()->start(); Node* context = UndefinedConstant(); Node* frame_state = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - TRACED_FOREACH(Type*, t0, kNumberTypes) { - Node* p0 = Parameter(t0, 0); - Node* call = - graph()->NewNode(javascript()->CallFunction(3, language_mode), - function, UndefinedConstant(), p0, context, - frame_state, frame_state, effect, control); - Reduction r = Reduce(call); + TRACED_FOREACH(Type*, t0, kNumberTypes) { + Node* p0 = Parameter(t0, 0); + Node* call = graph()->NewNode(javascript()->CallFunction(3), function, + UndefinedConstant(), p0, context, frame_state, + frame_state, effect, control); + Reduction r = Reduce(call); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsTruncateFloat64ToFloat32(p0)); - } + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsTruncateFloat64ToFloat32(p0)); } } diff --git a/deps/v8/test/unittests/compiler/js-context-relaxation-unittest.cc b/deps/v8/test/unittests/compiler/js-context-relaxation-unittest.cc deleted file mode 100644 index a44bd0278d..0000000000 --- a/deps/v8/test/unittests/compiler/js-context-relaxation-unittest.cc +++ /dev/null @@ -1,285 +0,0 @@ -// 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/compiler/js-context-relaxation.h" -#include "src/compiler/js-graph.h" -#include "test/unittests/compiler/graph-unittest.h" -#include "test/unittests/compiler/node-test-utils.h" - -namespace v8 { -namespace internal { -namespace compiler { - -class JSContextRelaxationTest : public GraphTest { - public: - JSContextRelaxationTest() : GraphTest(3), javascript_(zone()) {} - ~JSContextRelaxationTest() override {} - - protected: - Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags = - MachineOperatorBuilder::kNoFlags) { - MachineOperatorBuilder machine(zone(), MachineType::PointerRepresentation(), - flags); - JSGraph jsgraph(isolate(), graph(), common(), javascript(), nullptr, - &machine); - // TODO(titzer): mock the GraphReducer here for better unit testing. - GraphReducer graph_reducer(zone(), graph()); - JSContextRelaxation reducer; - return reducer.Reduce(node); - } - - Node* EmptyFrameState() { - MachineOperatorBuilder machine(zone()); - JSGraph jsgraph(isolate(), graph(), common(), javascript(), nullptr, - &machine); - return jsgraph.EmptyFrameState(); - } - - Node* ShallowFrameStateChain(Node* outer_context, - ContextCallingMode context_calling_mode) { - const FrameStateFunctionInfo* const frame_state_function_info = - common()->CreateFrameStateFunctionInfo( - FrameStateType::kJavaScriptFunction, 3, 0, - Handle<SharedFunctionInfo>(), context_calling_mode); - const Operator* op = common()->FrameState(BailoutId::None(), - OutputFrameStateCombine::Ignore(), - frame_state_function_info); - return graph()->NewNode(op, graph()->start(), graph()->start(), - graph()->start(), outer_context, graph()->start(), - graph()->start()); - } - - Node* DeepFrameStateChain(Node* outer_context, - ContextCallingMode context_calling_mode) { - const FrameStateFunctionInfo* const frame_state_function_info = - common()->CreateFrameStateFunctionInfo( - FrameStateType::kJavaScriptFunction, 3, 0, - Handle<SharedFunctionInfo>(), context_calling_mode); - const Operator* op = common()->FrameState(BailoutId::None(), - OutputFrameStateCombine::Ignore(), - frame_state_function_info); - Node* shallow_frame_state = - ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT); - return graph()->NewNode(op, graph()->start(), graph()->start(), - graph()->start(), graph()->start(), - graph()->start(), shallow_frame_state); - } - - JSOperatorBuilder* javascript() { return &javascript_; } - - private: - JSOperatorBuilder javascript_; -}; - - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionShallowFrameStateChainNoCrossCtx) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - Node* const frame_state = - ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state, frame_state, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node)); -} - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionShallowFrameStateChainCrossCtx) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - Node* const frame_state = - ShallowFrameStateChain(outer_context, CALL_CHANGES_NATIVE_CONTEXT); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state, frame_state, effect, control); - Reduction const r = Reduce(node); - EXPECT_FALSE(r.Changed()); - EXPECT_EQ(context, NodeProperties::GetContextInput(node)); -} - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepFrameStateChainNoCrossCtx) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - Node* const frame_state = - DeepFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state, frame_state, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node)); -} - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepFrameStateChainCrossCtx) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - Node* const frame_state = - DeepFrameStateChain(outer_context, CALL_CHANGES_NATIVE_CONTEXT); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state, frame_state, effect, control); - Reduction const r = Reduce(node); - EXPECT_FALSE(r.Changed()); - EXPECT_EQ(context, NodeProperties::GetContextInput(node)); -} - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepContextChainFullRelaxForCatch) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - const Operator* op = javascript()->CreateCatchContext(Handle<String>()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* nested_context = graph()->NewNode( - op, graph()->start(), graph()->start(), outer_context, effect, control); - Node* const frame_state_2 = - ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state_2, frame_state_2, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node)); -} - - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepContextChainFullRelaxForWith) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - const Operator* op = javascript()->CreateWithContext(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* nested_context = graph()->NewNode( - op, graph()->start(), graph()->start(), outer_context, effect, control); - Node* const frame_state_2 = - ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state_2, frame_state_2, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node)); -} - - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepContextChainFullRelaxForBlock) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::null(); - const Operator* op = javascript()->CreateBlockContext(scope_info); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* nested_context = - graph()->NewNode(op, graph()->start(), outer_context, effect, control); - Node* const frame_state_2 = - ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state_2, frame_state_2, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node)); -} - - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepContextChainPartialRelaxForScript) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::null(); - const Operator* op = javascript()->CreateScriptContext(scope_info); - Node* const frame_state_1 = - ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* nested_context = graph()->NewNode(op, graph()->start(), outer_context, - frame_state_1, effect, control); - Node* const frame_state_2 = - ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state_2, frame_state_2, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(nested_context, NodeProperties::GetContextInput(node)); -} - - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepContextChainPartialRelaxForModule) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - const Operator* op = javascript()->CreateModuleContext(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* nested_context = graph()->NewNode( - op, graph()->start(), graph()->start(), outer_context, effect, control); - Node* const frame_state_2 = - ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state_2, frame_state_2, effect, control); - Reduction const r = Reduce(node); - EXPECT_TRUE(r.Changed()); - EXPECT_EQ(nested_context, NodeProperties::GetContextInput(node)); -} - - -TEST_F(JSContextRelaxationTest, - RelaxJSCallFunctionDeepContextChainPartialNoRelax) { - Node* const input0 = Parameter(0); - Node* const input1 = Parameter(1); - Node* const context = Parameter(2); - Node* const outer_context = Parameter(3); - const Operator* op = javascript()->CreateFunctionContext(0); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Node* nested_context = - graph()->NewNode(op, graph()->start(), outer_context, effect, control); - Node* const frame_state_2 = - ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT); - Node* node = graph()->NewNode( - javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1, - context, frame_state_2, frame_state_2, effect, control); - Reduction const r = Reduce(node); - EXPECT_FALSE(r.Changed()); - EXPECT_EQ(context, NodeProperties::GetContextInput(node)); -} - -} // namespace compiler -} // namespace internal -} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc b/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc new file mode 100644 index 0000000000..837c5742d9 --- /dev/null +++ b/deps/v8/test/unittests/compiler/js-create-lowering-unittest.cc @@ -0,0 +1,236 @@ +// Copyright 2016 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-create-lowering.h" +#include "src/code-factory.h" +#include "src/compiler/access-builder.h" +#include "src/compiler/js-graph.h" +#include "src/compiler/js-operator.h" +#include "src/compiler/machine-operator.h" +#include "src/compiler/node-properties.h" +#include "src/compiler/operator-properties.h" +#include "src/isolate-inl.h" +#include "test/unittests/compiler/compiler-test-utils.h" +#include "test/unittests/compiler/graph-unittest.h" +#include "test/unittests/compiler/node-test-utils.h" +#include "testing/gmock-support.h" + +using testing::_; +using testing::BitEq; +using testing::IsNaN; + +namespace v8 { +namespace internal { +namespace compiler { + +class JSCreateLoweringTest : public TypedGraphTest { + public: + JSCreateLoweringTest() + : TypedGraphTest(3), javascript_(zone()), deps_(isolate(), zone()) {} + ~JSCreateLoweringTest() override {} + + protected: + Reduction Reduce(Node* node) { + MachineOperatorBuilder machine(zone()); + SimplifiedOperatorBuilder simplified(zone()); + JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified, + &machine); + // TODO(titzer): mock the GraphReducer here for better unit testing. + GraphReducer graph_reducer(zone(), graph()); + JSCreateLowering reducer(&graph_reducer, &deps_, &jsgraph, + MaybeHandle<LiteralsArray>(), zone()); + return reducer.Reduce(node); + } + + Node* FrameState(Handle<SharedFunctionInfo> shared, Node* outer_frame_state) { + Node* state_values = graph()->NewNode(common()->StateValues(0)); + return graph()->NewNode( + common()->FrameState( + BailoutId::None(), OutputFrameStateCombine::Ignore(), + common()->CreateFrameStateFunctionInfo( + FrameStateType::kJavaScriptFunction, 1, 0, shared)), + state_values, state_values, state_values, NumberConstant(0), + UndefinedConstant(), outer_frame_state); + } + + JSOperatorBuilder* javascript() { return &javascript_; } + + private: + JSOperatorBuilder javascript_; + CompilationDependencies deps_; +}; + +TEST_F(JSCreateLoweringTest, JSCreate) { + Handle<JSFunction> function = isolate()->object_function(); + Node* const target = Parameter(Type::Constant(function, graph()->zone())); + Node* const context = Parameter(Type::Any()); + Node* const effect = graph()->start(); + Reduction r = Reduce(graph()->NewNode(javascript()->Create(), target, target, + context, EmptyFrameState(), effect)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsFinishRegion( + IsAllocate(IsNumberConstant(function->initial_map()->instance_size()), + IsBeginRegion(effect), _), + _)); +} + +// ----------------------------------------------------------------------------- +// JSCreateArguments + +TEST_F(JSCreateLoweringTest, JSCreateArgumentsViaStub) { + Node* const closure = Parameter(Type::Any()); + Node* const context = UndefinedConstant(); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); + Node* const frame_state = FrameState(shared, graph()->start()); + Reduction r = Reduce(graph()->NewNode( + javascript()->CreateArguments(CreateArgumentsType::kUnmappedArguments), + closure, context, frame_state, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsCall(_, IsHeapConstant( + CodeFactory::FastNewStrictArguments(isolate()).code()), + closure, context, frame_state, effect, control)); +} + +TEST_F(JSCreateLoweringTest, JSCreateArgumentsRestParameterViaStub) { + Node* const closure = Parameter(Type::Any()); + Node* const context = UndefinedConstant(); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); + Node* const frame_state = FrameState(shared, graph()->start()); + Reduction r = Reduce(graph()->NewNode( + javascript()->CreateArguments(CreateArgumentsType::kRestParameter), + closure, context, frame_state, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsCall(_, IsHeapConstant( + CodeFactory::FastNewRestParameter(isolate()).code()), + closure, context, frame_state, effect, control)); +} + +TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedMapped) { + Node* const closure = Parameter(Type::Any()); + Node* const context = UndefinedConstant(); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); + Node* const frame_state_outer = FrameState(shared, graph()->start()); + Node* const frame_state_inner = FrameState(shared, frame_state_outer); + Reduction r = Reduce(graph()->NewNode( + javascript()->CreateArguments(CreateArgumentsType::kMappedArguments), + closure, context, frame_state_inner, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFinishRegion( + IsAllocate(IsNumberConstant(JSSloppyArgumentsObject::kSize), + _, control), + _)); +} + +TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedUnmapped) { + Node* const closure = Parameter(Type::Any()); + Node* const context = UndefinedConstant(); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); + Node* const frame_state_outer = FrameState(shared, graph()->start()); + Node* const frame_state_inner = FrameState(shared, frame_state_outer); + Reduction r = Reduce(graph()->NewNode( + javascript()->CreateArguments(CreateArgumentsType::kUnmappedArguments), + closure, context, frame_state_inner, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFinishRegion( + IsAllocate(IsNumberConstant(JSStrictArgumentsObject::kSize), + _, control), + _)); +} + +TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedRestArray) { + Node* const closure = Parameter(Type::Any()); + Node* const context = UndefinedConstant(); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); + Node* const frame_state_outer = FrameState(shared, graph()->start()); + Node* const frame_state_inner = FrameState(shared, frame_state_outer); + Reduction r = Reduce(graph()->NewNode( + javascript()->CreateArguments(CreateArgumentsType::kRestParameter), + closure, context, frame_state_inner, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFinishRegion( + IsAllocate(IsNumberConstant(JSArray::kSize), _, control), _)); +} + +// ----------------------------------------------------------------------------- +// JSCreateFunctionContext + +TEST_F(JSCreateLoweringTest, JSCreateFunctionContextViaInlinedAllocation) { + Node* const closure = Parameter(Type::Any()); + Node* const context = Parameter(Type::Any()); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction const r = + Reduce(graph()->NewNode(javascript()->CreateFunctionContext(8), closure, + context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( + 8 + Context::MIN_CONTEXT_SLOTS)), + IsBeginRegion(_), control), + _)); +} + +// ----------------------------------------------------------------------------- +// JSCreateWithContext + +TEST_F(JSCreateLoweringTest, JSCreateWithContext) { + Node* const object = Parameter(Type::Receiver()); + Node* const closure = Parameter(Type::Function()); + Node* const context = Parameter(Type::Any()); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction r = + Reduce(graph()->NewNode(javascript()->CreateWithContext(), object, + closure, context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( + Context::MIN_CONTEXT_SLOTS)), + IsBeginRegion(_), control), + _)); +} + +// ----------------------------------------------------------------------------- +// JSCreateCatchContext + +TEST_F(JSCreateLoweringTest, JSCreateCatchContext) { + Handle<String> name = factory()->length_string(); + Node* const exception = Parameter(Type::Receiver()); + Node* const closure = Parameter(Type::Function()); + Node* const context = Parameter(Type::Any()); + Node* const effect = graph()->start(); + Node* const control = graph()->start(); + Reduction r = + Reduce(graph()->NewNode(javascript()->CreateCatchContext(name), exception, + closure, context, effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( + Context::MIN_CONTEXT_SLOTS + 1)), + IsBeginRegion(_), control), + _)); +} + +} // 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 f38f8eaac7..919c1b2237 100644 --- a/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-intrinsic-lowering-unittest.cc @@ -7,7 +7,6 @@ #include "src/compiler/js-graph.h" #include "src/compiler/js-intrinsic-lowering.h" #include "src/compiler/js-operator.h" -#include "src/types-inl.h" #include "test/unittests/compiler/graph-unittest.h" #include "test/unittests/compiler/node-test-utils.h" #include "testing/gmock-support.h" @@ -24,9 +23,9 @@ namespace v8 { namespace internal { namespace compiler { -class JSIntrinsicLoweringTest : public TypedGraphTest { +class JSIntrinsicLoweringTest : public GraphTest { public: - JSIntrinsicLoweringTest() : TypedGraphTest(3), javascript_(zone()) {} + JSIntrinsicLoweringTest() : GraphTest(3), javascript_(zone()) {} ~JSIntrinsicLoweringTest() override {} protected: @@ -162,37 +161,6 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsArray) { // ----------------------------------------------------------------------------- -// %_IsDate - - -TEST_F(JSIntrinsicLoweringTest, InlineIsDate) { - 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::kInlineIsDate, 1), - input, context, effect, control)); - ASSERT_TRUE(r.Changed()); - - Node* phi = r.replacement(); - Capture<Node*> branch, if_false; - EXPECT_THAT( - phi, - IsPhi( - MachineRepresentation::kTagged, IsFalseConstant(), - IsWord32Equal(IsLoadField(AccessBuilder::ForMapInstanceType(), - IsLoadField(AccessBuilder::ForMap(), input, - effect, CaptureEq(&if_false)), - effect, _), - IsInt32Constant(JS_DATE_TYPE)), - IsMerge(IsIfTrue(AllOf(CaptureEq(&branch), - IsBranch(IsObjectIsSmi(input), control))), - AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); -} - - -// ----------------------------------------------------------------------------- // %_IsTypedArray @@ -224,38 +192,6 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsTypedArray) { // ----------------------------------------------------------------------------- -// %_IsFunction - - -TEST_F(JSIntrinsicLoweringTest, InlineIsFunction) { - Node* const input = Parameter(Type::Any()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce( - graph()->NewNode(javascript()->CallRuntime(Runtime::kInlineIsFunction, 1), - input, context, effect, control)); - ASSERT_TRUE(r.Changed()); - - Node* phi = r.replacement(); - Capture<Node*> branch, if_false; - EXPECT_THAT( - phi, - IsPhi( - MachineRepresentation::kTagged, IsFalseConstant(), - IsUint32LessThanOrEqual( - IsInt32Constant(FIRST_FUNCTION_TYPE), - IsLoadField(AccessBuilder::ForMapInstanceType(), - IsLoadField(AccessBuilder::ForMap(), input, effect, - CaptureEq(&if_false)), - effect, _)), - IsMerge(IsIfTrue(AllOf(CaptureEq(&branch), - IsBranch(IsObjectIsSmi(input), control))), - AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); -} - - -// ----------------------------------------------------------------------------- // %_IsRegExp @@ -290,75 +226,16 @@ TEST_F(JSIntrinsicLoweringTest, InlineIsRegExp) { // %_IsJSReceiver -TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithAny) { - Node* const input = Parameter(Type::Any()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce(graph()->NewNode( - javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input, - context, effect, control)); - ASSERT_TRUE(r.Changed()); - - Node* phi = r.replacement(); - Capture<Node *> branch, if_false; - EXPECT_THAT( - phi, - IsPhi( - MachineRepresentation::kTagged, IsFalseConstant(), - IsUint32LessThanOrEqual( - IsInt32Constant(FIRST_JS_RECEIVER_TYPE), - IsLoadField(AccessBuilder::ForMapInstanceType(), - IsLoadField(AccessBuilder::ForMap(), input, effect, - CaptureEq(&if_false)), - effect, _)), - IsMerge(IsIfTrue(AllOf(CaptureEq(&branch), - IsBranch(IsObjectIsSmi(input), control))), - AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch)))))); -} - - -TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithReceiver) { - Node* const input = Parameter(Type::Receiver()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce(graph()->NewNode( - javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input, - context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsTrueConstant()); -} - - -TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiverWithUndefined) { - Node* const input = Parameter(Type::Undefined()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce(graph()->NewNode( - javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input, - context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsFalseConstant()); -} - - -// ----------------------------------------------------------------------------- -// %_JSValueGetValue - - -TEST_F(JSIntrinsicLoweringTest, InlineJSValueGetValue) { +TEST_F(JSIntrinsicLoweringTest, InlineIsJSReceiver) { 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, + javascript()->CallRuntime(Runtime::kInlineIsJSReceiver, 1), input, context, effect, control)); ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsLoadField(AccessBuilder::ForValue(), input, effect, control)); + EXPECT_THAT(r.replacement(), IsObjectIsReceiver(input)); } diff --git a/deps/v8/test/unittests/compiler/js-operator-unittest.cc b/deps/v8/test/unittests/compiler/js-operator-unittest.cc index e0db771458..15b1427871 100644 --- a/deps/v8/test/unittests/compiler/js-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-operator-unittest.cc @@ -12,34 +12,8 @@ namespace v8 { namespace internal { namespace compiler { -namespace { - -const LanguageMode kLanguageModes[] = {SLOPPY, STRICT, STRONG}; - - -#if GTEST_HAS_COMBINE - -template <typename T> -class JSOperatorTestWithLanguageModeAndParam - : public TestWithZone, - public ::testing::WithParamInterface<::testing::tuple<LanguageMode, T>> { - protected: - LanguageMode language_mode() const { - return ::testing::get<0>(B::GetParam()); - } - const T& GetParam() const { return ::testing::get<1>(B::GetParam()); } - - private: - typedef ::testing::WithParamInterface<::testing::tuple<LanguageMode, T>> B; -}; - -#endif // GTEST_HAS_COMBINE - -} // namespace - - // ----------------------------------------------------------------------------- -// Shared operators without language mode. +// Shared operators. namespace { @@ -56,7 +30,6 @@ struct SharedOperator { int control_output_count; }; - const SharedOperator kSharedOperators[] = { #define SHARED(Name, properties, value_input_count, frame_state_input_count, \ effect_input_count, control_input_count, value_output_count, \ @@ -71,6 +44,10 @@ const SharedOperator kSharedOperators[] = { SHARED(NotEqual, Operator::kNoProperties, 2, 1, 1, 1, 1, 1, 2), SHARED(StrictEqual, Operator::kNoThrow, 2, 0, 1, 1, 1, 1, 0), SHARED(StrictNotEqual, Operator::kNoThrow, 2, 0, 1, 1, 1, 1, 0), + SHARED(LessThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(GreaterThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), + SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), SHARED(ToNumber, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), SHARED(ToString, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), SHARED(ToName, Operator::kNoProperties, 1, 1, 1, 1, 1, 1, 2), @@ -148,123 +125,6 @@ TEST_P(JSSharedOperatorTest, Properties) { INSTANTIATE_TEST_CASE_P(JSOperatorTest, JSSharedOperatorTest, ::testing::ValuesIn(kSharedOperators)); - -// ----------------------------------------------------------------------------- -// Shared operators with language mode. - - -#if GTEST_HAS_COMBINE - -namespace { - -struct SharedOperatorWithLanguageMode { - const Operator* (JSOperatorBuilder::*constructor)(LanguageMode); - IrOpcode::Value opcode; - Operator::Properties properties; - int value_input_count; - int frame_state_input_count; - int effect_input_count; - int control_input_count; - int value_output_count; - int effect_output_count; - int control_output_count; -}; - - -const SharedOperatorWithLanguageMode kSharedOperatorsWithLanguageMode[] = { -#define SHARED(Name, properties, value_input_count, frame_state_input_count, \ - effect_input_count, control_input_count, value_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_output_count \ - } - SHARED(LessThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), - SHARED(GreaterThan, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), - SHARED(LessThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), - SHARED(GreaterThanOrEqual, Operator::kNoProperties, 2, 2, 1, 1, 1, 1, 2), -#undef SHARED -}; - - -std::ostream& operator<<(std::ostream& os, - const SharedOperatorWithLanguageMode& sop) { - return os << IrOpcode::Mnemonic(sop.opcode); -} - -} // namespace - - -class JSSharedOperatorWithLanguageModeTest - : public JSOperatorTestWithLanguageModeAndParam< - SharedOperatorWithLanguageMode> {}; - - -TEST_P(JSSharedOperatorWithLanguageModeTest, InstancesAreGloballyShared) { - const SharedOperatorWithLanguageMode& sop = GetParam(); - JSOperatorBuilder javascript1(zone()); - JSOperatorBuilder javascript2(zone()); - EXPECT_EQ((javascript1.*sop.constructor)(language_mode()), - (javascript2.*sop.constructor)(language_mode())); -} - - -TEST_P(JSSharedOperatorWithLanguageModeTest, NumberOfInputsAndOutputs) { - JSOperatorBuilder javascript(zone()); - const SharedOperatorWithLanguageMode& sop = GetParam(); - const Operator* op = (javascript.*sop.constructor)(language_mode()); - - const int context_input_count = 1; - EXPECT_EQ(sop.value_input_count, op->ValueInputCount()); - EXPECT_EQ(context_input_count, OperatorProperties::GetContextInputCount(op)); - EXPECT_EQ(sop.frame_state_input_count, - OperatorProperties::GetFrameStateInputCount(op)); - EXPECT_EQ(sop.effect_input_count, op->EffectInputCount()); - EXPECT_EQ(sop.control_input_count, op->ControlInputCount()); - EXPECT_EQ(sop.value_input_count + context_input_count + - sop.frame_state_input_count + sop.effect_input_count + - sop.control_input_count, - OperatorProperties::GetTotalInputCount(op)); - - EXPECT_EQ(sop.value_output_count, op->ValueOutputCount()); - EXPECT_EQ(sop.effect_output_count, op->EffectOutputCount()); - EXPECT_EQ(sop.control_output_count, op->ControlOutputCount()); -} - - -TEST_P(JSSharedOperatorWithLanguageModeTest, OpcodeIsCorrect) { - JSOperatorBuilder javascript(zone()); - const SharedOperatorWithLanguageMode& sop = GetParam(); - const Operator* op = (javascript.*sop.constructor)(language_mode()); - EXPECT_EQ(sop.opcode, op->opcode()); -} - - -TEST_P(JSSharedOperatorWithLanguageModeTest, Parameter) { - JSOperatorBuilder javascript(zone()); - const SharedOperatorWithLanguageMode& sop = GetParam(); - const Operator* op = (javascript.*sop.constructor)(language_mode()); - EXPECT_EQ(language_mode(), OpParameter<LanguageMode>(op)); -} - - -TEST_P(JSSharedOperatorWithLanguageModeTest, Properties) { - JSOperatorBuilder javascript(zone()); - const SharedOperatorWithLanguageMode& sop = GetParam(); - const Operator* op = (javascript.*sop.constructor)(language_mode()); - EXPECT_EQ(sop.properties, op->properties()); -} - - -INSTANTIATE_TEST_CASE_P( - JSOperatorTest, JSSharedOperatorWithLanguageModeTest, - ::testing::Combine(::testing::ValuesIn(kLanguageModes), - ::testing::ValuesIn(kSharedOperatorsWithLanguageMode))); - -#endif // GTEST_HAS_COMBINE - } // namespace compiler } // namespace internal } // namespace v8 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 6fc89bb0ea..e37d4a2913 100644 --- a/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc +++ b/deps/v8/test/unittests/compiler/js-typed-lowering-unittest.cc @@ -92,18 +92,6 @@ class JSTypedLoweringTest : public TypedGraphTest { return reducer.Reduce(node); } - Node* FrameState(Handle<SharedFunctionInfo> shared, Node* outer_frame_state) { - Node* state_values = graph()->NewNode(common()->StateValues(0)); - return graph()->NewNode( - common()->FrameState(BailoutId::None(), - OutputFrameStateCombine::Ignore(), - common()->CreateFrameStateFunctionInfo( - FrameStateType::kJavaScriptFunction, 1, 0, - shared, CALL_MAINTAINS_NATIVE_CONTEXT)), - state_values, state_values, state_values, NumberConstant(0), - UndefinedConstant(), outer_frame_state); - } - Handle<JSArrayBuffer> NewArrayBuffer(void* bytes, size_t byte_length) { Handle<JSArrayBuffer> buffer = factory()->NewJSArrayBuffer(); JSArrayBuffer::Setup(buffer, isolate(), true, bytes, byte_length); @@ -435,15 +423,12 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) { Node* const effect = graph()->start(); Node* const control = graph()->start(); TRACED_FORRANGE(double, rhs, 0, 31) { - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce( - graph()->NewNode(javascript()->ShiftLeft(language_mode, hints), lhs, - NumberConstant(rhs), context, EmptyFrameState(), - EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsNumberShiftLeft(lhs, IsNumberConstant(BitEq(rhs)))); - } + Reduction r = Reduce(graph()->NewNode( + javascript()->ShiftLeft(hints), lhs, NumberConstant(rhs), context, + EmptyFrameState(), EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsNumberShiftLeft(lhs, IsNumberConstant(BitEq(rhs)))); } } @@ -455,13 +440,11 @@ TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) { Node* const context = UndefinedConstant(); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce(graph()->NewNode( - javascript()->ShiftLeft(language_mode, hints), lhs, rhs, context, - EmptyFrameState(), EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberShiftLeft(lhs, rhs)); - } + Reduction r = Reduce(graph()->NewNode(javascript()->ShiftLeft(hints), lhs, + rhs, context, EmptyFrameState(), + EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberShiftLeft(lhs, rhs)); } @@ -476,15 +459,12 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) { Node* const effect = graph()->start(); Node* const control = graph()->start(); TRACED_FORRANGE(double, rhs, 0, 31) { - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce( - graph()->NewNode(javascript()->ShiftRight(language_mode, hints), lhs, - NumberConstant(rhs), context, EmptyFrameState(), - EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsNumberShiftRight(lhs, IsNumberConstant(BitEq(rhs)))); - } + Reduction r = Reduce(graph()->NewNode( + javascript()->ShiftRight(hints), lhs, NumberConstant(rhs), context, + EmptyFrameState(), EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsNumberShiftRight(lhs, IsNumberConstant(BitEq(rhs)))); } } @@ -496,13 +476,11 @@ TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) { Node* const context = UndefinedConstant(); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce(graph()->NewNode( - javascript()->ShiftRight(language_mode, hints), lhs, rhs, context, - EmptyFrameState(), EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberShiftRight(lhs, rhs)); - } + Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRight(hints), lhs, + rhs, context, EmptyFrameState(), + EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberShiftRight(lhs, rhs)); } @@ -518,15 +496,12 @@ TEST_F(JSTypedLoweringTest, Node* const effect = graph()->start(); Node* const control = graph()->start(); TRACED_FORRANGE(double, rhs, 0, 31) { - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce(graph()->NewNode( - javascript()->ShiftRightLogical(language_mode, hints), lhs, - NumberConstant(rhs), context, EmptyFrameState(), EmptyFrameState(), - effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsNumberShiftRightLogical(lhs, IsNumberConstant(BitEq(rhs)))); - } + Reduction r = Reduce(graph()->NewNode( + javascript()->ShiftRightLogical(hints), lhs, NumberConstant(rhs), + context, EmptyFrameState(), EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), + IsNumberShiftRightLogical(lhs, IsNumberConstant(BitEq(rhs)))); } } @@ -538,13 +513,11 @@ TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndUnsigned32) { Node* const context = UndefinedConstant(); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction r = Reduce(graph()->NewNode( - javascript()->ShiftRightLogical(language_mode, hints), lhs, rhs, - context, EmptyFrameState(), EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsNumberShiftRightLogical(lhs, rhs)); - } + Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRightLogical(hints), + lhs, rhs, context, EmptyFrameState(), + EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsNumberShiftRightLogical(lhs, rhs)); } @@ -627,37 +600,34 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) { NewArrayBuffer(backing_store, sizeof(backing_store)); VectorSlotPair feedback; TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Handle<JSTypedArray> array = - factory()->NewJSTypedArray(type, buffer, 0, kLength); - int const element_size = static_cast<int>(array->element_size()); - - Node* key = Parameter( - Type::Range(kMinInt / element_size, kMaxInt / element_size, zone())); - Node* base = HeapConstant(array); - Node* vector = UndefinedConstant(); - Node* context = UndefinedConstant(); - Node* effect = graph()->start(); - Node* control = graph()->start(); - Reduction r = Reduce( - graph()->NewNode(javascript()->LoadProperty(language_mode, feedback), - base, key, vector, context, EmptyFrameState(), - EmptyFrameState(), effect, control)); + Handle<JSTypedArray> array = + factory()->NewJSTypedArray(type, buffer, 0, kLength); + int const element_size = static_cast<int>(array->element_size()); + + Node* key = Parameter( + Type::Range(kMinInt / element_size, kMaxInt / element_size, zone())); + Node* base = HeapConstant(array); + Node* vector = UndefinedConstant(); + Node* context = UndefinedConstant(); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Reduction r = Reduce(graph()->NewNode( + javascript()->LoadProperty(feedback), base, key, vector, context, + EmptyFrameState(), EmptyFrameState(), effect, control)); - Matcher<Node*> offset_matcher = - element_size == 1 - ? key - : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size))); + Matcher<Node*> offset_matcher = + element_size == 1 + ? key + : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size))); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsLoadBuffer(BufferAccess(type), - IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), - offset_matcher, - IsNumberConstant(array->byte_length()->Number()), effect, - control)); - } + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsLoadBuffer(BufferAccess(type), + IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), + offset_matcher, + IsNumberConstant(array->byte_length()->Number()), effect, + control)); } } @@ -669,32 +639,29 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) { NewArrayBuffer(backing_store, sizeof(backing_store)); VectorSlotPair feedback; TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Handle<JSTypedArray> array = - factory()->NewJSTypedArray(type, buffer, 0, kLength); - ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true); - - int min = random_number_generator()->NextInt(static_cast<int>(kLength)); - int max = random_number_generator()->NextInt(static_cast<int>(kLength)); - if (min > max) std::swap(min, max); - Node* key = Parameter(Type::Range(min, max, zone())); - Node* base = HeapConstant(array); - Node* vector = UndefinedConstant(); - Node* context = UndefinedConstant(); - Node* effect = graph()->start(); - Node* control = graph()->start(); - Reduction r = Reduce( - graph()->NewNode(javascript()->LoadProperty(language_mode, feedback), - base, key, vector, context, EmptyFrameState(), - EmptyFrameState(), effect, control)); + Handle<JSTypedArray> array = + factory()->NewJSTypedArray(type, buffer, 0, kLength); + ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true); + + int min = random_number_generator()->NextInt(static_cast<int>(kLength)); + int max = random_number_generator()->NextInt(static_cast<int>(kLength)); + if (min > max) std::swap(min, max); + Node* key = Parameter(Type::Range(min, max, zone())); + Node* base = HeapConstant(array); + Node* vector = UndefinedConstant(); + Node* context = UndefinedConstant(); + Node* effect = graph()->start(); + Node* control = graph()->start(); + Reduction r = Reduce(graph()->NewNode( + javascript()->LoadProperty(feedback), base, key, vector, context, + EmptyFrameState(), EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsLoadElement(access, - IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), - key, effect, control)); - } + ASSERT_TRUE(r.Changed()); + EXPECT_THAT( + r.replacement(), + IsLoadElement(access, + IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), + key, effect, control)); } } @@ -847,15 +814,12 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedStringLength) { Node* const context = UndefinedConstant(); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction const r = Reduce( - graph()->NewNode(javascript()->LoadNamed(language_mode, name, feedback), - receiver, vector, context, EmptyFrameState(), - EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsLoadField(AccessBuilder::ForStringLength(), - receiver, effect, control)); - } + Reduction const r = Reduce(graph()->NewNode( + javascript()->LoadNamed(name, feedback), receiver, vector, context, + EmptyFrameState(), EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsLoadField(AccessBuilder::ForStringLength(), + receiver, effect, control)); } @@ -869,14 +833,11 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedFunctionPrototype) { Node* const context = Parameter(Type::Internal(), 2); Node* const effect = graph()->start(); Node* const control = graph()->start(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { - Reduction const r = Reduce( - graph()->NewNode(javascript()->LoadNamed(language_mode, name, feedback), - receiver, vector, context, EmptyFrameState(), - EmptyFrameState(), effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), IsHeapConstant(function_prototype)); - } + Reduction const r = Reduce(graph()->NewNode( + javascript()->LoadNamed(name, feedback), receiver, vector, context, + EmptyFrameState(), EmptyFrameState(), effect, control)); + ASSERT_TRUE(r.Changed()); + EXPECT_THAT(r.replacement(), IsHeapConstant(function_prototype)); } @@ -886,7 +847,6 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedFunctionPrototype) { TEST_F(JSTypedLoweringTest, JSAddWithString) { BinaryOperationHints const hints = BinaryOperationHints::Any(); - TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { Node* lhs = Parameter(Type::String(), 0); Node* rhs = Parameter(Type::String(), 1); Node* context = Parameter(Type::Any(), 2); @@ -894,300 +854,15 @@ TEST_F(JSTypedLoweringTest, JSAddWithString) { Node* frame_state1 = EmptyFrameState(); Node* effect = graph()->start(); Node* control = graph()->start(); - Reduction r = Reduce( - graph()->NewNode(javascript()->Add(language_mode, hints), lhs, rhs, - context, frame_state0, frame_state1, effect, control)); + Reduction r = + Reduce(graph()->NewNode(javascript()->Add(hints), lhs, rhs, context, + frame_state0, frame_state1, effect, control)); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), IsCall(_, IsHeapConstant(CodeFactory::StringAdd( isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED).code()), lhs, rhs, context, frame_state0, effect, control)); - } -} - - -// ----------------------------------------------------------------------------- -// JSCreate - - -TEST_F(JSTypedLoweringTest, JSCreate) { - Handle<JSFunction> function = isolate()->object_function(); - Node* const target = Parameter(Type::Constant(function, graph()->zone())); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Reduction r = Reduce(graph()->NewNode(javascript()->Create(), target, target, - context, EmptyFrameState(), effect)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsFinishRegion( - IsAllocate(IsNumberConstant(function->initial_map()->instance_size()), - IsBeginRegion(effect), _), - _)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateArguments - - -TEST_F(JSTypedLoweringTest, JSCreateArgumentsViaStub) { - Node* const closure = Parameter(Type::Any()); - Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); - Node* const frame_state = FrameState(shared, graph()->start()); - Reduction r = Reduce( - graph()->NewNode(javascript()->CreateArguments( - CreateArgumentsParameters::kMappedArguments, 0), - closure, context, frame_state, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsCall(_, IsHeapConstant(CodeFactory::ArgumentsAccess( - isolate(), false, false) - .code()), - closure, IsNumberConstant(0), _, effect, control)); -} - - -TEST_F(JSTypedLoweringTest, JSCreateArgumentsRestArrayViaStub) { - Node* const closure = Parameter(Type::Any()); - Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); - Node* const frame_state = FrameState(shared, graph()->start()); - Reduction r = Reduce(graph()->NewNode( - javascript()->CreateArguments(CreateArgumentsParameters::kRestArray, 0), - closure, context, frame_state, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsCall(_, - IsHeapConstant(CodeFactory::RestArgumentsAccess(isolate()).code()), - IsNumberConstant(0), _, IsNumberConstant(0), _, effect, control)); -} - - -TEST_F(JSTypedLoweringTest, JSCreateArgumentsInlinedMapped) { - Node* const closure = Parameter(Type::Any()); - Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); - Node* const frame_state_outer = FrameState(shared, graph()->start()); - Node* const frame_state_inner = FrameState(shared, frame_state_outer); - Reduction r = Reduce( - graph()->NewNode(javascript()->CreateArguments( - CreateArgumentsParameters::kMappedArguments, 0), - closure, context, frame_state_inner, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsFinishRegion( - IsAllocate(IsNumberConstant(Heap::kSloppyArgumentsObjectSize), - _, control), - _)); -} - - -TEST_F(JSTypedLoweringTest, JSCreateArgumentsInlinedUnmapped) { - Node* const closure = Parameter(Type::Any()); - Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); - Node* const frame_state_outer = FrameState(shared, graph()->start()); - Node* const frame_state_inner = FrameState(shared, frame_state_outer); - Reduction r = Reduce( - graph()->NewNode(javascript()->CreateArguments( - CreateArgumentsParameters::kUnmappedArguments, 0), - closure, context, frame_state_inner, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsFinishRegion( - IsAllocate(IsNumberConstant(Heap::kStrictArgumentsObjectSize), - _, control), - _)); -} - - -TEST_F(JSTypedLoweringTest, JSCreateArgumentsInlinedRestArray) { - Node* const closure = Parameter(Type::Any()); - Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); - Node* const frame_state_outer = FrameState(shared, graph()->start()); - Node* const frame_state_inner = FrameState(shared, frame_state_outer); - Reduction r = Reduce(graph()->NewNode( - javascript()->CreateArguments(CreateArgumentsParameters::kRestArray, 0), - closure, context, frame_state_inner, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsFinishRegion( - IsAllocate(IsNumberConstant(JSArray::kSize), _, control), _)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateClosure - - -TEST_F(JSTypedLoweringTest, JSCreateClosure) { - Node* const context = UndefinedConstant(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); - Reduction r = - Reduce(graph()->NewNode(javascript()->CreateClosure(shared, NOT_TENURED), - context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsCall(_, IsHeapConstant(CodeFactory::FastNewClosure( - isolate(), shared->language_mode(), - shared->kind()).code()), - IsHeapConstant(shared), effect, control)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateLiteralArray - - -TEST_F(JSTypedLoweringTest, JSCreateLiteralArray) { - Handle<FixedArray> const constant_elements = factory()->NewFixedArray(12); - int const literal_flags = ArrayLiteral::kShallowElements; - int const literal_index = 1; - Node* const closure = Parameter(0); - Node* const context = Parameter(1); - Node* const frame_state = EmptyFrameState(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce( - graph()->NewNode(javascript()->CreateLiteralArray( - constant_elements, literal_flags, literal_index), - closure, context, frame_state, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsCall(_, IsHeapConstant( - CodeFactory::FastCloneShallowArray(isolate()).code()), - closure, IsNumberConstant(literal_index), - IsHeapConstant(constant_elements), context, frame_state, effect, - control)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateLiteralObject - - -TEST_F(JSTypedLoweringTest, JSCreateLiteralObject) { - Handle<FixedArray> const constant_properties = - factory()->NewFixedArray(6 * 2); - int const literal_flags = ObjectLiteral::kShallowProperties; - int const literal_index = 1; - Node* const closure = Parameter(0); - Node* const context = Parameter(1); - Node* const frame_state = EmptyFrameState(); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = Reduce( - graph()->NewNode(javascript()->CreateLiteralObject( - constant_properties, literal_flags, literal_index), - closure, context, frame_state, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT( - r.replacement(), - IsCall(_, IsHeapConstant( - CodeFactory::FastCloneShallowObject(isolate(), 6).code()), - closure, IsNumberConstant(literal_index), - IsHeapConstant(constant_properties), _, context, frame_state, - effect, control)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateFunctionContext - - -TEST_F(JSTypedLoweringTest, JSCreateFunctionContextViaInlinedAllocation) { - Node* const closure = Parameter(Type::Any()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = - Reduce(graph()->NewNode(javascript()->CreateFunctionContext(8), closure, - context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( - 8 + Context::MIN_CONTEXT_SLOTS)), - IsBeginRegion(_), control), - _)); -} - - -TEST_F(JSTypedLoweringTest, JSCreateFunctionContextViaStub) { - Node* const closure = Parameter(Type::Any()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction const r = - Reduce(graph()->NewNode(javascript()->CreateFunctionContext(32), closure, - context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsCall(_, IsHeapConstant( - CodeFactory::FastNewContext(isolate(), 32).code()), - closure, context, effect, control)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateWithContext - - -TEST_F(JSTypedLoweringTest, JSCreateWithContext) { - Node* const object = Parameter(Type::Receiver()); - Node* const closure = Parameter(Type::Function()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction r = - Reduce(graph()->NewNode(javascript()->CreateWithContext(), object, - closure, context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( - Context::MIN_CONTEXT_SLOTS)), - IsBeginRegion(_), control), - _)); -} - - -// ----------------------------------------------------------------------------- -// JSCreateCatchContext - - -TEST_F(JSTypedLoweringTest, JSCreateCatchContext) { - Handle<String> name = factory()->length_string(); - Node* const exception = Parameter(Type::Receiver()); - Node* const closure = Parameter(Type::Function()); - Node* const context = Parameter(Type::Any()); - Node* const effect = graph()->start(); - Node* const control = graph()->start(); - Reduction r = - Reduce(graph()->NewNode(javascript()->CreateCatchContext(name), exception, - closure, context, effect, control)); - ASSERT_TRUE(r.Changed()); - EXPECT_THAT(r.replacement(), - IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( - Context::MIN_CONTEXT_SLOTS + 1)), - IsBeginRegion(_), control), - _)); } diff --git a/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc b/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc index b77830aa5e..efc823dba6 100644 --- a/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc +++ b/deps/v8/test/unittests/compiler/liveness-analyzer-unittest.cc @@ -61,7 +61,7 @@ class LivenessAnalysisTest : public GraphTest { const FrameStateFunctionInfo* state_info = common()->CreateFrameStateFunctionInfo( FrameStateType::kJavaScriptFunction, 0, locals_count_, - Handle<SharedFunctionInfo>(), CALL_MAINTAINS_NATIVE_CONTEXT); + Handle<SharedFunctionInfo>()); const Operator* op = common()->FrameState( BailoutId(ast_num), OutputFrameStateCombine::Ignore(), state_info); diff --git a/deps/v8/test/unittests/compiler/move-optimizer-unittest.cc b/deps/v8/test/unittests/compiler/move-optimizer-unittest.cc index 413c58b6fe..5ccd0c6727 100644 --- a/deps/v8/test/unittests/compiler/move-optimizer-unittest.cc +++ b/deps/v8/test/unittests/compiler/move-optimizer-unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "src/compiler/move-optimizer.h" +#include "src/compiler/pipeline.h" #include "test/unittests/compiler/instruction-sequence-unittest.h" namespace v8 { @@ -227,8 +228,8 @@ TEST_F(MoveOptimizerTest, GapsCanMoveOverInstruction) { ctant_def->GetParallelMove(Instruction::GapPosition::END); ParallelMove* last_start = last->GetParallelMove(Instruction::GapPosition::START); - CHECK(inst1_start == nullptr || inst1_start->size() == 0); - CHECK(inst1_end == nullptr || inst1_end->size() == 0); + CHECK(inst1_start == nullptr || NonRedundantSize(inst1_start) == 0); + CHECK(inst1_end == nullptr || NonRedundantSize(inst1_end) == 0); CHECK(last_start->size() == 2); int redundants = 0; int assignment = 0; @@ -246,6 +247,98 @@ TEST_F(MoveOptimizerTest, GapsCanMoveOverInstruction) { } +TEST_F(MoveOptimizerTest, SubsetMovesMerge) { + StartBlock(); + EndBlock(Branch(Imm(), 1, 2)); + + StartBlock(); + EndBlock(Jump(2)); + Instruction* last_move_b1 = LastInstruction(); + AddMove(last_move_b1, Reg(0), Reg(1)); + AddMove(last_move_b1, Reg(2), Reg(3)); + + StartBlock(); + EndBlock(Jump(1)); + Instruction* last_move_b2 = LastInstruction(); + AddMove(last_move_b2, Reg(0), Reg(1)); + AddMove(last_move_b2, Reg(4), Reg(5)); + + StartBlock(); + EndBlock(Last()); + + Instruction* last = LastInstruction(); + + Optimize(); + + ParallelMove* last_move = last->parallel_moves()[0]; + CHECK_EQ(1, NonRedundantSize(last_move)); + CHECK(Contains(last_move, Reg(0), Reg(1))); + + ParallelMove* b1_move = last_move_b1->parallel_moves()[0]; + CHECK_EQ(1, NonRedundantSize(b1_move)); + CHECK(Contains(b1_move, Reg(2), Reg(3))); + + ParallelMove* b2_move = last_move_b2->parallel_moves()[0]; + CHECK_EQ(1, NonRedundantSize(b2_move)); + CHECK(Contains(b2_move, Reg(4), Reg(5))); +} + + +TEST_F(MoveOptimizerTest, GapConflictSubsetMovesDoNotMerge) { + StartBlock(); + EndBlock(Branch(Imm(), 1, 2)); + + StartBlock(); + EndBlock(Jump(2)); + Instruction* last_move_b1 = LastInstruction(); + AddMove(last_move_b1, Reg(0), Reg(1)); + AddMove(last_move_b1, Reg(2), Reg(0)); + AddMove(last_move_b1, Reg(4), Reg(5)); + + StartBlock(); + EndBlock(Jump(1)); + Instruction* last_move_b2 = LastInstruction(); + AddMove(last_move_b2, Reg(0), Reg(1)); + AddMove(last_move_b2, Reg(4), Reg(5)); + + StartBlock(); + EndBlock(Last()); + + Instruction* last = LastInstruction(); + + Optimize(); + + ParallelMove* last_move = last->parallel_moves()[0]; + CHECK_EQ(1, NonRedundantSize(last_move)); + CHECK(Contains(last_move, Reg(4), Reg(5))); + + ParallelMove* b1_move = last_move_b1->parallel_moves()[0]; + CHECK_EQ(2, NonRedundantSize(b1_move)); + CHECK(Contains(b1_move, Reg(0), Reg(1))); + CHECK(Contains(b1_move, Reg(2), Reg(0))); + + ParallelMove* b2_move = last_move_b2->parallel_moves()[0]; + CHECK_EQ(1, NonRedundantSize(b2_move)); + CHECK(Contains(b1_move, Reg(0), Reg(1))); +} + +TEST_F(MoveOptimizerTest, ClobberedDestinationsAreEliminated) { + StartBlock(); + EmitNop(); + Instruction* first_instr = LastInstruction(); + AddMove(first_instr, Reg(0), Reg(1)); + EmitOI(Reg(1), 0, nullptr); + Instruction* last_instr = LastInstruction(); + EndBlock(); + Optimize(); + + ParallelMove* first_move = first_instr->parallel_moves()[0]; + CHECK_EQ(0, NonRedundantSize(first_move)); + + ParallelMove* last_move = last_instr->parallel_moves()[0]; + CHECK_EQ(0, NonRedundantSize(last_move)); +} + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/compiler/node-test-utils.cc b/deps/v8/test/unittests/compiler/node-test-utils.cc index 54168ee70b..ee4cf5446e 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.cc +++ b/deps/v8/test/unittests/compiler/node-test-utils.cc @@ -323,13 +323,30 @@ class IsReturnMatcher final : public NodeMatcher { const Matcher<Node*>& control_matcher) : NodeMatcher(IrOpcode::kReturn), value_matcher_(value_matcher), + value2_matcher_(_), effect_matcher_(effect_matcher), - control_matcher_(control_matcher) {} + control_matcher_(control_matcher), + has_second_return_value_(false) {} + + IsReturnMatcher(const Matcher<Node*>& value_matcher, + const Matcher<Node*>& value2_matcher, + const Matcher<Node*>& effect_matcher, + const Matcher<Node*>& control_matcher) + : NodeMatcher(IrOpcode::kReturn), + value_matcher_(value_matcher), + value2_matcher_(value2_matcher), + effect_matcher_(effect_matcher), + control_matcher_(control_matcher), + has_second_return_value_(true) {} void DescribeTo(std::ostream* os) const final { NodeMatcher::DescribeTo(os); *os << " whose value ("; value_matcher_.DescribeTo(os); + if (has_second_return_value_) { + *os << ") and second value ("; + value2_matcher_.DescribeTo(os); + } *os << ") and effect ("; effect_matcher_.DescribeTo(os); *os << ") and control ("; @@ -341,6 +358,9 @@ class IsReturnMatcher final : public NodeMatcher { return (NodeMatcher::MatchAndExplain(node, listener) && PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "value", value_matcher_, listener) && + (!has_second_return_value_ || + PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), + "value2", value2_matcher_, listener)) && PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect", effect_matcher_, listener) && PrintMatchAndExplain(NodeProperties::GetControlInput(node), @@ -349,8 +369,10 @@ class IsReturnMatcher final : public NodeMatcher { private: const Matcher<Node*> value_matcher_; + const Matcher<Node*> value2_matcher_; const Matcher<Node*> effect_matcher_; const Matcher<Node*> control_matcher_; + bool has_second_return_value_; }; @@ -1467,7 +1489,6 @@ Matcher<Node*> IsDead() { return MakeMatcher(new NodeMatcher(IrOpcode::kDead)); } - Matcher<Node*> IsEnd(const Matcher<Node*>& control0_matcher) { return MakeMatcher(new IsControl1Matcher(IrOpcode::kEnd, control0_matcher)); } @@ -1577,6 +1598,13 @@ Matcher<Node*> IsReturn(const Matcher<Node*>& value_matcher, new IsReturnMatcher(value_matcher, effect_matcher, control_matcher)); } +Matcher<Node*> IsReturn2(const Matcher<Node*>& value_matcher, + const Matcher<Node*>& value2_matcher, + const Matcher<Node*>& effect_matcher, + const Matcher<Node*>& control_matcher) { + return MakeMatcher(new IsReturnMatcher(value_matcher, value2_matcher, + effect_matcher, control_matcher)); +} Matcher<Node*> IsTerminate(const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher) { @@ -1675,6 +1703,15 @@ Matcher<Node*> IsProjection(const Matcher<size_t>& index_matcher, return MakeMatcher(new IsProjectionMatcher(index_matcher, base_matcher)); } +Matcher<Node*> IsCall(const Matcher<const CallDescriptor*>& descriptor_matcher, + const Matcher<Node*>& value0_matcher, + const Matcher<Node*>& effect_matcher, + const Matcher<Node*>& control_matcher) { + std::vector<Matcher<Node*>> value_matchers; + value_matchers.push_back(value0_matcher); + return MakeMatcher(new IsCallMatcher(descriptor_matcher, value_matchers, + effect_matcher, control_matcher)); +} Matcher<Node*> IsCall(const Matcher<const CallDescriptor*>& descriptor_matcher, const Matcher<Node*>& value0_matcher, @@ -2106,6 +2143,7 @@ IS_UNOP_MATCHER(Float64ExtractLowWord32) IS_UNOP_MATCHER(Float64ExtractHighWord32) IS_UNOP_MATCHER(NumberToInt32) IS_UNOP_MATCHER(NumberToUint32) +IS_UNOP_MATCHER(ObjectIsReceiver) IS_UNOP_MATCHER(ObjectIsSmi) IS_UNOP_MATCHER(Word32Clz) #undef IS_UNOP_MATCHER diff --git a/deps/v8/test/unittests/compiler/node-test-utils.h b/deps/v8/test/unittests/compiler/node-test-utils.h index 8592f30566..03f2a3b88f 100644 --- a/deps/v8/test/unittests/compiler/node-test-utils.h +++ b/deps/v8/test/unittests/compiler/node-test-utils.h @@ -17,11 +17,8 @@ class ExternalReference; template <typename T> class Handle; class HeapObject; -template <class> -class TypeImpl; +class Type; enum TypeofMode : int; -struct ZoneTypeConfig; -typedef TypeImpl<ZoneTypeConfig> Type; namespace compiler { @@ -70,6 +67,10 @@ Matcher<Node*> IsFinishRegion(const Matcher<Node*>& value_matcher, Matcher<Node*> IsReturn(const Matcher<Node*>& value_matcher, const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher); +Matcher<Node*> IsReturn2(const Matcher<Node*>& value_matcher, + const Matcher<Node*>& value2_matcher, + const Matcher<Node*>& effect_matcher, + const Matcher<Node*>& control_matcher); Matcher<Node*> IsTerminate(const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher); Matcher<Node*> IsExternalConstant( @@ -246,6 +247,7 @@ Matcher<Node*> IsStoreElement(const Matcher<ElementAccess>& access_matcher, const Matcher<Node*>& value_matcher, const Matcher<Node*>& effect_matcher, const Matcher<Node*>& control_matcher); +Matcher<Node*> IsObjectIsReceiver(const Matcher<Node*>& value_matcher); Matcher<Node*> IsObjectIsSmi(const Matcher<Node*>& value_matcher); Matcher<Node*> IsLoad(const Matcher<LoadRepresentation>& rep_matcher, diff --git a/deps/v8/test/unittests/compiler/scheduler-rpo-unittest.cc b/deps/v8/test/unittests/compiler/scheduler-rpo-unittest.cc new file mode 100644 index 0000000000..713ee6e742 --- /dev/null +++ b/deps/v8/test/unittests/compiler/scheduler-rpo-unittest.cc @@ -0,0 +1,533 @@ +// 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/compiler/schedule.h" +#include "src/compiler/scheduler.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 { +namespace compiler { + +class SchedulerRPOTest : public TestWithZone { + public: + SchedulerRPOTest() {} + + 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); + if (!loops_allowed) { + CHECK(!order->at(i)->loop_end()); + CHECK(!order->at(i)->loop_header()); + } + } + } + + void CheckLoop(BasicBlockVector* order, BasicBlock** blocks, int body_size) { + BasicBlock* header = blocks[0]; + BasicBlock* end = header->loop_end(); + CHECK(end); + CHECK_GT(end->rpo_number(), 0); + CHECK_EQ(body_size, end->rpo_number() - header->rpo_number()); + for (int i = 0; i < body_size; i++) { + CHECK_GE(blocks[i]->rpo_number(), header->rpo_number()); + CHECK_LT(blocks[i]->rpo_number(), end->rpo_number()); + CHECK(header->LoopContains(blocks[i])); + CHECK(header->IsLoopHeader() || blocks[i]->loop_header() == header); + } + if (header->rpo_number() > 0) { + CHECK_NE(order->at(header->rpo_number() - 1)->loop_header(), header); + } + if (end->rpo_number() < static_cast<int>(order->size())) { + CHECK_NE(order->at(end->rpo_number())->loop_header(), header); + } + } + + struct TestLoop { + int count; + BasicBlock** nodes; + BasicBlock* header() { return nodes[0]; } + BasicBlock* last() { return nodes[count - 1]; } + ~TestLoop() { delete[] nodes; } + }; + + TestLoop* CreateLoop(Schedule* schedule, int count) { + TestLoop* loop = new TestLoop(); + loop->count = count; + loop->nodes = new BasicBlock*[count]; + for (int i = 0; i < count; i++) { + loop->nodes[i] = schedule->NewBasicBlock(); + if (i > 0) { + schedule->AddSuccessorForTesting(loop->nodes[i - 1], loop->nodes[i]); + } + } + schedule->AddSuccessorForTesting(loop->nodes[count - 1], loop->nodes[0]); + return loop; + } +}; + +TEST_F(SchedulerRPOTest, Degenerate1) { + Schedule schedule(zone()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 1, false); + EXPECT_EQ(schedule.start(), order->at(0)); +} + +TEST_F(SchedulerRPOTest, Degenerate2) { + Schedule schedule(zone()); + + schedule.AddGoto(schedule.start(), schedule.end()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 2, false); + EXPECT_EQ(schedule.start(), order->at(0)); + EXPECT_EQ(schedule.end(), order->at(1)); +} + +TEST_F(SchedulerRPOTest, Line) { + for (int i = 0; i < 10; i++) { + Schedule schedule(zone()); + + BasicBlock* last = schedule.start(); + for (int j = 0; j < i; j++) { + BasicBlock* block = schedule.NewBasicBlock(); + block->set_deferred(i & 1); + schedule.AddGoto(last, block); + last = block; + } + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 1 + i, false); + + 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) { + EXPECT_EQ(block->rpo_number() + 1, block->SuccessorAt(0)->rpo_number()); + } + } + } +} + +TEST_F(SchedulerRPOTest, SelfLoop) { + Schedule schedule(zone()); + schedule.AddSuccessorForTesting(schedule.start(), schedule.start()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 1, true); + BasicBlock* loop[] = {schedule.start()}; + CheckLoop(order, loop, 1); +} + +TEST_F(SchedulerRPOTest, EntryLoop) { + Schedule schedule(zone()); + BasicBlock* body = schedule.NewBasicBlock(); + schedule.AddSuccessorForTesting(schedule.start(), body); + schedule.AddSuccessorForTesting(body, schedule.start()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 2, true); + BasicBlock* loop[] = {schedule.start(), body}; + CheckLoop(order, loop, 2); +} + +TEST_F(SchedulerRPOTest, EndLoop) { + Schedule schedule(zone()); + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2)); + schedule.AddSuccessorForTesting(schedule.start(), loop1->header()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 3, true); + CheckLoop(order, loop1->nodes, loop1->count); +} + +TEST_F(SchedulerRPOTest, EndLoopNested) { + Schedule schedule(zone()); + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2)); + schedule.AddSuccessorForTesting(schedule.start(), loop1->header()); + schedule.AddSuccessorForTesting(loop1->last(), schedule.start()); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 3, true); + CheckLoop(order, loop1->nodes, loop1->count); +} + +TEST_F(SchedulerRPOTest, Diamond) { + Schedule schedule(zone()); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(A, C); + schedule.AddSuccessorForTesting(B, D); + schedule.AddSuccessorForTesting(C, D); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 4, false); + + 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()); +} + +TEST_F(SchedulerRPOTest, Loop1) { + Schedule schedule(zone()); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, C); + schedule.AddSuccessorForTesting(C, B); + schedule.AddSuccessorForTesting(C, D); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 4, true); + BasicBlock* loop[] = {B, C}; + CheckLoop(order, loop, 2); +} + +TEST_F(SchedulerRPOTest, Loop2) { + Schedule schedule(zone()); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, C); + schedule.AddSuccessorForTesting(C, B); + schedule.AddSuccessorForTesting(B, D); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 4, true); + BasicBlock* loop[] = {B, C}; + CheckLoop(order, loop, 2); +} + +TEST_F(SchedulerRPOTest, LoopN) { + for (int i = 0; i < 11; i++) { + Schedule schedule(zone()); + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.NewBasicBlock(); + BasicBlock* F = schedule.NewBasicBlock(); + BasicBlock* G = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, C); + schedule.AddSuccessorForTesting(C, D); + schedule.AddSuccessorForTesting(D, E); + schedule.AddSuccessorForTesting(E, F); + schedule.AddSuccessorForTesting(F, B); + schedule.AddSuccessorForTesting(B, G); + + // Throw in extra backedges from time to time. + if (i == 1) schedule.AddSuccessorForTesting(B, B); + if (i == 2) schedule.AddSuccessorForTesting(C, B); + if (i == 3) schedule.AddSuccessorForTesting(D, B); + if (i == 4) schedule.AddSuccessorForTesting(E, B); + if (i == 5) schedule.AddSuccessorForTesting(F, B); + + // Throw in extra loop exits from time to time. + if (i == 6) schedule.AddSuccessorForTesting(B, G); + if (i == 7) schedule.AddSuccessorForTesting(C, G); + if (i == 8) schedule.AddSuccessorForTesting(D, G); + if (i == 9) schedule.AddSuccessorForTesting(E, G); + if (i == 10) schedule.AddSuccessorForTesting(F, G); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 7, true); + BasicBlock* loop[] = {B, C, D, E, F}; + CheckLoop(order, loop, 5); + } +} + +TEST_F(SchedulerRPOTest, LoopNest1) { + Schedule schedule(zone()); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.NewBasicBlock(); + BasicBlock* F = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, C); + schedule.AddSuccessorForTesting(C, D); + schedule.AddSuccessorForTesting(D, C); + schedule.AddSuccessorForTesting(D, E); + schedule.AddSuccessorForTesting(E, B); + schedule.AddSuccessorForTesting(E, F); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 6, true); + BasicBlock* loop1[] = {B, C, D, E}; + CheckLoop(order, loop1, 4); + + BasicBlock* loop2[] = {C, D}; + CheckLoop(order, loop2, 2); +} + +TEST_F(SchedulerRPOTest, LoopNest2) { + Schedule schedule(zone()); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.NewBasicBlock(); + BasicBlock* F = schedule.NewBasicBlock(); + BasicBlock* G = schedule.NewBasicBlock(); + BasicBlock* H = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, C); + schedule.AddSuccessorForTesting(C, D); + schedule.AddSuccessorForTesting(D, E); + schedule.AddSuccessorForTesting(E, F); + schedule.AddSuccessorForTesting(F, G); + schedule.AddSuccessorForTesting(G, H); + + schedule.AddSuccessorForTesting(E, D); + schedule.AddSuccessorForTesting(F, C); + schedule.AddSuccessorForTesting(G, B); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 8, true); + BasicBlock* loop1[] = {B, C, D, E, F, G}; + CheckLoop(order, loop1, 6); + + BasicBlock* loop2[] = {C, D, E, F}; + CheckLoop(order, loop2, 4); + + BasicBlock* loop3[] = {D, E}; + CheckLoop(order, loop3, 2); +} + +TEST_F(SchedulerRPOTest, LoopFollow1) { + Schedule schedule(zone()); + + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); + base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); + + BasicBlock* A = schedule.start(); + BasicBlock* E = schedule.end(); + + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->header(), loop2->header()); + schedule.AddSuccessorForTesting(loop2->last(), E); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + + EXPECT_EQ(schedule.BasicBlockCount(), order->size()); + CheckLoop(order, loop1->nodes, loop1->count); + CheckLoop(order, loop2->nodes, loop2->count); +} + +TEST_F(SchedulerRPOTest, LoopFollow2) { + Schedule schedule(zone()); + + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); + base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); + + BasicBlock* A = schedule.start(); + BasicBlock* S = schedule.NewBasicBlock(); + BasicBlock* E = schedule.end(); + + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->header(), S); + schedule.AddSuccessorForTesting(S, loop2->header()); + schedule.AddSuccessorForTesting(loop2->last(), E); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + + EXPECT_EQ(schedule.BasicBlockCount(), order->size()); + CheckLoop(order, loop1->nodes, loop1->count); + CheckLoop(order, loop2->nodes, loop2->count); +} + +TEST_F(SchedulerRPOTest, LoopFollowN) { + for (int size = 1; size < 5; size++) { + for (int exit = 0; exit < size; exit++) { + Schedule schedule(zone()); + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, size)); + BasicBlock* A = schedule.start(); + BasicBlock* E = schedule.end(); + + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->nodes[exit], loop2->header()); + schedule.AddSuccessorForTesting(loop2->nodes[exit], E); + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + + EXPECT_EQ(schedule.BasicBlockCount(), order->size()); + CheckLoop(order, loop1->nodes, loop1->count); + CheckLoop(order, loop2->nodes, loop2->count); + } + } +} + +TEST_F(SchedulerRPOTest, NestedLoopFollow1) { + Schedule schedule(zone()); + + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); + base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* E = schedule.end(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, loop1->header()); + schedule.AddSuccessorForTesting(loop1->header(), loop2->header()); + schedule.AddSuccessorForTesting(loop2->last(), C); + schedule.AddSuccessorForTesting(C, E); + schedule.AddSuccessorForTesting(C, B); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + + 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); +} + +TEST_F(SchedulerRPOTest, LoopBackedges1) { + int size = 8; + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + Schedule schedule(zone()); + BasicBlock* A = schedule.start(); + BasicBlock* E = schedule.end(); + + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->last(), E); + + schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header()); + schedule.AddSuccessorForTesting(loop1->nodes[j], E); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, schedule.BasicBlockCount(), true); + CheckLoop(order, loop1->nodes, loop1->count); + } + } +} + +TEST_F(SchedulerRPOTest, LoopOutedges1) { + int size = 8; + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + Schedule schedule(zone()); + BasicBlock* A = schedule.start(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.end(); + + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->last(), E); + + schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header()); + schedule.AddSuccessorForTesting(loop1->nodes[j], D); + schedule.AddSuccessorForTesting(D, E); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, schedule.BasicBlockCount(), true); + CheckLoop(order, loop1->nodes, loop1->count); + } + } +} + +TEST_F(SchedulerRPOTest, LoopOutedges2) { + int size = 8; + for (int i = 0; i < size; i++) { + Schedule schedule(zone()); + BasicBlock* A = schedule.start(); + BasicBlock* E = schedule.end(); + + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->last(), E); + + for (int j = 0; j < size; j++) { + BasicBlock* O = schedule.NewBasicBlock(); + schedule.AddSuccessorForTesting(loop1->nodes[j], O); + schedule.AddSuccessorForTesting(O, E); + } + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, schedule.BasicBlockCount(), true); + CheckLoop(order, loop1->nodes, loop1->count); + } +} + +TEST_F(SchedulerRPOTest, LoopOutloops1) { + int size = 8; + for (int i = 0; i < size; i++) { + Schedule schedule(zone()); + BasicBlock* A = schedule.start(); + BasicBlock* E = schedule.end(); + base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); + schedule.AddSuccessorForTesting(A, loop1->header()); + schedule.AddSuccessorForTesting(loop1->last(), E); + + TestLoop** loopN = new TestLoop*[size]; + for (int j = 0; j < size; j++) { + loopN[j] = CreateLoop(&schedule, 2); + schedule.AddSuccessorForTesting(loop1->nodes[j], loopN[j]->header()); + schedule.AddSuccessorForTesting(loopN[j]->last(), E); + } + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, schedule.BasicBlockCount(), true); + CheckLoop(order, loop1->nodes, loop1->count); + + for (int j = 0; j < size; j++) { + CheckLoop(order, loopN[j]->nodes, loopN[j]->count); + delete loopN[j]; + } + delete[] loopN; + } +} + +TEST_F(SchedulerRPOTest, LoopMultibackedge) { + Schedule schedule(zone()); + + BasicBlock* A = schedule.start(); + BasicBlock* B = schedule.NewBasicBlock(); + BasicBlock* C = schedule.NewBasicBlock(); + BasicBlock* D = schedule.NewBasicBlock(); + BasicBlock* E = schedule.NewBasicBlock(); + + schedule.AddSuccessorForTesting(A, B); + schedule.AddSuccessorForTesting(B, C); + schedule.AddSuccessorForTesting(B, D); + schedule.AddSuccessorForTesting(B, E); + schedule.AddSuccessorForTesting(C, B); + schedule.AddSuccessorForTesting(D, B); + schedule.AddSuccessorForTesting(E, B); + + BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); + CheckRPONumbers(order, 5, true); + + BasicBlock* loop1[] = {B, C, D, E}; + CheckLoop(order, loop1, 4); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/compiler/scheduler-unittest.cc b/deps/v8/test/unittests/compiler/scheduler-unittest.cc index 523c8ce9d4..6cf07345a2 100644 --- a/deps/v8/test/unittests/compiler/scheduler-unittest.cc +++ b/deps/v8/test/unittests/compiler/scheduler-unittest.cc @@ -71,67 +71,6 @@ class SchedulerTest : public TestWithIsolateAndZone { }; -class SchedulerRPOTest : public SchedulerTest { - public: - SchedulerRPOTest() {} - - // TODO(titzer): pull RPO tests out to their own file. - 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); - if (!loops_allowed) { - CHECK(!order->at(i)->loop_end()); - CHECK(!order->at(i)->loop_header()); - } - } - } - - void CheckLoop(BasicBlockVector* order, BasicBlock** blocks, int body_size) { - BasicBlock* header = blocks[0]; - BasicBlock* end = header->loop_end(); - CHECK(end); - CHECK_GT(end->rpo_number(), 0); - CHECK_EQ(body_size, end->rpo_number() - header->rpo_number()); - for (int i = 0; i < body_size; i++) { - CHECK_GE(blocks[i]->rpo_number(), header->rpo_number()); - CHECK_LT(blocks[i]->rpo_number(), end->rpo_number()); - CHECK(header->LoopContains(blocks[i])); - CHECK(header->IsLoopHeader() || blocks[i]->loop_header() == header); - } - if (header->rpo_number() > 0) { - CHECK_NE(order->at(header->rpo_number() - 1)->loop_header(), header); - } - if (end->rpo_number() < static_cast<int>(order->size())) { - CHECK_NE(order->at(end->rpo_number())->loop_header(), header); - } - } - - struct TestLoop { - int count; - BasicBlock** nodes; - BasicBlock* header() { return nodes[0]; } - BasicBlock* last() { return nodes[count - 1]; } - ~TestLoop() { delete[] nodes; } - }; - - TestLoop* CreateLoop(Schedule* schedule, int count) { - TestLoop* loop = new TestLoop(); - loop->count = count; - loop->nodes = new BasicBlock* [count]; - for (int i = 0; i < count; i++) { - loop->nodes[i] = schedule->NewBasicBlock(); - if (i > 0) { - schedule->AddSuccessorForTesting(loop->nodes[i - 1], loop->nodes[i]); - } - } - schedule->AddSuccessorForTesting(loop->nodes[count - 1], loop->nodes[0]); - return loop; - } -}; - - namespace { const Operator kHeapConstant(IrOpcode::kHeapConstant, Operator::kPure, @@ -146,491 +85,6 @@ const Operator kMockTailCall(IrOpcode::kTailCall, Operator::kNoProperties, } // namespace -// ----------------------------------------------------------------------------- -// Special reverse-post-order block ordering. - - -TEST_F(SchedulerRPOTest, Degenerate1) { - Schedule schedule(zone()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 1, false); - EXPECT_EQ(schedule.start(), order->at(0)); -} - - -TEST_F(SchedulerRPOTest, Degenerate2) { - Schedule schedule(zone()); - - schedule.AddGoto(schedule.start(), schedule.end()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 2, false); - EXPECT_EQ(schedule.start(), order->at(0)); - EXPECT_EQ(schedule.end(), order->at(1)); -} - - -TEST_F(SchedulerRPOTest, Line) { - for (int i = 0; i < 10; i++) { - Schedule schedule(zone()); - - BasicBlock* last = schedule.start(); - for (int j = 0; j < i; j++) { - BasicBlock* block = schedule.NewBasicBlock(); - block->set_deferred(i & 1); - schedule.AddGoto(last, block); - last = block; - } - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 1 + i, false); - - 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) { - EXPECT_EQ(block->rpo_number() + 1, block->SuccessorAt(0)->rpo_number()); - } - } - } -} - - -TEST_F(SchedulerRPOTest, SelfLoop) { - Schedule schedule(zone()); - schedule.AddSuccessorForTesting(schedule.start(), schedule.start()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 1, true); - BasicBlock* loop[] = {schedule.start()}; - CheckLoop(order, loop, 1); -} - - -TEST_F(SchedulerRPOTest, EntryLoop) { - Schedule schedule(zone()); - BasicBlock* body = schedule.NewBasicBlock(); - schedule.AddSuccessorForTesting(schedule.start(), body); - schedule.AddSuccessorForTesting(body, schedule.start()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 2, true); - BasicBlock* loop[] = {schedule.start(), body}; - CheckLoop(order, loop, 2); -} - - -TEST_F(SchedulerRPOTest, EndLoop) { - Schedule schedule(zone()); - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2)); - schedule.AddSuccessorForTesting(schedule.start(), loop1->header()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 3, true); - CheckLoop(order, loop1->nodes, loop1->count); -} - - -TEST_F(SchedulerRPOTest, EndLoopNested) { - Schedule schedule(zone()); - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2)); - schedule.AddSuccessorForTesting(schedule.start(), loop1->header()); - schedule.AddSuccessorForTesting(loop1->last(), schedule.start()); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 3, true); - CheckLoop(order, loop1->nodes, loop1->count); -} - - -TEST_F(SchedulerRPOTest, Diamond) { - Schedule schedule(zone()); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(A, C); - schedule.AddSuccessorForTesting(B, D); - schedule.AddSuccessorForTesting(C, D); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 4, false); - - 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()); -} - - -TEST_F(SchedulerRPOTest, Loop1) { - Schedule schedule(zone()); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, C); - schedule.AddSuccessorForTesting(C, B); - schedule.AddSuccessorForTesting(C, D); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 4, true); - BasicBlock* loop[] = {B, C}; - CheckLoop(order, loop, 2); -} - - -TEST_F(SchedulerRPOTest, Loop2) { - Schedule schedule(zone()); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, C); - schedule.AddSuccessorForTesting(C, B); - schedule.AddSuccessorForTesting(B, D); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 4, true); - BasicBlock* loop[] = {B, C}; - CheckLoop(order, loop, 2); -} - - -TEST_F(SchedulerRPOTest, LoopN) { - for (int i = 0; i < 11; i++) { - Schedule schedule(zone()); - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.NewBasicBlock(); - BasicBlock* E = schedule.NewBasicBlock(); - BasicBlock* F = schedule.NewBasicBlock(); - BasicBlock* G = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, C); - schedule.AddSuccessorForTesting(C, D); - schedule.AddSuccessorForTesting(D, E); - schedule.AddSuccessorForTesting(E, F); - schedule.AddSuccessorForTesting(F, B); - schedule.AddSuccessorForTesting(B, G); - - // Throw in extra backedges from time to time. - if (i == 1) schedule.AddSuccessorForTesting(B, B); - if (i == 2) schedule.AddSuccessorForTesting(C, B); - if (i == 3) schedule.AddSuccessorForTesting(D, B); - if (i == 4) schedule.AddSuccessorForTesting(E, B); - if (i == 5) schedule.AddSuccessorForTesting(F, B); - - // Throw in extra loop exits from time to time. - if (i == 6) schedule.AddSuccessorForTesting(B, G); - if (i == 7) schedule.AddSuccessorForTesting(C, G); - if (i == 8) schedule.AddSuccessorForTesting(D, G); - if (i == 9) schedule.AddSuccessorForTesting(E, G); - if (i == 10) schedule.AddSuccessorForTesting(F, G); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 7, true); - BasicBlock* loop[] = {B, C, D, E, F}; - CheckLoop(order, loop, 5); - } -} - - -TEST_F(SchedulerRPOTest, LoopNest1) { - Schedule schedule(zone()); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.NewBasicBlock(); - BasicBlock* E = schedule.NewBasicBlock(); - BasicBlock* F = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, C); - schedule.AddSuccessorForTesting(C, D); - schedule.AddSuccessorForTesting(D, C); - schedule.AddSuccessorForTesting(D, E); - schedule.AddSuccessorForTesting(E, B); - schedule.AddSuccessorForTesting(E, F); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 6, true); - BasicBlock* loop1[] = {B, C, D, E}; - CheckLoop(order, loop1, 4); - - BasicBlock* loop2[] = {C, D}; - CheckLoop(order, loop2, 2); -} - - -TEST_F(SchedulerRPOTest, LoopNest2) { - Schedule schedule(zone()); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.NewBasicBlock(); - BasicBlock* E = schedule.NewBasicBlock(); - BasicBlock* F = schedule.NewBasicBlock(); - BasicBlock* G = schedule.NewBasicBlock(); - BasicBlock* H = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, C); - schedule.AddSuccessorForTesting(C, D); - schedule.AddSuccessorForTesting(D, E); - schedule.AddSuccessorForTesting(E, F); - schedule.AddSuccessorForTesting(F, G); - schedule.AddSuccessorForTesting(G, H); - - schedule.AddSuccessorForTesting(E, D); - schedule.AddSuccessorForTesting(F, C); - schedule.AddSuccessorForTesting(G, B); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 8, true); - BasicBlock* loop1[] = {B, C, D, E, F, G}; - CheckLoop(order, loop1, 6); - - BasicBlock* loop2[] = {C, D, E, F}; - CheckLoop(order, loop2, 4); - - BasicBlock* loop3[] = {D, E}; - CheckLoop(order, loop3, 2); -} - - -TEST_F(SchedulerRPOTest, LoopFollow1) { - Schedule schedule(zone()); - - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); - base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); - - BasicBlock* A = schedule.start(); - BasicBlock* E = schedule.end(); - - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->header(), loop2->header()); - schedule.AddSuccessorForTesting(loop2->last(), E); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - - EXPECT_EQ(schedule.BasicBlockCount(), order->size()); - CheckLoop(order, loop1->nodes, loop1->count); - CheckLoop(order, loop2->nodes, loop2->count); -} - - -TEST_F(SchedulerRPOTest, LoopFollow2) { - Schedule schedule(zone()); - - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); - base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); - - BasicBlock* A = schedule.start(); - BasicBlock* S = schedule.NewBasicBlock(); - BasicBlock* E = schedule.end(); - - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->header(), S); - schedule.AddSuccessorForTesting(S, loop2->header()); - schedule.AddSuccessorForTesting(loop2->last(), E); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - - EXPECT_EQ(schedule.BasicBlockCount(), order->size()); - CheckLoop(order, loop1->nodes, loop1->count); - CheckLoop(order, loop2->nodes, loop2->count); -} - - -TEST_F(SchedulerRPOTest, LoopFollowN) { - for (int size = 1; size < 5; size++) { - for (int exit = 0; exit < size; exit++) { - Schedule schedule(zone()); - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); - base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, size)); - BasicBlock* A = schedule.start(); - BasicBlock* E = schedule.end(); - - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->nodes[exit], loop2->header()); - schedule.AddSuccessorForTesting(loop2->nodes[exit], E); - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - - EXPECT_EQ(schedule.BasicBlockCount(), order->size()); - CheckLoop(order, loop1->nodes, loop1->count); - CheckLoop(order, loop2->nodes, loop2->count); - } - } -} - - -TEST_F(SchedulerRPOTest, NestedLoopFollow1) { - Schedule schedule(zone()); - - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 1)); - base::SmartPointer<TestLoop> loop2(CreateLoop(&schedule, 1)); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* E = schedule.end(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, loop1->header()); - schedule.AddSuccessorForTesting(loop1->header(), loop2->header()); - schedule.AddSuccessorForTesting(loop2->last(), C); - schedule.AddSuccessorForTesting(C, E); - schedule.AddSuccessorForTesting(C, B); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - - 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); -} - - -TEST_F(SchedulerRPOTest, LoopBackedges1) { - int size = 8; - for (int i = 0; i < size; i++) { - for (int j = 0; j < size; j++) { - Schedule schedule(zone()); - BasicBlock* A = schedule.start(); - BasicBlock* E = schedule.end(); - - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->last(), E); - - schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header()); - schedule.AddSuccessorForTesting(loop1->nodes[j], E); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, schedule.BasicBlockCount(), true); - CheckLoop(order, loop1->nodes, loop1->count); - } - } -} - - -TEST_F(SchedulerRPOTest, LoopOutedges1) { - int size = 8; - for (int i = 0; i < size; i++) { - for (int j = 0; j < size; j++) { - Schedule schedule(zone()); - BasicBlock* A = schedule.start(); - BasicBlock* D = schedule.NewBasicBlock(); - BasicBlock* E = schedule.end(); - - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->last(), E); - - schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header()); - schedule.AddSuccessorForTesting(loop1->nodes[j], D); - schedule.AddSuccessorForTesting(D, E); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, schedule.BasicBlockCount(), true); - CheckLoop(order, loop1->nodes, loop1->count); - } - } -} - - -TEST_F(SchedulerRPOTest, LoopOutedges2) { - int size = 8; - for (int i = 0; i < size; i++) { - Schedule schedule(zone()); - BasicBlock* A = schedule.start(); - BasicBlock* E = schedule.end(); - - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->last(), E); - - for (int j = 0; j < size; j++) { - BasicBlock* O = schedule.NewBasicBlock(); - schedule.AddSuccessorForTesting(loop1->nodes[j], O); - schedule.AddSuccessorForTesting(O, E); - } - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, schedule.BasicBlockCount(), true); - CheckLoop(order, loop1->nodes, loop1->count); - } -} - - -TEST_F(SchedulerRPOTest, LoopOutloops1) { - int size = 8; - for (int i = 0; i < size; i++) { - Schedule schedule(zone()); - BasicBlock* A = schedule.start(); - BasicBlock* E = schedule.end(); - base::SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size)); - schedule.AddSuccessorForTesting(A, loop1->header()); - schedule.AddSuccessorForTesting(loop1->last(), E); - - TestLoop** loopN = new TestLoop* [size]; - for (int j = 0; j < size; j++) { - loopN[j] = CreateLoop(&schedule, 2); - schedule.AddSuccessorForTesting(loop1->nodes[j], loopN[j]->header()); - schedule.AddSuccessorForTesting(loopN[j]->last(), E); - } - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, schedule.BasicBlockCount(), true); - CheckLoop(order, loop1->nodes, loop1->count); - - for (int j = 0; j < size; j++) { - CheckLoop(order, loopN[j]->nodes, loopN[j]->count); - delete loopN[j]; - } - delete[] loopN; - } -} - - -TEST_F(SchedulerRPOTest, LoopMultibackedge) { - Schedule schedule(zone()); - - BasicBlock* A = schedule.start(); - BasicBlock* B = schedule.NewBasicBlock(); - BasicBlock* C = schedule.NewBasicBlock(); - BasicBlock* D = schedule.NewBasicBlock(); - BasicBlock* E = schedule.NewBasicBlock(); - - schedule.AddSuccessorForTesting(A, B); - schedule.AddSuccessorForTesting(B, C); - schedule.AddSuccessorForTesting(B, D); - schedule.AddSuccessorForTesting(B, E); - schedule.AddSuccessorForTesting(C, B); - schedule.AddSuccessorForTesting(D, B); - schedule.AddSuccessorForTesting(E, B); - - BasicBlockVector* order = Scheduler::ComputeSpecialRPO(zone(), &schedule); - CheckRPONumbers(order, 5, true); - - BasicBlock* loop1[] = {B, C, D, E}; - CheckLoop(order, loop1, 4); -} - - -// ----------------------------------------------------------------------------- -// Graph end-to-end scheduling. - - TEST_F(SchedulerTest, BuildScheduleEmpty) { graph()->SetStart(graph()->NewNode(common()->Start(0))); graph()->SetEnd(graph()->NewNode(common()->End(1), graph()->start())); diff --git a/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc b/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc index 871189ad79..bd8509ff97 100644 --- a/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc +++ b/deps/v8/test/unittests/compiler/simplified-operator-unittest.cc @@ -6,7 +6,7 @@ #include "src/compiler/operator.h" #include "src/compiler/operator-properties.h" #include "src/compiler/simplified-operator.h" -#include "src/types-inl.h" +#include "src/types.h" #include "test/unittests/test-utils.h" namespace v8 { @@ -65,6 +65,8 @@ const PureOperator kPureOperators[] = { PURE(ChangeFloat64ToTagged, Operator::kNoProperties, 1), PURE(ChangeBoolToBit, Operator::kNoProperties, 1), PURE(ChangeBitToBool, Operator::kNoProperties, 1), + PURE(ObjectIsNumber, Operator::kNoProperties, 1), + PURE(ObjectIsReceiver, Operator::kNoProperties, 1), PURE(ObjectIsSmi, Operator::kNoProperties, 1) #undef PURE }; diff --git a/deps/v8/test/unittests/compiler/typer-unittest.cc b/deps/v8/test/unittests/compiler/typer-unittest.cc index 6e4d4d589f..9d664a6d3a 100644 --- a/deps/v8/test/unittests/compiler/typer-unittest.cc +++ b/deps/v8/test/unittests/compiler/typer-unittest.cc @@ -49,7 +49,7 @@ class TyperTest : public TypedGraphTest { } } - Types<Type, Type*, Zone> types_; + Types types_; JSOperatorBuilder javascript_; BinaryOperationHints const hints_ = BinaryOperationHints::Any(); Node* context_node_; @@ -115,7 +115,7 @@ class TyperTest : public TypedGraphTest { return result; } - double RandomInt(Type::RangeType* range) { + double RandomInt(RangeType* range) { return RandomInt(range->Min(), range->Max()); } @@ -149,12 +149,12 @@ class TyperTest : public TypedGraphTest { void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) { TestBinaryArithOpCloseToZero(op, opfun, 8); for (int i = 0; i < 100; ++i) { - Type::RangeType* r1 = RandomRange()->AsRange(); - Type::RangeType* r2 = RandomRange()->AsRange(); + Type* r1 = RandomRange(); + Type* r2 = RandomRange(); Type* expected_type = TypeBinaryOp(op, r1, r2); for (int i = 0; i < 10; i++) { - double x1 = RandomInt(r1); - double x2 = RandomInt(r2); + double x1 = RandomInt(r1->AsRange()); + double x2 = RandomInt(r2->AsRange()); double result_value = opfun(x1, x2); Type* result_type = Type::Constant( isolate()->factory()->NewNumber(result_value), zone()); @@ -166,12 +166,12 @@ class TyperTest : public TypedGraphTest { template <class BinaryFunction> void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) { for (int i = 0; i < 100; ++i) { - Type::RangeType* r1 = RandomRange()->AsRange(); - Type::RangeType* r2 = RandomRange()->AsRange(); + Type* r1 = RandomRange(); + Type* r2 = RandomRange(); Type* expected_type = TypeBinaryOp(op, r1, r2); for (int i = 0; i < 10; i++) { - double x1 = RandomInt(r1); - double x2 = RandomInt(r2); + double x1 = RandomInt(r1->AsRange()); + double x2 = RandomInt(r2->AsRange()); bool result_value = opfun(x1, x2); Type* result_type = Type::Constant(result_value ? isolate()->factory()->true_value() @@ -185,12 +185,12 @@ class TyperTest : public TypedGraphTest { template <class BinaryFunction> void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) { for (int i = 0; i < 100; ++i) { - Type::RangeType* r1 = RandomRange(true)->AsRange(); - Type::RangeType* r2 = RandomRange(true)->AsRange(); + Type* r1 = RandomRange(true); + Type* r2 = RandomRange(true); Type* expected_type = TypeBinaryOp(op, r1, r2); for (int i = 0; i < 10; i++) { - int32_t x1 = static_cast<int32_t>(RandomInt(r1)); - int32_t x2 = static_cast<int32_t>(RandomInt(r2)); + int32_t x1 = static_cast<int32_t>(RandomInt(r1->AsRange())); + int32_t x2 = static_cast<int32_t>(RandomInt(r2->AsRange())); double result_value = opfun(x1, x2); Type* result_type = Type::Constant( isolate()->factory()->NewNumber(result_value), zone()); @@ -240,109 +240,72 @@ int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; } TEST_F(TyperTest, TypeJSAdd) { - TestBinaryArithOp(javascript_.Add(LanguageMode::SLOPPY, hints_), - std::plus<double>()); - TestBinaryArithOp(javascript_.Add(LanguageMode::STRONG, hints_), - std::plus<double>()); + TestBinaryArithOp(javascript_.Add(hints_), std::plus<double>()); } TEST_F(TyperTest, TypeJSSubtract) { - TestBinaryArithOp(javascript_.Subtract(LanguageMode::SLOPPY, hints_), - std::minus<double>()); - TestBinaryArithOp(javascript_.Subtract(LanguageMode::STRONG, hints_), - std::minus<double>()); + TestBinaryArithOp(javascript_.Subtract(hints_), std::minus<double>()); } TEST_F(TyperTest, TypeJSMultiply) { - TestBinaryArithOp(javascript_.Multiply(LanguageMode::SLOPPY, hints_), - std::multiplies<double>()); - TestBinaryArithOp(javascript_.Multiply(LanguageMode::STRONG, hints_), - std::multiplies<double>()); + TestBinaryArithOp(javascript_.Multiply(hints_), std::multiplies<double>()); } TEST_F(TyperTest, TypeJSDivide) { - TestBinaryArithOp(javascript_.Divide(LanguageMode::SLOPPY, hints_), - std::divides<double>()); - TestBinaryArithOp(javascript_.Divide(LanguageMode::STRONG, hints_), - std::divides<double>()); + TestBinaryArithOp(javascript_.Divide(hints_), std::divides<double>()); } TEST_F(TyperTest, TypeJSModulus) { - TestBinaryArithOp(javascript_.Modulus(LanguageMode::SLOPPY, hints_), modulo); - TestBinaryArithOp(javascript_.Modulus(LanguageMode::STRONG, hints_), modulo); + TestBinaryArithOp(javascript_.Modulus(hints_), modulo); } TEST_F(TyperTest, TypeJSBitwiseOr) { - TestBinaryBitOp(javascript_.BitwiseOr(LanguageMode::SLOPPY, hints_), bit_or); - TestBinaryBitOp(javascript_.BitwiseOr(LanguageMode::STRONG, hints_), bit_or); + TestBinaryBitOp(javascript_.BitwiseOr(hints_), bit_or); } TEST_F(TyperTest, TypeJSBitwiseAnd) { - TestBinaryBitOp(javascript_.BitwiseAnd(LanguageMode::SLOPPY, hints_), - bit_and); - TestBinaryBitOp(javascript_.BitwiseAnd(LanguageMode::STRONG, hints_), - bit_and); + TestBinaryBitOp(javascript_.BitwiseAnd(hints_), bit_and); } TEST_F(TyperTest, TypeJSBitwiseXor) { - TestBinaryBitOp(javascript_.BitwiseXor(LanguageMode::SLOPPY, hints_), - bit_xor); - TestBinaryBitOp(javascript_.BitwiseXor(LanguageMode::STRONG, hints_), - bit_xor); + TestBinaryBitOp(javascript_.BitwiseXor(hints_), bit_xor); } TEST_F(TyperTest, TypeJSShiftLeft) { - TestBinaryBitOp(javascript_.ShiftLeft(LanguageMode::SLOPPY, hints_), - shift_left); - TestBinaryBitOp(javascript_.ShiftLeft(LanguageMode::STRONG, hints_), - shift_left); + TestBinaryBitOp(javascript_.ShiftLeft(hints_), shift_left); } TEST_F(TyperTest, TypeJSShiftRight) { - TestBinaryBitOp(javascript_.ShiftRight(LanguageMode::SLOPPY, hints_), - shift_right); - TestBinaryBitOp(javascript_.ShiftRight(LanguageMode::STRONG, hints_), - shift_right); + TestBinaryBitOp(javascript_.ShiftRight(hints_), shift_right); } TEST_F(TyperTest, TypeJSLessThan) { - TestBinaryCompareOp(javascript_.LessThan(LanguageMode::SLOPPY), - std::less<double>()); - TestBinaryCompareOp(javascript_.LessThan(LanguageMode::STRONG), - std::less<double>()); + TestBinaryCompareOp(javascript_.LessThan(), std::less<double>()); } TEST_F(TyperTest, TypeJSLessThanOrEqual) { - TestBinaryCompareOp(javascript_.LessThanOrEqual(LanguageMode::SLOPPY), - std::less_equal<double>()); - TestBinaryCompareOp(javascript_.LessThanOrEqual(LanguageMode::STRONG), - std::less_equal<double>()); + TestBinaryCompareOp(javascript_.LessThanOrEqual(), std::less_equal<double>()); } TEST_F(TyperTest, TypeJSGreaterThan) { - TestBinaryCompareOp(javascript_.GreaterThan(LanguageMode::SLOPPY), - std::greater<double>()); - TestBinaryCompareOp(javascript_.GreaterThan(LanguageMode::STRONG), - std::greater<double>()); + TestBinaryCompareOp(javascript_.GreaterThan(), std::greater<double>()); } TEST_F(TyperTest, TypeJSGreaterThanOrEqual) { - TestBinaryCompareOp(javascript_.GreaterThanOrEqual(LanguageMode::SLOPPY), - std::greater_equal<double>()); - TestBinaryCompareOp(javascript_.GreaterThanOrEqual(LanguageMode::STRONG), + TestBinaryCompareOp(javascript_.GreaterThanOrEqual(), std::greater_equal<double>()); } @@ -381,27 +344,15 @@ TEST_BINARY_MONOTONICITY(Equal) TEST_BINARY_MONOTONICITY(NotEqual) TEST_BINARY_MONOTONICITY(StrictEqual) TEST_BINARY_MONOTONICITY(StrictNotEqual) -#undef TEST_BINARY_MONOTONICITY - - -#define TEST_BINARY_MONOTONICITY(name) \ - TEST_F(TyperTest, Monotonicity_##name) { \ - TestBinaryMonotonicity(javascript_.name(LanguageMode::SLOPPY)); \ - TestBinaryMonotonicity(javascript_.name(LanguageMode::STRONG)); \ - } TEST_BINARY_MONOTONICITY(LessThan) TEST_BINARY_MONOTONICITY(GreaterThan) TEST_BINARY_MONOTONICITY(LessThanOrEqual) TEST_BINARY_MONOTONICITY(GreaterThanOrEqual) #undef TEST_BINARY_MONOTONICITY - -#define TEST_BINARY_MONOTONICITY(name) \ - TEST_F(TyperTest, Monotonicity_##name) { \ - TestBinaryMonotonicity( \ - javascript_.name(LanguageMode::SLOPPY, BinaryOperationHints::Any())); \ - TestBinaryMonotonicity( \ - javascript_.name(LanguageMode::STRONG, BinaryOperationHints::Any())); \ +#define TEST_BINARY_MONOTONICITY(name) \ + TEST_F(TyperTest, Monotonicity_##name) { \ + TestBinaryMonotonicity(javascript_.name(BinaryOperationHints::Any())); \ } TEST_BINARY_MONOTONICITY(BitwiseOr) TEST_BINARY_MONOTONICITY(BitwiseXor) diff --git a/deps/v8/test/unittests/heap/memory-reducer-unittest.cc b/deps/v8/test/unittests/heap/memory-reducer-unittest.cc index 1088f0127d..4787bc66d2 100644 --- a/deps/v8/test/unittests/heap/memory-reducer-unittest.cc +++ b/deps/v8/test/unittests/heap/memory-reducer-unittest.cc @@ -74,10 +74,9 @@ MemoryReducer::Event TimerEventPendingGC(double time_ms) { return TimerEvent(time_ms, true, false); } - -MemoryReducer::Event ContextDisposedEvent(double time_ms) { +MemoryReducer::Event PossibleGarbageEvent(double time_ms) { MemoryReducer::Event event; - event.type = MemoryReducer::kContextDisposed; + event.type = MemoryReducer::kPossibleGarbage; event.time_ms = time_ms; return event; } @@ -114,7 +113,7 @@ TEST(MemoryReducer, FromDoneToWait) { EXPECT_EQ(0, state1.started_gcs); EXPECT_EQ(2, state1.last_gc_time_ms); - state1 = MemoryReducer::Step(state0, ContextDisposedEvent(0)); + state1 = MemoryReducer::Step(state0, PossibleGarbageEvent(0)); EXPECT_EQ(MemoryReducer::kWait, state1.action); EXPECT_EQ(MemoryReducer::kLongDelayMs, state1.next_gc_start_ms); EXPECT_EQ(0, state1.started_gcs); @@ -127,7 +126,7 @@ TEST(MemoryReducer, FromWaitToWait) { MemoryReducer::State state0(WaitState(2, 1000.0)), state1(DoneState()); - state1 = MemoryReducer::Step(state0, ContextDisposedEvent(2000)); + state1 = MemoryReducer::Step(state0, PossibleGarbageEvent(2000)); EXPECT_EQ(MemoryReducer::kWait, state1.action); EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); EXPECT_EQ(state0.started_gcs, state1.started_gcs); @@ -250,7 +249,7 @@ TEST(MemoryReducer, FromRunToRun) { EXPECT_EQ(state0.started_gcs, state1.started_gcs); EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms); - state1 = MemoryReducer::Step(state0, ContextDisposedEvent(2000)); + state1 = MemoryReducer::Step(state0, PossibleGarbageEvent(2000)); EXPECT_EQ(MemoryReducer::kRun, state1.action); EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms); EXPECT_EQ(state0.started_gcs, state1.started_gcs); diff --git a/deps/v8/test/unittests/heap/slot-set-unittest.cc b/deps/v8/test/unittests/heap/slot-set-unittest.cc new file mode 100644 index 0000000000..376188915a --- /dev/null +++ b/deps/v8/test/unittests/heap/slot-set-unittest.cc @@ -0,0 +1,143 @@ +// Copyright 2016 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 <limits> + +#include "src/globals.h" +#include "src/heap/slot-set.h" +#include "src/heap/spaces.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace v8 { +namespace internal { + +TEST(SlotSet, InsertAndLookup1) { + SlotSet set; + set.SetPageStart(0); + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + EXPECT_FALSE(set.Lookup(i)); + } + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + set.Insert(i); + } + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + EXPECT_TRUE(set.Lookup(i)); + } +} + +TEST(SlotSet, InsertAndLookup2) { + SlotSet set; + set.SetPageStart(0); + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 7 == 0) { + set.Insert(i); + } + } + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 7 == 0) { + EXPECT_TRUE(set.Lookup(i)); + } else { + EXPECT_FALSE(set.Lookup(i)); + } + } +} + +TEST(SlotSet, Iterate) { + SlotSet set; + set.SetPageStart(0); + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 7 == 0) { + set.Insert(i); + } + } + + set.Iterate([](Address slot_address) { + uintptr_t intaddr = reinterpret_cast<uintptr_t>(slot_address); + if (intaddr % 3 == 0) { + return SlotSet::KEEP_SLOT; + } else { + return SlotSet::REMOVE_SLOT; + } + }); + + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 21 == 0) { + EXPECT_TRUE(set.Lookup(i)); + } else { + EXPECT_FALSE(set.Lookup(i)); + } + } +} + +TEST(SlotSet, Remove) { + SlotSet set; + set.SetPageStart(0); + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 7 == 0) { + set.Insert(i); + } + } + + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 3 != 0) { + set.Remove(i); + } + } + + for (int i = 0; i < Page::kPageSize; i += kPointerSize) { + if (i % 21 == 0) { + EXPECT_TRUE(set.Lookup(i)); + } else { + EXPECT_FALSE(set.Lookup(i)); + } + } +} + +void CheckRemoveRangeOn(uint32_t start, uint32_t end) { + SlotSet set; + set.SetPageStart(0); + uint32_t first = start == 0 ? 0 : start - kPointerSize; + uint32_t last = end == Page::kPageSize ? end - kPointerSize : end; + for (uint32_t i = first; i <= last; i += kPointerSize) { + set.Insert(i); + } + set.RemoveRange(start, end); + if (first != start) { + EXPECT_TRUE(set.Lookup(first)); + } + if (last == end) { + EXPECT_TRUE(set.Lookup(last)); + } + for (uint32_t i = start; i < end; i += kPointerSize) { + EXPECT_FALSE(set.Lookup(i)); + } +} + +TEST(SlotSet, RemoveRange) { + CheckRemoveRangeOn(0, Page::kPageSize); + CheckRemoveRangeOn(1 * kPointerSize, 1023 * kPointerSize); + for (uint32_t start = 0; start <= 32; start++) { + CheckRemoveRangeOn(start * kPointerSize, (start + 1) * kPointerSize); + CheckRemoveRangeOn(start * kPointerSize, (start + 2) * kPointerSize); + const uint32_t kEnds[] = {32, 64, 100, 128, 1024, 1500, 2048}; + for (int i = 0; i < sizeof(kEnds) / sizeof(uint32_t); i++) { + for (int k = -3; k <= 3; k++) { + uint32_t end = (kEnds[i] + k); + if (start < end) { + CheckRemoveRangeOn(start * kPointerSize, end * kPointerSize); + } + } + } + } + SlotSet set; + set.SetPageStart(0); + set.Insert(Page::kPageSize / 2); + set.RemoveRange(0, Page::kPageSize); + for (uint32_t i = 0; i < Page::kPageSize; i += kPointerSize) { + EXPECT_FALSE(set.Lookup(i)); + } +} + +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc index 2140aa83c7..839215f743 100644 --- a/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecode-array-builder-unittest.cc @@ -21,14 +21,16 @@ class BytecodeArrayBuilderTest : public TestWithIsolateAndZone { TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { - BytecodeArrayBuilder builder(isolate(), zone()); + BytecodeArrayBuilder builder(isolate(), zone(), 0, 1, 131); - builder.set_locals_count(200); - builder.set_context_count(1); - builder.set_parameter_count(0); - CHECK_EQ(builder.locals_count(), 200); + CHECK_EQ(builder.locals_count(), 131); CHECK_EQ(builder.context_count(), 1); - CHECK_EQ(builder.fixed_register_count(), 201); + CHECK_EQ(builder.fixed_register_count(), 132); + + // Emit argument creation operations. + builder.CreateArguments(CreateArgumentsType::kMappedArguments) + .CreateArguments(CreateArgumentsType::kUnmappedArguments) + .CreateArguments(CreateArgumentsType::kRestParameter); // Emit constant loads. builder.LoadLiteral(Smi::FromInt(0)) @@ -40,32 +42,23 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .LoadTrue() .LoadFalse(); - // Emit accumulator transfers. Stores followed by loads to the same register - // are not generated. Hence, a dummy instruction in between. Register reg(0); + Register other(reg.index() + 1); + Register wide(128); + builder.LoadAccumulatorWithRegister(reg) .LoadNull() .StoreAccumulatorInRegister(reg); // Emit register-register transfer. - Register other(1); builder.MoveRegister(reg, other); - - // Emit register-register exchanges. - Register wide(150); - builder.ExchangeRegisters(reg, wide); - builder.ExchangeRegisters(wide, reg); - Register wider(151); - builder.ExchangeRegisters(wide, wider); + builder.MoveRegister(reg, wide); // Emit global load / store operations. Factory* factory = isolate()->factory(); Handle<String> name = factory->NewStringFromStaticChars("var_name"); - builder.LoadGlobal(name, 1, LanguageMode::SLOPPY, - TypeofMode::NOT_INSIDE_TYPEOF) - .LoadGlobal(name, 1, LanguageMode::STRICT, TypeofMode::NOT_INSIDE_TYPEOF) - .LoadGlobal(name, 1, LanguageMode::SLOPPY, TypeofMode::INSIDE_TYPEOF) - .LoadGlobal(name, 1, LanguageMode::STRICT, TypeofMode::INSIDE_TYPEOF) + builder.LoadGlobal(name, 1, TypeofMode::NOT_INSIDE_TYPEOF) + .LoadGlobal(name, 1, TypeofMode::INSIDE_TYPEOF) .StoreGlobal(name, 1, LanguageMode::SLOPPY) .StoreGlobal(name, 1, LanguageMode::STRICT); @@ -76,12 +69,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .StoreContextSlot(reg, 1); // Emit load / store property operations. - builder.LoadNamedProperty(reg, name, 0, LanguageMode::SLOPPY) - .LoadKeyedProperty(reg, 0, LanguageMode::SLOPPY) + builder.LoadNamedProperty(reg, name, 0) + .LoadKeyedProperty(reg, 0) .StoreNamedProperty(reg, name, 0, LanguageMode::SLOPPY) .StoreKeyedProperty(reg, reg, 0, LanguageMode::SLOPPY) - .LoadNamedProperty(reg, name, 0, LanguageMode::STRICT) - .LoadKeyedProperty(reg, 0, LanguageMode::STRICT) .StoreNamedProperty(reg, name, 0, LanguageMode::STRICT) .StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT); @@ -97,65 +88,64 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { false); builder.CreateClosure(shared_info, NOT_TENURED); - // Emit argument creation operations. - builder.CreateArguments(CreateArgumentsType::kMappedArguments) - .CreateArguments(CreateArgumentsType::kUnmappedArguments); - // Emit literal creation operations. builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("a"), 0, 0) .CreateArrayLiteral(factory->NewFixedArray(1), 0, 0) .CreateObjectLiteral(factory->NewFixedArray(1), 0, 0); // Call operations. - builder.Call(reg, reg, 0, 0) - .Call(reg, reg, 0, 1024) + builder.Call(reg, other, 1, 0) + .Call(reg, wide, 1, 0) + .TailCall(reg, other, 1, 0) + .TailCall(reg, wide, 1, 0) .CallRuntime(Runtime::kIsArray, reg, 1) - .CallRuntimeForPair(Runtime::kLoadLookupSlot, reg, 1, reg) - .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1); + .CallRuntime(Runtime::kIsArray, wide, 1) + .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg, 1, other) + .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, wide, 1, other) + .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1) + .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, wide, 1); // Emit binary operator invocations. - builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) - .BinaryOperation(Token::Value::SUB, reg, Strength::WEAK) - .BinaryOperation(Token::Value::MUL, reg, Strength::WEAK) - .BinaryOperation(Token::Value::DIV, reg, Strength::WEAK) - .BinaryOperation(Token::Value::MOD, reg, Strength::WEAK); + builder.BinaryOperation(Token::Value::ADD, reg) + .BinaryOperation(Token::Value::SUB, reg) + .BinaryOperation(Token::Value::MUL, reg) + .BinaryOperation(Token::Value::DIV, reg) + .BinaryOperation(Token::Value::MOD, reg); // Emit bitwise operator invocations - builder.BinaryOperation(Token::Value::BIT_OR, reg, Strength::WEAK) - .BinaryOperation(Token::Value::BIT_XOR, reg, Strength::WEAK) - .BinaryOperation(Token::Value::BIT_AND, reg, Strength::WEAK); + builder.BinaryOperation(Token::Value::BIT_OR, reg) + .BinaryOperation(Token::Value::BIT_XOR, reg) + .BinaryOperation(Token::Value::BIT_AND, reg); // Emit shift operator invocations - builder.BinaryOperation(Token::Value::SHL, reg, Strength::WEAK) - .BinaryOperation(Token::Value::SAR, reg, Strength::WEAK) - .BinaryOperation(Token::Value::SHR, reg, Strength::WEAK); + builder.BinaryOperation(Token::Value::SHL, reg) + .BinaryOperation(Token::Value::SAR, reg) + .BinaryOperation(Token::Value::SHR, reg); // Emit count operatior invocations - builder.CountOperation(Token::Value::ADD, Strength::WEAK) - .CountOperation(Token::Value::SUB, Strength::WEAK); + builder.CountOperation(Token::Value::ADD).CountOperation(Token::Value::SUB); // Emit unary operator invocations. builder.LogicalNot().TypeOf(); // Emit delete - builder.Delete(reg, LanguageMode::SLOPPY) - .Delete(reg, LanguageMode::STRICT) - .DeleteLookupSlot(); + builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT); // Emit new. builder.New(reg, reg, 0); + builder.New(wide, wide, 0); // Emit test operator invocations. - builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) - .CompareOperation(Token::Value::NE, reg, Strength::WEAK) - .CompareOperation(Token::Value::EQ_STRICT, reg, Strength::WEAK) - .CompareOperation(Token::Value::NE_STRICT, reg, Strength::WEAK) - .CompareOperation(Token::Value::LT, reg, Strength::WEAK) - .CompareOperation(Token::Value::GT, reg, Strength::WEAK) - .CompareOperation(Token::Value::LTE, reg, Strength::WEAK) - .CompareOperation(Token::Value::GTE, reg, Strength::WEAK) - .CompareOperation(Token::Value::INSTANCEOF, reg, Strength::WEAK) - .CompareOperation(Token::Value::IN, reg, Strength::WEAK); + builder.CompareOperation(Token::Value::EQ, reg) + .CompareOperation(Token::Value::NE, reg) + .CompareOperation(Token::Value::EQ_STRICT, reg) + .CompareOperation(Token::Value::NE_STRICT, reg) + .CompareOperation(Token::Value::LT, reg) + .CompareOperation(Token::Value::GT, reg) + .CompareOperation(Token::Value::LTE, reg) + .CompareOperation(Token::Value::GTE, reg) + .CompareOperation(Token::Value::INSTANCEOF, reg) + .CompareOperation(Token::Value::IN, reg); // Emit cast operator invocations. builder.CastAccumulatorToNumber() @@ -168,50 +158,58 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { // Short jumps with Imm8 operands builder.Jump(&start) .JumpIfNull(&start) - .JumpIfUndefined(&start); + .JumpIfUndefined(&start) + .JumpIfNotHole(&start); + // Perform an operation that returns boolean value to // generate JumpIfTrue/False - builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + builder.CompareOperation(Token::Value::EQ, reg) .JumpIfTrue(&start) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfFalse(&start); // Perform an operation that returns a non-boolean operation to // generate JumpIfToBooleanTrue/False. - builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + builder.BinaryOperation(Token::Value::ADD, reg) .JumpIfTrue(&start) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfFalse(&start); // Insert dummy ops to force longer jumps for (int i = 0; i < 128; i++) { builder.LoadTrue(); } // Longer jumps requiring Constant operand - builder.Jump(&start) - .JumpIfNull(&start) - .JumpIfUndefined(&start); + builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start).JumpIfNotHole( + &start); // Perform an operation that returns boolean value to // generate JumpIfTrue/False - builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + builder.CompareOperation(Token::Value::EQ, reg) .JumpIfTrue(&start) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfFalse(&start); // Perform an operation that returns a non-boolean operation to // generate JumpIfToBooleanTrue/False. - builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + builder.BinaryOperation(Token::Value::ADD, reg) .JumpIfTrue(&start) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfFalse(&start); - // Emit throw in it's own basic block so that the rest of the code isn't - // omitted due to being dead. + // Emit stack check bytecode. + builder.StackCheck(); + + // Emit throw and re-throw in it's own basic block so that the rest of the + // code isn't omitted due to being dead. BytecodeLabel after_throw; - builder.Jump(&after_throw) - .Throw() - .Bind(&after_throw); + builder.Jump(&after_throw).Throw().Bind(&after_throw); + BytecodeLabel after_rethrow; + builder.Jump(&after_rethrow).ReThrow().Bind(&after_rethrow); - builder.ForInPrepare(reg, reg, reg) + builder.ForInPrepare(reg) .ForInDone(reg, reg) - .ForInNext(reg, reg, reg, reg) + .ForInNext(reg, reg, reg) + .ForInStep(reg); + builder.ForInPrepare(wide) + .ForInDone(reg, other) + .ForInNext(wide, wide, wide) .ForInStep(reg); // Wide constant pool loads @@ -223,28 +221,21 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { Handle<String> wide_name = factory->NewStringFromStaticChars("var_wide_name"); // Emit wide global load / store operations. - builder.LoadGlobal(name, 1024, LanguageMode::SLOPPY, - TypeofMode::NOT_INSIDE_TYPEOF) - .LoadGlobal(wide_name, 1, LanguageMode::STRICT, - TypeofMode::NOT_INSIDE_TYPEOF) - .LoadGlobal(name, 1024, LanguageMode::SLOPPY, TypeofMode::INSIDE_TYPEOF) - .LoadGlobal(wide_name, 1, LanguageMode::STRICT, TypeofMode::INSIDE_TYPEOF) + builder.LoadGlobal(name, 1024, TypeofMode::NOT_INSIDE_TYPEOF) + .LoadGlobal(name, 1024, TypeofMode::INSIDE_TYPEOF) .StoreGlobal(name, 1024, LanguageMode::SLOPPY) .StoreGlobal(wide_name, 1, LanguageMode::STRICT); // Emit wide load / store property operations. - builder.LoadNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY) - .LoadKeyedProperty(reg, 2056, LanguageMode::SLOPPY) + builder.LoadNamedProperty(reg, wide_name, 0) + .LoadKeyedProperty(reg, 2056) .StoreNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY) .StoreKeyedProperty(reg, reg, 2056, LanguageMode::SLOPPY) - .LoadNamedProperty(reg, wide_name, 0, LanguageMode::STRICT) - .LoadKeyedProperty(reg, 2056, LanguageMode::STRICT) .StoreNamedProperty(reg, wide_name, 0, LanguageMode::STRICT) .StoreKeyedProperty(reg, reg, 2056, LanguageMode::STRICT); // Emit wide context operations. - builder.LoadContextSlot(reg, 1024) - .StoreContextSlot(reg, 1024); + builder.LoadContextSlot(reg, 1024).StoreContextSlot(reg, 1024); // Emit wide load / store lookup slots. builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF) @@ -265,26 +256,31 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .CreateObjectLiteral(factory->NewFixedArray(2), 0, 0); // Longer jumps requiring ConstantWide operand - builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start); + builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start).JumpIfNotHole( + &start); // Perform an operation that returns boolean value to // generate JumpIfTrue/False - builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + builder.CompareOperation(Token::Value::EQ, reg) .JumpIfTrue(&start) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfFalse(&start); // Perform an operation that returns a non-boolean operation to // generate JumpIfToBooleanTrue/False. - builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + builder.BinaryOperation(Token::Value::ADD, reg) .JumpIfTrue(&start) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfFalse(&start); + builder.Debugger(); + builder.Return(); // Generate BytecodeArray. Handle<BytecodeArray> the_array = builder.ToBytecodeArray(); CHECK_EQ(the_array->frame_size(), - builder.fixed_register_count() * kPointerSize); + (builder.fixed_and_temporary_register_count() + + builder.translation_register_count()) * + kPointerSize); // Build scorecard of bytecodes encountered in the BytecodeArray. std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1); @@ -301,9 +297,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { CHECK_EQ(final_bytecode, Bytecode::kReturn); CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1); -#define CHECK_BYTECODE_PRESENT(Name, ...) \ - /* Check Bytecode is marked in scorecard */ \ - CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1); +#define CHECK_BYTECODE_PRESENT(Name, ...) \ + /* Check Bytecode is marked in scorecard, unless it's a debug break */ \ + if (!Bytecodes::IsDebugBreak(Bytecode::k##Name)) { \ + CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1); \ + } BYTECODE_LIST(CHECK_BYTECODE_PRESENT) #undef CHECK_BYTECODE_PRESENT } @@ -313,12 +311,9 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { for (int locals = 0; locals < 5; locals++) { for (int contexts = 0; contexts < 4; contexts++) { for (int temps = 0; temps < 3; temps++) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(locals); - builder.set_context_count(contexts); - - BytecodeRegisterAllocator temporaries(&builder); + BytecodeArrayBuilder builder(isolate(), zone(), 0, contexts, locals); + BytecodeRegisterAllocator temporaries( + zone(), builder.temporary_register_allocator()); for (int i = 0; i < temps; i++) { builder.StoreAccumulatorInRegister(temporaries.NewRegister()); } @@ -349,11 +344,7 @@ TEST_F(BytecodeArrayBuilderTest, RegisterValues) { TEST_F(BytecodeArrayBuilderTest, Parameters) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(10); - builder.set_locals_count(0); - builder.set_context_count(0); - + BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 0); Register param0(builder.Parameter(0)); Register param9(builder.Parameter(9)); CHECK_EQ(param9.index() - param0.index(), 9); @@ -361,12 +352,9 @@ TEST_F(BytecodeArrayBuilderTest, Parameters) { TEST_F(BytecodeArrayBuilderTest, RegisterType) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(10); - builder.set_locals_count(3); - builder.set_context_count(0); - - BytecodeRegisterAllocator register_allocator(&builder); + BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 3); + BytecodeRegisterAllocator register_allocator( + zone(), builder.temporary_register_allocator()); Register temp0 = register_allocator.NewRegister(); Register param0(builder.Parameter(0)); Register param9(builder.Parameter(9)); @@ -387,11 +375,7 @@ TEST_F(BytecodeArrayBuilderTest, RegisterType) { TEST_F(BytecodeArrayBuilderTest, Constants) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(0); - builder.set_context_count(0); - + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); Factory* factory = isolate()->factory(); Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14); Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2); @@ -402,7 +386,8 @@ TEST_F(BytecodeArrayBuilderTest, Constants) { .LoadLiteral(large_smi) .LoadLiteral(heap_num_1) .LoadLiteral(heap_num_1) - .LoadLiteral(heap_num_2_copy); + .LoadLiteral(heap_num_2_copy) + .Return(); Handle<BytecodeArray> array = builder.ToBytecodeArray(); // Should only have one entry for each identical constant. @@ -413,23 +398,19 @@ TEST_F(BytecodeArrayBuilderTest, Constants) { TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { static const int kFarJumpDistance = 256; - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(1); - builder.set_context_count(0); - + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1); Register reg(0); BytecodeLabel far0, far1, far2, far3, far4; BytecodeLabel near0, near1, near2, near3, near4; builder.Jump(&near0) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfTrue(&near1) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfFalse(&near2) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfTrue(&near3) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfFalse(&near4) .Bind(&near0) .Bind(&near1) @@ -437,13 +418,13 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { .Bind(&near3) .Bind(&near4) .Jump(&far0) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfTrue(&far1) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfFalse(&far2) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfTrue(&far3) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfFalse(&far4); for (int i = 0; i < kFarJumpDistance - 18; i++) { builder.LoadUndefined(); @@ -529,38 +510,31 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(1); - builder.set_context_count(0); + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1); Register reg(0); BytecodeLabel label0, label1, label2, label3, label4; builder.Bind(&label0) .Jump(&label0) .Bind(&label1) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfTrue(&label1) .Bind(&label2) - .CompareOperation(Token::Value::EQ, reg, Strength::WEAK) + .CompareOperation(Token::Value::EQ, reg) .JumpIfFalse(&label2) .Bind(&label3) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfTrue(&label3) .Bind(&label4) - .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) + .BinaryOperation(Token::Value::ADD, reg) .JumpIfFalse(&label4); for (int i = 0; i < 63; i++) { builder.Jump(&label4); } - builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) - .JumpIfFalse(&label4); - builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK) - .JumpIfTrue(&label3); - builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) - .JumpIfFalse(&label2); - builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK) - .JumpIfTrue(&label1); + builder.BinaryOperation(Token::Value::ADD, reg).JumpIfFalse(&label4); + builder.BinaryOperation(Token::Value::ADD, reg).JumpIfTrue(&label3); + builder.CompareOperation(Token::Value::EQ, reg).JumpIfFalse(&label2); + builder.CompareOperation(Token::Value::EQ, reg).JumpIfTrue(&label1); builder.Jump(&label0); builder.Return(); @@ -625,10 +599,7 @@ TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { TEST_F(BytecodeArrayBuilderTest, LabelReuse) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(0); - builder.set_context_count(0); + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); // Labels can only have 1 forward reference, but // can be referred to mulitple times once bound. @@ -656,16 +627,11 @@ TEST_F(BytecodeArrayBuilderTest, LabelReuse) { TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) { static const int kRepeats = 3; - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(0); - builder.set_context_count(0); - + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); for (int i = 0; i < kRepeats; i++) { BytecodeLabel label; builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label); } - builder.Return(); Handle<BytecodeArray> array = builder.ToBytecodeArray(); @@ -686,7 +652,6 @@ TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) { CHECK(iterator.done()); } - } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/interpreter/bytecode-array-iterator-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-array-iterator-unittest.cc index cd9f120cad..f2dcd7107c 100644 --- a/deps/v8/test/unittests/interpreter/bytecode-array-iterator-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecode-array-iterator-unittest.cc @@ -22,11 +22,7 @@ class BytecodeArrayIteratorTest : public TestWithIsolateAndZone { TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { // Use a builder to create an array with containing multiple bytecodes // with 0, 1 and 2 operands. - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(3); - builder.set_locals_count(2); - builder.set_context_count(0); - + BytecodeArrayBuilder builder(isolate(), zone(), 3, 2, 0); Factory* factory = isolate()->factory(); Handle<HeapObject> heap_num_0 = factory->NewHeapNumber(2.718); Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(2147483647); @@ -46,9 +42,10 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { .LoadLiteral(smi_0) .LoadLiteral(smi_1) .LoadAccumulatorWithRegister(reg_0) - .LoadNamedProperty(reg_1, name, feedback_slot, LanguageMode::SLOPPY) + .LoadNamedProperty(reg_1, name, feedback_slot) .StoreAccumulatorInRegister(reg_2) .CallRuntime(Runtime::kLoadIC_Miss, reg_0, 1) + .Debugger() .Return(); // Test iterator sees the expected output from the builder. @@ -82,7 +79,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { CHECK(!iterator.done()); iterator.Advance(); - CHECK_EQ(iterator.current_bytecode(), Bytecode::kLoadICSloppy); + CHECK_EQ(iterator.current_bytecode(), Bytecode::kLoadIC); CHECK_EQ(iterator.GetRegisterOperand(0).index(), reg_1.index()); CHECK_EQ(iterator.GetIndexOperand(1), name_index); CHECK_EQ(iterator.GetIndexOperand(2), feedback_slot); @@ -98,7 +95,11 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { CHECK_EQ(static_cast<Runtime::FunctionId>(iterator.GetIndexOperand(0)), Runtime::kLoadIC_Miss); CHECK_EQ(iterator.GetRegisterOperand(1).index(), reg_0.index()); - CHECK_EQ(iterator.GetCountOperand(2), 1); + CHECK_EQ(iterator.GetRegisterCountOperand(2), 1); + CHECK(!iterator.done()); + iterator.Advance(); + + CHECK_EQ(iterator.current_bytecode(), Bytecode::kDebugger); CHECK(!iterator.done()); iterator.Advance(); diff --git a/deps/v8/test/unittests/interpreter/bytecode-register-allocator-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-register-allocator-unittest.cc index 0620322162..ec29935b2f 100644 --- a/deps/v8/test/unittests/interpreter/bytecode-register-allocator-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecode-register-allocator-unittest.cc @@ -12,51 +12,219 @@ namespace v8 { namespace internal { namespace interpreter { +class TemporaryRegisterAllocatorTest : public TestWithIsolateAndZone { + public: + TemporaryRegisterAllocatorTest() : allocator_(zone(), 0) {} + ~TemporaryRegisterAllocatorTest() override {} + TemporaryRegisterAllocator* allocator() { return &allocator_; } + + private: + TemporaryRegisterAllocator allocator_; +}; + +TEST_F(TemporaryRegisterAllocatorTest, FirstAllocation) { + CHECK_EQ(allocator()->allocation_count(), 0); + int reg0_index = allocator()->BorrowTemporaryRegister(); + CHECK_EQ(reg0_index, 0); + CHECK_EQ(allocator()->allocation_count(), 1); + CHECK(allocator()->RegisterIsLive(Register(reg0_index))); + allocator()->ReturnTemporaryRegister(reg0_index); + CHECK(!allocator()->RegisterIsLive(Register(reg0_index))); + CHECK_EQ(allocator()->allocation_count(), 1); + CHECK(allocator()->first_temporary_register() == Register(0)); + CHECK(allocator()->last_temporary_register() == Register(0)); +} + +TEST_F(TemporaryRegisterAllocatorTest, SimpleAllocations) { + for (int i = 0; i < 13; i++) { + int reg_index = allocator()->BorrowTemporaryRegister(); + CHECK_EQ(reg_index, i); + CHECK_EQ(allocator()->allocation_count(), i + 1); + } + for (int i = 0; i < 13; i++) { + CHECK(allocator()->RegisterIsLive(Register(i))); + allocator()->ReturnTemporaryRegister(i); + CHECK(!allocator()->RegisterIsLive(Register(i))); + int reg_index = allocator()->BorrowTemporaryRegister(); + CHECK_EQ(reg_index, i); + CHECK_EQ(allocator()->allocation_count(), 13); + } + for (int i = 0; i < 13; i++) { + CHECK(allocator()->RegisterIsLive(Register(i))); + allocator()->ReturnTemporaryRegister(i); + CHECK(!allocator()->RegisterIsLive(Register(i))); + } +} + +TEST_F(TemporaryRegisterAllocatorTest, SimpleRangeAllocation) { + static const int kRunLength = 7; + int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); + CHECK(!allocator()->RegisterIsLive(Register(start))); + for (int i = 0; i < kRunLength; i++) { + CHECK(!allocator()->RegisterIsLive(Register(start + i))); + allocator()->BorrowConsecutiveTemporaryRegister(start + i); + CHECK(allocator()->RegisterIsLive(Register(start + i))); + } +} + +TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAbuttingFree) { + static const int kFreeCount = 3; + static const int kRunLength = 6; + + for (int i = 0; i < kFreeCount; i++) { + int to_free = allocator()->BorrowTemporaryRegister(); + CHECK_EQ(to_free, i); + } + for (int i = 0; i < kFreeCount; i++) { + allocator()->ReturnTemporaryRegister(i); + } + + int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); + CHECK(!allocator()->RegisterIsLive(Register(start))); + for (int i = 0; i < kRunLength; i++) { + CHECK(!allocator()->RegisterIsLive(Register(start + i))); + allocator()->BorrowConsecutiveTemporaryRegister(start + i); + CHECK(allocator()->RegisterIsLive(Register(start + i))); + } +} + +TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAbuttingHole) { + static const int kPreAllocatedCount = 7; + static const int kPreAllocatedFreeCount = 6; + static const int kRunLength = 8; + + for (int i = 0; i < kPreAllocatedCount; i++) { + int to_free = allocator()->BorrowTemporaryRegister(); + CHECK_EQ(to_free, i); + } + for (int i = 0; i < kPreAllocatedFreeCount; i++) { + allocator()->ReturnTemporaryRegister(i); + } + int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); + CHECK(!allocator()->RegisterIsLive(Register(start))); + CHECK_EQ(start, kPreAllocatedCount); + for (int i = 0; i < kRunLength; i++) { + CHECK(!allocator()->RegisterIsLive(Register(start + i))); + allocator()->BorrowConsecutiveTemporaryRegister(start + i); + CHECK(allocator()->RegisterIsLive(Register(start + i))); + } +} + +TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAvailableInTemporaries) { + static const int kNotRunLength = 13; + static const int kRunLength = 8; + + // Allocate big batch + for (int i = 0; i < kNotRunLength * 2 + kRunLength; i++) { + int allocated = allocator()->BorrowTemporaryRegister(); + CHECK_EQ(allocated, i); + } + // Free every other register either side of target. + for (int i = 0; i < kNotRunLength; i++) { + if ((i & 2) == 1) { + allocator()->ReturnTemporaryRegister(i); + allocator()->ReturnTemporaryRegister(kNotRunLength + kRunLength + i); + } + } + // Free all registers for target. + for (int i = kNotRunLength; i < kNotRunLength + kRunLength; i++) { + allocator()->ReturnTemporaryRegister(i); + } + + int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); + CHECK_EQ(start, kNotRunLength); + for (int i = 0; i < kRunLength; i++) { + CHECK(!allocator()->RegisterIsLive(Register(start + i))); + allocator()->BorrowConsecutiveTemporaryRegister(start + i); + CHECK(allocator()->RegisterIsLive(Register(start + i))); + } +} + +TEST_F(TemporaryRegisterAllocatorTest, RangeAvoidsTranslationBoundary) { + int boundary = RegisterTranslator::DistanceToTranslationWindow(Register(0)); + int limit = boundary + 64; + + for (int run_length = 2; run_length < 32; run_length += 7) { + ZoneVector<int> run_starts(zone()); + for (int start = 0; start < limit; start += run_length) { + int run_start = + allocator()->PrepareForConsecutiveTemporaryRegisters(run_length); + run_starts.push_back(run_start); + for (int i = 0; i < run_length; i++) { + allocator()->BorrowConsecutiveTemporaryRegister(run_start + i); + } + CHECK(run_start >= boundary || run_start + run_length <= boundary); + } + for (size_t batch = 0; batch < run_starts.size(); batch++) { + for (int i = run_starts[batch]; i < run_starts[batch] + run_length; i++) { + allocator()->ReturnTemporaryRegister(i); + } + } + } +} + +TEST_F(TemporaryRegisterAllocatorTest, NotInRange) { + for (int i = 0; i < 10; i++) { + int reg = allocator()->BorrowTemporaryRegisterNotInRange(2, 5); + CHECK(reg == i || (reg > 2 && reg == i + 4)); + } + for (int i = 0; i < 10; i++) { + if (i < 2) { + allocator()->ReturnTemporaryRegister(i); + } else { + allocator()->ReturnTemporaryRegister(i + 4); + } + } + int reg0 = allocator()->BorrowTemporaryRegisterNotInRange(0, 3); + CHECK_EQ(reg0, 4); + int reg1 = allocator()->BorrowTemporaryRegisterNotInRange(3, 10); + CHECK_EQ(reg1, 2); + int reg2 = allocator()->BorrowTemporaryRegisterNotInRange(2, 6); + CHECK_EQ(reg2, 1); + allocator()->ReturnTemporaryRegister(reg0); + allocator()->ReturnTemporaryRegister(reg1); + allocator()->ReturnTemporaryRegister(reg2); +} + class BytecodeRegisterAllocatorTest : public TestWithIsolateAndZone { public: BytecodeRegisterAllocatorTest() {} ~BytecodeRegisterAllocatorTest() override {} }; - TEST_F(BytecodeRegisterAllocatorTest, TemporariesRecycled) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(0); - builder.set_context_count(0); + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); int first; { - BytecodeRegisterAllocator temporaries(&builder); - first = temporaries.NewRegister().index(); - temporaries.NewRegister(); - temporaries.NewRegister(); - temporaries.NewRegister(); + BytecodeRegisterAllocator allocator(zone(), + builder.temporary_register_allocator()); + first = allocator.NewRegister().index(); + allocator.NewRegister(); + allocator.NewRegister(); + allocator.NewRegister(); } int second; { - BytecodeRegisterAllocator temporaries(&builder); - second = temporaries.NewRegister().index(); + BytecodeRegisterAllocator allocator(zone(), + builder.temporary_register_allocator()); + second = allocator.NewRegister().index(); } CHECK_EQ(first, second); } - TEST_F(BytecodeRegisterAllocatorTest, ConsecutiveRegisters) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(0); - builder.set_context_count(0); - - BytecodeRegisterAllocator temporaries(&builder); - temporaries.PrepareForConsecutiveAllocations(4); - Register reg0 = temporaries.NextConsecutiveRegister(); - Register other = temporaries.NewRegister(); - Register reg1 = temporaries.NextConsecutiveRegister(); - Register reg2 = temporaries.NextConsecutiveRegister(); - Register reg3 = temporaries.NextConsecutiveRegister(); + BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); + BytecodeRegisterAllocator allocator(zone(), + builder.temporary_register_allocator()); + allocator.PrepareForConsecutiveAllocations(4); + Register reg0 = allocator.NextConsecutiveRegister(); + Register other = allocator.NewRegister(); + Register reg1 = allocator.NextConsecutiveRegister(); + Register reg2 = allocator.NextConsecutiveRegister(); + Register reg3 = allocator.NextConsecutiveRegister(); USE(other); CHECK(Register::AreContiguous(reg0, reg1, reg2, reg3)); diff --git a/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc b/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc index 812ee46c9c..212e02996b 100644 --- a/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc +++ b/deps/v8/test/unittests/interpreter/bytecodes-unittest.cc @@ -9,19 +9,39 @@ #include "src/interpreter/bytecodes.h" #include "test/unittests/test-utils.h" - namespace v8 { namespace internal { namespace interpreter { TEST(OperandConversion, Registers) { - for (int i = 0; i < 128; i++) { - uint8_t operand_value = Register(i).ToOperand(); - Register r = Register::FromOperand(operand_value); - CHECK_EQ(i, r.index()); + int register_count = Register::MaxRegisterIndex() + 1; + int step = register_count / 7; + for (int i = 0; i < register_count; i += step) { + if (i <= kMaxInt8) { + uint8_t operand0 = Register(i).ToOperand(); + Register reg0 = Register::FromOperand(operand0); + CHECK_EQ(i, reg0.index()); + } + + uint16_t operand1 = Register(i).ToWideOperand(); + Register reg1 = Register::FromWideOperand(operand1); + CHECK_EQ(i, reg1.index()); + + uint32_t operand2 = Register(i).ToRawOperand(); + Register reg2 = Register::FromRawOperand(operand2); + CHECK_EQ(i, reg2.index()); } -} + for (int i = 0; i <= kMaxUInt8; i++) { + uint8_t operand = static_cast<uint8_t>(i); + Register reg = Register::FromOperand(operand); + if (i > 0 && i < -kMinInt8) { + CHECK(reg.is_parameter()); + } else { + CHECK(!reg.is_parameter()); + } + } +} TEST(OperandConversion, Parameters) { int parameter_counts[] = {7, 13, 99}; @@ -38,26 +58,115 @@ TEST(OperandConversion, Parameters) { } } - TEST(OperandConversion, RegistersParametersNoOverlap) { - std::vector<uint8_t> operand_count(256); + int register_count = Register::MaxRegisterIndex() + 1; + int parameter_count = Register::MaxParameterIndex() + 1; + int32_t register_space_size = base::bits::RoundUpToPowerOfTwo32( + static_cast<uint32_t>(register_count + parameter_count)); + uint32_t range = static_cast<uint32_t>(register_space_size); + std::vector<uint8_t> operand_count(range); - for (int i = 0; i <= kMaxInt8; i++) { + for (int i = 0; i < register_count; i += 1) { Register r = Register(i); - uint8_t operand = r.ToOperand(); + uint32_t operand = r.ToWideOperand(); + CHECK_LT(operand, operand_count.size()); operand_count[operand] += 1; CHECK_EQ(operand_count[operand], 1); } - int parameter_count = Register::MaxParameterIndex() + 1; - for (int i = 0; i < parameter_count; i++) { + for (int i = 0; i < parameter_count; i += 1) { Register r = Register::FromParameterIndex(i, parameter_count); - uint8_t operand = r.ToOperand(); + uint32_t operand = r.ToWideOperand(); + CHECK_LT(operand, operand_count.size()); operand_count[operand] += 1; CHECK_EQ(operand_count[operand], 1); } } +TEST(Bytecodes, HasAnyRegisterOperands) { + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kAdd), 1); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kCall), 2); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kCallRuntime), 1); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kCallRuntimeWide), 1); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kCallRuntimeForPair), + 2); + CHECK_EQ( + Bytecodes::NumberOfRegisterOperands(Bytecode::kCallRuntimeForPairWide), + 2); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kDeletePropertyStrict), + 1); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kForInPrepare), 1); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kForInPrepareWide), 1); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kInc), 0); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kJumpIfTrue), 0); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kNew), 2); + CHECK_EQ(Bytecodes::NumberOfRegisterOperands(Bytecode::kToName), 0); +} + +TEST(Bytecodes, RegisterOperandBitmaps) { + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kAdd), 1); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kCallRuntimeForPair), + 10); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kStar), 1); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kMov), 3); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kTestIn), 1); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kForInPrepare), 1); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kForInDone), 3); + CHECK_EQ(Bytecodes::GetRegisterOperandBitmap(Bytecode::kForInNext), 7); +} + +TEST(Bytecodes, RegisterOperands) { + CHECK(Bytecodes::IsRegisterOperandType(OperandType::kReg8)); + CHECK(Bytecodes::IsRegisterInputOperandType(OperandType::kReg8)); + CHECK(!Bytecodes::IsRegisterOutputOperandType(OperandType::kReg8)); + CHECK(!Bytecodes::IsRegisterInputOperandType(OperandType::kRegOut8)); + CHECK(Bytecodes::IsRegisterOutputOperandType(OperandType::kRegOut8)); + +#define IS_REGISTER_OPERAND_TYPE(Name, _) \ + CHECK(Bytecodes::IsRegisterOperandType(OperandType::k##Name)); + REGISTER_OPERAND_TYPE_LIST(IS_REGISTER_OPERAND_TYPE) +#undef IS_REGISTER_OPERAND_TYPE + +#define IS_NOT_REGISTER_OPERAND_TYPE(Name, _) \ + CHECK(!Bytecodes::IsRegisterOperandType(OperandType::k##Name)); + NON_REGISTER_OPERAND_TYPE_LIST(IS_NOT_REGISTER_OPERAND_TYPE) +#undef IS_NOT_REGISTER_OPERAND_TYPE + +#define IS_REGISTER_INPUT_OPERAND_TYPE(Name, _) \ + CHECK(Bytecodes::IsRegisterInputOperandType(OperandType::k##Name)); + REGISTER_INPUT_OPERAND_TYPE_LIST(IS_REGISTER_INPUT_OPERAND_TYPE) +#undef IS_REGISTER_INPUT_OPERAND_TYPE + +#define IS_NOT_REGISTER_INPUT_OPERAND_TYPE(Name, _) \ + CHECK(!Bytecodes::IsRegisterInputOperandType(OperandType::k##Name)); + NON_REGISTER_OPERAND_TYPE_LIST(IS_NOT_REGISTER_INPUT_OPERAND_TYPE); + REGISTER_OUTPUT_OPERAND_TYPE_LIST(IS_NOT_REGISTER_INPUT_OPERAND_TYPE) +#undef IS_NOT_REGISTER_INPUT_OPERAND_TYPE + +#define IS_REGISTER_OUTPUT_OPERAND_TYPE(Name, _) \ + CHECK(Bytecodes::IsRegisterOutputOperandType(OperandType::k##Name)); + REGISTER_OUTPUT_OPERAND_TYPE_LIST(IS_REGISTER_OUTPUT_OPERAND_TYPE) +#undef IS_REGISTER_OUTPUT_OPERAND_TYPE + +#define IS_NOT_REGISTER_OUTPUT_OPERAND_TYPE(Name, _) \ + CHECK(!Bytecodes::IsRegisterOutputOperandType(OperandType::k##Name)); + NON_REGISTER_OPERAND_TYPE_LIST(IS_NOT_REGISTER_OUTPUT_OPERAND_TYPE) + REGISTER_INPUT_OPERAND_TYPE_LIST(IS_NOT_REGISTER_OUTPUT_OPERAND_TYPE) +#undef IS_NOT_REGISTER_INPUT_OPERAND_TYPE +} + +TEST(Bytecodes, DebugBreak) { + for (uint32_t i = 0; i < Bytecodes::ToByte(Bytecode::kLast); i++) { + Bytecode bytecode = Bytecodes::FromByte(i); + Bytecode debugbreak = Bytecodes::GetDebugBreak(bytecode); + if (!Bytecodes::IsDebugBreak(debugbreak)) { + PrintF("Bytecode %s has no matching debug break with length %d\n", + Bytecodes::ToString(bytecode), Bytecodes::Size(bytecode)); + CHECK(false); + } + } +} + } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/interpreter/constant-array-builder-unittest.cc b/deps/v8/test/unittests/interpreter/constant-array-builder-unittest.cc index ea5d1bb8c3..b3ec5ff668 100644 --- a/deps/v8/test/unittests/interpreter/constant-array-builder-unittest.cc +++ b/deps/v8/test/unittests/interpreter/constant-array-builder-unittest.cc @@ -33,13 +33,11 @@ STATIC_CONST_MEMBER_DEFINITION const size_t TEST_F(ConstantArrayBuilderTest, AllocateAllEntries) { ConstantArrayBuilder builder(isolate(), zone()); for (size_t i = 0; i < kMaxCapacity; i++) { - Handle<Object> object = isolate()->factory()->NewNumberFromSize(i); - builder.Insert(object); - CHECK_EQ(builder.size(), i + 1); - CHECK(builder.At(i)->SameValue(*object)); + builder.Insert(handle(Smi::FromInt(static_cast<int>(i)), isolate())); } + CHECK_EQ(builder.size(), kMaxCapacity); for (size_t i = 0; i < kMaxCapacity; i++) { - CHECK_EQ(Handle<Smi>::cast(builder.At(i))->value(), static_cast<double>(i)); + CHECK_EQ(Handle<Smi>::cast(builder.At(i))->value(), i); } } @@ -158,8 +156,7 @@ TEST_F(ConstantArrayBuilderTest, ToFixedArray) { builder.Insert(object); CHECK(builder.At(i)->SameValue(*object)); } - Handle<FixedArray> constant_array = - builder.ToFixedArray(isolate()->factory()); + Handle<FixedArray> constant_array = builder.ToFixedArray(); CHECK_EQ(constant_array->length(), kNumberOfElements); for (size_t i = 0; i < kNumberOfElements; i++) { CHECK(constant_array->get(static_cast<int>(i))->SameValue(*builder.At(i))); diff --git a/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.cc b/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.cc index f57ca05b3f..3375a6b817 100644 --- a/deps/v8/test/unittests/compiler/interpreter-assembler-unittest.cc +++ b/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "test/unittests/compiler/interpreter-assembler-unittest.h" +#include "test/unittests/interpreter/interpreter-assembler-unittest.h" #include "src/code-factory.h" #include "src/compiler/graph.h" @@ -16,7 +16,10 @@ using ::testing::_; namespace v8 { namespace internal { -namespace compiler { + +using namespace compiler; + +namespace interpreter { const interpreter::Bytecode kBytecodes[] = { #define DEFINE_BYTECODE(Name, ...) interpreter::Bytecode::k##Name, @@ -24,55 +27,47 @@ const interpreter::Bytecode kBytecodes[] = { #undef DEFINE_BYTECODE }; - Matcher<Node*> IsIntPtrConstant(const intptr_t value) { return kPointerSize == 8 ? IsInt64Constant(static_cast<int64_t>(value)) : IsInt32Constant(static_cast<int32_t>(value)); } - Matcher<Node*> IsIntPtrAdd(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher) { return kPointerSize == 8 ? IsInt64Add(lhs_matcher, rhs_matcher) : IsInt32Add(lhs_matcher, rhs_matcher); } - Matcher<Node*> IsIntPtrSub(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher) { return kPointerSize == 8 ? IsInt64Sub(lhs_matcher, rhs_matcher) : IsInt32Sub(lhs_matcher, rhs_matcher); } - Matcher<Node*> IsWordShl(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher) { return kPointerSize == 8 ? IsWord64Shl(lhs_matcher, rhs_matcher) : IsWord32Shl(lhs_matcher, rhs_matcher); } - Matcher<Node*> IsWordSar(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher) { return kPointerSize == 8 ? IsWord64Sar(lhs_matcher, rhs_matcher) : IsWord32Sar(lhs_matcher, rhs_matcher); } - Matcher<Node*> IsWordOr(const Matcher<Node*>& lhs_matcher, const Matcher<Node*>& rhs_matcher) { return kPointerSize == 8 ? IsWord64Or(lhs_matcher, rhs_matcher) : IsWord32Or(lhs_matcher, rhs_matcher); } - Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsLoad( const Matcher<LoadRepresentation>& rep_matcher, const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher) { return ::i::compiler::IsLoad(rep_matcher, base_matcher, index_matcher, _, _); } - Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsStore( const Matcher<StoreRepresentation>& rep_matcher, const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher, @@ -81,52 +76,57 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsStore( value_matcher, _, _); } - Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperand( int offset) { return IsLoad( MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(offset))); } - Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest:: IsBytecodeOperandSignExtended(int offset) { Matcher<Node*> load_matcher = IsLoad( MachineType::Int8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(offset))); if (kPointerSize == 8) { load_matcher = IsChangeInt32ToInt64(load_matcher); } return load_matcher; } - Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperandShort( int offset) { if (TargetSupportsUnalignedAccess()) { return IsLoad( MachineType::Uint16(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(offset))); } else { Matcher<Node*> first_byte = IsLoad( MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(offset))); Matcher<Node*> second_byte = IsLoad( MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(offset + 1))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(offset + 1))); #if V8_TARGET_LITTLE_ENDIAN return IsWordOr(IsWordShl(second_byte, IsInt32Constant(kBitsPerByte)), first_byte); @@ -139,16 +139,17 @@ InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperandShort( } } - Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest:: IsBytecodeOperandShortSignExtended(int offset) { Matcher<Node*> load_matcher; if (TargetSupportsUnalignedAccess()) { load_matcher = IsLoad( MachineType::Int16(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(offset))); } else { #if V8_TARGET_LITTLE_ENDIAN int hi_byte_offset = offset + 1; @@ -162,15 +163,19 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest:: #endif Matcher<Node*> hi_byte = IsLoad( MachineType::Int8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(hi_byte_offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(hi_byte_offset))); hi_byte = IsWord32Shl(hi_byte, IsInt32Constant(kBitsPerByte)); Matcher<Node*> lo_byte = IsLoad( MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(lo_byte_offset))); + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsIntPtrAdd( + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(lo_byte_offset))); load_matcher = IsWord32Or(hi_byte, lo_byte); } @@ -180,7 +185,6 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest:: return load_matcher; } - TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -191,35 +195,37 @@ TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) { EXPECT_EQ(1, end->InputCount()); Node* tail_call_node = end->InputAt(0); - Matcher<Node*> next_bytecode_offset_matcher = - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(interpreter::Bytecodes::Size(bytecode))); - Matcher<Node*> target_bytecode_matcher = - m.IsLoad(MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - next_bytecode_offset_matcher); - Matcher<Node*> code_target_matcher = - m.IsLoad(MachineType::Pointer(), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsWord32Shl(target_bytecode_matcher, - IsInt32Constant(kPointerSizeLog2))); - - EXPECT_EQ(CallDescriptor::kCallCodeObject, m.call_descriptor()->kind()); - EXPECT_TRUE(m.call_descriptor()->flags() & CallDescriptor::kCanUseRoots); + Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd( + IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(interpreter::Bytecodes::Size(bytecode))); + Matcher<Node*> target_bytecode_matcher = m.IsLoad( + MachineType::Uint8(), + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + next_bytecode_offset_matcher); + Matcher<Node*> code_target_matcher = m.IsLoad( + MachineType::Pointer(), + IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), + IsWord32Shl(target_bytecode_matcher, + IsInt32Constant(kPointerSizeLog2))); + EXPECT_THAT( tail_call_node, - IsTailCall(m.call_descriptor(), code_target_matcher, - IsParameter(Linkage::kInterpreterAccumulatorParameter), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - next_bytecode_offset_matcher, - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsParameter(Linkage::kInterpreterContextParameter), _, _)); + IsTailCall( + _, code_target_matcher, + IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter), + IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter), + next_bytecode_offset_matcher, + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), + IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), + IsParameter(InterpreterDispatchDescriptor::kContextParameter), _, + _)); } } - TARGET_TEST_F(InterpreterAssemblerTest, Jump) { + // If debug code is enabled we emit extra code in Jump. + if (FLAG_debug_code) return; + int jump_offsets[] = {-9710, -77, 0, +3, +97109}; TRACED_FOREACH(int, jump_offset, jump_offsets) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { @@ -230,38 +236,39 @@ TARGET_TEST_F(InterpreterAssemblerTest, Jump) { EXPECT_EQ(1, end->InputCount()); Node* tail_call_node = end->InputAt(0); - Matcher<Node*> next_bytecode_offset_matcher = - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(jump_offset)); + Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd( + IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(jump_offset)); Matcher<Node*> target_bytecode_matcher = - m.IsLoad(MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - next_bytecode_offset_matcher); - Matcher<Node*> code_target_matcher = - m.IsLoad(MachineType::Pointer(), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsWord32Shl(target_bytecode_matcher, - IsInt32Constant(kPointerSizeLog2))); - - EXPECT_EQ(CallDescriptor::kCallCodeObject, m.call_descriptor()->kind()); - EXPECT_TRUE(m.call_descriptor()->flags() & CallDescriptor::kCanUseRoots); + m.IsLoad(MachineType::Uint8(), _, next_bytecode_offset_matcher); + Matcher<Node*> code_target_matcher = m.IsLoad( + MachineType::Pointer(), + IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), + IsWord32Shl(target_bytecode_matcher, + IsInt32Constant(kPointerSizeLog2))); + EXPECT_THAT( tail_call_node, - IsTailCall(m.call_descriptor(), code_target_matcher, - IsParameter(Linkage::kInterpreterAccumulatorParameter), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - next_bytecode_offset_matcher, - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsParameter(Linkage::kInterpreterContextParameter), _, _)); + IsTailCall( + _, code_target_matcher, + IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter), + IsParameter( + InterpreterDispatchDescriptor::kRegisterFileParameter), + next_bytecode_offset_matcher, _, + IsParameter( + InterpreterDispatchDescriptor::kDispatchTableParameter), + IsParameter(InterpreterDispatchDescriptor::kContextParameter), _, + _)); } } } - TARGET_TEST_F(InterpreterAssemblerTest, JumpIfWordEqual) { static const int kJumpIfTrueOffset = 73; + // If debug code is enabled we emit extra code in Jump. + if (FLAG_debug_code) return; + MachineOperatorBuilder machine(zone()); TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { @@ -276,61 +283,64 @@ TARGET_TEST_F(InterpreterAssemblerTest, JumpIfWordEqual) { int jump_offsets[] = {kJumpIfTrueOffset, interpreter::Bytecodes::Size(bytecode)}; for (int i = 0; i < static_cast<int>(arraysize(jump_offsets)); i++) { - Matcher<Node*> next_bytecode_offset_matcher = - IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsInt32Constant(jump_offsets[i])); + Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd( + IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + IsInt32Constant(jump_offsets[i])); Matcher<Node*> target_bytecode_matcher = - m.IsLoad(MachineType::Uint8(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - next_bytecode_offset_matcher); - Matcher<Node*> code_target_matcher = - m.IsLoad(MachineType::Pointer(), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsWord32Shl(target_bytecode_matcher, - IsInt32Constant(kPointerSizeLog2))); + m.IsLoad(MachineType::Uint8(), _, next_bytecode_offset_matcher); + Matcher<Node*> code_target_matcher = m.IsLoad( + MachineType::Pointer(), + IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), + IsWord32Shl(target_bytecode_matcher, + IsInt32Constant(kPointerSizeLog2))); EXPECT_THAT( end->InputAt(i), - IsTailCall(m.call_descriptor(), code_target_matcher, - IsParameter(Linkage::kInterpreterAccumulatorParameter), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - next_bytecode_offset_matcher, - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsParameter(Linkage::kInterpreterContextParameter), _, _)); + IsTailCall( + _, code_target_matcher, + IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter), + IsParameter( + InterpreterDispatchDescriptor::kRegisterFileParameter), + next_bytecode_offset_matcher, _, + IsParameter( + InterpreterDispatchDescriptor::kDispatchTableParameter), + IsParameter(InterpreterDispatchDescriptor::kContextParameter), _, + _)); } // TODO(oth): test control flow paths. } } +TARGET_TEST_F(InterpreterAssemblerTest, InterpreterReturn) { + // If debug code is enabled we emit extra code in InterpreterReturn. + if (FLAG_debug_code) return; -TARGET_TEST_F(InterpreterAssemblerTest, Return) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); - m.Return(); + m.InterpreterReturn(); Graph* graph = m.graph(); Node* end = graph->end(); EXPECT_EQ(1, end->InputCount()); Node* tail_call_node = end->InputAt(0); - EXPECT_EQ(CallDescriptor::kCallCodeObject, m.call_descriptor()->kind()); - EXPECT_TRUE(m.call_descriptor()->flags() & CallDescriptor::kCanUseRoots); Handle<HeapObject> exit_trampoline = isolate()->builtins()->InterpreterExitTrampoline(); EXPECT_THAT( tail_call_node, - IsTailCall(m.call_descriptor(), IsHeapConstant(exit_trampoline), - IsParameter(Linkage::kInterpreterAccumulatorParameter), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), - IsParameter(Linkage::kInterpreterDispatchTableParameter), - IsParameter(Linkage::kInterpreterContextParameter), _, _)); + IsTailCall( + _, IsHeapConstant(exit_trampoline), + IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter), + IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter), + IsParameter( + InterpreterDispatchDescriptor::kBytecodeOffsetParameter), + _, + IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter), + IsParameter(InterpreterDispatchDescriptor::kContextParameter), _, + _)); } } - TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -338,7 +348,7 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { for (int i = 0; i < number_of_operands; i++) { int offset = interpreter::Bytecodes::GetOperandOffset(bytecode, i); switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) { - case interpreter::OperandType::kCount8: + case interpreter::OperandType::kRegCount8: EXPECT_THAT(m.BytecodeOperandCount(i), m.IsBytecodeOperand(offset)); break; case interpreter::OperandType::kIdx8: @@ -350,11 +360,14 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { break; case interpreter::OperandType::kMaybeReg8: case interpreter::OperandType::kReg8: + case interpreter::OperandType::kRegOut8: + case interpreter::OperandType::kRegOutPair8: + case interpreter::OperandType::kRegOutTriple8: case interpreter::OperandType::kRegPair8: EXPECT_THAT(m.BytecodeOperandReg(i), m.IsBytecodeOperandSignExtended(offset)); break; - case interpreter::OperandType::kCount16: + case interpreter::OperandType::kRegCount16: EXPECT_THAT(m.BytecodeOperandCount(i), m.IsBytecodeOperandShort(offset)); break; @@ -362,7 +375,12 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { EXPECT_THAT(m.BytecodeOperandIdx(i), m.IsBytecodeOperandShort(offset)); break; + case interpreter::OperandType::kMaybeReg16: case interpreter::OperandType::kReg16: + case interpreter::OperandType::kRegOut16: + case interpreter::OperandType::kRegOutPair16: + case interpreter::OperandType::kRegOutTriple16: + case interpreter::OperandType::kRegPair16: EXPECT_THAT(m.BytecodeOperandReg(i), m.IsBytecodeOperandShortSignExtended(offset)); break; @@ -374,15 +392,15 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { } } - TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); // Should be incoming accumulator if not set. - EXPECT_THAT(m.GetAccumulator(), - IsParameter(Linkage::kInterpreterAccumulatorParameter)); + EXPECT_THAT( + m.GetAccumulator(), + IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter)); - // Should be set by SedtAccumulator. + // Should be set by SetAccumulator. Node* accumulator_value_1 = m.Int32Constant(0xdeadbeef); m.SetAccumulator(accumulator_value_1); EXPECT_THAT(m.GetAccumulator(), accumulator_value_1); @@ -399,11 +417,18 @@ TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) { Node* tail_call_node = end->InputAt(0); EXPECT_THAT(tail_call_node, - IsTailCall(m.call_descriptor(), _, accumulator_value_2, _, _, _, - _, _, _)); + IsTailCall(_, _, accumulator_value_2, _, _, _, _, _, _)); } } +TARGET_TEST_F(InterpreterAssemblerTest, GetSetContext) { + TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { + InterpreterAssemblerForTest m(this, bytecode); + Node* context_node = m.Int32Constant(100); + m.SetContext(context_node); + EXPECT_THAT(m.GetContext(), context_node); + } +} TARGET_TEST_F(InterpreterAssemblerTest, RegisterLocation) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { @@ -413,12 +438,11 @@ TARGET_TEST_F(InterpreterAssemblerTest, RegisterLocation) { EXPECT_THAT( reg_location_node, IsIntPtrAdd( - IsParameter(Linkage::kInterpreterRegisterFileParameter), + IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter), IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)))); } } - TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -426,13 +450,13 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadRegister) { Node* load_reg_node = m.LoadRegister(reg_index_node); EXPECT_THAT( load_reg_node, - m.IsLoad(MachineType::AnyTagged(), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)))); + m.IsLoad( + MachineType::AnyTagged(), + IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter), + IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)))); } } - TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -441,15 +465,15 @@ TARGET_TEST_F(InterpreterAssemblerTest, StoreRegister) { Node* store_reg_node = m.StoreRegister(store_value, reg_index_node); EXPECT_THAT( store_reg_node, - m.IsStore(StoreRepresentation(MachineRepresentation::kTagged, - kNoWriteBarrier), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)), - store_value)); + m.IsStore( + StoreRepresentation(MachineRepresentation::kTagged, + kNoWriteBarrier), + IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter), + IsWordShl(reg_index_node, IsInt32Constant(kPointerSizeLog2)), + store_value)); } } - TARGET_TEST_F(InterpreterAssemblerTest, SmiTag) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -461,7 +485,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, SmiTag) { } } - TARGET_TEST_F(InterpreterAssemblerTest, IntPtrAdd) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -472,7 +495,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, IntPtrAdd) { } } - TARGET_TEST_F(InterpreterAssemblerTest, IntPtrSub) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -483,7 +505,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, IntPtrSub) { } } - TARGET_TEST_F(InterpreterAssemblerTest, WordShl) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -493,7 +514,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, WordShl) { } } - TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -501,7 +521,7 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) { Node* load_constant = m.LoadConstantPoolEntry(index); Matcher<Node*> constant_pool_matcher = m.IsLoad( MachineType::AnyTagged(), - IsParameter(Linkage::kInterpreterBytecodeArrayParameter), + IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter), IsIntPtrConstant(BytecodeArray::kConstantPoolOffset - kHeapObjectTag)); EXPECT_THAT( load_constant, @@ -512,7 +532,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadConstantPoolEntry) { } } - TARGET_TEST_F(InterpreterAssemblerTest, LoadFixedArrayElement) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -529,7 +548,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadFixedArrayElement) { } } - TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -542,7 +560,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) { } } - TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -558,7 +575,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) { } } - TARGET_TEST_F(InterpreterAssemblerTest, StoreContextSlot) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); @@ -577,21 +593,22 @@ TARGET_TEST_F(InterpreterAssemblerTest, StoreContextSlot) { } } - TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime2) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); Node* arg1 = m.Int32Constant(2); Node* arg2 = m.Int32Constant(3); - Node* call_runtime = m.CallRuntime(Runtime::kAdd, arg1, arg2); + Node* context = + m.Parameter(InterpreterDispatchDescriptor::kContextParameter); + Node* call_runtime = m.CallRuntime(Runtime::kAdd, context, arg1, arg2); EXPECT_THAT( call_runtime, IsCall(_, _, arg1, arg2, _, IsInt32Constant(2), - IsParameter(Linkage::kInterpreterContextParameter), _, _)); + IsParameter(InterpreterDispatchDescriptor::kContextParameter), _, + _)); } } - TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) { const int kResultSizes[] = {1, 2}; TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { @@ -602,6 +619,8 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) { Node* function_id = m.Int32Constant(0); Node* first_arg = m.Int32Constant(1); Node* arg_count = m.Int32Constant(2); + Node* context = + m.Parameter(InterpreterDispatchDescriptor::kContextParameter); Matcher<Node*> function_table = IsExternalConstant( ExternalReference::runtime_function_table_address(isolate())); @@ -612,63 +631,53 @@ TARGET_TEST_F(InterpreterAssemblerTest, CallRuntime) { m.IsLoad(MachineType::Pointer(), function, IsInt32Constant(offsetof(Runtime::Function, entry))); - Node* call_runtime = - m.CallRuntime(function_id, first_arg, arg_count, result_size); + Node* call_runtime = m.CallRuntimeN(function_id, context, first_arg, + arg_count, result_size); EXPECT_THAT( call_runtime, IsCall(_, IsHeapConstant(builtin.code()), arg_count, first_arg, function_entry, - IsParameter(Linkage::kInterpreterContextParameter), _, _)); + IsParameter(InterpreterDispatchDescriptor::kContextParameter), + _, _)); } } } - -TARGET_TEST_F(InterpreterAssemblerTest, CallIC) { - TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { - InterpreterAssemblerForTest m(this, bytecode); - LoadWithVectorDescriptor descriptor(isolate()); - Node* target = m.Int32Constant(1); - Node* arg1 = m.Int32Constant(2); - Node* arg2 = m.Int32Constant(3); - Node* arg3 = m.Int32Constant(4); - Node* arg4 = m.Int32Constant(5); - Node* call_ic = m.CallIC(descriptor, target, arg1, arg2, arg3, arg4); - EXPECT_THAT( - call_ic, - IsCall(_, target, arg1, arg2, arg3, arg4, - IsParameter(Linkage::kInterpreterContextParameter), _, _)); - } -} - - TARGET_TEST_F(InterpreterAssemblerTest, CallJS) { - TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { - InterpreterAssemblerForTest m(this, bytecode); - Callable builtin = CodeFactory::InterpreterPushArgsAndCall(isolate()); - Node* function = m.Int32Constant(0); - Node* first_arg = m.Int32Constant(1); - Node* arg_count = m.Int32Constant(2); - Node* call_js = m.CallJS(function, first_arg, arg_count); - EXPECT_THAT( - call_js, - IsCall(_, IsHeapConstant(builtin.code()), arg_count, first_arg, - function, IsParameter(Linkage::kInterpreterContextParameter), _, - _)); + TailCallMode tail_call_modes[] = {TailCallMode::kDisallow, + TailCallMode::kAllow}; + TRACED_FOREACH(TailCallMode, tail_call_mode, tail_call_modes) { + TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { + InterpreterAssemblerForTest m(this, bytecode); + Callable builtin = + CodeFactory::InterpreterPushArgsAndCall(isolate(), tail_call_mode); + Node* function = m.Int32Constant(0); + Node* first_arg = m.Int32Constant(1); + Node* arg_count = m.Int32Constant(2); + Node* context = + m.Parameter(InterpreterDispatchDescriptor::kContextParameter); + Node* call_js = + m.CallJS(function, context, first_arg, arg_count, tail_call_mode); + EXPECT_THAT( + call_js, + IsCall(_, IsHeapConstant(builtin.code()), arg_count, first_arg, + function, + IsParameter(InterpreterDispatchDescriptor::kContextParameter), + _, _)); + } } } - TARGET_TEST_F(InterpreterAssemblerTest, LoadTypeFeedbackVector) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); Node* feedback_vector = m.LoadTypeFeedbackVector(); - Matcher<Node*> load_function_matcher = - m.IsLoad(MachineType::AnyTagged(), - IsParameter(Linkage::kInterpreterRegisterFileParameter), - IsIntPtrConstant( - InterpreterFrameConstants::kFunctionFromRegisterPointer)); + Matcher<Node*> load_function_matcher = m.IsLoad( + MachineType::AnyTagged(), + IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter), + IsIntPtrConstant( + InterpreterFrameConstants::kFunctionFromRegisterPointer)); Matcher<Node*> load_shared_function_info_matcher = m.IsLoad(MachineType::AnyTagged(), load_function_matcher, IsIntPtrConstant(JSFunction::kSharedFunctionInfoOffset - @@ -682,6 +691,6 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadTypeFeedbackVector) { } } -} // namespace compiler +} // namespace interpreter } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.h b/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.h new file mode 100644 index 0000000000..321c72490b --- /dev/null +++ b/deps/v8/test/unittests/interpreter/interpreter-assembler-unittest.h @@ -0,0 +1,57 @@ +// 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. + +#ifndef V8_UNITTESTS_INTERPRETER_INTERPRETER_ASSEMBLER_UNITTEST_H_ +#define V8_UNITTESTS_INTERPRETER_INTERPRETER_ASSEMBLER_UNITTEST_H_ + +#include "src/compiler/machine-operator.h" +#include "src/interpreter/interpreter-assembler.h" +#include "test/unittests/test-utils.h" +#include "testing/gmock-support.h" + +namespace v8 { +namespace internal { +namespace interpreter { + +using ::testing::Matcher; + +class InterpreterAssemblerTest : public TestWithIsolateAndZone { + public: + InterpreterAssemblerTest() {} + ~InterpreterAssemblerTest() override {} + + class InterpreterAssemblerForTest final : public InterpreterAssembler { + public: + InterpreterAssemblerForTest(InterpreterAssemblerTest* test, + Bytecode bytecode) + : InterpreterAssembler(test->isolate(), test->zone(), bytecode) {} + ~InterpreterAssemblerForTest() override {} + + Matcher<compiler::Node*> IsLoad( + const Matcher<compiler::LoadRepresentation>& rep_matcher, + const Matcher<compiler::Node*>& base_matcher, + const Matcher<compiler::Node*>& index_matcher); + Matcher<compiler::Node*> IsStore( + const Matcher<compiler::StoreRepresentation>& rep_matcher, + const Matcher<compiler::Node*>& base_matcher, + const Matcher<compiler::Node*>& index_matcher, + const Matcher<compiler::Node*>& value_matcher); + + Matcher<compiler::Node*> IsBytecodeOperand(int offset); + Matcher<compiler::Node*> IsBytecodeOperandSignExtended(int offset); + Matcher<compiler::Node*> IsBytecodeOperandShort(int offset); + Matcher<compiler::Node*> IsBytecodeOperandShortSignExtended(int offset); + + using InterpreterAssembler::graph; + + private: + DISALLOW_COPY_AND_ASSIGN(InterpreterAssemblerForTest); + }; +}; + +} // namespace interpreter +} // namespace internal +} // namespace v8 + +#endif // V8_UNITTESTS_INTERPRETER_INTERPRETER_ASSEMBLER_UNITTEST_H_ diff --git a/deps/v8/test/unittests/interpreter/register-translator-unittest.cc b/deps/v8/test/unittests/interpreter/register-translator-unittest.cc new file mode 100644 index 0000000000..e9f65a6af0 --- /dev/null +++ b/deps/v8/test/unittests/interpreter/register-translator-unittest.cc @@ -0,0 +1,260 @@ +// 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 <stack> + +#include "src/v8.h" + +#include "src/interpreter/register-translator.h" +#include "src/isolate.h" +#include "test/unittests/test-utils.h" + +namespace v8 { +namespace internal { +namespace interpreter { + +class RegisterTranslatorTest : public TestWithIsolateAndZone, + private RegisterMover { + public: + RegisterTranslatorTest() : translator_(this), move_count_(0) { + window_start_ = + RegisterTranslator::DistanceToTranslationWindow(Register(0)); + window_width_ = + Register::MaxRegisterIndexForByteOperand() - window_start_ + 1; + } + + ~RegisterTranslatorTest() override {} + + bool PopMoveAndMatch(Register from, Register to) { + if (!moves_.empty()) { + CHECK(from.is_valid() && to.is_valid()); + const std::pair<Register, Register> top = moves_.top(); + moves_.pop(); + return top.first == from && top.second == to; + } else { + return false; + } + } + + int move_count() const { return move_count_; } + RegisterTranslator* translator() { return &translator_; } + + int window_start() const { return window_start_; } + int window_width() const { return window_width_; } + int window_limit() const { return window_start_ + window_width_; } + + protected: + static const char* const kBadOperandRegex; + + private: + void MoveRegisterUntranslated(Register from, Register to) override { + moves_.push(std::make_pair(from, to)); + move_count_++; + } + + RegisterTranslator translator_; + std::stack<std::pair<Register, Register>> moves_; + int move_count_; + int window_start_; + int window_width_; +}; + +const char* const RegisterTranslatorTest::kBadOperandRegex = + ".*OperandType::kReg8 \\|\\| .*OperandType::kRegOut8\\) && " + "RegisterIsMovableToWindow.*"; + +TEST_F(RegisterTranslatorTest, TestFrameSizeAdjustmentsForTranslationWindow) { + EXPECT_EQ(0, RegisterTranslator::RegisterCountAdjustment(0, 0)); + EXPECT_EQ(0, RegisterTranslator::RegisterCountAdjustment(10, 10)); + EXPECT_EQ(window_width(), + RegisterTranslator::RegisterCountAdjustment(173, 0)); + EXPECT_EQ(window_width(), + RegisterTranslator::RegisterCountAdjustment(173, 137)); + EXPECT_EQ(window_width(), + RegisterTranslator::RegisterCountAdjustment(173, 137)); + // TODO(oth): Add a kMaxParameters8 that derives this info from the frame. + int param_limit = FLAG_enable_embedded_constant_pool ? 119 : 120; + EXPECT_EQ(0, RegisterTranslator::RegisterCountAdjustment(0, param_limit)); + EXPECT_EQ(window_limit(), + RegisterTranslator::RegisterCountAdjustment(0, 128)); + EXPECT_EQ(window_limit(), + RegisterTranslator::RegisterCountAdjustment(0, 129)); + EXPECT_EQ(window_limit() - 32, + RegisterTranslator::RegisterCountAdjustment(32, 129)); +} + +TEST_F(RegisterTranslatorTest, TestInTranslationWindow) { + EXPECT_GE(window_start(), 0); + EXPECT_FALSE( + RegisterTranslator::InTranslationWindow(Register(window_start() - 1))); + EXPECT_TRUE(RegisterTranslator::InTranslationWindow( + Register(Register::MaxRegisterIndexForByteOperand()))); + EXPECT_FALSE(RegisterTranslator::InTranslationWindow( + Register(Register::MaxRegisterIndexForByteOperand() + 1))); + for (int index = window_start(); index < window_limit(); index += 1) { + EXPECT_TRUE(RegisterTranslator::InTranslationWindow(Register(index))); + } +} + +TEST_F(RegisterTranslatorTest, FitsInReg8Operand) { + EXPECT_GT(window_start(), 0); + EXPECT_TRUE(RegisterTranslator::FitsInReg8Operand( + Register::FromParameterIndex(0, 3))); + EXPECT_TRUE(RegisterTranslator::FitsInReg8Operand( + Register::FromParameterIndex(2, 3))); + EXPECT_TRUE(RegisterTranslator::FitsInReg8Operand(Register(0))); + EXPECT_TRUE( + RegisterTranslator::FitsInReg8Operand(Register(window_start() - 1))); + EXPECT_FALSE(RegisterTranslator::FitsInReg8Operand(Register(kMaxInt8))); + EXPECT_FALSE(RegisterTranslator::FitsInReg8Operand(Register(kMaxInt8 + 1))); + for (int index = window_start(); index < window_limit(); index += 1) { + EXPECT_FALSE(RegisterTranslator::FitsInReg8Operand(Register(index))); + } +} + +TEST_F(RegisterTranslatorTest, FitsInReg16Operand) { + EXPECT_GT(window_start(), 0); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand( + Register::FromParameterIndex(0, 3))); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand( + Register::FromParameterIndex(2, 3))); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand( + Register::FromParameterIndex(0, 999))); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand( + Register::FromParameterIndex(0, Register::MaxParameterIndex() + 1))); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand(Register(0))); + EXPECT_TRUE( + RegisterTranslator::FitsInReg16Operand(Register(window_start() - 1))); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand(Register(kMaxInt8 + 1))); + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand(Register(kMaxInt8 + 2))); + for (int index = 0; index <= kMaxInt16 - window_width(); index += 1) { + EXPECT_TRUE(RegisterTranslator::FitsInReg16Operand(Register(index))); + } + for (int index = Register::MaxRegisterIndex() - window_width() + 1; + index < Register::MaxRegisterIndex() + 2; index += 1) { + EXPECT_FALSE(RegisterTranslator::FitsInReg16Operand(Register(index))); + } +} + +TEST_F(RegisterTranslatorTest, NoTranslationRequired) { + Register window_reg(window_start()); + Register local_reg(57); + uint32_t operands[] = {local_reg.ToRawOperand()}; + translator()->TranslateInputRegisters(Bytecode::kLdar, operands, 1); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(0, move_count()); + + Register param_reg = Register::FromParameterIndex(129, 130); + operands[0] = param_reg.ToRawOperand(); + translator()->TranslateInputRegisters(Bytecode::kAdd, operands, 1); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(0, move_count()); +} + +TEST_F(RegisterTranslatorTest, TranslationRequired) { + Register window_reg(window_start()); + Register local_reg(137); + Register local_reg_translated(local_reg.index() + window_width()); + + uint32_t operands[] = {local_reg.ToRawOperand()}; + translator()->TranslateInputRegisters(Bytecode::kLdar, operands, 1); + EXPECT_EQ(1, move_count()); + EXPECT_TRUE(PopMoveAndMatch(local_reg_translated, window_reg)); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(1, move_count()); + EXPECT_FALSE(PopMoveAndMatch(window_reg, local_reg_translated)); + + operands[0] = local_reg.ToRawOperand(); + translator()->TranslateInputRegisters(Bytecode::kStar, operands, 1); + EXPECT_EQ(1, move_count()); + EXPECT_FALSE(PopMoveAndMatch(local_reg_translated, window_reg)); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(2, move_count()); + EXPECT_TRUE(PopMoveAndMatch(window_reg, local_reg_translated)); + + Register param_reg = Register::FromParameterIndex(0, 130); + operands[0] = {param_reg.ToRawOperand()}; + translator()->TranslateInputRegisters(Bytecode::kLdar, operands, 1); + EXPECT_EQ(3, move_count()); + EXPECT_TRUE(PopMoveAndMatch(param_reg, window_reg)); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(3, move_count()); + EXPECT_FALSE(PopMoveAndMatch(window_reg, param_reg)); + + operands[0] = {param_reg.ToRawOperand()}; + translator()->TranslateInputRegisters(Bytecode::kStar, operands, 1); + EXPECT_EQ(3, move_count()); + EXPECT_FALSE(PopMoveAndMatch(local_reg_translated, window_reg)); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(4, move_count()); + EXPECT_TRUE(PopMoveAndMatch(window_reg, param_reg)); +} + +TEST_F(RegisterTranslatorTest, RangeTranslation) { + Register window0(window_start()); + Register window1(window_start() + 1); + Register window2(window_start() + 2); + uint32_t operands[3]; + + // Bytecode::kNew with valid range operand. + Register constructor0(0); + Register args0(1); + operands[0] = constructor0.ToRawOperand(); + operands[1] = args0.ToRawOperand(); + operands[2] = 1; + translator()->TranslateInputRegisters(Bytecode::kNew, operands, 3); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(0, move_count()); + + // Bytecode::kNewWide with valid range operand. + Register constructor1(128); + Register constructor1_translated(constructor1.index() + window_width()); + Register args1(129); + Register args1_translated(args1.index() + window_width()); + operands[0] = constructor1.ToRawOperand(); + operands[1] = args1.ToRawOperand(); + operands[2] = 3; + translator()->TranslateInputRegisters(Bytecode::kNewWide, operands, 3); + translator()->TranslateOutputRegisters(); + EXPECT_EQ(0, move_count()); +} + +TEST_F(RegisterTranslatorTest, BadRange0) { + // Bytecode::kNew with invalid range operand (kMaybeReg8). + Register constructor1(128); + Register args1(129); + uint32_t operands[] = {constructor1.ToRawOperand(), args1.ToRawOperand(), 3}; + ASSERT_DEATH_IF_SUPPORTED( + translator()->TranslateInputRegisters(Bytecode::kNew, operands, 3), + kBadOperandRegex); +} + +TEST_F(RegisterTranslatorTest, BadRange1) { + // Bytecode::kForInPrepare with invalid range operand (kRegTriple8) + Register for_in_state(160); + Register for_in_state_translated(for_in_state.index() + window_width()); + uint32_t operands[] = {for_in_state.ToRawOperand()}; + ASSERT_DEATH_IF_SUPPORTED(translator()->TranslateInputRegisters( + Bytecode::kForInPrepare, operands, 1), + kBadOperandRegex); +} + +TEST_F(RegisterTranslatorTest, BadRange2) { + // Bytecode::kForInNext with invalid range operand (kRegPair8) + Register receiver(192); + Register receiver_translated(receiver.index() + window_width()); + Register index(193); + Register index_translated(index.index() + window_width()); + Register cache_info_pair(194); + Register cache_info_pair_translated(cache_info_pair.index() + window_width()); + uint32_t operands[] = {receiver.ToRawOperand(), index.ToRawOperand(), + cache_info_pair.ToRawOperand()}; + ASSERT_DEATH_IF_SUPPORTED( + translator()->TranslateInputRegisters(Bytecode::kForInNext, operands, 3), + kBadOperandRegex); +} + +} // namespace interpreter +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/unittests.gyp b/deps/v8/test/unittests/unittests.gyp index 5339da35fd..638fd847bf 100644 --- a/deps/v8/test/unittests/unittests.gyp +++ b/deps/v8/test/unittests/unittests.gyp @@ -60,10 +60,9 @@ 'compiler/instruction-selector-unittest.h', 'compiler/instruction-sequence-unittest.cc', 'compiler/instruction-sequence-unittest.h', - 'compiler/interpreter-assembler-unittest.cc', - 'compiler/interpreter-assembler-unittest.h', + 'compiler/int64-lowering-unittest.cc', 'compiler/js-builtin-reducer-unittest.cc', - 'compiler/js-context-relaxation-unittest.cc', + 'compiler/js-create-lowering-unittest.cc', 'compiler/js-intrinsic-lowering-unittest.cc', 'compiler/js-operator-unittest.cc', 'compiler/js-typed-lowering-unittest.cc', @@ -86,6 +85,7 @@ 'compiler/schedule-unittest.cc', 'compiler/select-lowering-unittest.cc', 'compiler/scheduler-unittest.cc', + 'compiler/scheduler-rpo-unittest.cc', 'compiler/simplified-operator-reducer-unittest.cc', 'compiler/simplified-operator-unittest.cc', 'compiler/state-values-utils-unittest.cc', @@ -99,6 +99,9 @@ 'interpreter/bytecode-array-iterator-unittest.cc', 'interpreter/bytecode-register-allocator-unittest.cc', 'interpreter/constant-array-builder-unittest.cc', + 'interpreter/interpreter-assembler-unittest.cc', + 'interpreter/interpreter-assembler-unittest.h', + 'interpreter/register-translator-unittest.cc', 'libplatform/default-platform-unittest.cc', 'libplatform/task-queue-unittest.cc', 'libplatform/worker-thread-unittest.cc', @@ -107,6 +110,7 @@ 'heap/memory-reducer-unittest.cc', 'heap/heap-unittest.cc', 'heap/scavenge-job-unittest.cc', + 'heap/slot-set-unittest.cc', 'locked-queue-unittest.cc', 'run-all-unittests.cc', 'runtime/runtime-interpreter-unittest.cc', @@ -114,6 +118,7 @@ 'test-utils.cc', 'wasm/ast-decoder-unittest.cc', 'wasm/encoder-unittest.cc', + 'wasm/loop-assignment-analysis-unittest.cc', 'wasm/module-decoder-unittest.cc', 'wasm/wasm-macro-gen-unittest.cc', ], diff --git a/deps/v8/test/unittests/wasm/ast-decoder-unittest.cc b/deps/v8/test/unittests/wasm/ast-decoder-unittest.cc index 923c554604..672158714a 100644 --- a/deps/v8/test/unittests/wasm/ast-decoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/ast-decoder-unittest.cc @@ -35,6 +35,8 @@ static const WasmOpcode kInt32BinopOpcodes[] = { kExprI32Shl, kExprI32ShrU, kExprI32ShrS, kExprI32Eq, kExprI32LtS, kExprI32LeS, kExprI32LtU, kExprI32LeU}; +#define WASM_BRV_IF_ZERO(depth, val) \ + kExprBrIf, static_cast<byte>(depth), val, WASM_ZERO #define EXPECT_VERIFIES(env, x) Verify(kSuccess, env, x, x + arraysize(x)) @@ -87,10 +89,10 @@ class WasmDecoderTest : public TestWithZone { static void init_env(FunctionEnv* env, FunctionSig* sig) { env->module = nullptr; env->sig = sig; - env->local_int32_count = 0; - env->local_int64_count = 0; - env->local_float32_count = 0; - env->local_float64_count = 0; + env->local_i32_count = 0; + env->local_i64_count = 0; + env->local_f32_count = 0; + env->local_f64_count = 0; env->SumLocals(); } @@ -179,9 +181,9 @@ static FunctionEnv CreateInt32FunctionEnv(FunctionSig* sig, int count) { FunctionEnv env; env.module = nullptr; env.sig = sig; - env.local_int32_count = count; - env.local_float64_count = 0; - env.local_float32_count = 0; + env.local_i32_count = count; + env.local_f64_count = 0; + env.local_f32_count = 0; env.total_locals = static_cast<unsigned>(count + sig->parameter_count()); return env; } @@ -251,9 +253,6 @@ TEST_F(WasmDecoderTest, Int64Const) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, Float32Const) { byte code[] = {kExprF32Const, 0, 0, 0, 0}; float* ptr = reinterpret_cast<float*>(code + 1); @@ -273,8 +272,6 @@ TEST_F(WasmDecoderTest, Float64Const) { } } -#endif - TEST_F(WasmDecoderTest, Int32Const_off_end) { byte code[] = {kExprI32Const, 0xaa, 0xbb, 0xcc, 0x44}; @@ -338,7 +335,7 @@ TEST_F(WasmDecoderTest, GetLocal_off_end) { TEST_F(WasmDecoderTest, GetLocal_varint) { - env_i_i.local_int32_count = 1000000000; + env_i_i.local_i32_count = 1000000000; env_i_i.total_locals += 1000000000; { @@ -532,16 +529,11 @@ TEST_F(WasmDecoderTest, ExprBlock1b) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, ExprBlock1c) { static const byte code[] = {kExprBlock, 1, kExprF32Const, 0, 0, 0, 0}; EXPECT_VERIFIES(&env_f_ff, code); } -#endif - TEST_F(WasmDecoderTest, IfEmpty) { static const byte code[] = {kExprIf, kExprGetLocal, 0, kExprNop}; @@ -704,9 +696,6 @@ TEST_F(WasmDecoderTest, ReturnVoid2) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, ReturnVoid3) { EXPECT_VERIFIES_INLINE(&env_v_v, kExprI8Const, 0); EXPECT_VERIFIES_INLINE(&env_v_v, kExprI32Const, 0, 0, 0, 0); @@ -717,8 +706,6 @@ TEST_F(WasmDecoderTest, ReturnVoid3) { EXPECT_VERIFIES_INLINE(&env_v_i, kExprGetLocal, 0); } -#endif - TEST_F(WasmDecoderTest, Unreachable1) { EXPECT_VERIFIES_INLINE(&env_v_v, kExprUnreachable); @@ -881,9 +868,6 @@ TEST_F(WasmDecoderTest, MacrosStmt) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, MacrosBreak) { EXPECT_VERIFIES_INLINE(&env_v_v, WASM_LOOP(1, WASM_BREAK(0))); @@ -895,8 +879,6 @@ TEST_F(WasmDecoderTest, MacrosBreak) { WASM_LOOP(1, WASM_BREAKV(0, WASM_F64(0.0)))); } -#endif - TEST_F(WasmDecoderTest, MacrosContinue) { EXPECT_VERIFIES_INLINE(&env_v_v, WASM_LOOP(1, WASM_CONTINUE(0))); @@ -1204,14 +1186,13 @@ namespace { class TestModuleEnv : public ModuleEnv { public: TestModuleEnv() { - mem_start = 0; - mem_end = 0; + instance = nullptr; module = &mod; linker = nullptr; - function_code = nullptr; mod.globals = new std::vector<WasmGlobal>; mod.signatures = new std::vector<FunctionSig*>; mod.functions = new std::vector<WasmFunction>; + mod.import_table = new std::vector<WasmImport>; } byte AddGlobal(MachineType mem_type) { mod.globals->push_back({0, mem_type, 0, false}); @@ -1228,6 +1209,11 @@ class TestModuleEnv : public ModuleEnv { CHECK(mod.functions->size() <= 127); return static_cast<byte>(mod.functions->size() - 1); } + byte AddImport(FunctionSig* sig) { + mod.import_table->push_back({sig, 0, 0}); + CHECK(mod.import_table->size() <= 127); + return static_cast<byte>(mod.import_table->size() - 1); + } private: WasmModule mod; @@ -1265,9 +1251,6 @@ TEST_F(WasmDecoderTest, CallsWithTooFewArguments) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, CallsWithSpilloverArgs) { static LocalType a_i_ff[] = {kAstI32, kAstF32, kAstF32}; FunctionSig sig_i_ff(1, 2, a_i_ff); @@ -1331,8 +1314,6 @@ TEST_F(WasmDecoderTest, CallsWithMismatchedSigs3) { EXPECT_FAILURE_INLINE(env, WASM_CALL_FUNCTION(1, WASM_F32(17.6))); } -#endif - TEST_F(WasmDecoderTest, SimpleIndirectCalls) { FunctionEnv* env = &env_i_i; @@ -1389,6 +1370,39 @@ TEST_F(WasmDecoderTest, IndirectCallsWithMismatchedSigs3) { EXPECT_FAILURE_INLINE(env, WASM_CALL_INDIRECT(f1, WASM_ZERO, WASM_F32(17.6))); } +TEST_F(WasmDecoderTest, SimpleImportCalls) { + FunctionEnv* env = &env_i_i; + TestModuleEnv module_env; + env->module = &module_env; + + byte f0 = module_env.AddImport(sigs.i_v()); + byte f1 = module_env.AddImport(sigs.i_i()); + byte f2 = module_env.AddImport(sigs.i_ii()); + + EXPECT_VERIFIES_INLINE(env, WASM_CALL_IMPORT0(f0)); + EXPECT_VERIFIES_INLINE(env, WASM_CALL_IMPORT(f1, WASM_I8(22))); + EXPECT_VERIFIES_INLINE(env, WASM_CALL_IMPORT(f2, WASM_I8(32), WASM_I8(72))); +} + +TEST_F(WasmDecoderTest, ImportCallsWithMismatchedSigs3) { + FunctionEnv* env = &env_i_i; + TestModuleEnv module_env; + env->module = &module_env; + + byte f0 = module_env.AddImport(sigs.i_f()); + + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT0(f0)); + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT(f0, WASM_I8(17))); + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT(f0, WASM_I64(27))); + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT(f0, WASM_F64(37.2))); + + byte f1 = module_env.AddImport(sigs.i_d()); + + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT0(f1)); + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT(f1, WASM_I8(16))); + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT(f1, WASM_I64(16))); + EXPECT_FAILURE_INLINE(env, WASM_CALL_IMPORT(f1, WASM_F32(17.6))); +} TEST_F(WasmDecoderTest, Int32Globals) { FunctionEnv* env = &env_i_i; @@ -1575,28 +1589,22 @@ TEST_F(WasmDecoderTest, BreakNesting3) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, BreaksWithMultipleTypes) { EXPECT_FAILURE_INLINE( - &env_i_i, - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_ZERO, WASM_I8(7)), WASM_F32(7.7))); - EXPECT_FAILURE_INLINE(&env_i_i, - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_ZERO, WASM_I8(7)), - WASM_BRV_IF(0, WASM_ZERO, WASM_F32(7.7)))); + &env_i_i, WASM_BLOCK(2, WASM_BRV_IF_ZERO(0, WASM_I8(7)), WASM_F32(7.7))); + EXPECT_FAILURE_INLINE(&env_i_i, - WASM_BLOCK(3, WASM_BRV_IF(0, WASM_ZERO, WASM_I8(8)), - WASM_BRV_IF(0, WASM_ZERO, WASM_I8(0)), - WASM_BRV_IF(0, WASM_ZERO, WASM_F32(7.7)))); + WASM_BLOCK(2, WASM_BRV_IF_ZERO(0, WASM_I8(7)), + WASM_BRV_IF_ZERO(0, WASM_F32(7.7)))); EXPECT_FAILURE_INLINE(&env_i_i, - WASM_BLOCK(3, WASM_BRV_IF(0, WASM_ZERO, WASM_I8(9)), - WASM_BRV_IF(0, WASM_ZERO, WASM_F32(7.7)), - WASM_BRV_IF(0, WASM_ZERO, WASM_I8(11)))); + WASM_BLOCK(3, WASM_BRV_IF_ZERO(0, WASM_I8(8)), + WASM_BRV_IF_ZERO(0, WASM_I8(0)), + WASM_BRV_IF_ZERO(0, WASM_F32(7.7)))); + EXPECT_FAILURE_INLINE(&env_i_i, WASM_BLOCK(3, WASM_BRV_IF_ZERO(0, WASM_I8(9)), + WASM_BRV_IF_ZERO(0, WASM_F32(7.7)), + WASM_BRV_IF_ZERO(0, WASM_I8(11)))); } -#endif - TEST_F(WasmDecoderTest, BreakNesting_6_levels) { for (int mask = 0; mask < 64; mask++) { @@ -1630,9 +1638,6 @@ TEST_F(WasmDecoderTest, BreakNesting_6_levels) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, ExprBreak_TypeCheck) { FunctionEnv* envs[] = {&env_i_i, &env_l_l, &env_f_ff, &env_d_dd}; for (size_t i = 0; i < arraysize(envs); i++) { @@ -1655,17 +1660,14 @@ TEST_F(WasmDecoderTest, ExprBreak_TypeCheck) { WASM_F64(1.2))); } -#endif - TEST_F(WasmDecoderTest, ExprBreak_TypeCheckAll) { byte code1[] = {WASM_BLOCK(2, WASM_IF(WASM_ZERO, WASM_BRV(0, WASM_GET_LOCAL(0))), WASM_GET_LOCAL(1))}; - byte code2[] = {WASM_BLOCK( - 2, WASM_IF(WASM_ZERO, WASM_BRV_IF(0, WASM_ZERO, WASM_GET_LOCAL(0))), - WASM_GET_LOCAL(1))}; - + byte code2[] = { + WASM_BLOCK(2, WASM_IF(WASM_ZERO, WASM_BRV_IF_ZERO(0, WASM_GET_LOCAL(0))), + WASM_GET_LOCAL(1))}; for (size_t i = 0; i < arraysize(kLocalTypes); i++) { for (size_t j = 0; j < arraysize(kLocalTypes); j++) { @@ -1715,37 +1717,42 @@ TEST_F(WasmDecoderTest, ExprBr_Unify) { } } +TEST_F(WasmDecoderTest, ExprBrIf_cond_type) { + FunctionEnv env; + byte code[] = { + WASM_BLOCK(1, WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)))}; + for (size_t i = 0; i < arraysize(kLocalTypes); i++) { + for (size_t j = 0; j < arraysize(kLocalTypes); j++) { + LocalType types[] = {kLocalTypes[i], kLocalTypes[j]}; + FunctionSig sig(0, 2, types); + init_env(&env, &sig); -TEST_F(WasmDecoderTest, ExprBrIf_type) { - EXPECT_VERIFIES_INLINE( - &env_i_i, - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(0)), - WASM_GET_LOCAL(0))); - EXPECT_FAILURE_INLINE( - &env_d_dd, - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(0)), - WASM_GET_LOCAL(0))); + if (types[1] == kAstI32) { + EXPECT_VERIFIES(&env, code); + } else { + EXPECT_FAILURE(&env, code); + } + } + } +} +TEST_F(WasmDecoderTest, ExprBrIf_val_type) { FunctionEnv env; + byte code[] = { + WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)), + WASM_GET_LOCAL(0))}; for (size_t i = 0; i < arraysize(kLocalTypes); i++) { - LocalType type = kLocalTypes[i]; - LocalType storage[] = {kAstI32, kAstI32, type}; - FunctionSig sig(1, 2, storage); - init_env(&env, &sig); // (i32, X) -> i32 - - byte code1[] = { - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)), - WASM_GET_LOCAL(0))}; - - byte code2[] = { - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_GET_LOCAL(1), WASM_GET_LOCAL(0)), - WASM_GET_LOCAL(0))}; - if (type == kAstI32) { - EXPECT_VERIFIES(&env, code1); - EXPECT_VERIFIES(&env, code2); - } else { - EXPECT_FAILURE(&env, code1); - EXPECT_FAILURE(&env, code2); + for (size_t j = 0; j < arraysize(kLocalTypes); j++) { + LocalType types[] = {kLocalTypes[i], kLocalTypes[i], kLocalTypes[j], + kAstI32}; + FunctionSig sig(1, 3, types); + init_env(&env, &sig); + + if (i == j) { + EXPECT_VERIFIES(&env, code); + } else { + EXPECT_FAILURE(&env, code); + } } } } @@ -1761,13 +1768,10 @@ TEST_F(WasmDecoderTest, ExprBrIf_Unify) { FunctionSig sig(1, 2, storage); init_env(&env, &sig); // (i32, X) -> i32 - byte code1[] = { - WASM_BLOCK(2, WASM_BRV_IF(0, WASM_ZERO, WASM_GET_LOCAL(which)), - WASM_GET_LOCAL(which ^ 1))}; - byte code2[] = { - WASM_LOOP(2, WASM_BRV_IF(1, WASM_ZERO, WASM_GET_LOCAL(which)), - WASM_GET_LOCAL(which ^ 1))}; - + byte code1[] = {WASM_BLOCK(2, WASM_BRV_IF_ZERO(0, WASM_GET_LOCAL(which)), + WASM_GET_LOCAL(which ^ 1))}; + byte code2[] = {WASM_LOOP(2, WASM_BRV_IF_ZERO(1, WASM_GET_LOCAL(which)), + WASM_GET_LOCAL(which ^ 1))}; if (type == kAstI32) { EXPECT_VERIFIES(&env, code1); @@ -1800,6 +1804,12 @@ TEST_F(WasmDecoderTest, TableSwitch0c) { EXPECT_VERIFIES(&env_v_v, code); } +TEST_F(WasmDecoderTest, TableSwitch0d) { + static byte code[] = { + WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 2, WASM_CASE_BR(0), WASM_CASE_BR(1)), + WASM_I8(67))}; + EXPECT_VERIFIES(&env_v_v, code); +} TEST_F(WasmDecoderTest, TableSwitch1) { static byte code[] = {WASM_TABLESWITCH_OP(1, 1, WASM_CASE(0)), @@ -1831,9 +1841,6 @@ TEST_F(WasmDecoderTest, TableSwitch2) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, TableSwitch1b) { EXPECT_VERIFIES_INLINE(&env_i_i, WASM_TABLESWITCH_OP(1, 1, WASM_CASE(0)), WASM_TABLESWITCH_BODY(WASM_GET_LOCAL(0), WASM_ZERO)); @@ -1845,29 +1852,25 @@ TEST_F(WasmDecoderTest, TableSwitch1b) { WASM_TABLESWITCH_BODY(WASM_ZERO, WASM_F64(0.0))); } -#endif - - -TEST_F(WasmDecoderTest, TableSwitch_br) { - EXPECT_VERIFIES_INLINE(&env_i_i, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(0)), - WASM_GET_LOCAL(0)); +TEST_F(WasmDecoderTest, TableSwitch_br1) { for (int depth = 0; depth < 2; depth++) { - EXPECT_VERIFIES_INLINE( - &env_i_i, WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth)), - WASM_GET_LOCAL(0))); + byte code[] = {WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth)), + WASM_GET_LOCAL(0))}; + EXPECT_VERIFIES(&env_v_i, code); + EXPECT_FAILURE(&env_i_i, code); } } TEST_F(WasmDecoderTest, TableSwitch_invalid_br) { for (int depth = 1; depth < 4; depth++) { - EXPECT_FAILURE_INLINE(&env_i_i, + EXPECT_FAILURE_INLINE(&env_v_i, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth)), WASM_GET_LOCAL(0)); EXPECT_FAILURE_INLINE( - &env_i_i, - WASM_BLOCK(1, WASM_TABLESWITCH_OP(0, 1, WASM_CASE_BR(depth + 1)), - WASM_GET_LOCAL(0))); + &env_v_i, + WASM_TABLESWITCH_OP(0, 2, WASM_CASE_BR(depth), WASM_CASE_BR(depth)), + WASM_GET_LOCAL(0)); } } @@ -1880,17 +1883,12 @@ TEST_F(WasmDecoderTest, TableSwitch_invalid_case_ref) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, TableSwitch1_br) { EXPECT_VERIFIES_INLINE( &env_i_i, WASM_TABLESWITCH_OP(1, 1, WASM_CASE(0)), WASM_TABLESWITCH_BODY(WASM_GET_LOCAL(0), WASM_BRV(0, WASM_ZERO))); } -#endif - TEST_F(WasmDecoderTest, TableSwitch2_br) { EXPECT_VERIFIES_INLINE( @@ -1914,9 +1912,6 @@ TEST_F(WasmDecoderTest, TableSwitch2x2) { } -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 - TEST_F(WasmDecoderTest, ExprBreakNesting1) { EXPECT_VERIFIES_INLINE(&env_v_v, WASM_BLOCK(1, WASM_BRV(0, WASM_ZERO))); EXPECT_VERIFIES_INLINE(&env_v_v, WASM_BLOCK(1, WASM_BR(0))); @@ -1934,18 +1929,56 @@ TEST_F(WasmDecoderTest, ExprBreakNesting1) { EXPECT_VERIFIES_INLINE(&env_v_v, WASM_LOOP(1, WASM_BR(1))); } -#endif - TEST_F(WasmDecoderTest, Select) { EXPECT_VERIFIES_INLINE( + &env_i_i, WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_ZERO)); + EXPECT_VERIFIES_INLINE(&env_f_ff, + WASM_SELECT(WASM_F32(0.0), WASM_F32(0.0), WASM_ZERO)); + EXPECT_VERIFIES_INLINE(&env_d_dd, + WASM_SELECT(WASM_F64(0.0), WASM_F64(0.0), WASM_ZERO)); + EXPECT_VERIFIES_INLINE(&env_l_l, + WASM_SELECT(WASM_I64(0), WASM_I64(0), WASM_ZERO)); +} + +TEST_F(WasmDecoderTest, Select_fail1) { + EXPECT_FAILURE_INLINE(&env_i_i, WASM_SELECT(WASM_F32(0.0), WASM_GET_LOCAL(0), + WASM_GET_LOCAL(0))); + EXPECT_FAILURE_INLINE(&env_i_i, WASM_SELECT(WASM_GET_LOCAL(0), WASM_F32(0.0), + WASM_GET_LOCAL(0))); + EXPECT_FAILURE_INLINE( &env_i_i, - WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_GET_LOCAL(0))); + WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_F32(0.0))); } +TEST_F(WasmDecoderTest, Select_fail2) { + for (size_t i = 0; i < arraysize(kLocalTypes); i++) { + LocalType type = kLocalTypes[i]; + if (type == kAstI32) continue; + + LocalType types[] = {type, kAstI32, type}; + FunctionSig sig(1, 2, types); + FunctionEnv env; + init_env(&env, &sig); + + EXPECT_VERIFIES_INLINE( + &env, + WASM_SELECT(WASM_GET_LOCAL(1), WASM_GET_LOCAL(1), WASM_GET_LOCAL(0))); + + EXPECT_FAILURE_INLINE( + &env, + WASM_SELECT(WASM_GET_LOCAL(1), WASM_GET_LOCAL(0), WASM_GET_LOCAL(0))); + + EXPECT_FAILURE_INLINE( + &env, + WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(0))); + + EXPECT_FAILURE_INLINE( + &env, + WASM_SELECT(WASM_GET_LOCAL(0), WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); + } +} -// TODO(tizer): Fix on arm and reenable. -#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_ARM64 TEST_F(WasmDecoderTest, Select_TypeCheck) { EXPECT_FAILURE_INLINE(&env_i_i, WASM_SELECT(WASM_F32(9.9), WASM_GET_LOCAL(0), @@ -1958,22 +1991,18 @@ TEST_F(WasmDecoderTest, Select_TypeCheck) { &env_i_i, WASM_SELECT(WASM_F32(9.9), WASM_GET_LOCAL(0), WASM_I64(0))); } -#endif - class WasmOpcodeLengthTest : public TestWithZone { public: WasmOpcodeLengthTest() : TestWithZone() {} }; - -#define EXPECT_LENGTH(expected, opcode) \ - { \ - static const byte code[] = {opcode, 0, 0, 0, 0, 0, 0, 0, 0}; \ - EXPECT_EQ(expected, OpcodeLength(code)); \ +#define EXPECT_LENGTH(expected, opcode) \ + { \ + static const byte code[] = {opcode, 0, 0, 0, 0, 0, 0, 0, 0}; \ + EXPECT_EQ(expected, OpcodeLength(code, code + sizeof(code))); \ } - TEST_F(WasmOpcodeLengthTest, Statements) { EXPECT_LENGTH(1, kExprNop); EXPECT_LENGTH(2, kExprBlock); @@ -1997,6 +2026,7 @@ TEST_F(WasmOpcodeLengthTest, MiscExpressions) { EXPECT_LENGTH(2, kExprLoadGlobal); EXPECT_LENGTH(2, kExprStoreGlobal); EXPECT_LENGTH(2, kExprCallFunction); + EXPECT_LENGTH(2, kExprCallImport); EXPECT_LENGTH(2, kExprCallIndirect); EXPECT_LENGTH(1, kExprIf); EXPECT_LENGTH(1, kExprIfElse); @@ -2014,11 +2044,11 @@ TEST_F(WasmOpcodeLengthTest, VariableLength) { byte size5[] = {kExprLoadGlobal, 1 | 0x80, 2 | 0x80, 3 | 0x80, 4}; byte size6[] = {kExprLoadGlobal, 1 | 0x80, 2 | 0x80, 3 | 0x80, 4 | 0x80, 5}; - EXPECT_EQ(2, OpcodeLength(size2)); - EXPECT_EQ(3, OpcodeLength(size3)); - EXPECT_EQ(4, OpcodeLength(size4)); - EXPECT_EQ(5, OpcodeLength(size5)); - EXPECT_EQ(6, OpcodeLength(size6)); + EXPECT_EQ(2, OpcodeLength(size2, size2 + sizeof(size2))); + EXPECT_EQ(3, OpcodeLength(size3, size3 + sizeof(size3))); + EXPECT_EQ(4, OpcodeLength(size4, size4 + sizeof(size4))); + EXPECT_EQ(5, OpcodeLength(size5, size5 + sizeof(size5))); + EXPECT_EQ(6, OpcodeLength(size6, size6 + sizeof(size6))); } @@ -2183,14 +2213,12 @@ class WasmOpcodeArityTest : public TestWithZone { WasmOpcodeArityTest() : TestWithZone() {} }; - -#define EXPECT_ARITY(expected, ...) \ - { \ - static const byte code[] = {__VA_ARGS__}; \ - EXPECT_EQ(expected, OpcodeArity(&env, code)); \ +#define EXPECT_ARITY(expected, ...) \ + { \ + static const byte code[] = {__VA_ARGS__}; \ + EXPECT_EQ(expected, OpcodeArity(&env, code, code + sizeof(code))); \ } - TEST_F(WasmOpcodeArityTest, Control) { FunctionEnv env; EXPECT_ARITY(0, kExprNop); @@ -2249,12 +2277,16 @@ TEST_F(WasmOpcodeArityTest, Calls) { module.AddSignature(sigs.f_ff()); module.AddSignature(sigs.i_d()); + module.AddImport(sigs.f_ff()); + module.AddImport(sigs.i_d()); + { FunctionEnv env; WasmDecoderTest::init_env(&env, sigs.i_ii()); env.module = &module; EXPECT_ARITY(2, kExprCallFunction, 0); + EXPECT_ARITY(2, kExprCallImport, 0); EXPECT_ARITY(3, kExprCallIndirect, 0); EXPECT_ARITY(1, kExprBr); EXPECT_ARITY(2, kExprBrIf); @@ -2266,6 +2298,7 @@ TEST_F(WasmOpcodeArityTest, Calls) { env.module = &module; EXPECT_ARITY(1, kExprCallFunction, 1); + EXPECT_ARITY(1, kExprCallImport, 1); EXPECT_ARITY(2, kExprCallIndirect, 1); EXPECT_ARITY(1, kExprBr); EXPECT_ARITY(2, kExprBrIf); diff --git a/deps/v8/test/unittests/wasm/encoder-unittest.cc b/deps/v8/test/unittests/wasm/encoder-unittest.cc index 156cf6b1e5..e09e71aeb8 100644 --- a/deps/v8/test/unittests/wasm/encoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/encoder-unittest.cc @@ -56,28 +56,28 @@ TEST_F(EncoderTest, Function_Builder_Variable_Indexing) { WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone); uint16_t f_index = builder->AddFunction(); WasmFunctionBuilder* function = builder->FunctionAt(f_index); - uint16_t local_float32 = function->AddLocal(kAstF32); + uint16_t local_f32 = function->AddLocal(kAstF32); uint16_t param_float32 = function->AddParam(kAstF32); - uint16_t local_int32 = function->AddLocal(kAstI32); - uint16_t local_float64 = function->AddLocal(kAstF64); - uint16_t local_int64 = function->AddLocal(kAstI64); + uint16_t local_i32 = function->AddLocal(kAstI32); + uint16_t local_f64 = function->AddLocal(kAstF64); + uint16_t local_i64 = function->AddLocal(kAstI64); uint16_t param_int32 = function->AddParam(kAstI32); - uint16_t local_int32_2 = function->AddLocal(kAstI32); + uint16_t local_i32_2 = function->AddLocal(kAstI32); byte code[] = {kExprGetLocal, static_cast<uint8_t>(param_float32)}; uint32_t local_indices[] = {1}; function->EmitCode(code, sizeof(code), local_indices, 1); code[1] = static_cast<uint8_t>(param_int32); function->EmitCode(code, sizeof(code), local_indices, 1); - code[1] = static_cast<uint8_t>(local_int32); + code[1] = static_cast<uint8_t>(local_i32); function->EmitCode(code, sizeof(code), local_indices, 1); - code[1] = static_cast<uint8_t>(local_int32_2); + code[1] = static_cast<uint8_t>(local_i32_2); function->EmitCode(code, sizeof(code), local_indices, 1); - code[1] = static_cast<uint8_t>(local_int64); + code[1] = static_cast<uint8_t>(local_i64); function->EmitCode(code, sizeof(code), local_indices, 1); - code[1] = static_cast<uint8_t>(local_float32); + code[1] = static_cast<uint8_t>(local_f32); function->EmitCode(code, sizeof(code), local_indices, 1); - code[1] = static_cast<uint8_t>(local_float64); + code[1] = static_cast<uint8_t>(local_f64); function->EmitCode(code, sizeof(code), local_indices, 1); WasmFunctionEncoder* f = function->Build(&zone, builder); diff --git a/deps/v8/test/unittests/wasm/loop-assignment-analysis-unittest.cc b/deps/v8/test/unittests/wasm/loop-assignment-analysis-unittest.cc new file mode 100644 index 0000000000..958621970c --- /dev/null +++ b/deps/v8/test/unittests/wasm/loop-assignment-analysis-unittest.cc @@ -0,0 +1,211 @@ +// Copyright 2016 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 "test/unittests/test-utils.h" + +#include "src/v8.h" + +#include "test/cctest/wasm/test-signatures.h" + +#include "src/bit-vector.h" +#include "src/objects.h" + +#include "src/wasm/ast-decoder.h" +#include "src/wasm/wasm-macro-gen.h" +#include "src/wasm/wasm-module.h" + +#define WASM_SET_ZERO(i) WASM_SET_LOCAL(i, WASM_ZERO) + +namespace v8 { +namespace internal { +namespace wasm { + +class WasmLoopAssignmentAnalyzerTest : public TestWithZone { + public: + WasmLoopAssignmentAnalyzerTest() : TestWithZone(), sigs() { + init_env(&env, sigs.v_v()); + } + + TestSignatures sigs; + FunctionEnv env; + + static void init_env(FunctionEnv* env, FunctionSig* sig) { + env->module = nullptr; + env->sig = sig; + env->local_i32_count = 0; + env->local_i64_count = 0; + env->local_f32_count = 0; + env->local_f64_count = 0; + env->SumLocals(); + } + + BitVector* Analyze(const byte* start, const byte* end) { + return AnalyzeLoopAssignmentForTesting(zone(), &env, start, end); + } +}; + + +TEST_F(WasmLoopAssignmentAnalyzerTest, Empty0) { + byte code[] = { 0 }; + BitVector* assigned = Analyze(code, code); + CHECK_NULL(assigned); +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, Empty1) { + byte code[] = {kExprLoop, 0}; + for (int i = 0; i < 5; i++) { + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + CHECK_EQ(false, assigned->Contains(j)); + } + env.AddLocals(kAstI32, 1); + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, One) { + env.AddLocals(kAstI32, 5); + for (int i = 0; i < 5; i++) { + byte code[] = {WASM_LOOP(1, WASM_SET_ZERO(i))}; + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + CHECK_EQ(j == i, assigned->Contains(j)); + } + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, OneBeyond) { + env.AddLocals(kAstI32, 5); + for (int i = 0; i < 5; i++) { + byte code[] = {WASM_LOOP(1, WASM_SET_ZERO(i)), WASM_SET_ZERO(1)}; + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + CHECK_EQ(j == i, assigned->Contains(j)); + } + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, Two) { + env.AddLocals(kAstI32, 5); + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 5; j++) { + byte code[] = {WASM_LOOP(2, WASM_SET_ZERO(i), WASM_SET_ZERO(j))}; + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int k = 0; k < assigned->length(); k++) { + bool expected = k == i || k == j; + CHECK_EQ(expected, assigned->Contains(k)); + } + } + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, NestedIf) { + env.AddLocals(kAstI32, 5); + for (int i = 0; i < 5; i++) { + byte code[] = {WASM_LOOP( + 1, WASM_IF_ELSE(WASM_SET_ZERO(0), WASM_SET_ZERO(i), WASM_SET_ZERO(1)))}; + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + bool expected = i == j || j == 0 || j == 1; + CHECK_EQ(expected, assigned->Contains(j)); + } + } +} + + +static byte LEBByte(uint32_t val, byte which) { + byte b = (val >> (which * 7)) & 0x7F; + if (val >> ((which + 1) * 7)) b |= 0x80; + return b; +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, BigLocal) { + env.AddLocals(kAstI32, 65000); + for (int i = 13; i < 65000; i = static_cast<int>(i * 1.5)) { + byte code[] = {kExprLoop, + 1, + kExprSetLocal, + LEBByte(i, 0), + LEBByte(i, 1), + LEBByte(i, 2), + 11, + 12, + 13}; + + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + bool expected = i == j; + CHECK_EQ(expected, assigned->Contains(j)); + } + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, Break) { + env.AddLocals(kAstI32, 3); + byte code[] = { + WASM_LOOP(1, WASM_IF(WASM_GET_LOCAL(0), WASM_BRV(1, WASM_SET_ZERO(1)))), + WASM_SET_ZERO(0)}; + + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + bool expected = j == 1; + CHECK_EQ(expected, assigned->Contains(j)); + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, Loop1) { + env.AddLocals(kAstI32, 5); + byte code[] = { + WASM_LOOP(1, WASM_IF(WASM_GET_LOCAL(0), + WASM_BRV(0, WASM_SET_LOCAL( + 3, WASM_I32_SUB(WASM_GET_LOCAL(0), + WASM_I8(1)))))), + WASM_GET_LOCAL(0)}; + + BitVector* assigned = Analyze(code, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + bool expected = j == 3; + CHECK_EQ(expected, assigned->Contains(j)); + } +} + + +TEST_F(WasmLoopAssignmentAnalyzerTest, Loop2) { + env.AddLocals(kAstI32, 3); + const byte kIter = 0; + env.AddLocals(kAstF32, 3); + const byte kSum = 3; + + byte code[] = {WASM_BLOCK( + 3, + WASM_WHILE( + WASM_GET_LOCAL(kIter), + WASM_BLOCK(2, WASM_SET_LOCAL( + kSum, WASM_F32_ADD( + WASM_GET_LOCAL(kSum), + WASM_LOAD_MEM(MachineType::Float32(), + WASM_GET_LOCAL(kIter)))), + WASM_SET_LOCAL(kIter, WASM_I32_SUB(WASM_GET_LOCAL(kIter), + WASM_I8(4))))), + WASM_STORE_MEM(MachineType::Float32(), WASM_ZERO, WASM_GET_LOCAL(kSum)), + WASM_GET_LOCAL(kIter))}; + + BitVector* assigned = Analyze(code + 2, code + arraysize(code)); + for (int j = 0; j < assigned->length(); j++) { + bool expected = j == kIter || j == kSum; + CHECK_EQ(expected, assigned->Contains(j)); + } +} + + +} // namespace wasm +} // namespace internal +} // namespace v8 diff --git a/deps/v8/test/unittests/wasm/module-decoder-unittest.cc b/deps/v8/test/unittests/wasm/module-decoder-unittest.cc index 0738b5909b..467ffcc232 100644 --- a/deps/v8/test/unittests/wasm/module-decoder-unittest.cc +++ b/deps/v8/test/unittests/wasm/module-decoder-unittest.cc @@ -45,6 +45,15 @@ struct LocalTypePair { {kLocalF64, kAstF64}}; +// TODO(titzer): use these macros everywhere below. +#define U32_LE(v) \ + static_cast<byte>(v), static_cast<byte>((v) >> 8), \ + static_cast<byte>((v) >> 16), static_cast<byte>((v) >> 24) + + +#define U16_LE(v) static_cast<byte>(v), static_cast<byte>((v) >> 8) + + TEST_F(WasmModuleVerifyTest, DecodeEmpty) { static const byte data[1]{kDeclEnd}; { @@ -61,7 +70,7 @@ TEST_F(WasmModuleVerifyTest, DecodeEmpty) { TEST_F(WasmModuleVerifyTest, OneGlobal) { - const byte data[] = { + static const byte data[] = { kDeclGlobals, 1, 0, @@ -100,7 +109,7 @@ TEST_F(WasmModuleVerifyTest, OneGlobal) { TEST_F(WasmModuleVerifyTest, ZeroGlobals) { - const byte data[] = { + static const byte data[] = { kDeclGlobals, 0, // declare 0 globals }; ModuleResult result = DecodeModule(data, data + arraysize(data)); @@ -125,7 +134,7 @@ static void AppendUint32v(std::vector<byte>& buffer, uint32_t val) { TEST_F(WasmModuleVerifyTest, NGlobals) { - const byte data[] = { + static const byte data[] = { 0, 0, 0, 0, // name offset kMemI32, // memory type 0, // exported @@ -146,7 +155,7 @@ TEST_F(WasmModuleVerifyTest, NGlobals) { TEST_F(WasmModuleVerifyTest, GlobalWithInvalidNameOffset) { - const byte data[] = { + static const byte data[] = { kDeclGlobals, 1, // declare one global 0, @@ -162,7 +171,7 @@ TEST_F(WasmModuleVerifyTest, GlobalWithInvalidNameOffset) { TEST_F(WasmModuleVerifyTest, GlobalWithInvalidMemoryType) { - const byte data[] = { + static const byte data[] = { kDeclGlobals, 1, // declare one global 0, @@ -178,7 +187,7 @@ TEST_F(WasmModuleVerifyTest, GlobalWithInvalidMemoryType) { TEST_F(WasmModuleVerifyTest, TwoGlobals) { - const byte data[] = { + static const byte data[] = { kDeclGlobals, 2, 0, @@ -333,10 +342,10 @@ TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) { EXPECT_EQ(kCodeStartOffset, function->code_start_offset); EXPECT_EQ(kCodeEndOffset, function->code_end_offset); - EXPECT_EQ(523, function->local_int32_count); - EXPECT_EQ(1037, function->local_int64_count); - EXPECT_EQ(1551, function->local_float32_count); - EXPECT_EQ(2065, function->local_float64_count); + EXPECT_EQ(523, function->local_i32_count); + EXPECT_EQ(1037, function->local_i64_count); + EXPECT_EQ(1551, function->local_f32_count); + EXPECT_EQ(2065, function->local_f64_count); EXPECT_TRUE(function->exported); EXPECT_FALSE(function->external); @@ -373,10 +382,10 @@ TEST_F(WasmModuleVerifyTest, OneFunctionImported) { EXPECT_EQ(0, function->code_start_offset); EXPECT_EQ(0, function->code_end_offset); - EXPECT_EQ(0, function->local_int32_count); - EXPECT_EQ(0, function->local_int64_count); - EXPECT_EQ(0, function->local_float32_count); - EXPECT_EQ(0, function->local_float64_count); + EXPECT_EQ(0, function->local_i32_count); + EXPECT_EQ(0, function->local_i64_count); + EXPECT_EQ(0, function->local_f32_count); + EXPECT_EQ(0, function->local_f64_count); EXPECT_FALSE(function->exported); EXPECT_TRUE(function->external); @@ -410,10 +419,10 @@ TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody) { EXPECT_EQ(kCodeStartOffset, function->code_start_offset); EXPECT_EQ(kCodeEndOffset, function->code_end_offset); - EXPECT_EQ(0, function->local_int32_count); - EXPECT_EQ(0, function->local_int64_count); - EXPECT_EQ(0, function->local_float32_count); - EXPECT_EQ(0, function->local_float64_count); + EXPECT_EQ(0, function->local_i32_count); + EXPECT_EQ(0, function->local_i64_count); + EXPECT_EQ(0, function->local_f32_count); + EXPECT_EQ(0, function->local_f64_count); EXPECT_FALSE(function->exported); EXPECT_FALSE(function->external); @@ -450,10 +459,10 @@ TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody_WithLocals) { EXPECT_EQ(kCodeStartOffset, function->code_start_offset); EXPECT_EQ(kCodeEndOffset, function->code_end_offset); - EXPECT_EQ(513, function->local_int32_count); - EXPECT_EQ(1027, function->local_int64_count); - EXPECT_EQ(1541, function->local_float32_count); - EXPECT_EQ(2055, function->local_float64_count); + EXPECT_EQ(513, function->local_i32_count); + EXPECT_EQ(1027, function->local_i64_count); + EXPECT_EQ(1541, function->local_f32_count); + EXPECT_EQ(2055, function->local_f64_count); EXPECT_FALSE(function->exported); EXPECT_FALSE(function->external); @@ -463,10 +472,13 @@ TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody_WithLocals) { TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) { - static const byte kCodeStartOffset = 2 + kDeclGlobalSize + 4 + 2 + 17; + static const byte kDeclMemorySize = 4; + static const byte kCodeStartOffset = + 2 + kDeclMemorySize + kDeclGlobalSize + 4 + 2 + 17; static const byte kCodeEndOffset = kCodeStartOffset + 3; static const byte data[] = { + kDeclMemory, 28, 28, 1, // global#0 -------------------------------------------------- kDeclGlobals, 1, 0, 0, 0, 0, // name offset kMemU8, // memory type @@ -531,24 +543,17 @@ TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) { TEST_F(WasmModuleVerifyTest, OneDataSegment) { const byte data[] = { - kDeclDataSegments, - 1, - 0xaa, - 0xbb, - 0x09, + kDeclMemory, 28, 28, 1, kDeclDataSegments, 1, 0xaa, 0xbb, 0x09, 0, // dest addr - 11, - 0, - 0, + 11, 0, 0, 0, // source offset - 3, - 0, - 0, + 3, 0, 0, 0, // source size 1, // init }; { + EXPECT_VERIFIES(data); ModuleResult result = DecodeModule(data, data + arraysize(data)); EXPECT_TRUE(result.ok()); EXPECT_EQ(0, result.val->globals->size()); @@ -565,7 +570,7 @@ TEST_F(WasmModuleVerifyTest, OneDataSegment) { if (result.val) delete result.val; } - for (size_t size = 1; size < arraysize(data); size++) { + for (size_t size = 5; size < arraysize(data); size++) { // Should fall off end of module bytes. ModuleResult result = DecodeModule(data, data + size); EXPECT_FALSE(result.ok()); @@ -576,32 +581,18 @@ TEST_F(WasmModuleVerifyTest, OneDataSegment) { TEST_F(WasmModuleVerifyTest, TwoDataSegments) { const byte data[] = { - kDeclDataSegments, - 2, - 0xee, - 0xff, - 0x07, + kDeclMemory, 28, 28, 1, kDeclDataSegments, 2, 0xee, 0xff, 0x07, 0, // dest addr - 9, - 0, - 0, + 9, 0, 0, 0, // #0: source offset - 4, - 0, - 0, + 4, 0, 0, 0, // source size 0, // init - 0xcc, - 0xdd, - 0x06, + 0xcc, 0xdd, 0x06, 0, // #1: dest addr - 6, - 0, - 0, + 6, 0, 0, 0, // source offset - 10, - 0, - 0, + 10, 0, 0, 0, // source size 1, // init }; @@ -629,7 +620,7 @@ TEST_F(WasmModuleVerifyTest, TwoDataSegments) { if (result.val) delete result.val; } - for (size_t size = 1; size < arraysize(data); size++) { + for (size_t size = 5; size < arraysize(data); size++) { // Should fall off end of module bytes. ModuleResult result = DecodeModule(data, data + size); EXPECT_FALSE(result.ok()); @@ -638,6 +629,71 @@ TEST_F(WasmModuleVerifyTest, TwoDataSegments) { } +TEST_F(WasmModuleVerifyTest, DataSegmentWithInvalidSource) { + const int dest_addr = 0x100; + const byte mem_size_log2 = 15; + const int kDataSize = 19; + + for (int source_offset = 0; source_offset < 5 + kDataSize; source_offset++) { + for (int source_size = -1; source_size < 5 + kDataSize; source_size += 3) { + byte data[] = { + kDeclMemory, + mem_size_log2, + mem_size_log2, + 1, + kDeclDataSegments, + 1, + U32_LE(dest_addr), + U32_LE(source_offset), + U32_LE(source_size), + 1, // init + }; + + STATIC_ASSERT(kDataSize == arraysize(data)); + + if (source_offset < kDataSize && source_size >= 0 && + (source_offset + source_size) <= kDataSize) { + EXPECT_VERIFIES(data); + } else { + EXPECT_FAILURE(data); + } + } + } +} + + +TEST_F(WasmModuleVerifyTest, DataSegmentWithInvalidDest) { + const int source_size = 3; + const int source_offset = 11; + + for (byte mem_size_log2 = 12; mem_size_log2 < 20; mem_size_log2++) { + int mem_size = 1 << mem_size_log2; + + for (int dest_addr = mem_size - source_size; + dest_addr < mem_size + source_size; dest_addr++) { + byte data[] = { + kDeclMemory, + mem_size_log2, + mem_size_log2, + 1, + kDeclDataSegments, + 1, + U32_LE(dest_addr), + U32_LE(source_offset), + U32_LE(source_size), + 1, // init + }; + + if (dest_addr <= (mem_size - source_size)) { + EXPECT_VERIFIES(data); + } else { + EXPECT_FAILURE(data); + } + } + } +} + + // To make below tests for indirect calls much shorter. #define FUNCTION(sig_index, external) \ kDeclFunctionImport, static_cast<byte>(sig_index), \ @@ -848,7 +904,7 @@ class WasmFunctionVerifyTest : public TestWithZone {}; TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) { - byte data[] = { + static const byte data[] = { 0, kLocalVoid, // signature 3, 0, // local int32 count 4, 0, // local int64 count @@ -868,10 +924,10 @@ TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) { EXPECT_EQ(0, function->name_offset); EXPECT_EQ(arraysize(data) - 1, function->code_start_offset); EXPECT_EQ(arraysize(data), function->code_end_offset); - EXPECT_EQ(3, function->local_int32_count); - EXPECT_EQ(4, function->local_int64_count); - EXPECT_EQ(5, function->local_float32_count); - EXPECT_EQ(6, function->local_float64_count); + EXPECT_EQ(3, function->local_i32_count); + EXPECT_EQ(4, function->local_i64_count); + EXPECT_EQ(5, function->local_f32_count); + EXPECT_EQ(6, function->local_f64_count); EXPECT_FALSE(function->external); EXPECT_FALSE(function->exported); } @@ -889,7 +945,7 @@ TEST_F(WasmModuleVerifyTest, WLLSectionNoLen) { TEST_F(WasmModuleVerifyTest, WLLSectionEmpty) { - const byte data[] = { + static const byte data[] = { kDeclWLL, 0, // empty section }; ModuleResult result = DecodeModule(data, data + arraysize(data)); @@ -899,7 +955,7 @@ TEST_F(WasmModuleVerifyTest, WLLSectionEmpty) { TEST_F(WasmModuleVerifyTest, WLLSectionOne) { - const byte data[] = { + static const byte data[] = { kDeclWLL, 1, // LEB128 1 0, // one byte section @@ -911,10 +967,10 @@ TEST_F(WasmModuleVerifyTest, WLLSectionOne) { TEST_F(WasmModuleVerifyTest, WLLSectionTen) { - const byte data[] = { + static const byte data[] = { kDeclWLL, - 10, // LEB128 10 - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10 byte section + 10, // LEB128 10 + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10 byte section }; ModuleResult result = DecodeModule(data, data + arraysize(data)); EXPECT_TRUE(result.ok()); @@ -923,20 +979,19 @@ TEST_F(WasmModuleVerifyTest, WLLSectionTen) { TEST_F(WasmModuleVerifyTest, WLLSectionOverflow) { - const byte data[] = { + static const byte data[] = { kDeclWLL, - 11, // LEB128 11 - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10 byte section + 11, // LEB128 11 + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10 byte section }; EXPECT_FAILURE(data); } TEST_F(WasmModuleVerifyTest, WLLSectionUnderflow) { - const byte data[] = { - kDeclWLL, - 0xff, 0xff, 0xff, 0xff, 0x0f, // LEB128 0xffffffff - 1, 2, 3, 4, // 4 byte section + static const byte data[] = { + kDeclWLL, 0xff, 0xff, 0xff, 0xff, 0x0f, // LEB128 0xffffffff + 1, 2, 3, 4, // 4 byte section }; EXPECT_FAILURE(data); } @@ -944,14 +999,92 @@ TEST_F(WasmModuleVerifyTest, WLLSectionUnderflow) { TEST_F(WasmModuleVerifyTest, WLLSectionLoop) { // Would infinite loop decoding if wrapping and allowed. - const byte data[] = { - kDeclWLL, - 0xfa, 0xff, 0xff, 0xff, 0x0f, // LEB128 0xfffffffa - 1, 2, 3, 4, // 4 byte section + static const byte data[] = { + kDeclWLL, 0xfa, 0xff, 0xff, 0xff, 0x0f, // LEB128 0xfffffffa + 1, 2, 3, 4, // 4 byte section }; EXPECT_FAILURE(data); } +TEST_F(WasmModuleVerifyTest, ImportTable_empty) { + static const byte data[] = {kDeclSignatures, 0, kDeclImportTable, 0}; + EXPECT_VERIFIES(data); +} + +TEST_F(WasmModuleVerifyTest, ImportTable_nosigs) { + static const byte data[] = {kDeclImportTable, 0}; + EXPECT_FAILURE(data); +} + +TEST_F(WasmModuleVerifyTest, ImportTable_invalid_sig) { + static const byte data[] = { + kDeclSignatures, + 0, + kDeclImportTable, + 1, + 0, + 0, // sig index + 1, + 0, + 0, + 0, // module name + 1, + 0, + 0, + 0 // function name + }; + EXPECT_FAILURE(data); +} + +TEST_F(WasmModuleVerifyTest, ImportTable_one_sig) { + static const byte data[] = { + kDeclSignatures, + 1, + 0, + static_cast<byte>(kAstStmt), + kDeclImportTable, + 1, + 0, + 0, // sig index + 1, + 0, + 0, + 0, // module name + 1, + 0, + 0, + 0 // function name + }; + EXPECT_VERIFIES(data); +} + +TEST_F(WasmModuleVerifyTest, ImportTable_off_end) { + static const byte data[] = { + kDeclSignatures, + 1, + 0, + static_cast<byte>(kAstStmt), + kDeclImportTable, + 1, + 0, + 0, // sig index + 1, + 0, + 0, + 0, // module name + 1, + 0, + 0, + 0 // function name + }; + + for (size_t length = 5; length < sizeof(data); length++) { + ModuleResult result = DecodeModule(data, data + length); + EXPECT_FALSE(result.ok()); + if (result.val) delete result.val; + } +} + } // namespace wasm } // namespace internal } // namespace v8 diff --git a/deps/v8/test/unittests/wasm/wasm-macro-gen-unittest.cc b/deps/v8/test/unittests/wasm/wasm-macro-gen-unittest.cc index c5bb5eca00..f3f604b3ed 100644 --- a/deps/v8/test/unittests/wasm/wasm-macro-gen-unittest.cc +++ b/deps/v8/test/unittests/wasm/wasm-macro-gen-unittest.cc @@ -131,15 +131,25 @@ TEST_F(WasmMacroGenTest, Expressions) { EXPECT_SIZE(6, WASM_LOOP(3, WASM_NOP, WASM_NOP, WASM_ZERO)); } - -TEST_F(WasmMacroGenTest, FunctionCalls) { +TEST_F(WasmMacroGenTest, CallFunction) { EXPECT_SIZE(2, WASM_CALL_FUNCTION0(0)); EXPECT_SIZE(2, WASM_CALL_FUNCTION0(1)); EXPECT_SIZE(2, WASM_CALL_FUNCTION0(11)); EXPECT_SIZE(4, WASM_CALL_FUNCTION(0, WASM_ZERO)); EXPECT_SIZE(6, WASM_CALL_FUNCTION(1, WASM_ZERO, WASM_ZERO)); +} + +TEST_F(WasmMacroGenTest, CallImport) { + EXPECT_SIZE(2, WASM_CALL_IMPORT0(0)); + EXPECT_SIZE(2, WASM_CALL_IMPORT0(1)); + EXPECT_SIZE(2, WASM_CALL_IMPORT0(11)); + + EXPECT_SIZE(4, WASM_CALL_IMPORT(0, WASM_ZERO)); + EXPECT_SIZE(6, WASM_CALL_IMPORT(1, WASM_ZERO, WASM_ZERO)); +} +TEST_F(WasmMacroGenTest, CallIndirect) { EXPECT_SIZE(4, WASM_CALL_INDIRECT0(0, WASM_ZERO)); EXPECT_SIZE(4, WASM_CALL_INDIRECT0(1, WASM_ZERO)); EXPECT_SIZE(4, WASM_CALL_INDIRECT0(11, WASM_ZERO)); diff --git a/deps/v8/test/webkit/fast/regex/toString-expected.txt b/deps/v8/test/webkit/fast/regex/toString-expected.txt index 154411242e..08852f9543 100644 --- a/deps/v8/test/webkit/fast/regex/toString-expected.txt +++ b/deps/v8/test/webkit/fast/regex/toString-expected.txt @@ -58,3 +58,4 @@ PASS successfullyParsed is true TEST COMPLETE + diff --git a/deps/v8/test/webkit/function-declarations-in-switch-statement-expected.txt b/deps/v8/test/webkit/function-declarations-in-switch-statement-expected.txt index 602b8b9f87..938e028933 100644 --- a/deps/v8/test/webkit/function-declarations-in-switch-statement-expected.txt +++ b/deps/v8/test/webkit/function-declarations-in-switch-statement-expected.txt @@ -26,7 +26,7 @@ PASS 20 is 20 WARN: shouldBe() expects string arguments PASS 20 is 20 WARN: shouldBe() expects string arguments -PASS 20 is 20 +FAIL -1 should be 20. Was -1. PASS successfullyParsed is true TEST COMPLETE diff --git a/deps/v8/test/webkit/webkit.status b/deps/v8/test/webkit/webkit.status index 971cf4691f..fa527427bc 100644 --- a/deps/v8/test/webkit/webkit.status +++ b/deps/v8/test/webkit/webkit.status @@ -35,9 +35,8 @@ 'dfg-inline-arguments-reset-changetype': [PASS, FAIL], # TODO(turbofan): We run out of stack earlier on 64-bit for now. 'fast/js/deep-recursion-test': [PASS, NO_VARIANTS], - # This test leads to a SyntaxError from conflicting let declarations - # in ES2015 - 'function-declarations-in-switch-statement': [FAIL], + # Irregexp interpreter overflows stack. We should just not crash. + 'fast/js/regexp-stack-overflow': [PASS, FAIL], }], # ALWAYS ['mode == debug', { # Too slow in debug mode. |