| // Copyright 2014 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/api/api-inl.h" |
| #include "src/codegen/code-factory.h" |
| #include "src/codegen/compiler.h" |
| #include "src/codegen/optimized-compilation-info.h" |
| #include "src/compiler/common-operator.h" |
| #include "src/compiler/graph.h" |
| #include "src/compiler/linkage.h" |
| #include "src/compiler/machine-operator.h" |
| #include "src/compiler/node.h" |
| #include "src/compiler/operator.h" |
| #include "src/compiler/pipeline.h" |
| #include "src/compiler/schedule.h" |
| #include "src/objects/objects-inl.h" |
| #include "src/parsing/parse-info.h" |
| #include "src/zone/zone.h" |
| #include "test/cctest/cctest.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace compiler { |
| |
| static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite, |
| "dummy", 0, 0, 0, 0, 0, 0); |
| |
| // So we can get a real JS function. |
| static Handle<JSFunction> Compile(const char* source) { |
| Isolate* isolate = CcTest::i_isolate(); |
| Handle<String> source_code = isolate->factory() |
| ->NewStringFromUtf8(CStrVector(source)) |
| .ToHandleChecked(); |
| Handle<SharedFunctionInfo> shared = |
| Compiler::GetSharedFunctionInfoForScript( |
| isolate, source_code, Compiler::ScriptDetails(), |
| v8::ScriptOriginOptions(), nullptr, nullptr, |
| v8::ScriptCompiler::kNoCompileOptions, |
| ScriptCompiler::kNoCacheNoReason, NOT_NATIVES_CODE) |
| .ToHandleChecked(); |
| return isolate->factory()->NewFunctionFromSharedFunctionInfo( |
| shared, isolate->native_context()); |
| } |
| |
| |
| TEST(TestLinkageCreate) { |
| HandleAndZoneScope handles; |
| Handle<JSFunction> function = Compile("a + b"); |
| Handle<SharedFunctionInfo> shared(function->shared(), handles.main_isolate()); |
| OptimizedCompilationInfo info(handles.main_zone(), function->GetIsolate(), |
| shared, function, CodeKind::TURBOFAN); |
| auto call_descriptor = Linkage::ComputeIncoming(info.zone(), &info); |
| CHECK(call_descriptor); |
| } |
| |
| |
| TEST(TestLinkageJSFunctionIncoming) { |
| const char* sources[] = {"(function() { })", "(function(a) { })", |
| "(function(a,b) { })", "(function(a,b,c) { })"}; |
| |
| for (int i = 0; i < 3; i++) { |
| HandleAndZoneScope handles; |
| Handle<JSFunction> function = |
| Handle<JSFunction>::cast(v8::Utils::OpenHandle( |
| *v8::Local<v8::Function>::Cast(CompileRun(sources[i])))); |
| Handle<SharedFunctionInfo> shared(function->shared(), |
| handles.main_isolate()); |
| OptimizedCompilationInfo info(handles.main_zone(), function->GetIsolate(), |
| shared, function, CodeKind::TURBOFAN); |
| auto call_descriptor = Linkage::ComputeIncoming(info.zone(), &info); |
| CHECK(call_descriptor); |
| |
| CHECK_EQ(1 + i, static_cast<int>(call_descriptor->JSParameterCount())); |
| CHECK_EQ(1, static_cast<int>(call_descriptor->ReturnCount())); |
| CHECK_EQ(Operator::kNoProperties, call_descriptor->properties()); |
| CHECK_EQ(true, call_descriptor->IsJSFunctionCall()); |
| } |
| } |
| |
| |
| TEST(TestLinkageJSCall) { |
| HandleAndZoneScope handles; |
| Handle<JSFunction> function = Compile("a + c"); |
| Handle<SharedFunctionInfo> shared(function->shared(), handles.main_isolate()); |
| OptimizedCompilationInfo info(handles.main_zone(), function->GetIsolate(), |
| shared, function, CodeKind::TURBOFAN); |
| |
| for (int i = 0; i < 32; i++) { |
| auto call_descriptor = Linkage::GetJSCallDescriptor( |
| info.zone(), false, i, CallDescriptor::kNoFlags); |
| CHECK(call_descriptor); |
| CHECK_EQ(i, static_cast<int>(call_descriptor->JSParameterCount())); |
| CHECK_EQ(1, static_cast<int>(call_descriptor->ReturnCount())); |
| CHECK_EQ(Operator::kNoProperties, call_descriptor->properties()); |
| CHECK_EQ(true, call_descriptor->IsJSFunctionCall()); |
| } |
| } |
| |
| |
| TEST(TestLinkageRuntimeCall) { |
| // TODO(titzer): test linkage creation for outgoing runtime calls. |
| } |
| |
| |
| TEST(TestLinkageStubCall) { |
| // TODO(bbudge) Add tests for FP registers. |
| Isolate* isolate = CcTest::InitIsolateOnce(); |
| Zone zone(isolate->allocator(), ZONE_NAME); |
| Callable callable = Builtins::CallableFor(isolate, Builtins::kToNumber); |
| OptimizedCompilationInfo info(ArrayVector("test"), &zone, |
| CodeKind::FOR_TESTING); |
| auto call_descriptor = Linkage::GetStubCallDescriptor( |
| &zone, callable.descriptor(), 0, CallDescriptor::kNoFlags, |
| Operator::kNoProperties); |
| CHECK(call_descriptor); |
| CHECK_EQ(0, static_cast<int>(call_descriptor->StackParameterCount())); |
| CHECK_EQ(1, static_cast<int>(call_descriptor->ReturnCount())); |
| CHECK_EQ(Operator::kNoProperties, call_descriptor->properties()); |
| CHECK_EQ(false, call_descriptor->IsJSFunctionCall()); |
| |
| CHECK_EQ(call_descriptor->GetParameterType(0), MachineType::AnyTagged()); |
| CHECK_EQ(call_descriptor->GetReturnType(0), MachineType::AnyTagged()); |
| // TODO(titzer): test linkage creation for outgoing stub calls. |
| } |
| |
| TEST(TestFPLinkageStubCall) { |
| Isolate* isolate = CcTest::InitIsolateOnce(); |
| Zone zone(isolate->allocator(), ZONE_NAME); |
| Callable callable = |
| Builtins::CallableFor(isolate, Builtins::kWasmFloat64ToNumber); |
| OptimizedCompilationInfo info(ArrayVector("test"), &zone, |
| CodeKind::FOR_TESTING); |
| auto call_descriptor = Linkage::GetStubCallDescriptor( |
| &zone, callable.descriptor(), 0, CallDescriptor::kNoFlags, |
| Operator::kNoProperties); |
| CHECK(call_descriptor); |
| CHECK_EQ(0, static_cast<int>(call_descriptor->StackParameterCount())); |
| CHECK_EQ(1, static_cast<int>(call_descriptor->ParameterCount())); |
| CHECK_EQ(1, static_cast<int>(call_descriptor->ReturnCount())); |
| CHECK_EQ(Operator::kNoProperties, call_descriptor->properties()); |
| CHECK_EQ(false, call_descriptor->IsJSFunctionCall()); |
| |
| CHECK_EQ(call_descriptor->GetInputType(1), MachineType::Float64()); |
| CHECK(call_descriptor->GetInputLocation(1).IsRegister()); |
| CHECK_EQ(call_descriptor->GetReturnType(0), MachineType::AnyTagged()); |
| CHECK(call_descriptor->GetReturnLocation(0).IsRegister()); |
| CHECK_EQ(call_descriptor->GetReturnLocation(0).GetLocation(), |
| kReturnRegister0.code()); |
| } |
| |
| } // namespace compiler |
| } // namespace internal |
| } // namespace v8 |