Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

3
deps/v8/test/common/DEPS vendored Normal file
View File

@ -0,0 +1,3 @@
include_rules = [
"+src",
]

126
deps/v8/test/common/assembler-tester.h vendored Normal file
View File

@ -0,0 +1,126 @@
// Copyright 2018 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_TEST_COMMON_ASSEMBLER_TESTER_H_
#define V8_TEST_COMMON_ASSEMBLER_TESTER_H_
#include <memory>
#include "src/codegen/assembler.h"
#include "src/codegen/flush-instruction-cache.h"
#include "src/common/code-memory-access.h"
namespace v8 {
namespace internal {
class TestingAssemblerBuffer : public AssemblerBuffer {
public:
TestingAssemblerBuffer(size_t requested, void* address,
JitPermission jit_permission = JitPermission::kNoJit)
: protection_reconfiguration_is_allowed_(true) {
size_t page_size = v8::internal::AllocatePageSize();
size_t alloc_size = RoundUp(requested, page_size);
CHECK_GE(kMaxInt, alloc_size);
reservation_ = VirtualMemory(
GetPlatformPageAllocator(), alloc_size, address, page_size,
jit_permission == JitPermission::kNoJit
? v8::PageAllocator::Permission::kNoAccess
: v8::PageAllocator::Permission::kNoAccessWillJitLater);
CHECK(reservation_.IsReserved());
MakeWritable();
}
~TestingAssemblerBuffer() override { reservation_.Free(); }
uint8_t* start() const override {
return reinterpret_cast<uint8_t*>(reservation_.address());
}
int size() const override { return static_cast<int>(reservation_.size()); }
std::unique_ptr<AssemblerBuffer> Grow(int new_size) override {
FATAL("Cannot grow TestingAssemblerBuffer");
}
std::unique_ptr<AssemblerBuffer> CreateView() const {
return ExternalAssemblerBuffer(start(), size());
}
void MakeExecutable() {
// Flush the instruction cache as part of making the buffer executable.
// Note: we do this before setting permissions to ReadExecute because on
// some older ARM kernels there is a bug which causes an access error on
// cache flush instructions to trigger access error on non-writable memory.
// See https://bugs.chromium.org/p/v8/issues/detail?id=8157
FlushInstructionCache(start(), size());
if (protection_reconfiguration_is_allowed_) {
bool result = SetPermissions(GetPlatformPageAllocator(), start(), size(),
v8::PageAllocator::kReadExecute);
CHECK(result);
}
}
void MakeWritable() {
if (protection_reconfiguration_is_allowed_) {
bool result = SetPermissions(GetPlatformPageAllocator(), start(), size(),
v8::PageAllocator::kReadWrite);
CHECK(result);
}
}
void MakeWritableAndExecutable() {
bool result = SetPermissions(GetPlatformPageAllocator(), start(), size(),
v8::PageAllocator::kReadWriteExecute);
CHECK(result);
// Once buffer protection is set to RWX it might not be allowed to be
// changed anymore.
protection_reconfiguration_is_allowed_ =
!V8_HEAP_USE_PTHREAD_JIT_WRITE_PROTECT &&
!V8_HEAP_USE_BECORE_JIT_WRITE_PROTECT &&
protection_reconfiguration_is_allowed_;
}
private:
VirtualMemory reservation_;
bool protection_reconfiguration_is_allowed_;
};
// This scope class is mostly necesasry for arm64 tests running on Apple Silicon
// (M1) which prohibits reconfiguration of page permissions for RWX pages.
// Instead of altering the page permissions one must flip the X-W state by
// calling pthread_jit_write_protect_np() function.
// See RwxMemoryWriteScope for details.
class V8_NODISCARD AssemblerBufferWriteScope final {
public:
explicit AssemblerBufferWriteScope(TestingAssemblerBuffer& buffer)
: buffer_(buffer) {
buffer_.MakeWritable();
}
~AssemblerBufferWriteScope() { buffer_.MakeExecutable(); }
// Disable copy constructor and copy-assignment operator, since this manages
// a resource and implicit copying of the scope can yield surprising errors.
AssemblerBufferWriteScope(const AssemblerBufferWriteScope&) = delete;
AssemblerBufferWriteScope& operator=(const AssemblerBufferWriteScope&) =
delete;
private:
RwxMemoryWriteScopeForTesting rwx_write_scope_;
TestingAssemblerBuffer& buffer_;
};
static inline std::unique_ptr<TestingAssemblerBuffer> AllocateAssemblerBuffer(
size_t requested = v8::internal::AssemblerBase::kDefaultBufferSize,
void* address = nullptr,
JitPermission jit_permission = JitPermission::kMapAsJittable) {
return std::make_unique<TestingAssemblerBuffer>(requested, address,
jit_permission);
}
} // namespace internal
} // namespace v8
#endif // V8_TEST_COMMON_ASSEMBLER_TESTER_H_

145
deps/v8/test/common/c-signature.h vendored Normal file
View File

@ -0,0 +1,145 @@
// Copyright 2022 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_COMMON_C_SIGNATURE_H_
#define V8_COMMON_C_SIGNATURE_H_
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
#include "include/v8-fast-api-calls.h"
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
#include "src/codegen/machine-type.h"
namespace v8 {
namespace internal {
namespace compiler {
#define FOREACH_CTYPE_MACHINE_TYPE_MAPPING(V) \
V(void, MachineType::None()) \
V(bool, MachineType::Uint8()) \
V(int8_t, MachineType::Int8()) \
V(uint8_t, MachineType::Uint8()) \
V(int16_t, MachineType::Int16()) \
V(uint16_t, MachineType::Uint16()) \
V(int32_t, MachineType::Int32()) \
V(uint32_t, MachineType::Uint32()) \
V(int64_t, MachineType::Int64()) \
V(uint64_t, MachineType::Uint64()) \
V(float, MachineType::Float32()) \
V(double, MachineType::Float64()) \
V(void*, MachineType::Pointer()) \
V(int*, MachineType::Pointer())
template <typename T>
inline constexpr MachineType MachineTypeForC() {
static_assert(
std::is_convertible<T, Tagged<Object>>::value,
"all non-specialized types must be convertible to Tagged<Object>");
return MachineType::AnyTagged();
}
#define DECLARE_TEMPLATE_SPECIALIZATION(ctype, mtype) \
template <> \
inline MachineType constexpr MachineTypeForC<ctype>() { \
return mtype; \
}
FOREACH_CTYPE_MACHINE_TYPE_MAPPING(DECLARE_TEMPLATE_SPECIALIZATION)
#undef DECLARE_TEMPLATE_SPECIALIZATION
#ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
template <>
inline MachineType constexpr MachineTypeForC<v8::AnyCType>() {
return MachineType::Int64();
}
#endif // V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
// Helper for building machine signatures from C types.
class CSignature : public MachineSignature {
protected:
CSignature(size_t return_count, size_t parameter_count, MachineType* reps)
: MachineSignature(return_count, parameter_count, reps) {}
public:
friend Zone;
template <typename... Params>
static void VerifyParams(MachineSignature* sig) {
// Verifies the C signature against the machine types.
std::array<MachineType, sizeof...(Params)> params{
{MachineTypeForC<Params>()...}};
for (size_t p = 0; p < params.size(); ++p) {
CHECK_EQ(sig->GetParam(p), params[p]);
}
}
static CSignature* FromMachine(Zone* zone, MachineSignature* msig) {
return reinterpret_cast<CSignature*>(msig);
}
template <typename... ParamMachineTypes>
static CSignature* New(Zone* zone, MachineType ret,
ParamMachineTypes... params) {
constexpr size_t param_count = sizeof...(params);
std::array<MachineType, param_count> param_arr{{params...}};
const size_t buffer_size =
param_count + (ret == MachineType::None() ? 0 : 1);
MachineType* buffer = zone->AllocateArray<MachineType>(buffer_size);
size_t pos = 0;
size_t return_count = 0;
if (ret != MachineType::None()) {
buffer[pos++] = ret;
return_count++;
}
for (MachineType p : param_arr) {
// Check that there are no MachineType::None()'s in the parameters.
CHECK_NE(MachineType::None(), p);
buffer[pos++] = p;
}
DCHECK_EQ(buffer_size, pos);
return zone->New<CSignature>(return_count, param_count, buffer);
}
};
// Helper classes for instantiating Signature objects to be callable from C.
template <typename Ret, typename... Params>
class CSignatureOf : public CSignature {
public:
CSignatureOf() : CSignature(kReturnCount, kParamCount, storage_) {
constexpr std::array<MachineType, kParamCount> param_types{
MachineTypeForC<Params>()...};
if (kReturnCount == 1) storage_[0] = MachineTypeForC<Ret>();
static_assert(
std::is_same<decltype(*reps_), decltype(*param_types.data())>::value,
"type mismatch, cannot memcpy");
if (kParamCount > 0) {
#if V8_CC_GNU
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
#endif
memcpy(storage_ + kReturnCount, param_types.data(),
sizeof(*storage_) * kParamCount);
#if V8_CC_GNU
#pragma GCC diagnostic pop
#endif
}
}
private:
static constexpr size_t kReturnCount =
MachineTypeForC<Ret>() == MachineType::None() ? 0 : 1;
static constexpr size_t kParamCount = sizeof...(Params);
MachineType storage_[kReturnCount + kParamCount];
};
using CSignature_i_ii = CSignatureOf<int32_t, int32_t, int32_t>;
using CSignature_u_uu = CSignatureOf<uint32_t, uint32_t, uint32_t>;
using CSignature_f_ff = CSignatureOf<float, float, float>;
using CSignature_d_dd = CSignatureOf<double, double, double>;
using CSignature_o_oo = CSignatureOf<Object, Object, Object>;
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMMON_C_SIGNATURE_H_

74
deps/v8/test/common/call-tester.h vendored Normal file
View File

@ -0,0 +1,74 @@
// Copyright 2022 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_COMMON_CALL_TESTER_H_
#define V8_COMMON_CALL_TESTER_H_
#include "src/execution/simulator.h"
#include "src/handles/handles.h"
#include "src/objects/code.h"
#include "test/common/c-signature.h"
namespace v8 {
namespace internal {
namespace compiler {
template <typename R>
class CallHelper {
public:
explicit CallHelper(Isolate* isolate, MachineSignature* csig)
: csig_(csig), isolate_(isolate) {
USE(isolate_);
}
virtual ~CallHelper() = default;
template <typename... Params>
R Call(Params... args) {
CSignature::VerifyParams<Params...>(csig_);
Address entry = Generate();
auto fn = GeneratedCode<R, Params...>::FromAddress(isolate_, entry);
return fn.Call(args...);
}
protected:
MachineSignature* csig_;
virtual Address Generate() = 0;
private:
Isolate* isolate_;
};
template <>
template <typename... Params>
Tagged<Object> CallHelper<Tagged<Object>>::Call(Params... args) {
CSignature::VerifyParams<Params...>(csig_);
Address entry = Generate();
auto fn = GeneratedCode<Address, Params...>::FromAddress(isolate_, entry);
return Tagged<Object>(fn.Call(args...));
}
// A call helper that calls the given code object assuming C calling convention.
template <typename T>
class CodeRunner : public CallHelper<T> {
public:
CodeRunner(Isolate* isolate, Handle<InstructionStream> istream,
MachineSignature* csig)
: CallHelper<T>(isolate, csig), istream_(istream) {}
CodeRunner(Isolate* isolate, DirectHandle<Code> code, MachineSignature* csig)
: CallHelper<T>(isolate, csig),
istream_(code->instruction_stream(), isolate) {}
~CodeRunner() override = default;
Address Generate() override { return istream_->instruction_start(); }
private:
Handle<InstructionStream> istream_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMMON_CALL_TESTER_H_

View File

@ -0,0 +1,115 @@
// Copyright 2022 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_TEST_COMMON_CODE_ASSEMBLER_TESTER_H_
#define V8_TEST_COMMON_CODE_ASSEMBLER_TESTER_H_
#include "src/codegen/assembler.h"
#include "src/codegen/interface-descriptors.h"
#include "src/compiler/code-assembler-compilation-job.h"
#include "src/compiler/code-assembler.h"
#include "src/compiler/raw-machine-assembler.h"
#include "src/execution/isolate.h"
#include "src/handles/handles.h"
namespace v8 {
namespace internal {
namespace compiler {
class CodeAssemblerTester {
public:
CodeAssemblerTester(Isolate* isolate,
const CallInterfaceDescriptor& descriptor,
const char* name = "test")
: isolate_(isolate),
job_(CodeAssemblerCompilationJob::NewJobForTesting(
isolate, Builtin::kNoBuiltinId, [](CodeAssemblerState*) {},
[this](Builtin, Handle<Code> code) { this->code_ = code; },
[&descriptor](Zone* zone) {
return Linkage::GetStubCallDescriptor(
zone, descriptor, descriptor.GetStackParameterCount(),
CallDescriptor::kNoFlags, Operator::kNoProperties);
},
CodeKind::FOR_TESTING, name)),
scope_(isolate) {}
// Test generating code for a stub. Assumes VoidDescriptor call interface.
explicit CodeAssemblerTester(Isolate* isolate, const char* name = "test")
: CodeAssemblerTester(isolate, VoidDescriptor{}, name) {}
// Test generating code for a JS function (e.g. builtins).
CodeAssemblerTester(Isolate* isolate, int parameter_count,
CodeKind kind = CodeKind::BUILTIN,
const char* name = "test")
: isolate_(isolate),
job_(CodeAssemblerCompilationJob::NewJobForTesting(
isolate, Builtin::kNoBuiltinId, [](CodeAssemblerState*) {},
[this](Builtin, Handle<Code> code) { this->code_ = code; },
[parameter_count](Zone* zone) {
return Linkage::GetJSCallDescriptor(zone, false, parameter_count,
CallDescriptor::kCanUseRoots);
},
kind, name)),
scope_(isolate) {
// Parameter count must include at least the receiver.
DCHECK_LE(1, parameter_count);
}
CodeAssemblerTester(Isolate* isolate, CodeKind kind,
const char* name = "test")
: CodeAssemblerTester(isolate, 1, kind, name) {}
CodeAssemblerTester(Isolate* isolate, CallDescriptor* call_descriptor,
const char* name = "test")
: isolate_(isolate),
job_(CodeAssemblerCompilationJob::NewJobForTesting(
isolate, Builtin::kNoBuiltinId, [](CodeAssemblerState*) {},
[this](Builtin, Handle<Code> code) { this->code_ = code; },
[call_descriptor](Zone*) { return call_descriptor; },
CodeKind::FOR_TESTING, name)),
scope_(isolate) {}
CodeAssemblerState* state() { return &job_->code_assembler_state_; }
// Direct low-level access to the machine assembler, for testing only.
RawMachineAssembler* raw_assembler_for_testing() {
return job_->raw_assembler();
}
Handle<Code> GenerateCode() {
return GenerateCode(AssemblerOptions::Default(scope_.isolate()));
}
Handle<Code> GenerateCode(const AssemblerOptions& options) {
// The use of a CompilationJob is awkward, but is done to avoid duplicating
// pipeline code.
job_->assembler_options_ = options;
if (state()->InsideBlock()) {
CodeAssembler(state()).Unreachable();
}
CHECK_EQ(CompilationJob::SUCCEEDED, job_->PrepareJob(isolate_));
CHECK_EQ(CompilationJob::SUCCEEDED,
job_->ExecuteJob(isolate_->counters()->runtime_call_stats(),
isolate_->main_thread_local_isolate()));
CHECK_EQ(CompilationJob::SUCCEEDED, job_->FinalizeJob(isolate_));
CHECK(!code_.is_null());
return code_;
}
Handle<Code> GenerateCodeCloseAndEscape() {
return scope_.CloseAndEscape(GenerateCode());
}
private:
Isolate* isolate_;
std::unique_ptr<CodeAssemblerCompilationJob> job_;
HandleScope scope_;
Handle<Code> code_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_TEST_COMMON_CODE_ASSEMBLER_TESTER_H_

38
deps/v8/test/common/flag-utils.h vendored Normal file
View File

@ -0,0 +1,38 @@
// Copyright 2020 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_TEST_COMMON_FLAG_UTILS_H
#define V8_TEST_COMMON_FLAG_UTILS_H
#include "src/base/macros.h"
#include "src/flags/flags.h"
namespace v8 {
namespace internal {
template <typename T>
class V8_NODISCARD FlagScope {
public:
FlagScope(FlagValue<T>* flag, T new_value)
: flag_(flag), previous_value_(*flag) {
*flag = new_value;
}
~FlagScope() { *flag_ = previous_value_; }
private:
FlagValue<T>* flag_;
T previous_value_;
};
} // namespace internal
} // namespace v8
#define FLAG_VALUE_SCOPE(flag, value) \
::v8::internal::FlagScope< \
typename decltype(::v8::internal::v8_flags.flag)::underlying_type> \
UNIQUE_IDENTIFIER(__scope_##flag)(&::v8::internal::v8_flags.flag, value)
#define FLAG_SCOPE(flag) FLAG_VALUE_SCOPE(flag, true)
#endif // V8_TEST_COMMON_FLAG_UTILS_H

View File

@ -0,0 +1,90 @@
// Copyright 2022 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_COMMON_NODEOBSERVER_TESTER_H_
#define V8_COMMON_NODEOBSERVER_TESTER_H_
#include "src/compiler/node-observer.h"
#include "src/compiler/simplified-operator.h"
#include "src/objects/type-hints.h"
namespace v8 {
namespace internal {
namespace compiler {
// Helpers to test TurboFan compilation using the %ObserveNode intrinsic.
struct ObserveNodeScope {
public:
ObserveNodeScope(Isolate* isolate, NodeObserver* node_observer)
: isolate_(isolate) {
DCHECK_NOT_NULL(isolate_);
DCHECK_NULL(isolate_->node_observer());
isolate_->set_node_observer(node_observer);
}
~ObserveNodeScope() {
DCHECK_NOT_NULL(isolate_->node_observer());
// Checks that the code wrapped by %ObserveNode() was actually compiled in
// the test.
CHECK(isolate_->node_observer()->has_observed_changes());
isolate_->set_node_observer(nullptr);
}
private:
Isolate* isolate_;
};
class CreationObserver : public NodeObserver {
public:
explicit CreationObserver(std::function<void(const Node*)> handler)
: handler_(handler) {
DCHECK(handler_);
}
Observation OnNodeCreated(const Node* node) override {
handler_(node);
return Observation::kStop;
}
private:
std::function<void(const Node*)> handler_;
};
class ModificationObserver : public NodeObserver {
public:
explicit ModificationObserver(
std::function<void(const Node*)> on_created_handler,
std::function<NodeObserver::Observation(
const Node*, const ObservableNodeState& old_state)>
on_changed_handler)
: on_created_handler_(on_created_handler),
on_changed_handler_(on_changed_handler) {
DCHECK(on_created_handler_);
DCHECK(on_changed_handler_);
}
Observation OnNodeCreated(const Node* node) override {
on_created_handler_(node);
return Observation::kContinue;
}
Observation OnNodeChanged(const char* reducer_name, const Node* node,
const ObservableNodeState& old_state) override {
return on_changed_handler_(node, old_state);
}
private:
std::function<void(const Node*)> on_created_handler_;
std::function<NodeObserver::Observation(const Node*,
const ObservableNodeState& old_state)>
on_changed_handler_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMMON_NODEOBSERVER_TESTER_H_

58
deps/v8/test/common/streaming-helper.h vendored Normal file
View File

@ -0,0 +1,58 @@
// Copyright 2023 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_COMMON_STREAMING_HELPER_H_
#define V8_COMMON_STREAMING_HELPER_H_
#include "include/v8-script.h"
namespace v8 {
namespace internal {
class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
public:
explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
size_t GetMoreData(const uint8_t** src) override {
// Unlike in real use cases, this function will never block.
if (chunks_[index_] == nullptr) {
return 0;
}
// Copy the data, since the caller takes ownership of it.
size_t len = strlen(chunks_[index_]);
// We don't need to zero-terminate since we return the length.
uint8_t* copy = new uint8_t[len];
memcpy(copy, chunks_[index_], len);
*src = copy;
++index_;
return len;
}
// Helper for constructing a string from chunks (the compilation needs it
// too).
static char* FullSourceString(const char** chunks) {
size_t total_len = 0;
for (size_t i = 0; chunks[i] != nullptr; ++i) {
total_len += strlen(chunks[i]);
}
char* full_string = new char[total_len + 1];
size_t offset = 0;
for (size_t i = 0; chunks[i] != nullptr; ++i) {
size_t len = strlen(chunks[i]);
memcpy(full_string + offset, chunks[i], len);
offset += len;
}
full_string[total_len] = 0;
return full_string;
}
private:
const char** chunks_;
unsigned index_;
};
} // namespace internal
} // namespace v8
#endif // V8_COMMON_STREAMING_HELPER_H_

273
deps/v8/test/common/types-fuzz.h vendored Normal file
View File

@ -0,0 +1,273 @@
// Copyright 2014 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_TEST_CCTEST_TYPES_H_
#define V8_TEST_CCTEST_TYPES_H_
#include "src/base/utils/random-number-generator.h"
#include "src/compiler/js-heap-broker.h"
#include "src/execution/isolate.h"
#include "src/handles/handles-inl.h"
#include "src/heap/factory.h"
#include "src/init/v8.h"
namespace v8 {
namespace internal {
namespace compiler {
class Types {
public:
Types(Zone* zone, Isolate* isolate, v8::base::RandomNumberGenerator* rng)
: integers(isolate),
zone_(zone),
js_heap_broker_(isolate, zone),
js_heap_broker_scope_(&js_heap_broker_, isolate, zone),
current_broker_(&js_heap_broker_),
rng_(rng) {
#define DECLARE_TYPE(name, value) \
name = Type::name(); \
types.push_back(name);
PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
#undef DECLARE_TYPE
if (!PersistentHandlesScope::IsActive(isolate)) {
persistent_scope_.emplace(isolate);
}
SignedSmall = Type::SignedSmall();
UnsignedSmall = Type::UnsignedSmall();
DirectHandle<i::Map> object_map =
CanonicalHandle(isolate->factory()->NewContextfulMapForCurrentContext(
JS_OBJECT_TYPE, JSObject::kHeaderSize));
Handle<i::Smi> smi = CanonicalHandle(Smi::FromInt(666));
Handle<i::HeapNumber> boxed_smi =
CanonicalHandle(isolate->factory()->NewHeapNumber(666));
Handle<i::HeapNumber> signed32 =
CanonicalHandle(isolate->factory()->NewHeapNumber(0x40000000));
Handle<i::HeapNumber> float1 =
CanonicalHandle(isolate->factory()->NewHeapNumber(1.53));
Handle<i::HeapNumber> float2 =
CanonicalHandle(isolate->factory()->NewHeapNumber(0.53));
// float3 is identical to float1 in order to test that OtherNumberConstant
// types are equal by double value and not by handle pointer value.
Handle<i::HeapNumber> float3 =
CanonicalHandle(isolate->factory()->NewHeapNumber(1.53));
Handle<i::JSObject> object1 =
CanonicalHandle(isolate->factory()->NewJSObjectFromMap(object_map));
Handle<i::JSObject> object2 =
CanonicalHandle(isolate->factory()->NewJSObjectFromMap(object_map));
Handle<i::JSArray> array =
CanonicalHandle(isolate->factory()->NewJSArray(20));
Handle<i::Hole> uninitialized = isolate->factory()->uninitialized_value();
Handle<i::Oddball> undefined = isolate->factory()->undefined_value();
Handle<i::HeapNumber> nan = isolate->factory()->nan_value();
Handle<i::Hole> the_hole_value = isolate->factory()->the_hole_value();
SmiConstant = Type::Constant(js_heap_broker(), smi, zone);
Signed32Constant = Type::Constant(signed32->value(), zone);
ObjectConstant1 = Type::Constant(js_heap_broker(), object1, zone);
ObjectConstant2 = Type::Constant(js_heap_broker(), object2, zone);
ArrayConstant = Type::Constant(js_heap_broker(), array, zone);
UninitializedConstant =
Type::Constant(js_heap_broker(), uninitialized, zone);
values.push_back(smi);
values.push_back(boxed_smi);
values.push_back(signed32);
values.push_back(object1);
values.push_back(object2);
values.push_back(array);
values.push_back(uninitialized);
values.push_back(undefined);
values.push_back(nan);
values.push_back(the_hole_value);
values.push_back(float1);
values.push_back(float2);
values.push_back(float3);
values.push_back(isolate->factory()->empty_string());
values.push_back(
CanonicalHandle(isolate->factory()->NewStringFromStaticChars(
"I'm a little string value, short and stout...")));
values.push_back(
CanonicalHandle(isolate->factory()->NewStringFromStaticChars(
"Ask not for whom the typer types; it types for thee.")));
for (IndirectHandle<i::Object> obj : values) {
types.push_back(Type::Constant(js_heap_broker(), obj, zone));
}
integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY));
integers.push_back(isolate->factory()->NewNumber(+V8_INFINITY));
integers.push_back(isolate->factory()->NewNumber(-rng_->NextInt(10)));
integers.push_back(isolate->factory()->NewNumber(+rng_->NextInt(10)));
for (int i = 0; i < 10; ++i) {
double x = rng_->NextInt();
integers.push_back(isolate->factory()->NewNumber(x));
x *= rng_->NextInt();
if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x));
}
Integer = Type::Range(-V8_INFINITY, +V8_INFINITY, zone);
for (int i = 0; i < 30; ++i) {
types.push_back(Fuzz());
}
}
~Types() {
if (persistent_scope_) {
persistent_scope_->Detach();
}
}
#define DECLARE_TYPE(name, value) Type name;
PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
#undef DECLARE_TYPE
Type SignedSmall;
Type UnsignedSmall;
Type SmiConstant;
Type Signed32Constant;
Type ObjectConstant1;
Type ObjectConstant2;
Type ArrayConstant;
Type UninitializedConstant;
Type Integer;
std::vector<Type> types;
std::vector<IndirectHandle<i::Object>> values;
DirectHandleVector<i::Object>
integers; // "Integer" values used for range limits.
Type Constant(double value) { return Type::Constant(value, zone_); }
Type Constant(Handle<i::Object> value) {
return Type::Constant(js_heap_broker(), value, zone_);
}
Type HeapConstant(Handle<i::HeapObject> value) {
return Type::Constant(js_heap_broker(), value, zone_);
}
Type Range(double min, double max) { return Type::Range(min, max, zone_); }
Type Union(Type t1, Type t2) { return Type::Union(t1, t2, zone_); }
Type Intersect(Type t1, Type t2) { return Type::Intersect(t1, t2, zone_); }
Type Random() { return types[rng_->NextInt(static_cast<int>(types.size()))]; }
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.
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) { \
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
}
return result;
}
case 1: { // constant
int i = rng_->NextInt(static_cast<int>(values.size()));
if (IsHeapNumber(*values[i])) {
return Type::Constant(Cast<HeapNumber>(*values[i])->value(), zone_);
}
return Type::Constant(js_heap_broker(), values[i], zone_);
}
case 2: { // range
int i = rng_->NextInt(static_cast<int>(integers.size()));
int j = rng_->NextInt(static_cast<int>(integers.size()));
double min = Object::NumberValue(*integers[i]);
double max = Object::NumberValue(*integers[j]);
if (min > max) std::swap(min, max);
return Type::Range(min, max, zone_);
}
default: { // union
int n = rng_->NextInt(10);
Type type = None;
for (int i = 0; i < n; ++i) {
Type operand = Fuzz(depth - 1);
type = Type::Union(type, operand, zone_);
}
return type;
}
}
UNREACHABLE();
}
Zone* zone() { return zone_; }
JSHeapBroker* js_heap_broker() { return &js_heap_broker_; }
template <typename T>
IndirectHandle<T> CanonicalHandle(Tagged<T> object) {
return js_heap_broker_.CanonicalPersistentHandle(object);
}
template <typename T>
IndirectHandle<T> CanonicalHandle(T object) {
static_assert(kTaggedCanConvertToRawObjects);
return CanonicalHandle(Tagged<T>(object));
}
template <typename T>
IndirectHandle<T> CanonicalHandle(IndirectHandle<T> handle) {
return CanonicalHandle(*handle);
}
template <typename T>
IndirectHandle<T> CanonicalHandle(DirectHandle<T> handle) {
return CanonicalHandle(*handle);
}
private:
Zone* zone_;
JSHeapBroker js_heap_broker_;
JSHeapBrokerScopeForTesting js_heap_broker_scope_;
std::optional<PersistentHandlesScope> persistent_scope_;
CurrentHeapBrokerScope current_broker_;
v8::base::RandomNumberGenerator* rng_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif

21
deps/v8/test/common/value-helper.cc vendored Normal file
View File

@ -0,0 +1,21 @@
// Copyright 2022 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/common/value-helper.h"
namespace v8 {
namespace internal {
namespace compiler {
// Define constexpr arrays of ValueHelper for external references.
constexpr int8_t ValueHelper::int8_array[];
constexpr int16_t ValueHelper::int16_array[];
constexpr uint32_t ValueHelper::uint32_array[];
constexpr uint64_t ValueHelper::uint64_array[];
constexpr float ValueHelper::float32_array[];
constexpr double ValueHelper::float64_array[];
} // namespace compiler
} // namespace internal
} // namespace v8

401
deps/v8/test/common/value-helper.h vendored Normal file
View File

@ -0,0 +1,401 @@
// Copyright 2022 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_COMMON_VALUE_HELPER_H_
#define V8_COMMON_VALUE_HELPER_H_
#include <stdint.h>
#include "src/base/template-utils.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node.h"
#include "src/execution/isolate.h"
#include "src/objects/objects.h"
namespace v8 {
namespace internal {
namespace compiler {
// A collection of utilities related to numerical and heap values, including
// example input values of various types, including int32_t, uint32_t, double,
// etc.
class ValueHelper {
public:
static constexpr float float32_array[] = {
-std::numeric_limits<float>::infinity(),
-2.70497e+38f,
-1.4698e+37f,
-1.22813e+35f,
-1.20555e+35f,
-1.34584e+34f,
-1.0079e+32f,
-6.49364e+26f,
-3.06077e+25f,
-1.46821e+25f,
-1.17658e+23f,
-1.9617e+22f,
-2.7357e+20f,
-9223372036854775808.0f, // INT64_MIN
-1.48708e+13f,
-1.89633e+12f,
-4.66622e+11f,
-2.22581e+11f,
-1.45381e+10f,
-2147483904.0f, // First float32 after INT32_MIN
-2147483648.0f, // INT32_MIN
-2147483520.0f, // Last float32 before INT32_MIN
-1.3956e+09f,
-1.32951e+09f,
-1.30721e+09f,
-1.19756e+09f,
-9.26822e+08f,
-6.35647e+08f,
-4.00037e+08f,
-1.81227e+08f,
-5.09256e+07f,
-964300.0f,
-192446.0f,
-28455.0f,
-27194.0f,
-26401.0f,
-20575.0f,
-17069.0f,
-9167.0f,
-960.178f,
-113.0f,
-62.0f,
-15.0f,
-7.0f,
-1.0f,
-0.0256635f,
-4.60374e-07f,
-3.63759e-10f,
-4.30175e-14f,
-5.27385e-15f,
-1.5707963267948966f,
-1.48084e-15f,
-2.220446049250313e-16f,
-1.05755e-19f,
-3.2995e-21f,
-1.67354e-23f,
-1.11885e-23f,
-1.78506e-30f,
-5.07594e-31f,
-3.65799e-31f,
-1.43718e-34f,
-1.27126e-38f,
-0.0f,
0.0f,
1.17549e-38f,
1.56657e-37f,
4.08512e-29f,
3.31357e-28f,
6.25073e-22f,
4.1723e-13f,
1.44343e-09f,
1.5707963267948966f,
5.27004e-08f,
9.48298e-08f,
5.57888e-07f,
4.89988e-05f,
0.244326f,
1.0f,
12.4895f,
19.0f,
47.0f,
106.0f,
538.324f,
564.536f,
819.124f,
7048.0f,
12611.0f,
19878.0f,
20309.0f,
797056.0f,
1.77219e+09f,
2147483648.0f, // INT32_MAX + 1
2147483904.0f, // INT32_MAX + 1 and significand = 1.
4294967296.0f, // UINT32_MAX + 1
1.51116e+11f,
4.18193e+13f,
3.59167e+16f,
9223372036854775808.0f, // INT64_MAX + 1
18446744073709551616.0f, // UINT64_MAX + 1
3.38211e+19f,
2.67488e+20f,
1.78831e+21f,
9.20914e+21f,
8.35654e+23f,
1.4495e+24f,
5.94015e+25f,
4.43608e+30f,
2.44502e+33f,
2.61152e+33f,
1.38178e+37f,
1.71306e+37f,
3.31899e+38f,
3.40282e+38f,
std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::quiet_NaN(),
-std::numeric_limits<float>::quiet_NaN()};
static constexpr base::Vector<const float> float32_vector() {
return base::ArrayVector(float32_array);
}
static constexpr double float64_array[] = {
-2e66,
-2.220446049250313e-16,
-9223373136366403584.0,
-9223372036854775808.0, // INT64_MIN
-2147483649.5,
-2147483648.25,
-2147483648.0,
-2147483647.875,
-2147483647.125,
-2147483647.0,
-999.75,
-2e66,
-1.75,
-1.5707963267948966,
-1.0,
-0.5,
-0.0,
0.0,
3e-88,
0.125,
0.25,
0.375,
0.5,
1.0,
1.17549e-38,
1.56657e-37,
1.0000001,
1.25,
1.5707963267948966,
2,
3.1e7,
5.125,
6.25,
888,
982983.25,
2147483647.0,
2147483647.375,
2147483647.75,
2147483648.0,
2147483648.25,
2147483649.25,
9223372036854775808.0, // INT64_MAX + 1
9223373136366403584.0,
18446744073709551616.0, // UINT64_MAX + 1
2e66,
V8_INFINITY,
-V8_INFINITY,
std::numeric_limits<double>::quiet_NaN(),
-std::numeric_limits<double>::quiet_NaN()};
static constexpr base::Vector<const double> float64_vector() {
return base::ArrayVector(float64_array);
}
static constexpr uint32_t uint32_array[] = {
0x00000000, 0x00000001, 0xFFFFFFFF, 0x1B09788B, 0x04C5FCE8, 0xCC0DE5BF,
// This row is useful for testing lea optimizations on intel.
0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000008, 0x00000009,
0x273A798E, 0x187937A3, 0xECE3AF83, 0x5495A16B, 0x0B668ECC, 0x11223344,
0x0000009E, 0x00000043, 0x0000AF73, 0x0000116B, 0x00658ECC, 0x002B3B4C,
0x88776655, 0x70000000, 0x07200000, 0x7FFFFFFF, 0x56123761, 0x7FFFFF00,
0x761C4761, 0x80000000, 0x88888888, 0xA0000000, 0xDDDDDDDD, 0xE0000000,
0xEEEEEEEE, 0xFFFFFFFD, 0xF0000000, 0x007FFFFF, 0x003FFFFF, 0x001FFFFF,
0x000FFFFF, 0x0007FFFF, 0x0003FFFF, 0x0001FFFF, 0x0000FFFF, 0x00007FFF,
0x00003FFF, 0x00001FFF, 0x00000FFF, 0x000007FF, 0x000003FF, 0x000001FF,
// Bit pattern of a quiet NaN and signaling NaN, with or without
// additional payload.
0x7FC00000, 0x7F800000, 0x7FFFFFFF, 0x7F876543};
static constexpr base::Vector<const uint32_t> uint32_vector() {
return base::ArrayVector(uint32_array);
}
static base::Vector<const int32_t> int32_vector() {
return base::Vector<const int32_t>::cast(uint32_vector());
}
static constexpr uint64_t uint64_array[] = {
0x00000000, 0x00000001, 0xFFFFFFFF, 0x1B09788B, 0x04C5FCE8, 0xCC0DE5BF,
0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000008, 0x00000009,
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFD,
0x0000000000000000, 0x0000000100000000, 0xFFFFFFFF00000000,
0x1B09788B00000000, 0x04C5FCE800000000, 0xCC0DE5BF00000000,
0x0000000200000000, 0x0000000300000000, 0x0000000400000000,
0x0000000500000000, 0x0000000800000000, 0x0000000900000000,
0x273A798E187937A3, 0xECE3AF835495A16B, 0x0B668ECC11223344, 0x0000009E,
0x00000043, 0x0000AF73, 0x0000116B, 0x00658ECC, 0x002B3B4C, 0x88776655,
0x70000000, 0x07200000, 0x7FFFFFFF, 0x56123761, 0x7FFFFF00,
0x761C4761EEEEEEEE, 0x80000000EEEEEEEE, 0x88888888DDDDDDDD,
0xA0000000DDDDDDDD, 0xDDDDDDDDAAAAAAAA, 0xE0000000AAAAAAAA,
0xEEEEEEEEEEEEEEEE, 0xFFFFFFFDEEEEEEEE, 0xF0000000DDDDDDDD,
0x007FFFFFDDDDDDDD, 0x003FFFFFAAAAAAAA, 0x001FFFFFAAAAAAAA, 0x000FFFFF,
0x0007FFFF, 0x0003FFFF, 0x0001FFFF, 0x0000FFFF, 0x00007FFF, 0x00003FFF,
0x00001FFF, 0x00000FFF, 0x000007FF, 0x000003FF, 0x000001FF,
0x00003FFFFFFFFFFF, 0x00001FFFFFFFFFFF, 0x00000FFFFFFFFFFF,
0x000007FFFFFFFFFF, 0x000003FFFFFFFFFF, 0x000001FFFFFFFFFF,
0x8000008000000000, 0x8000008000000001, 0x8000000000000400,
0x8000000000000401, 0x0000000000000020,
0x8000000000000000, // int64_t min
0x7FFFFFFFFFFFFFFF, // int64_t max
// Bit pattern of a quiet NaN and signaling NaN, with or without
// additional payload.
0x7FF8000000000000, 0x7FF0000000000000, 0x7FF8123456789ABC,
0x7FF7654321FEDCBA};
static constexpr base::Vector<const uint64_t> uint64_vector() {
return base::ArrayVector(uint64_array);
}
static base::Vector<const int64_t> int64_vector() {
return base::Vector<const int64_t>::cast(uint64_vector());
}
static constexpr int16_t int16_array[] = {
0, 1, 2, INT16_MAX - 1, INT16_MAX, INT16_MIN, INT16_MIN + 1, -2, -1};
static constexpr base::Vector<const int16_t> int16_vector() {
return base::ArrayVector(int16_array);
}
static base::Vector<const uint16_t> uint16_vector() {
return base::Vector<const uint16_t>::cast(int16_vector());
}
static constexpr int8_t int8_array[] = {
0, 1, 2, INT8_MAX - 1, INT8_MAX, INT8_MIN, INT8_MIN + 1, -2, -1};
static constexpr base::Vector<const int8_t> int8_vector() {
return base::ArrayVector(int8_array);
}
static base::Vector<const uint8_t> uint8_vector() {
return base::Vector<const uint8_t>::cast(base::ArrayVector(int8_array));
}
static constexpr uint32_t ror_array[31] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
static constexpr base::Vector<const uint32_t> ror_vector() {
return base::ArrayVector(ror_array);
}
template <typename T>
static inline base::Vector<const T> GetVector();
};
template <>
inline base::Vector<const int8_t> ValueHelper::GetVector() {
return int8_vector();
}
template <>
inline base::Vector<const uint8_t> ValueHelper::GetVector() {
return uint8_vector();
}
template <>
inline base::Vector<const int16_t> ValueHelper::GetVector() {
return int16_vector();
}
template <>
inline base::Vector<const uint16_t> ValueHelper::GetVector() {
return uint16_vector();
}
template <>
inline base::Vector<const int32_t> ValueHelper::GetVector() {
return int32_vector();
}
template <>
inline base::Vector<const uint32_t> ValueHelper::GetVector() {
return uint32_vector();
}
template <>
inline base::Vector<const int64_t> ValueHelper::GetVector() {
return int64_vector();
}
template <>
inline base::Vector<const float> ValueHelper::GetVector() {
return float32_vector();
}
template <>
inline base::Vector<const double> ValueHelper::GetVector() {
return float64_vector();
}
// Helper macros that can be used in FOR_INT32_INPUTS(i) { ... i ... }
#define FOR_INPUTS(ctype, itype, var) \
for (ctype var : ::v8::internal::compiler::ValueHelper::itype##_vector())
#define FOR_INT32_INPUTS(var) FOR_INPUTS(int32_t, int32, var)
#define FOR_UINT32_INPUTS(var) FOR_INPUTS(uint32_t, uint32, var)
#define FOR_INT16_INPUTS(var) FOR_INPUTS(int16_t, int16, var)
#define FOR_UINT16_INPUTS(var) FOR_INPUTS(uint16_t, uint16, var)
#define FOR_INT8_INPUTS(var) FOR_INPUTS(int8_t, int8, var)
#define FOR_UINT8_INPUTS(var) FOR_INPUTS(uint8_t, uint8, var)
#define FOR_INT64_INPUTS(var) FOR_INPUTS(int64_t, int64, var)
#define FOR_UINT64_INPUTS(var) FOR_INPUTS(uint64_t, uint64, var)
#define FOR_FLOAT32_INPUTS(var) FOR_INPUTS(float, float32, var)
#define FOR_FLOAT64_INPUTS(var) FOR_INPUTS(double, float64, var)
#define FOR_INT32_SHIFTS(var) for (int32_t var = 0; var < 32; var++)
#define FOR_UINT32_SHIFTS(var) for (uint32_t var = 0; var < 32; var++)
template <typename type>
struct FloatCompareWrapper {
type value;
explicit FloatCompareWrapper(type x) : value(x) {}
bool operator==(FloatCompareWrapper<type> const& other) const {
return std::isnan(value)
? std::isnan(other.value)
: value == other.value &&
std::signbit(value) == std::signbit(other.value);
}
};
template <typename type>
std::ostream& operator<<(std::ostream& out, FloatCompareWrapper<type> wrapper) {
uint8_t bytes[sizeof(type)];
memcpy(bytes, &wrapper.value, sizeof(type));
out << wrapper.value << " (0x";
const char* kHexDigits = "0123456789ABCDEF";
for (unsigned i = 0; i < sizeof(type); ++i) {
out << kHexDigits[bytes[i] >> 4] << kHexDigits[bytes[i] & 15];
}
return out << ")";
}
#define CHECK_FLOAT_EQ(lhs, rhs) \
do { \
using FloatWrapper = ::v8::internal::compiler::FloatCompareWrapper<float>; \
CHECK_EQ(FloatWrapper(lhs), FloatWrapper(rhs)); \
} while (false)
#define CHECK_DOUBLE_EQ(lhs, rhs) \
do { \
using DoubleWrapper = \
::v8::internal::compiler::FloatCompareWrapper<double>; \
CHECK_EQ(DoubleWrapper(lhs), DoubleWrapper(rhs)); \
} while (false)
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMMON_VALUE_HELPER_H_

1
deps/v8/test/common/wasm/OWNERS vendored Normal file
View File

@ -0,0 +1 @@
file:../../../src/wasm/OWNERS

50
deps/v8/test/common/wasm/flag-utils.h vendored Normal file
View File

@ -0,0 +1,50 @@
// Copyright 2017 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_TEST_COMMON_WASM_FLAG_UTILS_H
#define V8_TEST_COMMON_WASM_FLAG_UTILS_H
#include "src/wasm/wasm-features.h"
#include "test/common/flag-utils.h"
namespace v8::internal::wasm {
#define EXPERIMENTAL_FLAG_SCOPE(flag) FLAG_SCOPE(experimental_wasm_##flag)
class V8_NODISCARD WasmFeatureScope {
public:
explicit WasmFeatureScope(WasmEnabledFeatures* features,
WasmEnabledFeature feature, bool val = true)
: prev_(features->contains(feature)),
feature_(feature),
features_(features) {
set(val);
}
~WasmFeatureScope() { set(prev_); }
private:
void set(bool val) {
if (val) {
features_->Add(feature_);
} else {
features_->Remove(feature_);
}
}
bool const prev_;
WasmEnabledFeature const feature_;
WasmEnabledFeatures* const features_;
};
#define WASM_FEATURE_SCOPE(feat) \
WasmFeatureScope feat##_scope(&this->enabled_features_, \
WasmEnabledFeature::feat)
#define WASM_FEATURE_SCOPE_VAL(feat, val) \
WasmFeatureScope feat##_scope(&this->enabled_features_, \
WasmEnabledFeature::feat, val)
} // namespace v8::internal::wasm
#endif // V8_TEST_COMMON_WASM_FLAG_UTILS_H

View File

@ -0,0 +1,115 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TEST_SIGNATURES_H
#define TEST_SIGNATURES_H
#include "src/codegen/signature.h"
#include "src/wasm/value-type.h"
#include "src/wasm/wasm-opcodes.h"
namespace v8::internal::wasm {
// A helper class with many useful signatures in order to simplify tests.
class TestSignatures {
public:
#define SIG(name, Maker, ...) \
static FunctionSig* name() { \
static auto kSig = Maker(__VA_ARGS__); \
return &kSig; \
}
// Empty signature.
static FunctionSig* v_v() {
static FixedSizeSignature<ValueType, 0, 0> kSig;
return &kSig;
}
// Signatures with no return value.
SIG(v_i, MakeSigNoReturn, kWasmI32)
SIG(v_ii, MakeSigNoReturn, kWasmI32, kWasmI32)
SIG(v_iii, MakeSigNoReturn, kWasmI32, kWasmI32, kWasmI32)
SIG(v_a, MakeSigNoReturn, kWasmExternRef)
SIG(v_c, MakeSigNoReturn, kWasmFuncRef)
SIG(v_d, MakeSigNoReturn, kWasmF64)
// Returning one i32 value.
SIG(i_v, MakeSig1Return, kWasmI32)
SIG(i_i, MakeSig1Return, kWasmI32, kWasmI32)
SIG(i_ii, MakeSig1Return, kWasmI32, kWasmI32, kWasmI32)
SIG(i_iii, MakeSig1Return, kWasmI32, kWasmI32, kWasmI32, kWasmI32)
SIG(i_f, MakeSig1Return, kWasmI32, kWasmF32)
SIG(i_ff, MakeSig1Return, kWasmI32, kWasmF32, kWasmF32)
SIG(i_d, MakeSig1Return, kWasmI32, kWasmF64)
SIG(i_dd, MakeSig1Return, kWasmI32, kWasmF64, kWasmF64)
SIG(i_ll, MakeSig1Return, kWasmI32, kWasmI64, kWasmI64)
SIG(i_a, MakeSig1Return, kWasmI32, kWasmExternRef)
SIG(i_aa, MakeSig1Return, kWasmI32, kWasmExternRef, kWasmExternRef)
SIG(i_c, MakeSig1Return, kWasmI32, kWasmFuncRef)
SIG(i_s, MakeSig1Return, kWasmI32, kWasmS128)
// Returning one i64 value.
SIG(l_v, MakeSig1Return, kWasmI64)
SIG(l_a, MakeSig1Return, kWasmI64, kWasmExternRef)
SIG(l_c, MakeSig1Return, kWasmI64, kWasmFuncRef)
SIG(l_l, MakeSig1Return, kWasmI64, kWasmI64)
SIG(l_ll, MakeSig1Return, kWasmI64, kWasmI64, kWasmI64)
// Returning one f32 value.
SIG(f_f, MakeSig1Return, kWasmF32, kWasmF32)
SIG(f_ff, MakeSig1Return, kWasmF32, kWasmF32, kWasmF32)
// Returning one f64 value.
SIG(d_d, MakeSig1Return, kWasmF64, kWasmF64)
SIG(d_dd, MakeSig1Return, kWasmF64, kWasmF64, kWasmF64)
// Returning other values.
SIG(a_v, MakeSig1Return, kWasmExternRef)
SIG(c_v, MakeSig1Return, kWasmFuncRef)
SIG(a_a, MakeSig1Return, kWasmExternRef, kWasmExternRef)
SIG(c_c, MakeSig1Return, kWasmFuncRef, kWasmFuncRef)
SIG(s_i, MakeSig1Return, kWasmS128, kWasmI32)
SIG(s_s, MakeSig1Return, kWasmS128, kWasmS128)
SIG(s_ss, MakeSig1Return, kWasmS128, kWasmS128, kWasmS128)
// Multi-return.
static FunctionSig* ii_v() {
static auto kSig =
FixedSizeSignature<ValueType>::Returns(kWasmI32, kWasmI32);
return &kSig;
}
static FunctionSig* iii_v() {
static auto kSig =
FixedSizeSignature<ValueType>::Returns(kWasmI32, kWasmI32, kWasmI32);
return &kSig;
}
static FunctionSig* many(Zone* zone, ValueType ret, ValueType param,
int count) {
FunctionSig::Builder builder(zone, ret == kWasmVoid ? 0 : 1, count);
if (ret != kWasmVoid) builder.AddReturn(ret);
for (int i = 0; i < count; i++) {
builder.AddParam(param);
}
return builder.Get();
}
private:
template <typename... ParamTypes>
static FixedSizeSignature<ValueType, 0, sizeof...(ParamTypes)>
MakeSigNoReturn(ParamTypes... param_types) {
return FixedSizeSignature<ValueType>::Params(param_types...);
}
template <typename... ParamTypes>
static FixedSizeSignature<ValueType, 1, sizeof...(ParamTypes)> MakeSig1Return(
ValueType return_type, ParamTypes... param_types) {
return FixedSizeSignature<ValueType>::Returns(return_type)
.Params(param_types...);
}
};
} // namespace v8::internal::wasm
#endif // TEST_SIGNATURES_H

1099
deps/v8/test/common/wasm/wasm-macro-gen.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,166 @@
// 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/common/wasm/wasm-module-runner.h"
#include "src/execution/isolate.h"
#include "src/handles/handles.h"
#include "src/objects/heap-number-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/property-descriptor.h"
#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-engine.h"
#include "src/wasm/wasm-js.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-result.h"
namespace v8::internal::wasm::testing {
MaybeDirectHandle<WasmModuleObject> CompileForTesting(
Isolate* isolate, ErrorThrower* thrower,
base::Vector<const uint8_t> bytes) {
auto enabled_features = WasmEnabledFeatures::FromIsolate(isolate);
MaybeDirectHandle<WasmModuleObject> module = GetWasmEngine()->SyncCompile(
isolate, enabled_features, CompileTimeImports{}, thrower,
base::OwnedCopyOf(bytes));
DCHECK_EQ(thrower->error(), module.is_null());
return module;
}
MaybeDirectHandle<WasmInstanceObject> CompileAndInstantiateForTesting(
Isolate* isolate, ErrorThrower* thrower,
base::Vector<const uint8_t> bytes) {
MaybeDirectHandle<WasmModuleObject> module =
CompileForTesting(isolate, thrower, bytes);
if (module.is_null()) return {};
return GetWasmEngine()->SyncInstantiate(isolate, thrower,
module.ToHandleChecked(), {}, {});
}
DirectHandleVector<Object> MakeDefaultArguments(Isolate* isolate,
const FunctionSig* sig) {
size_t param_count = sig->parameter_count();
DirectHandleVector<Object> arguments(isolate, param_count);
for (size_t i = 0; i < param_count; ++i) {
switch (sig->GetParam(i).kind()) {
case kI32:
case kF32:
case kF64:
case kS128:
// Argument here for kS128 does not matter as we should error out before
// hitting this case.
arguments[i] =
direct_handle(Smi::FromInt(static_cast<int>(i)), isolate);
break;
case kI64:
arguments[i] = BigInt::FromInt64(isolate, static_cast<int64_t>(i));
break;
case kRefNull:
arguments[i] = isolate->factory()->null_value();
break;
case kRef:
arguments[i] = isolate->factory()->undefined_value();
break;
case kI8:
case kI16:
case kF16:
case kVoid:
case kTop:
case kBottom:
UNREACHABLE();
}
}
return arguments;
}
int32_t CompileAndRunWasmModule(Isolate* isolate, const uint8_t* module_start,
const uint8_t* module_end) {
HandleScope scope(isolate);
ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
MaybeDirectHandle<WasmInstanceObject> instance =
CompileAndInstantiateForTesting(
isolate, &thrower,
base::VectorOf(module_start, module_end - module_start));
if (instance.is_null()) {
return -1;
}
return CallWasmFunctionForTesting(isolate, instance.ToHandleChecked(), "main",
{});
}
MaybeDirectHandle<WasmExportedFunction> GetExportedFunction(
Isolate* isolate, DirectHandle<WasmInstanceObject> instance,
const char* name) {
DirectHandle<JSObject> exports_object;
DirectHandle<Name> exports =
isolate->factory()->InternalizeUtf8String("exports");
exports_object = Cast<JSObject>(
JSObject::GetProperty(isolate, instance, exports).ToHandleChecked());
DirectHandle<Name> main_name =
isolate->factory()->NewStringFromAsciiChecked(name);
PropertyDescriptor desc;
Maybe<bool> property_found = JSReceiver::GetOwnPropertyDescriptor(
isolate, exports_object, main_name, &desc);
if (!property_found.FromMaybe(false)) return {};
if (!IsJSFunction(*desc.value())) return {};
return Cast<WasmExportedFunction>(desc.value());
}
int32_t CallWasmFunctionForTesting(
Isolate* isolate, DirectHandle<WasmInstanceObject> instance,
const char* name, base::Vector<const DirectHandle<Object>> args,
std::unique_ptr<const char[]>* exception) {
DCHECK_IMPLIES(exception != nullptr, *exception == nullptr);
MaybeDirectHandle<WasmExportedFunction> maybe_export =
GetExportedFunction(isolate, instance, name);
DirectHandle<WasmExportedFunction> exported_function;
if (!maybe_export.ToHandle(&exported_function)) {
return -1;
}
// Call the JS function.
DirectHandle<Object> undefined = isolate->factory()->undefined_value();
MaybeDirectHandle<Object> retval =
Execution::Call(isolate, exported_function, undefined, args);
// The result should be a number.
if (retval.is_null()) {
DCHECK(isolate->has_exception());
if (exception && !isolate->is_execution_terminating()) {
DirectHandle<String> exception_string = Object::NoSideEffectsToString(
isolate, direct_handle(isolate->exception(), isolate));
*exception = exception_string->ToCString();
}
isolate->clear_internal_exception();
return -1;
}
DirectHandle<Object> result = retval.ToHandleChecked();
// Multi-value returns, get the first return value (see InterpretWasmModule).
if (IsJSArray(*result)) {
auto receiver = Cast<JSReceiver>(result);
result = JSObject::GetElement(isolate, receiver, 0).ToHandleChecked();
}
if (IsSmi(*result)) {
return Smi::ToInt(*result);
}
if (IsHeapNumber(*result)) {
return static_cast<int32_t>(Cast<HeapNumber>(*result)->value());
}
if (IsBigInt(*result)) {
return static_cast<int32_t>(Cast<BigInt>(*result)->AsInt64());
}
return -1;
}
void SetupIsolateForWasmModule(Isolate* isolate) { WasmJs::Install(isolate); }
} // namespace v8::internal::wasm::testing

View File

@ -0,0 +1,60 @@
// 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 V8_WASM_MODULE_RUNNER_H_
#define V8_WASM_MODULE_RUNNER_H_
#include "src/execution/isolate.h"
#include "src/objects/objects.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-result.h"
namespace v8 {
namespace internal {
namespace wasm {
namespace testing {
// Returns a MaybeHandle to the JsToWasm wrapper of the wasm function exported
// with the given name by the provided instance.
MaybeDirectHandle<WasmExportedFunction> GetExportedFunction(
Isolate* isolate, DirectHandle<WasmInstanceObject> instance,
const char* name);
// Call an exported wasm function by name. Returns -1 if the export does not
// exist or throws an error. Errors are cleared from the isolate before
// returning. {exception} is set to a string representation of the exception (if
// set and an exception occurs).
int32_t CallWasmFunctionForTesting(
Isolate* isolate, DirectHandle<WasmInstanceObject> instance,
const char* name, base::Vector<const DirectHandle<Object>> args,
std::unique_ptr<const char[]>* exception = nullptr);
// Decode, verify, and run the function labeled "main" in the
// given encoded module. The module should have no imports.
int32_t CompileAndRunWasmModule(Isolate* isolate, const uint8_t* module_start,
const uint8_t* module_end);
// Decode and compile the given module with no imports.
MaybeDirectHandle<WasmModuleObject> CompileForTesting(
Isolate* isolate, ErrorThrower* thrower, base::Vector<const uint8_t> bytes);
// Decode, compile, and instantiate the given module with no imports.
MaybeDirectHandle<WasmInstanceObject> CompileAndInstantiateForTesting(
Isolate* isolate, ErrorThrower* thrower, base::Vector<const uint8_t> bytes);
// Generate an array of default arguments for the given signature, to be used
// when calling compiled code.
DirectHandleVector<Object> MakeDefaultArguments(Isolate* isolate,
const FunctionSig* sig);
// Install function map, module symbol for testing
void SetupIsolateForWasmModule(Isolate* isolate);
} // namespace testing
} // namespace wasm
} // namespace internal
} // namespace v8
#endif // V8_WASM_MODULE_RUNNER_H_