2016-06-01 21:08:22 +00:00
|
|
|
// 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.
|
|
|
|
|
2017-04-07 12:50:15 +00:00
|
|
|
#include <cmath>
|
|
|
|
|
2019-05-17 12:13:44 +00:00
|
|
|
#include "src/api/api-inl.h"
|
2021-06-24 13:32:01 +00:00
|
|
|
#include "src/base/strings.h"
|
2016-06-02 15:02:08 +00:00
|
|
|
#include "src/base/utils/random-number-generator.h"
|
2017-03-21 11:17:41 +00:00
|
|
|
#include "src/builtins/builtins-promise-gen.h"
|
2018-12-13 09:46:59 +00:00
|
|
|
#include "src/builtins/builtins-promise.h"
|
2017-09-05 02:19:29 +00:00
|
|
|
#include "src/builtins/builtins-string-gen.h"
|
2019-05-21 09:30:15 +00:00
|
|
|
#include "src/codegen/code-factory.h"
|
|
|
|
#include "src/codegen/code-stub-assembler.h"
|
Reland "[codegen] Add static interface descriptors"
This is a reland of ae0752df1b84d8c53cc7b2af71013a9e678a9c6e
Reland fixes:
* Remove UNREACHABLE() from constexpr switch, since we don't have a
CONSTEXPR_UNREACHABLE() (it's ok, the switch is exhaustive for the
enum anyway).
* Fix IsRegisterArray trait to use public inheritance and size_t for
std::array size.
Original change's description:
> [codegen] Add static interface descriptors
>
> Add a new CRTP StaticCallInterfaceDescriptor class, which provides
> static constexpr getters for a descriptor's registers, parameter counts,
> and so on. Each CallInterfaceDescriptor subclass is changed to extend
> StaticCallInterfaceDescriptor, with StaticCallInterfaceDescriptor itself
> extending CallInterfaceDescriptor to still provide a dynamic lookup
> where needed.
>
> StaticCallInterfaceDescriptor provides a couple of customisation points,
> where it reads its CRTP derived descriptor's static fields and
> functions, with default fallbacks where appropriate. With these
> customisation points, the definition of CallInterfaceDescriptor
> subclasses is simplified to:
>
> a) Providing parameter names (as before)
> b) Providing parameter types (as before)
> c) Optionally setting flags (like kNoContext or kAllowVarArgs) as
> static booleans on the class.
> d) Optionally providing a `registers()` method that returns a
> std::array<Register, N> of registers that may be used for
> parameters (if not provided, this defaults to the implementation
> specific default register set).
>
> Parameter registers (and register count) are automagically set based on
> the number of parameters and number of given registers, with extra magic
> to ignore no_reg registers (to reduce ia32 special casing). The
> CallInterfaceDescriptorData is initialized based on these static
> functions, rather than manual per-descriptor initializers.
>
> This allows us to skip loading descriptors dynamically for CallBuiltin
> in Sparkplug, and instead lets us use a bit of template magic to
> statically set up arguments for the calls. Any other users of statically
> known descriptors will also benefit, thanks to C++ picking the static
> methods over the dynamic methods on the base class when available.
>
> Because we can remove various virtual functions and trigger heavier
> inlining of constantly known values, binary size slightly decreases with
> this change.
>
> Note that torque-generated descriptors are changed to use the same magic,
> rather than having Torque-specific magic, for consistency.
>
> Bug: v8:11420
> Change-Id: Icc5e238b6313a08734feb564204a13226b450c22
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2814518
> Auto-Submit: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
> Reviewed-by: Clemens Backes <clemensb@chromium.org>
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Reviewed-by: Jakob Gruber <jgruber@chromium.org>
> Commit-Queue: Clemens Backes <clemensb@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#73996}
TBR=nicohartmann@chromium.org,clemensb@chromium.org,ishell@chromium.org,clemensb@chromium.org
Bug: v8:11420
Change-Id: Icd1f6cdb3c178e74460044b1e9623139929ceba8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2831872
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74010}
2021-04-16 14:52:06 +00:00
|
|
|
#include "src/codegen/interface-descriptors-inl.h"
|
2016-08-26 08:41:20 +00:00
|
|
|
#include "src/compiler/node.h"
|
2017-02-23 11:46:29 +00:00
|
|
|
#include "src/debug/debug.h"
|
2019-05-22 07:55:37 +00:00
|
|
|
#include "src/execution/isolate.h"
|
2018-07-25 14:11:56 +00:00
|
|
|
#include "src/heap/heap-inl.h"
|
2019-05-24 13:51:59 +00:00
|
|
|
#include "src/numbers/hash-seed-inl.h"
|
2018-05-17 12:28:56 +00:00
|
|
|
#include "src/objects/hash-table-inl.h"
|
2018-12-17 17:01:48 +00:00
|
|
|
#include "src/objects/heap-number-inl.h"
|
2018-08-16 16:01:36 +00:00
|
|
|
#include "src/objects/js-array-buffer-inl.h"
|
2018-07-25 14:11:56 +00:00
|
|
|
#include "src/objects/js-array-inl.h"
|
2019-05-23 08:51:46 +00:00
|
|
|
#include "src/objects/objects-inl.h"
|
2019-02-07 20:27:25 +00:00
|
|
|
#include "src/objects/ordered-hash-table-inl.h"
|
2018-02-26 12:40:05 +00:00
|
|
|
#include "src/objects/promise-inl.h"
|
2018-11-03 00:13:22 +00:00
|
|
|
#include "src/objects/smi.h"
|
2018-12-13 23:35:14 +00:00
|
|
|
#include "src/objects/struct-inl.h"
|
2019-05-20 08:54:18 +00:00
|
|
|
#include "src/objects/transitions-inl.h"
|
2019-05-21 06:38:38 +00:00
|
|
|
#include "src/strings/char-predicates.h"
|
2020-10-13 15:44:09 +00:00
|
|
|
#include "test/cctest/cctest-utils.h"
|
2016-06-17 13:19:58 +00:00
|
|
|
#include "test/cctest/compiler/code-assembler-tester.h"
|
2016-06-01 21:08:22 +00:00
|
|
|
#include "test/cctest/compiler/function-tester.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
2017-07-18 13:45:08 +00:00
|
|
|
namespace compiler {
|
2016-06-01 21:08:22 +00:00
|
|
|
|
2017-04-07 12:50:15 +00:00
|
|
|
namespace {
|
|
|
|
|
2018-05-11 11:00:17 +00:00
|
|
|
using Label = CodeAssemblerLabel;
|
|
|
|
template <class T>
|
|
|
|
using TVariable = TypedCodeAssemblerVariable<T>;
|
2019-10-30 16:35:38 +00:00
|
|
|
using PromiseResolvingFunctions = TorqueStructPromiseResolvingFunctions;
|
2017-07-18 13:45:08 +00:00
|
|
|
|
2020-09-09 17:25:41 +00:00
|
|
|
intptr_t sum10(intptr_t a0, intptr_t a1, intptr_t a2, intptr_t a3, intptr_t a4,
|
|
|
|
intptr_t a5, intptr_t a6, intptr_t a7, intptr_t a8,
|
|
|
|
intptr_t a9) {
|
2019-08-14 13:03:56 +00:00
|
|
|
return a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9;
|
2017-04-24 11:58:50 +00:00
|
|
|
}
|
|
|
|
|
2017-08-21 15:23:17 +00:00
|
|
|
static int sum3(int a0, int a1, int a2) { return a0 + a1 + a2; }
|
|
|
|
|
2017-04-24 11:58:50 +00:00
|
|
|
} // namespace
|
|
|
|
|
2019-03-16 19:51:22 +00:00
|
|
|
TEST(CallCFunction) {
|
2017-04-24 11:58:50 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 0;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-04-24 11:58:50 +00:00
|
|
|
|
|
|
|
{
|
2019-10-30 17:54:06 +00:00
|
|
|
const TNode<ExternalReference> fun_constant = m.ExternalConstant(
|
2019-08-14 13:03:56 +00:00
|
|
|
ExternalReference::Create(reinterpret_cast<Address>(sum10)));
|
2017-04-24 11:58:50 +00:00
|
|
|
|
|
|
|
MachineType type_intptr = MachineType::IntPtr();
|
|
|
|
|
2021-02-22 16:56:41 +00:00
|
|
|
TNode<IntPtrT> const result = m.UncheckedCast<IntPtrT>(
|
2019-03-16 19:51:22 +00:00
|
|
|
m.CallCFunction(fun_constant, type_intptr,
|
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(0)),
|
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(1)),
|
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(2)),
|
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(3)),
|
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(4)),
|
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(5)),
|
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(6)),
|
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(7)),
|
2019-08-14 13:03:56 +00:00
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(8)),
|
2021-02-22 16:56:41 +00:00
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(9))));
|
2017-04-24 11:58:50 +00:00
|
|
|
m.Return(m.SmiTag(result));
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2017-04-24 11:58:50 +00:00
|
|
|
|
|
|
|
Handle<Object> result = ft.Call().ToHandleChecked();
|
2019-08-14 13:03:56 +00:00
|
|
|
CHECK_EQ(45, Handle<Smi>::cast(result)->value());
|
2017-04-24 11:58:50 +00:00
|
|
|
}
|
|
|
|
|
2019-03-16 19:51:22 +00:00
|
|
|
TEST(CallCFunctionWithCallerSavedRegisters) {
|
2017-08-21 15:23:17 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 0;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
{
|
2019-10-30 17:54:06 +00:00
|
|
|
const TNode<ExternalReference> fun_constant = m.ExternalConstant(
|
2018-04-25 07:28:14 +00:00
|
|
|
ExternalReference::Create(reinterpret_cast<Address>(sum3)));
|
2017-08-21 15:23:17 +00:00
|
|
|
|
|
|
|
MachineType type_intptr = MachineType::IntPtr();
|
|
|
|
|
2021-02-22 16:56:41 +00:00
|
|
|
TNode<IntPtrT> const result =
|
|
|
|
m.UncheckedCast<IntPtrT>(m.CallCFunctionWithCallerSavedRegisters(
|
2021-05-11 09:03:52 +00:00
|
|
|
fun_constant, type_intptr, SaveFPRegsMode::kSave,
|
2021-02-22 16:56:41 +00:00
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(0)),
|
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(1)),
|
|
|
|
std::make_pair(type_intptr, m.IntPtrConstant(2))));
|
2017-08-21 15:23:17 +00:00
|
|
|
m.Return(m.SmiTag(result));
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<Object> result = ft.Call().ToHandleChecked();
|
|
|
|
CHECK_EQ(3, Handle<Smi>::cast(result)->value());
|
|
|
|
}
|
|
|
|
|
2019-09-11 09:53:03 +00:00
|
|
|
TEST(NumberToString) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2019-09-11 09:53:03 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
auto input = m.Parameter<Number>(1);
|
2019-09-11 09:53:03 +00:00
|
|
|
|
|
|
|
Label bailout(&m);
|
|
|
|
m.Return(m.NumberToString(input, &bailout));
|
|
|
|
|
|
|
|
m.BIND(&bailout);
|
|
|
|
m.Return(m.UndefinedConstant());
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
double inputs[] = {
|
|
|
|
1, 2, 42, 153, -1, -100, 0, 51095154, -1241950,
|
|
|
|
std::nan("-1"), std::nan("1"), std::nan("2"),
|
|
|
|
-std::numeric_limits<double>::infinity(),
|
|
|
|
std::numeric_limits<double>::infinity(),
|
|
|
|
-0.0, -0.001, -0.5, -0.999, -1.0,
|
|
|
|
0.0, 0.001, 0.5, 0.999, 1.0,
|
|
|
|
-2147483647.9, -2147483648.0, -2147483648.5, -2147483648.9, // SmiMin.
|
|
|
|
2147483646.9, 2147483647.0, 2147483647.5, 2147483647.9, // SmiMax.
|
|
|
|
-4294967295.9, -4294967296.0, -4294967296.5, -4294967297.0, // - 2^32.
|
|
|
|
4294967295.9, 4294967296.0, 4294967296.5, 4294967297.0, // 2^32.
|
|
|
|
};
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
const int kFullCacheSize = isolate->heap()->MaxNumberToStringCacheSize();
|
|
|
|
const int test_count = arraysize(inputs);
|
|
|
|
for (int i = 0; i < test_count; i++) {
|
|
|
|
int cache_length_before_addition = factory->number_string_cache()->length();
|
|
|
|
Handle<Object> input = factory->NewNumber(inputs[i]);
|
|
|
|
Handle<String> expected = factory->NumberToString(input);
|
|
|
|
|
|
|
|
Handle<Object> result = ft.Call(input).ToHandleChecked();
|
|
|
|
if (result->IsUndefined(isolate)) {
|
|
|
|
// Query may fail if cache was resized, in which case the entry is not
|
|
|
|
// added to the cache.
|
|
|
|
CHECK_LT(cache_length_before_addition, kFullCacheSize);
|
|
|
|
CHECK_EQ(factory->number_string_cache()->length(), kFullCacheSize);
|
|
|
|
expected = factory->NumberToString(input);
|
|
|
|
result = ft.Call(input).ToHandleChecked();
|
|
|
|
}
|
|
|
|
CHECK(!result->IsUndefined(isolate));
|
|
|
|
CHECK_EQ(*expected, *result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-24 11:58:50 +00:00
|
|
|
namespace {
|
|
|
|
|
2017-04-07 12:50:15 +00:00
|
|
|
void CheckToUint32Result(uint32_t expected, Handle<Object> result) {
|
|
|
|
const int64_t result_int64 = NumberToInt64(*result);
|
|
|
|
const uint32_t result_uint32 = NumberToUint32(*result);
|
|
|
|
|
|
|
|
CHECK_EQ(static_cast<int64_t>(result_uint32), result_int64);
|
|
|
|
CHECK_EQ(expected, result_uint32);
|
|
|
|
|
|
|
|
// Ensure that the result is normalized to a Smi, i.e. a HeapNumber is only
|
|
|
|
// returned if the result is not within Smi range.
|
|
|
|
const bool expected_fits_into_intptr =
|
|
|
|
static_cast<int64_t>(expected) <=
|
|
|
|
static_cast<int64_t>(std::numeric_limits<intptr_t>::max());
|
|
|
|
if (expected_fits_into_intptr &&
|
|
|
|
Smi::IsValid(static_cast<intptr_t>(expected))) {
|
|
|
|
CHECK(result->IsSmi());
|
|
|
|
} else {
|
|
|
|
CHECK(result->IsHeapNumber());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST(ToUint32) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-04-07 12:50:15 +00:00
|
|
|
|
2020-07-15 11:03:22 +00:00
|
|
|
const int kContextOffset = 3;
|
2020-09-30 17:40:39 +00:00
|
|
|
auto context = m.Parameter<Context>(kNumParams + kContextOffset);
|
|
|
|
auto input = m.Parameter<Object>(1);
|
2017-04-07 12:50:15 +00:00
|
|
|
m.Return(m.ToUint32(context, input));
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2017-04-07 12:50:15 +00:00
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
double inputs[] = {
|
|
|
|
std::nan("-1"), std::nan("1"), std::nan("2"),
|
|
|
|
-std::numeric_limits<double>::infinity(),
|
|
|
|
std::numeric_limits<double>::infinity(),
|
|
|
|
-0.0, -0.001, -0.5, -0.999, -1.0,
|
|
|
|
0.0, 0.001, 0.5, 0.999, 1.0,
|
|
|
|
-2147483647.9, -2147483648.0, -2147483648.5, -2147483648.9, // SmiMin.
|
|
|
|
2147483646.9, 2147483647.0, 2147483647.5, 2147483647.9, // SmiMax.
|
|
|
|
-4294967295.9, -4294967296.0, -4294967296.5, -4294967297.0, // - 2^32.
|
|
|
|
4294967295.9, 4294967296.0, 4294967296.5, 4294967297.0, // 2^32.
|
|
|
|
};
|
|
|
|
|
|
|
|
uint32_t expectations[] = {
|
|
|
|
0, 0, 0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0, 0, 0, 0, 4294967295,
|
|
|
|
0, 0, 0, 0, 1,
|
|
|
|
2147483649, 2147483648, 2147483648, 2147483648,
|
|
|
|
2147483646, 2147483647, 2147483647, 2147483647,
|
|
|
|
1, 0, 0, 4294967295,
|
|
|
|
4294967295, 0, 0, 1,
|
|
|
|
};
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
STATIC_ASSERT(arraysize(inputs) == arraysize(expectations));
|
|
|
|
|
|
|
|
const int test_count = arraysize(inputs);
|
|
|
|
for (int i = 0; i < test_count; i++) {
|
|
|
|
Handle<Object> input_obj = factory->NewNumber(inputs[i]);
|
|
|
|
Handle<HeapNumber> input_num;
|
|
|
|
|
|
|
|
// Check with Smi input.
|
|
|
|
if (input_obj->IsSmi()) {
|
|
|
|
Handle<Smi> input_smi = Handle<Smi>::cast(input_obj);
|
|
|
|
Handle<Object> result = ft.Call(input_smi).ToHandleChecked();
|
|
|
|
CheckToUint32Result(expectations[i], result);
|
|
|
|
input_num = factory->NewHeapNumber(inputs[i]);
|
|
|
|
} else {
|
|
|
|
input_num = Handle<HeapNumber>::cast(input_obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check with HeapNumber input.
|
|
|
|
{
|
|
|
|
CHECK(input_num->IsHeapNumber());
|
|
|
|
Handle<Object> result = ft.Call(input_num).ToHandleChecked();
|
|
|
|
CheckToUint32Result(expectations[i], result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// A couple of final cases for ToNumber conversions.
|
|
|
|
CheckToUint32Result(0, ft.Call(factory->undefined_value()).ToHandleChecked());
|
|
|
|
CheckToUint32Result(0, ft.Call(factory->null_value()).ToHandleChecked());
|
|
|
|
CheckToUint32Result(0, ft.Call(factory->false_value()).ToHandleChecked());
|
|
|
|
CheckToUint32Result(1, ft.Call(factory->true_value()).ToHandleChecked());
|
|
|
|
CheckToUint32Result(
|
|
|
|
42,
|
|
|
|
ft.Call(factory->NewStringFromAsciiChecked("0x2A")).ToHandleChecked());
|
|
|
|
|
|
|
|
ft.CheckThrows(factory->match_symbol());
|
|
|
|
}
|
|
|
|
|
2018-06-05 08:00:23 +00:00
|
|
|
namespace {
|
2018-06-07 15:33:01 +00:00
|
|
|
void IsValidPositiveSmiCase(Isolate* isolate, intptr_t value) {
|
2018-06-05 08:00:23 +00:00
|
|
|
const int kNumParams = 0;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
m.Return(
|
|
|
|
m.SelectBooleanConstant(m.IsValidPositiveSmi(m.IntPtrConstant(value))));
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
MaybeHandle<Object> maybe_handle = ft.Call();
|
|
|
|
|
2018-06-07 15:33:01 +00:00
|
|
|
bool expected = i::PlatformSmiTagging::IsValidSmi(value) && (value >= 0);
|
2018-06-05 08:00:23 +00:00
|
|
|
if (expected) {
|
|
|
|
CHECK(maybe_handle.ToHandleChecked()->IsTrue(isolate));
|
|
|
|
} else {
|
|
|
|
CHECK(maybe_handle.ToHandleChecked()->IsFalse(isolate));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST(IsValidPositiveSmi) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2018-06-07 15:33:01 +00:00
|
|
|
IsValidPositiveSmiCase(isolate, -1);
|
|
|
|
IsValidPositiveSmiCase(isolate, 0);
|
|
|
|
IsValidPositiveSmiCase(isolate, 1);
|
|
|
|
|
|
|
|
IsValidPositiveSmiCase(isolate, 0x3FFFFFFFU);
|
|
|
|
IsValidPositiveSmiCase(isolate, 0xC0000000U);
|
|
|
|
IsValidPositiveSmiCase(isolate, 0x40000000U);
|
|
|
|
IsValidPositiveSmiCase(isolate, 0xBFFFFFFFU);
|
2018-06-05 08:00:23 +00:00
|
|
|
|
2019-05-27 11:31:49 +00:00
|
|
|
using int32_limits = std::numeric_limits<int32_t>;
|
2018-06-07 15:33:01 +00:00
|
|
|
IsValidPositiveSmiCase(isolate, int32_limits::max());
|
|
|
|
IsValidPositiveSmiCase(isolate, int32_limits::min());
|
2019-03-06 17:45:15 +00:00
|
|
|
#if V8_TARGET_ARCH_64_BIT
|
2018-06-05 08:00:23 +00:00
|
|
|
IsValidPositiveSmiCase(isolate,
|
2018-06-07 15:33:01 +00:00
|
|
|
static_cast<intptr_t>(int32_limits::max()) + 1);
|
2018-06-05 08:00:23 +00:00
|
|
|
IsValidPositiveSmiCase(isolate,
|
2018-06-07 15:33:01 +00:00
|
|
|
static_cast<intptr_t>(int32_limits::min()) - 1);
|
2018-06-05 08:00:23 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-10-21 15:11:17 +00:00
|
|
|
TEST(ConvertToRelativeIndex) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 3;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2019-10-21 15:11:17 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
enum Result { kFound, kNotFound };
|
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
auto index = m.Parameter<Number>(1);
|
|
|
|
auto length_number = m.Parameter<Number>(2);
|
|
|
|
auto expected_relative_index = m.Parameter<Number>(3);
|
2019-10-21 15:11:17 +00:00
|
|
|
|
2019-10-25 13:14:41 +00:00
|
|
|
TNode<UintPtrT> length = m.ChangeUintPtrNumberToUintPtr(length_number);
|
2019-10-21 15:11:17 +00:00
|
|
|
TNode<UintPtrT> expected =
|
2019-10-25 13:14:41 +00:00
|
|
|
m.ChangeUintPtrNumberToUintPtr(expected_relative_index);
|
2019-10-21 15:11:17 +00:00
|
|
|
|
2019-10-22 13:32:29 +00:00
|
|
|
TNode<UintPtrT> result = m.ConvertToRelativeIndex(index, length);
|
2019-10-21 15:11:17 +00:00
|
|
|
|
|
|
|
m.Return(m.SelectBooleanConstant(m.WordEqual(result, expected)));
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
const double kMaxSmi = static_cast<double>(kSmiMaxValue);
|
|
|
|
const double kMaxInt32 =
|
|
|
|
static_cast<double>(std::numeric_limits<int32_t>::max());
|
|
|
|
const double kMaxUInt32 =
|
|
|
|
static_cast<double>(std::numeric_limits<uint32_t>::max());
|
|
|
|
const double kMaxUIntPtr =
|
|
|
|
static_cast<double>(std::numeric_limits<uintptr_t>::max());
|
|
|
|
|
|
|
|
struct {
|
|
|
|
double index;
|
|
|
|
double length;
|
|
|
|
double expected_result;
|
|
|
|
} test_cases[] = {
|
|
|
|
// Simple Smi-range cases.
|
|
|
|
{0, 0, 0},
|
|
|
|
{0, 42, 0},
|
|
|
|
{5, 42, 5},
|
|
|
|
{100, 42, 42},
|
|
|
|
{-10, 153, 153 - 10},
|
|
|
|
{-200, 153, 0},
|
|
|
|
// Beyond Smi-range index cases.
|
|
|
|
{0, kMaxSmi, 0},
|
|
|
|
{-153, kMaxSmi, kMaxSmi - 153},
|
|
|
|
{kMaxSmi + 153, kMaxSmi, kMaxSmi},
|
|
|
|
{kMaxSmi * 33, kMaxSmi, kMaxSmi},
|
|
|
|
{-kMaxSmi, kMaxSmi, 0},
|
|
|
|
{-kMaxSmi - 1, kMaxSmi, 0},
|
|
|
|
{-kMaxSmi - 153, kMaxSmi, 0},
|
|
|
|
{-kMaxSmi * 33, kMaxSmi, 0},
|
|
|
|
{-std::numeric_limits<double>::infinity(), 153, 0},
|
|
|
|
{std::numeric_limits<double>::infinity(), 424242, 424242},
|
|
|
|
// Beyond Smi-range length cases.
|
|
|
|
{kMaxSmi + 2, kMaxSmi + 1, kMaxSmi + 1},
|
|
|
|
{-kMaxSmi + 2, kMaxSmi + 1, 3},
|
|
|
|
{kMaxInt32 + 1, kMaxInt32, kMaxInt32},
|
|
|
|
{-kMaxInt32 + 1, kMaxInt32, 1},
|
|
|
|
{kMaxUInt32 + 1, kMaxUInt32, kMaxUInt32},
|
|
|
|
{-42, kMaxUInt32, kMaxUInt32 - 42},
|
|
|
|
{-kMaxUInt32 - 1, kMaxUInt32, 0},
|
|
|
|
{-kMaxUInt32, kMaxUInt32, 0},
|
|
|
|
{-kMaxUInt32 + 1, kMaxUInt32, 1},
|
|
|
|
{-kMaxUInt32 + 5, kMaxUInt32, 5},
|
|
|
|
{-kMaxUInt32 + 5, kMaxUInt32 + 1, 6},
|
|
|
|
{-kMaxSmi * 33, kMaxSmi * 153, kMaxSmi * (153 - 33)},
|
|
|
|
{0, kMaxSafeInteger, 0},
|
|
|
|
{kMaxSmi, kMaxSafeInteger, kMaxSmi},
|
|
|
|
{kMaxSmi * 153, kMaxSafeInteger, kMaxSmi * 153},
|
|
|
|
{-10, kMaxSafeInteger, kMaxSafeInteger - 10},
|
|
|
|
{-kMaxSafeInteger, kMaxSafeInteger, 0},
|
|
|
|
{-kMaxSafeInteger + 1, kMaxSafeInteger, 1},
|
|
|
|
{-kMaxSafeInteger + 42, kMaxSafeInteger, 42},
|
|
|
|
{kMaxSafeInteger - 153, kMaxSafeInteger, kMaxSafeInteger - 153},
|
|
|
|
{kMaxSafeInteger - 1, kMaxSafeInteger, kMaxSafeInteger - 1},
|
|
|
|
{kMaxSafeInteger, kMaxSafeInteger, kMaxSafeInteger},
|
|
|
|
{kMaxSafeInteger + 1, kMaxSafeInteger, kMaxSafeInteger},
|
|
|
|
{kMaxSafeInteger + 42, kMaxSafeInteger, kMaxSafeInteger},
|
|
|
|
{kMaxSafeInteger * 11, kMaxSafeInteger, kMaxSafeInteger},
|
|
|
|
};
|
|
|
|
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
for (size_t i = 0; i < arraysize(test_cases); i++) {
|
|
|
|
if (test_cases[i].length > kMaxUIntPtr) {
|
|
|
|
// Test cases where length does not fit into uintptr are not valid, so
|
|
|
|
// skip them instead of ifdef'ing the test cases above.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Handle<Object> index = factory->NewNumber(test_cases[i].index);
|
|
|
|
Handle<Object> length = factory->NewNumber(test_cases[i].length);
|
|
|
|
Handle<Object> expected = factory->NewNumber(test_cases[i].expected_result);
|
|
|
|
|
|
|
|
ft.CheckTrue(index, length, expected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-01 21:08:22 +00:00
|
|
|
TEST(FixedArrayAccessSmiIndex) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-01 21:08:22 +00:00
|
|
|
Handle<FixedArray> array = isolate->factory()->NewFixedArray(5);
|
|
|
|
array->set(4, Smi::FromInt(733));
|
|
|
|
m.Return(m.LoadFixedArrayElement(m.HeapConstant(array),
|
2020-07-07 09:45:58 +00:00
|
|
|
m.SmiTag(m.IntPtrConstant(4)), 0));
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode());
|
2016-06-01 21:08:22 +00:00
|
|
|
MaybeHandle<Object> result = ft.Call();
|
|
|
|
CHECK_EQ(733, Handle<Smi>::cast(result.ToHandleChecked())->value());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(LoadHeapNumberValue) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-01 21:08:22 +00:00
|
|
|
Handle<HeapNumber> number = isolate->factory()->NewHeapNumber(1234);
|
2018-02-23 13:46:00 +00:00
|
|
|
m.Return(m.SmiFromInt32(m.Signed(
|
2017-10-20 15:18:53 +00:00
|
|
|
m.ChangeFloat64ToUint32(m.LoadHeapNumberValue(m.HeapConstant(number))))));
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode());
|
2016-06-01 21:08:22 +00:00
|
|
|
MaybeHandle<Object> result = ft.Call();
|
|
|
|
CHECK_EQ(1234, Handle<Smi>::cast(result.ToHandleChecked())->value());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(LoadInstanceType) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-01 21:08:22 +00:00
|
|
|
Handle<HeapObject> undefined = isolate->factory()->undefined_value();
|
2018-02-23 13:46:00 +00:00
|
|
|
m.Return(m.SmiFromInt32(m.LoadInstanceType(m.HeapConstant(undefined))));
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode());
|
2016-06-01 21:08:22 +00:00
|
|
|
MaybeHandle<Object> result = ft.Call();
|
|
|
|
CHECK_EQ(InstanceType::ODDBALL_TYPE,
|
|
|
|
Handle<Smi>::cast(result.ToHandleChecked())->value());
|
|
|
|
}
|
|
|
|
|
2016-10-20 12:27:18 +00:00
|
|
|
TEST(DecodeWordFromWord32) {
|
2016-06-01 21:08:22 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-17 13:19:58 +00:00
|
|
|
|
2019-11-15 11:58:57 +00:00
|
|
|
using TestBitField = base::BitField<unsigned, 3, 3>;
|
2017-12-18 18:35:25 +00:00
|
|
|
m.Return(m.SmiTag(
|
|
|
|
m.Signed(m.DecodeWordFromWord32<TestBitField>(m.Int32Constant(0x2F)))));
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode());
|
2016-06-01 21:08:22 +00:00
|
|
|
MaybeHandle<Object> result = ft.Call();
|
|
|
|
// value = 00101111
|
|
|
|
// mask = 00111000
|
|
|
|
// result = 101
|
|
|
|
CHECK_EQ(5, Handle<Smi>::cast(result.ToHandleChecked())->value());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(JSFunction) {
|
2020-07-15 11:03:22 +00:00
|
|
|
const int kNumParams = 2; // left, right.
|
2016-06-01 21:08:22 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.SmiFromInt32(m.Int32Add(m.SmiToInt32(m.Parameter<Smi>(1)),
|
|
|
|
m.SmiToInt32(m.Parameter<Smi>(2)))));
|
2016-06-01 21:08:22 +00:00
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-06-01 21:08:22 +00:00
|
|
|
|
2020-07-15 11:03:22 +00:00
|
|
|
MaybeHandle<Object> result = ft.Call(handle(Smi::FromInt(23), isolate),
|
2016-06-17 13:19:58 +00:00
|
|
|
handle(Smi::FromInt(34), isolate));
|
|
|
|
CHECK_EQ(57, Handle<Smi>::cast(result.ToHandleChecked())->value());
|
2016-06-01 21:08:22 +00:00
|
|
|
}
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
TEST(ComputeIntegerHash) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
2018-07-16 09:52:50 +00:00
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2020-01-07 18:08:52 +00:00
|
|
|
m.Return(m.SmiFromInt32(m.UncheckedCast<Int32T>(
|
2020-09-30 17:40:39 +00:00
|
|
|
m.ComputeSeededHash(m.SmiUntag(m.Parameter<Smi>(1))))));
|
2018-07-16 09:52:50 +00:00
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
base::RandomNumberGenerator rand_gen(FLAG_random_seed);
|
|
|
|
|
|
|
|
for (int i = 0; i < 1024; i++) {
|
|
|
|
int k = rand_gen.NextInt(Smi::kMaxValue);
|
|
|
|
|
|
|
|
Handle<Smi> key(Smi::FromInt(k), isolate);
|
2018-07-16 09:52:50 +00:00
|
|
|
Handle<Object> result = ft.Call(key).ToHandleChecked();
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2019-02-14 21:10:30 +00:00
|
|
|
uint32_t hash = ComputeSeededHash(k, HashSeed(isolate));
|
2019-01-09 14:38:22 +00:00
|
|
|
Smi expected = Smi::FromInt(hash);
|
2016-06-02 15:02:08 +00:00
|
|
|
CHECK_EQ(expected, Smi::cast(*result));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-19 13:37:12 +00:00
|
|
|
TEST(ToString) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.ToStringImpl(m.Parameter<Context>(kNumParams + 3),
|
|
|
|
m.Parameter<Object>(1)));
|
2016-10-19 13:37:12 +00:00
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-10-19 13:37:12 +00:00
|
|
|
|
|
|
|
Handle<FixedArray> test_cases = isolate->factory()->NewFixedArray(5);
|
|
|
|
Handle<FixedArray> smi_test = isolate->factory()->NewFixedArray(2);
|
|
|
|
smi_test->set(0, Smi::FromInt(42));
|
|
|
|
Handle<String> str(isolate->factory()->InternalizeUtf8String("42"));
|
|
|
|
smi_test->set(1, *str);
|
|
|
|
test_cases->set(0, *smi_test);
|
|
|
|
|
|
|
|
Handle<FixedArray> number_test = isolate->factory()->NewFixedArray(2);
|
|
|
|
Handle<HeapNumber> num(isolate->factory()->NewHeapNumber(3.14));
|
|
|
|
number_test->set(0, *num);
|
|
|
|
str = isolate->factory()->InternalizeUtf8String("3.14");
|
|
|
|
number_test->set(1, *str);
|
|
|
|
test_cases->set(1, *number_test);
|
|
|
|
|
|
|
|
Handle<FixedArray> string_test = isolate->factory()->NewFixedArray(2);
|
|
|
|
str = isolate->factory()->InternalizeUtf8String("test");
|
|
|
|
string_test->set(0, *str);
|
|
|
|
string_test->set(1, *str);
|
|
|
|
test_cases->set(2, *string_test);
|
|
|
|
|
|
|
|
Handle<FixedArray> oddball_test = isolate->factory()->NewFixedArray(2);
|
2018-07-04 09:10:05 +00:00
|
|
|
oddball_test->set(0, ReadOnlyRoots(isolate).undefined_value());
|
2016-10-19 13:37:12 +00:00
|
|
|
str = isolate->factory()->InternalizeUtf8String("undefined");
|
|
|
|
oddball_test->set(1, *str);
|
|
|
|
test_cases->set(3, *oddball_test);
|
|
|
|
|
|
|
|
Handle<FixedArray> tostring_test = isolate->factory()->NewFixedArray(2);
|
|
|
|
Handle<FixedArray> js_array_storage = isolate->factory()->NewFixedArray(2);
|
|
|
|
js_array_storage->set(0, Smi::FromInt(1));
|
|
|
|
js_array_storage->set(1, Smi::FromInt(2));
|
|
|
|
Handle<JSArray> js_array = isolate->factory()->NewJSArray(2);
|
|
|
|
JSArray::SetContent(js_array, js_array_storage);
|
|
|
|
tostring_test->set(0, *js_array);
|
|
|
|
str = isolate->factory()->InternalizeUtf8String("1,2");
|
|
|
|
tostring_test->set(1, *str);
|
|
|
|
test_cases->set(4, *tostring_test);
|
|
|
|
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
2018-06-11 09:53:20 +00:00
|
|
|
Handle<FixedArray> test =
|
|
|
|
handle(FixedArray::cast(test_cases->get(i)), isolate);
|
2016-10-19 13:37:12 +00:00
|
|
|
Handle<Object> obj = handle(test->get(0), isolate);
|
2018-06-11 09:53:20 +00:00
|
|
|
Handle<String> expected = handle(String::cast(test->get(1)), isolate);
|
2016-10-19 13:37:12 +00:00
|
|
|
Handle<Object> result = ft.Call(obj).ToHandleChecked();
|
|
|
|
CHECK(result->IsString());
|
2018-06-20 16:32:59 +00:00
|
|
|
CHECK(String::Equals(isolate, Handle<String>::cast(result), expected));
|
2016-10-19 13:37:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
TEST(TryToName) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2016-06-17 13:19:58 +00:00
|
|
|
const int kNumParams = 3;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
enum Result { kKeyIsIndex, kKeyIsUnique, kBailout };
|
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
auto key = m.Parameter<Object>(1);
|
|
|
|
auto expected_result = m.UncheckedParameter<MaybeObject>(2);
|
|
|
|
auto expected_arg = m.Parameter<Object>(3);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Label passed(&m), failed(&m);
|
|
|
|
Label if_keyisindex(&m), if_keyisunique(&m), if_bailout(&m);
|
2017-01-19 13:27:59 +00:00
|
|
|
{
|
2019-08-23 12:40:12 +00:00
|
|
|
TYPED_VARIABLE_DEF(IntPtrT, var_index, &m);
|
2019-09-17 13:44:42 +00:00
|
|
|
TYPED_VARIABLE_DEF(Name, var_unique, &m);
|
2019-10-16 13:06:24 +00:00
|
|
|
TYPED_VARIABLE_DEF(IntPtrT, var_expected, &m);
|
2017-01-19 13:27:59 +00:00
|
|
|
|
|
|
|
m.TryToName(key, &if_keyisindex, &var_index, &if_keyisunique, &var_unique,
|
|
|
|
&if_bailout);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_keyisindex);
|
2019-08-23 12:40:12 +00:00
|
|
|
m.GotoIfNot(m.TaggedEqual(expected_result,
|
|
|
|
m.SmiConstant(Smi::FromInt(kKeyIsIndex))),
|
2017-02-17 16:25:07 +00:00
|
|
|
&failed);
|
2019-10-16 13:06:24 +00:00
|
|
|
|
|
|
|
Label if_expectedissmi(&m), if_expectedisheapnumber(&m), check_result(&m);
|
|
|
|
m.Branch(m.TaggedIsSmi(expected_arg), &if_expectedissmi,
|
|
|
|
&if_expectedisheapnumber);
|
|
|
|
|
|
|
|
m.BIND(&if_expectedissmi);
|
|
|
|
var_expected = m.SmiUntag(m.CAST(expected_arg));
|
|
|
|
m.Goto(&check_result);
|
|
|
|
|
|
|
|
m.BIND(&if_expectedisheapnumber);
|
|
|
|
CSA_ASSERT(&m, m.IsHeapNumber(m.CAST(expected_arg)));
|
|
|
|
TNode<Float64T> value = m.LoadHeapNumberValue(m.CAST(expected_arg));
|
|
|
|
// We know this to be safe as all expected values are in intptr
|
|
|
|
// range.
|
|
|
|
var_expected = m.UncheckedCast<IntPtrT>(m.ChangeFloat64ToUintPtr(value));
|
|
|
|
m.Goto(&check_result);
|
|
|
|
|
|
|
|
m.BIND(&check_result);
|
|
|
|
m.Branch(m.IntPtrEqual(var_expected.value(), var_index.value()), &passed,
|
|
|
|
&failed);
|
2017-01-19 13:27:59 +00:00
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_keyisunique);
|
2019-08-23 12:40:12 +00:00
|
|
|
m.GotoIfNot(m.TaggedEqual(expected_result,
|
|
|
|
m.SmiConstant(Smi::FromInt(kKeyIsUnique))),
|
2017-02-17 16:25:07 +00:00
|
|
|
&failed);
|
2019-08-23 12:40:12 +00:00
|
|
|
m.Branch(m.TaggedEqual(expected_arg, var_unique.value()), &passed,
|
|
|
|
&failed);
|
2017-01-19 13:27:59 +00:00
|
|
|
}
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_bailout);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(
|
2019-08-23 12:40:12 +00:00
|
|
|
m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
|
2016-06-02 15:02:08 +00:00
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&passed);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Return(m.BooleanConstant(true));
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&failed);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Return(m.BooleanConstant(false));
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Handle<Object> expect_index(Smi::FromInt(kKeyIsIndex), isolate);
|
|
|
|
Handle<Object> expect_unique(Smi::FromInt(kKeyIsUnique), isolate);
|
|
|
|
Handle<Object> expect_bailout(Smi::FromInt(kBailout), isolate);
|
|
|
|
|
|
|
|
{
|
|
|
|
// TryToName(<zero smi>) => if_keyisindex: smi value.
|
2019-11-15 10:39:28 +00:00
|
|
|
Handle<Object> key(Smi::zero(), isolate);
|
2016-06-02 15:02:08 +00:00
|
|
|
ft.CheckTrue(key, expect_index, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// TryToName(<positive smi>) => if_keyisindex: smi value.
|
|
|
|
Handle<Object> key(Smi::FromInt(153), isolate);
|
|
|
|
ft.CheckTrue(key, expect_index, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2016-09-06 16:17:08 +00:00
|
|
|
// TryToName(<negative smi>) => if_keyisindex: smi value.
|
|
|
|
// A subsequent bounds check needs to take care of this case.
|
2016-06-02 15:02:08 +00:00
|
|
|
Handle<Object> key(Smi::FromInt(-1), isolate);
|
2016-09-06 16:17:08 +00:00
|
|
|
ft.CheckTrue(key, expect_index, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// TryToName(<heap number with int value>) => if_keyisindex: number.
|
|
|
|
Handle<Object> key(isolate->factory()->NewHeapNumber(153));
|
|
|
|
Handle<Object> index(Smi::FromInt(153), isolate);
|
|
|
|
ft.CheckTrue(key, expect_index, index);
|
2016-06-02 15:02:08 +00:00
|
|
|
}
|
|
|
|
|
2017-08-03 05:20:48 +00:00
|
|
|
{
|
|
|
|
// TryToName(<true>) => if_keyisunique: "true".
|
|
|
|
Handle<Object> key = isolate->factory()->true_value();
|
|
|
|
Handle<Object> unique = isolate->factory()->InternalizeUtf8String("true");
|
|
|
|
ft.CheckTrue(key, expect_unique, unique);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// TryToName(<false>) => if_keyisunique: "false".
|
|
|
|
Handle<Object> key = isolate->factory()->false_value();
|
|
|
|
Handle<Object> unique = isolate->factory()->InternalizeUtf8String("false");
|
|
|
|
ft.CheckTrue(key, expect_unique, unique);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// TryToName(<null>) => if_keyisunique: "null".
|
|
|
|
Handle<Object> key = isolate->factory()->null_value();
|
|
|
|
Handle<Object> unique = isolate->factory()->InternalizeUtf8String("null");
|
|
|
|
ft.CheckTrue(key, expect_unique, unique);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// TryToName(<undefined>) => if_keyisunique: "undefined".
|
|
|
|
Handle<Object> key = isolate->factory()->undefined_value();
|
|
|
|
Handle<Object> unique =
|
|
|
|
isolate->factory()->InternalizeUtf8String("undefined");
|
|
|
|
ft.CheckTrue(key, expect_unique, unique);
|
|
|
|
}
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
{
|
|
|
|
// TryToName(<symbol>) => if_keyisunique: <symbol>.
|
|
|
|
Handle<Object> key = isolate->factory()->NewSymbol();
|
|
|
|
ft.CheckTrue(key, expect_unique, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// TryToName(<internalized string>) => if_keyisunique: <internalized string>
|
|
|
|
Handle<Object> key = isolate->factory()->InternalizeUtf8String("test");
|
|
|
|
ft.CheckTrue(key, expect_unique, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// TryToName(<internalized number string>) => if_keyisindex: number.
|
|
|
|
Handle<Object> key = isolate->factory()->InternalizeUtf8String("153");
|
|
|
|
Handle<Object> index(Smi::FromInt(153), isolate);
|
|
|
|
ft.CheckTrue(key, expect_index, index);
|
|
|
|
}
|
|
|
|
|
2016-09-06 16:17:08 +00:00
|
|
|
{
|
2019-10-16 13:06:24 +00:00
|
|
|
// TryToName(<internalized uncacheable number string greater than
|
2020-02-12 13:41:02 +00:00
|
|
|
// array index but less than MAX_SAFE_INTEGER>) => 32-bit platforms
|
|
|
|
// take the if_keyisunique path, 64-bit platforms bail out because they
|
|
|
|
// let the runtime handle the string-to-size_t parsing.
|
2019-10-16 13:06:24 +00:00
|
|
|
Handle<Object> key =
|
|
|
|
isolate->factory()->InternalizeUtf8String("4294967296");
|
2020-02-12 13:41:02 +00:00
|
|
|
#if V8_TARGET_ARCH_64_BIT
|
|
|
|
ft.CheckTrue(key, expect_bailout);
|
|
|
|
#else
|
2019-10-16 13:06:24 +00:00
|
|
|
ft.CheckTrue(key, expect_unique, key);
|
2020-02-12 13:41:02 +00:00
|
|
|
#endif
|
2019-10-16 13:06:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// TryToName(<internalized uncacheable number string greater than
|
|
|
|
// INT_MAX but less than array index>) => bailout.
|
2016-09-06 16:17:08 +00:00
|
|
|
Handle<Object> key =
|
|
|
|
isolate->factory()->InternalizeUtf8String("4294967294");
|
2019-08-22 14:32:33 +00:00
|
|
|
ft.CheckTrue(key, expect_bailout);
|
2016-09-06 16:17:08 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 13:06:24 +00:00
|
|
|
{
|
|
|
|
// TryToName(<internalized uncacheable number string less than
|
2019-11-11 20:05:11 +00:00
|
|
|
// INT_MAX>) => bailout
|
2019-10-16 13:06:24 +00:00
|
|
|
Handle<Object> key =
|
|
|
|
isolate->factory()->InternalizeUtf8String("2147483647");
|
2019-11-11 20:05:11 +00:00
|
|
|
ft.CheckTrue(key, expect_bailout);
|
2019-10-16 13:06:24 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 16:17:08 +00:00
|
|
|
{
|
|
|
|
// TryToName(<non-internalized number string>) => if_keyisindex: number.
|
|
|
|
Handle<String> key = isolate->factory()->NewStringFromAsciiChecked("153");
|
|
|
|
uint32_t dummy;
|
|
|
|
CHECK(key->AsArrayIndex(&dummy));
|
|
|
|
CHECK(key->HasHashCode());
|
|
|
|
CHECK(!key->IsInternalizedString());
|
|
|
|
Handle<Object> index(Smi::FromInt(153), isolate);
|
|
|
|
ft.CheckTrue(key, expect_index, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2019-10-16 13:06:24 +00:00
|
|
|
// TryToName(<number string without cached index>) => is_keyisindex: number.
|
2016-09-06 16:17:08 +00:00
|
|
|
Handle<String> key = isolate->factory()->NewStringFromAsciiChecked("153");
|
|
|
|
CHECK(!key->HasHashCode());
|
2019-11-11 20:05:11 +00:00
|
|
|
ft.CheckTrue(key, expect_bailout);
|
2016-09-06 16:17:08 +00:00
|
|
|
}
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
{
|
|
|
|
// TryToName(<non-internalized string>) => bailout.
|
|
|
|
Handle<Object> key = isolate->factory()->NewStringFromAsciiChecked("test");
|
|
|
|
ft.CheckTrue(key, expect_bailout);
|
|
|
|
}
|
2017-01-19 13:27:59 +00:00
|
|
|
|
2021-06-08 15:35:13 +00:00
|
|
|
{
|
2017-01-19 13:27:59 +00:00
|
|
|
// TryToName(<thin string>) => internalized version.
|
|
|
|
Handle<String> s = isolate->factory()->NewStringFromAsciiChecked("foo");
|
|
|
|
Handle<String> internalized = isolate->factory()->InternalizeString(s);
|
|
|
|
ft.CheckTrue(s, expect_unique, internalized);
|
|
|
|
}
|
|
|
|
|
2021-06-08 15:35:13 +00:00
|
|
|
{
|
2017-01-19 13:27:59 +00:00
|
|
|
// TryToName(<thin two-byte string>) => internalized version.
|
2021-06-24 13:32:01 +00:00
|
|
|
base::uc16 array1[] = {2001, 2002, 2003};
|
2019-04-23 14:19:00 +00:00
|
|
|
Handle<String> s = isolate->factory()
|
2021-06-17 15:43:55 +00:00
|
|
|
->NewStringFromTwoByte(base::ArrayVector(array1))
|
2019-04-23 14:19:00 +00:00
|
|
|
.ToHandleChecked();
|
2017-01-19 13:27:59 +00:00
|
|
|
Handle<String> internalized = isolate->factory()->InternalizeString(s);
|
|
|
|
ft.CheckTrue(s, expect_unique, internalized);
|
|
|
|
}
|
2016-06-02 15:02:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2016-10-25 08:30:37 +00:00
|
|
|
template <typename Dictionary>
|
|
|
|
void TestEntryToIndex() {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-10-25 08:30:37 +00:00
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
TNode<IntPtrT> entry = m.SmiUntag(m.Parameter<Smi>(1));
|
2018-05-11 11:00:17 +00:00
|
|
|
TNode<IntPtrT> result = m.EntryToIndex<Dictionary>(entry);
|
2016-10-25 08:30:37 +00:00
|
|
|
m.Return(m.SmiTag(result));
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-10-25 08:30:37 +00:00
|
|
|
|
|
|
|
// Test a wide range of entries but staying linear in the first 100 entries.
|
|
|
|
for (int entry = 0; entry < Dictionary::kMaxCapacity;
|
|
|
|
entry = entry * 1.01 + 1) {
|
|
|
|
Handle<Object> result =
|
|
|
|
ft.Call(handle(Smi::FromInt(entry), isolate)).ToHandleChecked();
|
2019-10-16 12:24:54 +00:00
|
|
|
CHECK_EQ(Dictionary::EntryToIndex(InternalIndex(entry)),
|
|
|
|
Smi::ToInt(*result));
|
2016-10-25 08:30:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(NameDictionaryEntryToIndex) { TestEntryToIndex<NameDictionary>(); }
|
|
|
|
TEST(GlobalDictionaryEntryToIndex) { TestEntryToIndex<GlobalDictionary>(); }
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
template <typename Dictionary>
|
|
|
|
void TestNameDictionaryLookup() {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2016-06-17 13:19:58 +00:00
|
|
|
const int kNumParams = 4;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
enum Result { kFound, kNotFound };
|
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
auto dictionary = m.Parameter<Dictionary>(1);
|
|
|
|
auto unique_name = m.Parameter<Name>(2);
|
|
|
|
auto expected_result = m.Parameter<Smi>(3);
|
|
|
|
auto expected_arg = m.Parameter<Object>(4);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Label passed(&m), failed(&m);
|
|
|
|
Label if_found(&m), if_not_found(&m);
|
2018-05-11 11:00:17 +00:00
|
|
|
TVariable<IntPtrT> var_name_index(&m);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
m.NameDictionaryLookup<Dictionary>(dictionary, unique_name, &if_found,
|
2016-06-27 12:26:57 +00:00
|
|
|
&var_name_index, &if_not_found);
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_found);
|
2017-02-17 16:25:07 +00:00
|
|
|
m.GotoIfNot(
|
2019-08-23 12:40:12 +00:00
|
|
|
m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
|
2016-06-02 15:02:08 +00:00
|
|
|
&failed);
|
2018-05-11 11:00:17 +00:00
|
|
|
m.Branch(
|
|
|
|
m.WordEqual(m.SmiUntag(m.CAST(expected_arg)), var_name_index.value()),
|
|
|
|
&passed, &failed);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_not_found);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(
|
2019-08-23 12:40:12 +00:00
|
|
|
m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
|
2016-06-02 15:02:08 +00:00
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&passed);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Return(m.BooleanConstant(true));
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&failed);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Return(m.BooleanConstant(false));
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Handle<Object> expect_found(Smi::FromInt(kFound), isolate);
|
|
|
|
Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate);
|
|
|
|
|
|
|
|
Handle<Dictionary> dictionary = Dictionary::New(isolate, 40);
|
|
|
|
PropertyDetails fake_details = PropertyDetails::Empty();
|
|
|
|
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
Handle<Name> keys[] = {
|
|
|
|
factory->InternalizeUtf8String("0"),
|
|
|
|
factory->InternalizeUtf8String("42"),
|
|
|
|
factory->InternalizeUtf8String("-153"),
|
|
|
|
factory->InternalizeUtf8String("0.0"),
|
|
|
|
factory->InternalizeUtf8String("4.2"),
|
|
|
|
factory->InternalizeUtf8String(""),
|
|
|
|
factory->InternalizeUtf8String("name"),
|
|
|
|
factory->NewSymbol(),
|
|
|
|
factory->NewPrivateSymbol(),
|
|
|
|
};
|
|
|
|
|
|
|
|
for (size_t i = 0; i < arraysize(keys); i++) {
|
2021-02-12 12:41:33 +00:00
|
|
|
Handle<Object> value =
|
|
|
|
factory->NewPropertyCell(keys[i], fake_details, keys[i]);
|
2018-07-13 09:32:35 +00:00
|
|
|
dictionary =
|
|
|
|
Dictionary::Add(isolate, dictionary, keys[i], value, fake_details);
|
2016-06-02 15:02:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < arraysize(keys); i++) {
|
2019-10-16 12:24:54 +00:00
|
|
|
InternalIndex entry = dictionary->FindEntry(isolate, keys[i]);
|
2016-06-27 12:26:57 +00:00
|
|
|
int name_index =
|
|
|
|
Dictionary::EntryToIndex(entry) + Dictionary::kEntryKeyIndex;
|
2019-10-16 12:24:54 +00:00
|
|
|
CHECK(entry.is_found());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2016-06-27 12:26:57 +00:00
|
|
|
Handle<Object> expected_name_index(Smi::FromInt(name_index), isolate);
|
|
|
|
ft.CheckTrue(dictionary, keys[i], expect_found, expected_name_index);
|
2016-06-02 15:02:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Handle<Name> non_existing_keys[] = {
|
|
|
|
factory->InternalizeUtf8String("1"),
|
|
|
|
factory->InternalizeUtf8String("-42"),
|
|
|
|
factory->InternalizeUtf8String("153"),
|
|
|
|
factory->InternalizeUtf8String("-1.0"),
|
|
|
|
factory->InternalizeUtf8String("1.3"),
|
|
|
|
factory->InternalizeUtf8String("a"),
|
|
|
|
factory->InternalizeUtf8String("boom"),
|
|
|
|
factory->NewSymbol(),
|
|
|
|
factory->NewPrivateSymbol(),
|
|
|
|
};
|
|
|
|
|
|
|
|
for (size_t i = 0; i < arraysize(non_existing_keys); i++) {
|
2019-10-16 12:24:54 +00:00
|
|
|
InternalIndex entry = dictionary->FindEntry(isolate, non_existing_keys[i]);
|
|
|
|
CHECK(entry.is_not_found());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
ft.CheckTrue(dictionary, non_existing_keys[i], expect_not_found);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST(NameDictionaryLookup) { TestNameDictionaryLookup<NameDictionary>(); }
|
|
|
|
|
|
|
|
TEST(GlobalDictionaryLookup) { TestNameDictionaryLookup<GlobalDictionary>(); }
|
|
|
|
|
2017-11-07 09:35:59 +00:00
|
|
|
TEST(NumberDictionaryLookup) {
|
2016-06-02 15:02:08 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2016-06-17 13:19:58 +00:00
|
|
|
const int kNumParams = 4;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
enum Result { kFound, kNotFound };
|
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
auto dictionary = m.Parameter<NumberDictionary>(1);
|
|
|
|
TNode<IntPtrT> key = m.SmiUntag(m.Parameter<Smi>(2));
|
|
|
|
auto expected_result = m.Parameter<Smi>(3);
|
|
|
|
auto expected_arg = m.Parameter<Object>(4);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Label passed(&m), failed(&m);
|
|
|
|
Label if_found(&m), if_not_found(&m);
|
2018-05-11 11:00:17 +00:00
|
|
|
TVariable<IntPtrT> var_entry(&m);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2017-11-07 09:35:59 +00:00
|
|
|
m.NumberDictionaryLookup(dictionary, key, &if_found, &var_entry,
|
|
|
|
&if_not_found);
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_found);
|
2017-02-17 16:25:07 +00:00
|
|
|
m.GotoIfNot(
|
2019-08-23 12:40:12 +00:00
|
|
|
m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
|
2016-06-02 15:02:08 +00:00
|
|
|
&failed);
|
2018-05-11 11:00:17 +00:00
|
|
|
m.Branch(m.WordEqual(m.SmiUntag(m.CAST(expected_arg)), var_entry.value()),
|
|
|
|
&passed, &failed);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_not_found);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(
|
2019-08-23 12:40:12 +00:00
|
|
|
m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
|
2016-06-02 15:02:08 +00:00
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&passed);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Return(m.BooleanConstant(true));
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&failed);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Return(m.BooleanConstant(false));
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Handle<Object> expect_found(Smi::FromInt(kFound), isolate);
|
|
|
|
Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate);
|
|
|
|
|
|
|
|
const int kKeysCount = 1000;
|
2017-11-07 09:35:59 +00:00
|
|
|
Handle<NumberDictionary> dictionary =
|
|
|
|
NumberDictionary::New(isolate, kKeysCount);
|
2016-06-02 15:02:08 +00:00
|
|
|
uint32_t keys[kKeysCount];
|
|
|
|
|
|
|
|
Handle<Object> fake_value(Smi::FromInt(42), isolate);
|
|
|
|
PropertyDetails fake_details = PropertyDetails::Empty();
|
|
|
|
|
|
|
|
base::RandomNumberGenerator rand_gen(FLAG_random_seed);
|
|
|
|
|
|
|
|
for (int i = 0; i < kKeysCount; i++) {
|
|
|
|
int random_key = rand_gen.NextInt(Smi::kMaxValue);
|
|
|
|
keys[i] = static_cast<uint32_t>(random_key);
|
2019-10-16 12:24:54 +00:00
|
|
|
if (dictionary->FindEntry(isolate, keys[i]).is_found()) continue;
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2018-07-13 09:32:35 +00:00
|
|
|
dictionary = NumberDictionary::Add(isolate, dictionary, keys[i], fake_value,
|
|
|
|
fake_details);
|
2016-06-02 15:02:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now try querying existing keys.
|
|
|
|
for (int i = 0; i < kKeysCount; i++) {
|
2019-10-16 12:24:54 +00:00
|
|
|
InternalIndex entry = dictionary->FindEntry(isolate, keys[i]);
|
|
|
|
CHECK(entry.is_found());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Handle<Object> key(Smi::FromInt(keys[i]), isolate);
|
2019-10-16 12:24:54 +00:00
|
|
|
Handle<Object> expected_entry(Smi::FromInt(entry.as_int()), isolate);
|
2016-06-02 15:02:08 +00:00
|
|
|
ft.CheckTrue(dictionary, key, expect_found, expected_entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now try querying random keys which do not exist in the dictionary.
|
|
|
|
for (int i = 0; i < kKeysCount;) {
|
|
|
|
int random_key = rand_gen.NextInt(Smi::kMaxValue);
|
2019-10-16 12:24:54 +00:00
|
|
|
InternalIndex entry = dictionary->FindEntry(isolate, random_key);
|
|
|
|
if (entry.is_found()) continue;
|
2016-06-02 15:02:08 +00:00
|
|
|
i++;
|
|
|
|
|
|
|
|
Handle<Object> key(Smi::FromInt(random_key), isolate);
|
|
|
|
ft.CheckTrue(dictionary, key, expect_not_found);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-04 11:16:49 +00:00
|
|
|
TEST(TransitionLookup) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 4;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2018-04-04 11:16:49 +00:00
|
|
|
|
|
|
|
enum Result { kFound, kNotFound };
|
|
|
|
|
|
|
|
class TempAssembler : public CodeStubAssembler {
|
|
|
|
public:
|
|
|
|
explicit TempAssembler(compiler::CodeAssemblerState* state)
|
|
|
|
: CodeStubAssembler(state) {}
|
|
|
|
|
|
|
|
void Generate() {
|
2020-09-30 17:40:39 +00:00
|
|
|
auto transitions = Parameter<TransitionArray>(1);
|
|
|
|
auto name = Parameter<Name>(2);
|
|
|
|
auto expected_result = Parameter<Smi>(3);
|
|
|
|
auto expected_arg = Parameter<Object>(4);
|
2018-04-04 11:16:49 +00:00
|
|
|
|
|
|
|
Label passed(this), failed(this);
|
|
|
|
Label if_found(this), if_not_found(this);
|
|
|
|
TVARIABLE(IntPtrT, var_transition_index);
|
|
|
|
|
|
|
|
TransitionLookup(name, transitions, &if_found, &var_transition_index,
|
|
|
|
&if_not_found);
|
|
|
|
|
|
|
|
BIND(&if_found);
|
2019-08-23 12:40:12 +00:00
|
|
|
GotoIfNot(TaggedEqual(expected_result, SmiConstant(kFound)), &failed);
|
|
|
|
Branch(TaggedEqual(expected_arg, SmiTag(var_transition_index.value())),
|
2018-04-04 11:16:49 +00:00
|
|
|
&passed, &failed);
|
|
|
|
|
|
|
|
BIND(&if_not_found);
|
2019-08-23 12:40:12 +00:00
|
|
|
Branch(TaggedEqual(expected_result, SmiConstant(kNotFound)), &passed,
|
2018-04-04 11:16:49 +00:00
|
|
|
&failed);
|
|
|
|
|
|
|
|
BIND(&passed);
|
|
|
|
Return(BooleanConstant(true));
|
|
|
|
|
|
|
|
BIND(&failed);
|
|
|
|
Return(BooleanConstant(false));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
TempAssembler(asm_tester.state()).Generate();
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<Object> expect_found(Smi::FromInt(kFound), isolate);
|
|
|
|
Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate);
|
|
|
|
|
|
|
|
const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
|
|
|
|
STATIC_ASSERT(ATTRS_COUNT == 8);
|
|
|
|
|
|
|
|
const int kKeysCount = 300;
|
|
|
|
Handle<Map> root_map = Map::Create(isolate, 0);
|
|
|
|
Handle<Name> keys[kKeysCount];
|
|
|
|
|
|
|
|
base::RandomNumberGenerator rand_gen(FLAG_random_seed);
|
|
|
|
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
Handle<FieldType> any = FieldType::Any(isolate);
|
|
|
|
|
|
|
|
for (int i = 0; i < kKeysCount; i++) {
|
|
|
|
Handle<Name> name;
|
|
|
|
if (i % 30 == 0) {
|
|
|
|
name = factory->NewPrivateSymbol();
|
|
|
|
} else if (i % 10 == 0) {
|
|
|
|
name = factory->NewSymbol();
|
|
|
|
} else {
|
|
|
|
int random_key = rand_gen.NextInt(Smi::kMaxValue);
|
2020-05-26 11:17:38 +00:00
|
|
|
name = CcTest::MakeName("p", random_key);
|
2018-04-04 11:16:49 +00:00
|
|
|
}
|
|
|
|
keys[i] = name;
|
|
|
|
|
|
|
|
bool is_private = name->IsPrivate();
|
|
|
|
PropertyAttributes base_attributes = is_private ? DONT_ENUM : NONE;
|
|
|
|
|
|
|
|
// Ensure that all the combinations of cases are covered:
|
|
|
|
// 1) there is a "base" attributes transition
|
|
|
|
// 2) there are other non-base attributes transitions
|
|
|
|
if ((i & 1) == 0) {
|
2018-06-19 09:00:37 +00:00
|
|
|
CHECK(!Map::CopyWithField(isolate, root_map, name, any, base_attributes,
|
2018-05-28 15:44:58 +00:00
|
|
|
PropertyConstness::kMutable,
|
2018-04-04 11:16:49 +00:00
|
|
|
Representation::Tagged(), INSERT_TRANSITION)
|
|
|
|
.is_null());
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((i & 2) == 0) {
|
|
|
|
for (int j = 0; j < ATTRS_COUNT; j++) {
|
|
|
|
PropertyAttributes attributes = static_cast<PropertyAttributes>(j);
|
|
|
|
if (attributes == base_attributes) continue;
|
|
|
|
// Don't add private symbols with enumerable attributes.
|
|
|
|
if (is_private && ((attributes & DONT_ENUM) == 0)) continue;
|
2018-06-19 09:00:37 +00:00
|
|
|
CHECK(!Map::CopyWithField(isolate, root_map, name, any, attributes,
|
2018-05-28 15:44:58 +00:00
|
|
|
PropertyConstness::kMutable,
|
2018-04-04 11:16:49 +00:00
|
|
|
Representation::Tagged(), INSERT_TRANSITION)
|
|
|
|
.is_null());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Reland [in-place weak refs] Fix MaybeObject function names
E.g., "ToWeakHeapObject" was misleading, since it didn't convert to a weak heap
object, instead returned a weakly pointed heap object. Change the function names
(in this case, to "GetHeapObjectIfWeak") to reflect this.
Also make casts explicit, if a MaybeObject is an Object, we can call cast<Object>().
Previous version: https://chromium-review.googlesource.com/1219025
BUG=v8:7308
TBR=ishell@chromium.org, ulan@chromium.org, ahaas@chromium.org, yangguo@chromium.org, tebbi@chromium.org
Change-Id: I503d4a2a3a68f85e9e02e1c2f9fc1c4187c8e9a1
Reviewed-on: https://chromium-review.googlesource.com/1226800
Reviewed-by: Marja Hölttä <marja@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55934}
2018-09-17 07:36:25 +00:00
|
|
|
CHECK(root_map->raw_transitions()
|
|
|
|
->GetHeapObjectAssumeStrong()
|
|
|
|
.IsTransitionArray());
|
2018-04-04 11:16:49 +00:00
|
|
|
Handle<TransitionArray> transitions(
|
Reland [in-place weak refs] Fix MaybeObject function names
E.g., "ToWeakHeapObject" was misleading, since it didn't convert to a weak heap
object, instead returned a weakly pointed heap object. Change the function names
(in this case, to "GetHeapObjectIfWeak") to reflect this.
Also make casts explicit, if a MaybeObject is an Object, we can call cast<Object>().
Previous version: https://chromium-review.googlesource.com/1219025
BUG=v8:7308
TBR=ishell@chromium.org, ulan@chromium.org, ahaas@chromium.org, yangguo@chromium.org, tebbi@chromium.org
Change-Id: I503d4a2a3a68f85e9e02e1c2f9fc1c4187c8e9a1
Reviewed-on: https://chromium-review.googlesource.com/1226800
Reviewed-by: Marja Hölttä <marja@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55934}
2018-09-17 07:36:25 +00:00
|
|
|
TransitionArray::cast(
|
|
|
|
root_map->raw_transitions()->GetHeapObjectAssumeStrong()),
|
2018-06-23 09:05:50 +00:00
|
|
|
isolate);
|
2018-07-12 10:06:42 +00:00
|
|
|
DCHECK(transitions->IsSortedNoDuplicates());
|
2018-04-04 11:16:49 +00:00
|
|
|
|
|
|
|
// Ensure we didn't overflow transition array and therefore all the
|
|
|
|
// combinations of cases are covered.
|
2018-06-05 10:21:35 +00:00
|
|
|
CHECK(TransitionsAccessor(isolate, root_map).CanHaveMoreTransitions());
|
2018-04-04 11:16:49 +00:00
|
|
|
|
|
|
|
// Now try querying keys.
|
|
|
|
bool positive_lookup_tested = false;
|
|
|
|
bool negative_lookup_tested = false;
|
|
|
|
for (int i = 0; i < kKeysCount; i++) {
|
|
|
|
Handle<Name> name = keys[i];
|
|
|
|
|
|
|
|
int transition_number = transitions->SearchNameForTesting(*name);
|
|
|
|
|
|
|
|
if (transition_number != TransitionArray::kNotFound) {
|
|
|
|
Handle<Smi> expected_value(
|
|
|
|
Smi::FromInt(TransitionArray::ToKeyIndex(transition_number)),
|
|
|
|
isolate);
|
|
|
|
ft.CheckTrue(transitions, name, expect_found, expected_value);
|
|
|
|
positive_lookup_tested = true;
|
|
|
|
} else {
|
|
|
|
ft.CheckTrue(transitions, name, expect_not_found);
|
|
|
|
negative_lookup_tested = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CHECK(positive_lookup_tested);
|
|
|
|
CHECK(negative_lookup_tested);
|
|
|
|
}
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
void AddProperties(Handle<JSObject> object, Handle<Name> names[],
|
|
|
|
size_t count) {
|
2016-06-27 12:26:57 +00:00
|
|
|
Isolate* isolate = object->GetIsolate();
|
2016-06-02 15:02:08 +00:00
|
|
|
for (size_t i = 0; i < count; i++) {
|
2016-06-27 12:26:57 +00:00
|
|
|
Handle<Object> value(Smi::FromInt(static_cast<int>(42 + i)), isolate);
|
2018-06-19 09:00:37 +00:00
|
|
|
JSObject::AddProperty(isolate, object, names[i], value, NONE);
|
2016-06-02 15:02:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-27 12:26:57 +00:00
|
|
|
Handle<AccessorPair> CreateAccessorPair(FunctionTester* ft,
|
|
|
|
const char* getter_body,
|
|
|
|
const char* setter_body) {
|
|
|
|
Handle<AccessorPair> pair = ft->isolate->factory()->NewAccessorPair();
|
|
|
|
if (getter_body) {
|
|
|
|
pair->set_getter(*ft->NewFunction(getter_body));
|
|
|
|
}
|
|
|
|
if (setter_body) {
|
|
|
|
pair->set_setter(*ft->NewFunction(setter_body));
|
|
|
|
}
|
|
|
|
return pair;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddProperties(Handle<JSObject> object, Handle<Name> names[],
|
|
|
|
size_t names_count, Handle<Object> values[],
|
|
|
|
size_t values_count, int seed = 0) {
|
|
|
|
Isolate* isolate = object->GetIsolate();
|
|
|
|
for (size_t i = 0; i < names_count; i++) {
|
|
|
|
Handle<Object> value = values[(seed + i) % values_count];
|
|
|
|
if (value->IsAccessorPair()) {
|
|
|
|
Handle<AccessorPair> pair = Handle<AccessorPair>::cast(value);
|
|
|
|
Handle<Object> getter(pair->getter(), isolate);
|
|
|
|
Handle<Object> setter(pair->setter(), isolate);
|
|
|
|
JSObject::DefineAccessor(object, names[i], getter, setter, NONE).Check();
|
|
|
|
} else {
|
2018-06-19 09:00:37 +00:00
|
|
|
JSObject::AddProperty(isolate, object, names[i], value, NONE);
|
2016-06-27 12:26:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
} // namespace
|
|
|
|
|
2016-06-27 12:26:57 +00:00
|
|
|
TEST(TryHasOwnProperty) {
|
2016-06-02 15:02:08 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2020-07-15 11:03:22 +00:00
|
|
|
const int kNumParams = 3;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
enum Result { kFound, kNotFound, kBailout };
|
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
auto object = m.Parameter<HeapObject>(1);
|
|
|
|
auto unique_name = m.Parameter<Name>(2);
|
|
|
|
TNode<MaybeObject> expected_result = m.UncheckedParameter<MaybeObject>(3);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Label passed(&m), failed(&m);
|
|
|
|
Label if_found(&m), if_not_found(&m), if_bailout(&m);
|
|
|
|
|
2019-08-22 09:56:32 +00:00
|
|
|
TNode<Map> map = m.LoadMap(object);
|
|
|
|
TNode<Uint16T> instance_type = m.LoadMapInstanceType(map);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2016-06-27 12:26:57 +00:00
|
|
|
m.TryHasOwnProperty(object, map, instance_type, unique_name, &if_found,
|
2016-06-02 15:02:08 +00:00
|
|
|
&if_not_found, &if_bailout);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_found);
|
2019-08-23 12:40:12 +00:00
|
|
|
m.Branch(
|
|
|
|
m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
|
|
|
|
&passed, &failed);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_not_found);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(
|
2019-08-23 12:40:12 +00:00
|
|
|
m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
|
2016-06-02 15:02:08 +00:00
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_bailout);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(
|
2019-08-23 12:40:12 +00:00
|
|
|
m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
|
2016-06-02 15:02:08 +00:00
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&passed);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Return(m.BooleanConstant(true));
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&failed);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Return(m.BooleanConstant(false));
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Handle<Object> expect_found(Smi::FromInt(kFound), isolate);
|
|
|
|
Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate);
|
|
|
|
Handle<Object> expect_bailout(Smi::FromInt(kBailout), isolate);
|
|
|
|
|
|
|
|
Factory* factory = isolate->factory();
|
2016-06-27 12:26:57 +00:00
|
|
|
|
|
|
|
Handle<Name> deleted_property_name =
|
|
|
|
factory->InternalizeUtf8String("deleted");
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
Handle<Name> names[] = {
|
|
|
|
factory->InternalizeUtf8String("a"),
|
|
|
|
factory->InternalizeUtf8String("bb"),
|
|
|
|
factory->InternalizeUtf8String("ccc"),
|
|
|
|
factory->InternalizeUtf8String("dddd"),
|
|
|
|
factory->InternalizeUtf8String("eeeee"),
|
|
|
|
factory->InternalizeUtf8String(""),
|
|
|
|
factory->InternalizeUtf8String("name"),
|
|
|
|
factory->NewSymbol(),
|
|
|
|
factory->NewPrivateSymbol(),
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<Handle<JSObject>> objects;
|
|
|
|
|
|
|
|
{
|
2016-06-27 12:26:57 +00:00
|
|
|
// Fast object, no inobject properties.
|
|
|
|
int inobject_properties = 0;
|
|
|
|
Handle<Map> map = Map::Create(isolate, inobject_properties);
|
|
|
|
Handle<JSObject> object = factory->NewJSObjectFromMap(map);
|
2016-06-02 15:02:08 +00:00
|
|
|
AddProperties(object, names, arraysize(names));
|
|
|
|
CHECK_EQ(JS_OBJECT_TYPE, object->map().instance_type());
|
2016-06-27 12:26:57 +00:00
|
|
|
CHECK_EQ(inobject_properties, object->map().GetInObjectProperties());
|
2016-06-02 15:02:08 +00:00
|
|
|
CHECK(!object->map().is_dictionary_map());
|
|
|
|
objects.push_back(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2016-06-27 12:26:57 +00:00
|
|
|
// Fast object, all inobject properties.
|
|
|
|
int inobject_properties = arraysize(names) * 2;
|
|
|
|
Handle<Map> map = Map::Create(isolate, inobject_properties);
|
|
|
|
Handle<JSObject> object = factory->NewJSObjectFromMap(map);
|
|
|
|
AddProperties(object, names, arraysize(names));
|
|
|
|
CHECK_EQ(JS_OBJECT_TYPE, object->map().instance_type());
|
|
|
|
CHECK_EQ(inobject_properties, object->map().GetInObjectProperties());
|
|
|
|
CHECK(!object->map().is_dictionary_map());
|
|
|
|
objects.push_back(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// Fast object, half inobject properties.
|
|
|
|
int inobject_properties = arraysize(names) / 2;
|
|
|
|
Handle<Map> map = Map::Create(isolate, inobject_properties);
|
|
|
|
Handle<JSObject> object = factory->NewJSObjectFromMap(map);
|
|
|
|
AddProperties(object, names, arraysize(names));
|
|
|
|
CHECK_EQ(JS_OBJECT_TYPE, object->map().instance_type());
|
|
|
|
CHECK_EQ(inobject_properties, object->map().GetInObjectProperties());
|
|
|
|
CHECK(!object->map().is_dictionary_map());
|
|
|
|
objects.push_back(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// Dictionary mode object.
|
2017-11-08 12:56:08 +00:00
|
|
|
Handle<JSFunction> function =
|
2020-11-10 11:22:49 +00:00
|
|
|
factory->NewFunctionForTesting(factory->empty_string());
|
2016-06-02 15:02:08 +00:00
|
|
|
Handle<JSObject> object = factory->NewJSObject(function);
|
|
|
|
AddProperties(object, names, arraysize(names));
|
2019-06-06 19:39:54 +00:00
|
|
|
JSObject::NormalizeProperties(isolate, object, CLEAR_INOBJECT_PROPERTIES, 0,
|
|
|
|
"test");
|
2016-06-27 12:26:57 +00:00
|
|
|
|
2018-06-19 09:00:37 +00:00
|
|
|
JSObject::AddProperty(isolate, object, deleted_property_name, object, NONE);
|
2017-10-16 10:55:06 +00:00
|
|
|
CHECK(JSObject::DeleteProperty(object, deleted_property_name,
|
|
|
|
LanguageMode::kSloppy)
|
2016-06-27 12:26:57 +00:00
|
|
|
.FromJust());
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
CHECK_EQ(JS_OBJECT_TYPE, object->map().instance_type());
|
|
|
|
CHECK(object->map().is_dictionary_map());
|
|
|
|
objects.push_back(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2016-06-27 12:26:57 +00:00
|
|
|
// Global object.
|
2017-11-08 12:56:08 +00:00
|
|
|
Handle<JSFunction> function =
|
2020-11-10 11:22:49 +00:00
|
|
|
factory->NewFunctionForTesting(factory->empty_string());
|
2016-06-02 15:02:08 +00:00
|
|
|
JSFunction::EnsureHasInitialMap(function);
|
|
|
|
function->initial_map().set_instance_type(JS_GLOBAL_OBJECT_TYPE);
|
|
|
|
function->initial_map().set_is_prototype_map(true);
|
2017-12-07 11:03:41 +00:00
|
|
|
function->initial_map().set_is_dictionary_map(true);
|
[builtins] Speed-up Object.prototype.toString.
The @@toStringTag lookup in Object.prototype.toString causes quite a
lot of overhead and oftentimes dominates the builtin performance. These
lookups are almost always negative, especially for primitive values,
and Object.prototype.toString is often used to implement predicates
(like in Node core or in AngularJS), so having a way to skip the
negative lookup yields big performance gains.
This CL introduces a "MayHaveInterestingSymbols" bit on every map,
which says whether instances with this map may have an interesting
symbol. Currently only @@toStringTag is considered an interesting
symbol, but we can extend that in the future.
In the Object.prototype.toString we can use the interesting symbols
bit to do a quick check on the prototype chain to see if there are
any maps that might have the @@toStringTag, and if not, we can just
immediately return the result, which is very fast because it's derived
from the instance type. This also avoids the ToObject conversions for
primitive values, which is important, since this causes unnecessary
GC traffic and in for example AngularJS, strings are also often probed
via the Object.prototype.toString based predicates.
This boosts Speedometer/AngularJS by over 3% and Speedometer overall
by up to 1%. On the microbenchmark from the similar SpiderMonkey bug
(https://bugzilla.mozilla.org/show_bug.cgi?id=1369042), we go from
roughly 450ms to 70ms, which corresponds to a 6.5x improvement.
```
function f() {
var res = "";
var a = [1, 2, 3];
var toString = Object.prototype.toString;
var t = new Date;
for (var i = 0; i < 5000000; i++)
res = toString.call(a);
print(new Date - t);
return res;
}
f();
```
The design document at https://goo.gl/e8CruQ has some additional
data points.
TBR=ulan@chromium.org
Bug: v8:6654
Change-Id: I31932cf41ecddad079d294e2c322a852af0ed244
Reviewed-on: https://chromium-review.googlesource.com/593620
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47034}
2017-08-01 08:11:14 +00:00
|
|
|
function->initial_map().set_may_have_interesting_symbols(true);
|
2016-06-02 15:02:08 +00:00
|
|
|
Handle<JSObject> object = factory->NewJSGlobalObject(function);
|
|
|
|
AddProperties(object, names, arraysize(names));
|
2016-06-27 12:26:57 +00:00
|
|
|
|
2018-06-19 09:00:37 +00:00
|
|
|
JSObject::AddProperty(isolate, object, deleted_property_name, object, NONE);
|
2017-10-16 10:55:06 +00:00
|
|
|
CHECK(JSObject::DeleteProperty(object, deleted_property_name,
|
|
|
|
LanguageMode::kSloppy)
|
2016-06-27 12:26:57 +00:00
|
|
|
.FromJust());
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map().instance_type());
|
|
|
|
CHECK(object->map().is_dictionary_map());
|
|
|
|
objects.push_back(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
for (Handle<JSObject> object : objects) {
|
|
|
|
for (size_t name_index = 0; name_index < arraysize(names); name_index++) {
|
|
|
|
Handle<Name> name = names[name_index];
|
|
|
|
CHECK(JSReceiver::HasProperty(object, name).FromJust());
|
|
|
|
ft.CheckTrue(object, name, expect_found);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Handle<Name> non_existing_names[] = {
|
2016-06-27 12:26:57 +00:00
|
|
|
factory->NewSymbol(),
|
2016-06-02 15:02:08 +00:00
|
|
|
factory->InternalizeUtf8String("ne_a"),
|
|
|
|
factory->InternalizeUtf8String("ne_bb"),
|
2016-06-27 12:26:57 +00:00
|
|
|
factory->NewPrivateSymbol(),
|
2016-06-02 15:02:08 +00:00
|
|
|
factory->InternalizeUtf8String("ne_ccc"),
|
|
|
|
factory->InternalizeUtf8String("ne_dddd"),
|
2016-06-27 12:26:57 +00:00
|
|
|
deleted_property_name,
|
2016-06-02 15:02:08 +00:00
|
|
|
};
|
|
|
|
for (Handle<JSObject> object : objects) {
|
|
|
|
for (size_t key_index = 0; key_index < arraysize(non_existing_names);
|
|
|
|
key_index++) {
|
2016-06-27 12:26:57 +00:00
|
|
|
Handle<Name> name = non_existing_names[key_index];
|
|
|
|
CHECK(!JSReceiver::HasProperty(object, name).FromJust());
|
|
|
|
ft.CheckTrue(object, name, expect_not_found);
|
2016-06-02 15:02:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2017-11-08 12:56:08 +00:00
|
|
|
Handle<JSFunction> function =
|
2020-11-10 11:22:49 +00:00
|
|
|
factory->NewFunctionForTesting(factory->empty_string());
|
2016-06-02 15:02:08 +00:00
|
|
|
Handle<JSProxy> object = factory->NewJSProxy(function, objects[0]);
|
|
|
|
CHECK_EQ(JS_PROXY_TYPE, object->map().instance_type());
|
|
|
|
ft.CheckTrue(object, names[0], expect_bailout);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Handle<JSObject> object = isolate->global_proxy();
|
|
|
|
CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map().instance_type());
|
|
|
|
ft.CheckTrue(object, names[0], expect_bailout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-27 12:26:57 +00:00
|
|
|
TEST(TryGetOwnProperty) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
|
|
|
|
const int kNumParams = 2;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-27 12:26:57 +00:00
|
|
|
|
|
|
|
Handle<Symbol> not_found_symbol = factory->NewSymbol();
|
|
|
|
Handle<Symbol> bailout_symbol = factory->NewSymbol();
|
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
auto object = m.Parameter<JSReceiver>(1);
|
|
|
|
auto unique_name = m.Parameter<Name>(2);
|
|
|
|
auto context = m.Parameter<Context>(kNumParams + 3);
|
2016-06-27 12:26:57 +00:00
|
|
|
|
2020-01-10 14:23:19 +00:00
|
|
|
TVariable<Object> var_value(&m);
|
2016-06-27 12:26:57 +00:00
|
|
|
Label if_found(&m), if_not_found(&m), if_bailout(&m);
|
|
|
|
|
2019-08-22 09:56:32 +00:00
|
|
|
TNode<Map> map = m.LoadMap(object);
|
|
|
|
TNode<Uint16T> instance_type = m.LoadMapInstanceType(map);
|
2016-06-27 12:26:57 +00:00
|
|
|
|
|
|
|
m.TryGetOwnProperty(context, object, object, map, instance_type,
|
|
|
|
unique_name, &if_found, &var_value, &if_not_found,
|
|
|
|
&if_bailout);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_found);
|
2019-11-27 17:32:26 +00:00
|
|
|
m.Return(m.UncheckedCast<Object>(var_value.value()));
|
2016-06-27 12:26:57 +00:00
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_not_found);
|
2016-06-27 12:26:57 +00:00
|
|
|
m.Return(m.HeapConstant(not_found_symbol));
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_bailout);
|
2016-06-27 12:26:57 +00:00
|
|
|
m.Return(m.HeapConstant(bailout_symbol));
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-06-27 12:26:57 +00:00
|
|
|
|
|
|
|
Handle<Name> deleted_property_name =
|
|
|
|
factory->InternalizeUtf8String("deleted");
|
|
|
|
|
|
|
|
Handle<Name> names[] = {
|
|
|
|
factory->InternalizeUtf8String("bb"),
|
|
|
|
factory->NewSymbol(),
|
|
|
|
factory->InternalizeUtf8String("a"),
|
|
|
|
factory->InternalizeUtf8String("ccc"),
|
|
|
|
factory->InternalizeUtf8String("esajefe"),
|
|
|
|
factory->NewPrivateSymbol(),
|
|
|
|
factory->InternalizeUtf8String("eeeee"),
|
|
|
|
factory->InternalizeUtf8String("p1"),
|
|
|
|
factory->InternalizeUtf8String("acshw23e"),
|
|
|
|
factory->InternalizeUtf8String(""),
|
|
|
|
factory->InternalizeUtf8String("dddd"),
|
|
|
|
factory->NewPrivateSymbol(),
|
|
|
|
factory->InternalizeUtf8String("name"),
|
|
|
|
factory->InternalizeUtf8String("p2"),
|
|
|
|
factory->InternalizeUtf8String("p3"),
|
|
|
|
factory->InternalizeUtf8String("p4"),
|
|
|
|
factory->NewPrivateSymbol(),
|
|
|
|
};
|
|
|
|
Handle<Object> values[] = {
|
2020-11-10 11:22:49 +00:00
|
|
|
factory->NewFunctionForTesting(factory->empty_string()),
|
2016-06-27 12:26:57 +00:00
|
|
|
factory->NewSymbol(),
|
|
|
|
factory->InternalizeUtf8String("a"),
|
|
|
|
CreateAccessorPair(&ft, "() => 188;", "() => 199;"),
|
2020-11-10 11:22:49 +00:00
|
|
|
factory->NewFunctionForTesting(factory->InternalizeUtf8String("bb")),
|
2016-06-27 12:26:57 +00:00
|
|
|
factory->InternalizeUtf8String("ccc"),
|
|
|
|
CreateAccessorPair(&ft, "() => 88;", nullptr),
|
|
|
|
handle(Smi::FromInt(1), isolate),
|
|
|
|
factory->InternalizeUtf8String(""),
|
|
|
|
CreateAccessorPair(&ft, nullptr, "() => 99;"),
|
|
|
|
factory->NewHeapNumber(4.2),
|
|
|
|
handle(Smi::FromInt(153), isolate),
|
2017-11-08 12:56:08 +00:00
|
|
|
factory->NewJSObject(
|
2020-11-10 11:22:49 +00:00
|
|
|
factory->NewFunctionForTesting(factory->empty_string())),
|
2016-06-27 12:26:57 +00:00
|
|
|
factory->NewPrivateSymbol(),
|
|
|
|
};
|
|
|
|
STATIC_ASSERT(arraysize(values) < arraysize(names));
|
|
|
|
|
|
|
|
base::RandomNumberGenerator rand_gen(FLAG_random_seed);
|
|
|
|
|
|
|
|
std::vector<Handle<JSObject>> objects;
|
|
|
|
|
|
|
|
{
|
|
|
|
// Fast object, no inobject properties.
|
|
|
|
int inobject_properties = 0;
|
|
|
|
Handle<Map> map = Map::Create(isolate, inobject_properties);
|
|
|
|
Handle<JSObject> object = factory->NewJSObjectFromMap(map);
|
|
|
|
AddProperties(object, names, arraysize(names), values, arraysize(values),
|
|
|
|
rand_gen.NextInt());
|
|
|
|
CHECK_EQ(JS_OBJECT_TYPE, object->map().instance_type());
|
|
|
|
CHECK_EQ(inobject_properties, object->map().GetInObjectProperties());
|
|
|
|
CHECK(!object->map().is_dictionary_map());
|
|
|
|
objects.push_back(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// Fast object, all inobject properties.
|
|
|
|
int inobject_properties = arraysize(names) * 2;
|
|
|
|
Handle<Map> map = Map::Create(isolate, inobject_properties);
|
|
|
|
Handle<JSObject> object = factory->NewJSObjectFromMap(map);
|
|
|
|
AddProperties(object, names, arraysize(names), values, arraysize(values),
|
|
|
|
rand_gen.NextInt());
|
|
|
|
CHECK_EQ(JS_OBJECT_TYPE, object->map().instance_type());
|
|
|
|
CHECK_EQ(inobject_properties, object->map().GetInObjectProperties());
|
|
|
|
CHECK(!object->map().is_dictionary_map());
|
|
|
|
objects.push_back(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// Fast object, half inobject properties.
|
|
|
|
int inobject_properties = arraysize(names) / 2;
|
|
|
|
Handle<Map> map = Map::Create(isolate, inobject_properties);
|
|
|
|
Handle<JSObject> object = factory->NewJSObjectFromMap(map);
|
|
|
|
AddProperties(object, names, arraysize(names), values, arraysize(values),
|
|
|
|
rand_gen.NextInt());
|
|
|
|
CHECK_EQ(JS_OBJECT_TYPE, object->map().instance_type());
|
|
|
|
CHECK_EQ(inobject_properties, object->map().GetInObjectProperties());
|
|
|
|
CHECK(!object->map().is_dictionary_map());
|
|
|
|
objects.push_back(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// Dictionary mode object.
|
2017-11-08 12:56:08 +00:00
|
|
|
Handle<JSFunction> function =
|
2020-11-10 11:22:49 +00:00
|
|
|
factory->NewFunctionForTesting(factory->empty_string());
|
2016-06-27 12:26:57 +00:00
|
|
|
Handle<JSObject> object = factory->NewJSObject(function);
|
|
|
|
AddProperties(object, names, arraysize(names), values, arraysize(values),
|
|
|
|
rand_gen.NextInt());
|
2019-06-06 19:39:54 +00:00
|
|
|
JSObject::NormalizeProperties(isolate, object, CLEAR_INOBJECT_PROPERTIES, 0,
|
|
|
|
"test");
|
2016-06-27 12:26:57 +00:00
|
|
|
|
2018-06-19 09:00:37 +00:00
|
|
|
JSObject::AddProperty(isolate, object, deleted_property_name, object, NONE);
|
2017-10-16 10:55:06 +00:00
|
|
|
CHECK(JSObject::DeleteProperty(object, deleted_property_name,
|
|
|
|
LanguageMode::kSloppy)
|
2016-06-27 12:26:57 +00:00
|
|
|
.FromJust());
|
|
|
|
|
|
|
|
CHECK_EQ(JS_OBJECT_TYPE, object->map().instance_type());
|
|
|
|
CHECK(object->map().is_dictionary_map());
|
|
|
|
objects.push_back(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// Global object.
|
|
|
|
Handle<JSGlobalObject> object = isolate->global_object();
|
|
|
|
AddProperties(object, names, arraysize(names), values, arraysize(values),
|
|
|
|
rand_gen.NextInt());
|
|
|
|
|
2018-06-19 09:00:37 +00:00
|
|
|
JSObject::AddProperty(isolate, object, deleted_property_name, object, NONE);
|
2017-10-16 10:55:06 +00:00
|
|
|
CHECK(JSObject::DeleteProperty(object, deleted_property_name,
|
|
|
|
LanguageMode::kSloppy)
|
2016-06-27 12:26:57 +00:00
|
|
|
.FromJust());
|
|
|
|
|
|
|
|
CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map().instance_type());
|
|
|
|
CHECK(object->map().is_dictionary_map());
|
|
|
|
objects.push_back(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(ishell): test proxy and interceptors when they are supported.
|
|
|
|
|
|
|
|
{
|
|
|
|
for (Handle<JSObject> object : objects) {
|
|
|
|
for (size_t name_index = 0; name_index < arraysize(names); name_index++) {
|
|
|
|
Handle<Name> name = names[name_index];
|
|
|
|
Handle<Object> expected_value =
|
2018-06-19 09:00:37 +00:00
|
|
|
JSReceiver::GetProperty(isolate, object, name).ToHandleChecked();
|
2016-06-27 12:26:57 +00:00
|
|
|
Handle<Object> value = ft.Call(object, name).ToHandleChecked();
|
|
|
|
CHECK(expected_value->SameValue(*value));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Handle<Name> non_existing_names[] = {
|
|
|
|
factory->NewSymbol(),
|
|
|
|
factory->InternalizeUtf8String("ne_a"),
|
|
|
|
factory->InternalizeUtf8String("ne_bb"),
|
|
|
|
factory->NewPrivateSymbol(),
|
|
|
|
factory->InternalizeUtf8String("ne_ccc"),
|
|
|
|
factory->InternalizeUtf8String("ne_dddd"),
|
|
|
|
deleted_property_name,
|
|
|
|
};
|
|
|
|
for (Handle<JSObject> object : objects) {
|
|
|
|
for (size_t key_index = 0; key_index < arraysize(non_existing_names);
|
|
|
|
key_index++) {
|
|
|
|
Handle<Name> name = non_existing_names[key_index];
|
|
|
|
Handle<Object> expected_value =
|
2018-06-19 09:00:37 +00:00
|
|
|
JSReceiver::GetProperty(isolate, object, name).ToHandleChecked();
|
2016-06-27 12:26:57 +00:00
|
|
|
CHECK(expected_value->IsUndefined(isolate));
|
|
|
|
Handle<Object> value = ft.Call(object, name).ToHandleChecked();
|
|
|
|
CHECK_EQ(*not_found_symbol, *value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2017-11-08 12:56:08 +00:00
|
|
|
Handle<JSFunction> function =
|
2020-11-10 11:22:49 +00:00
|
|
|
factory->NewFunctionForTesting(factory->empty_string());
|
2016-06-27 12:26:57 +00:00
|
|
|
Handle<JSProxy> object = factory->NewJSProxy(function, objects[0]);
|
|
|
|
CHECK_EQ(JS_PROXY_TYPE, object->map().instance_type());
|
|
|
|
Handle<Object> value = ft.Call(object, names[0]).ToHandleChecked();
|
|
|
|
// Proxies are not supported yet.
|
|
|
|
CHECK_EQ(*bailout_symbol, *value);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Handle<JSObject> object = isolate->global_proxy();
|
|
|
|
CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map().instance_type());
|
|
|
|
// Global proxies are not supported yet.
|
|
|
|
Handle<Object> value = ft.Call(object, names[0]).ToHandleChecked();
|
|
|
|
CHECK_EQ(*bailout_symbol, *value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
void AddElement(Handle<JSObject> object, uint32_t index, Handle<Object> value,
|
|
|
|
PropertyAttributes attributes = NONE) {
|
2018-07-10 06:40:11 +00:00
|
|
|
JSObject::AddDataElement(object, index, value, attributes);
|
2016-06-02 15:02:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST(TryLookupElement) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2016-06-27 12:26:57 +00:00
|
|
|
const int kNumParams = 3;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2017-03-24 14:12:14 +00:00
|
|
|
enum Result { kFound, kAbsent, kNotFound, kBailout };
|
2016-06-02 15:02:08 +00:00
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
auto object = m.Parameter<HeapObject>(1);
|
|
|
|
TNode<IntPtrT> index = m.SmiUntag(m.Parameter<Smi>(2));
|
|
|
|
TNode<MaybeObject> expected_result = m.UncheckedParameter<MaybeObject>(3);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Label passed(&m), failed(&m);
|
2017-03-24 14:12:14 +00:00
|
|
|
Label if_found(&m), if_not_found(&m), if_bailout(&m), if_absent(&m);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2019-08-22 09:56:32 +00:00
|
|
|
TNode<Map> map = m.LoadMap(object);
|
|
|
|
TNode<Uint16T> instance_type = m.LoadMapInstanceType(map);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2017-03-24 14:12:14 +00:00
|
|
|
m.TryLookupElement(object, map, instance_type, index, &if_found, &if_absent,
|
2016-06-02 15:02:08 +00:00
|
|
|
&if_not_found, &if_bailout);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_found);
|
2019-08-23 12:40:12 +00:00
|
|
|
m.Branch(
|
|
|
|
m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
|
|
|
|
&passed, &failed);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_absent);
|
2019-08-23 12:40:12 +00:00
|
|
|
m.Branch(
|
|
|
|
m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kAbsent))),
|
|
|
|
&passed, &failed);
|
2017-03-24 14:12:14 +00:00
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_not_found);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(
|
2019-08-23 12:40:12 +00:00
|
|
|
m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
|
2016-06-02 15:02:08 +00:00
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_bailout);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(
|
2019-08-23 12:40:12 +00:00
|
|
|
m.TaggedEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
|
2016-06-02 15:02:08 +00:00
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&passed);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Return(m.BooleanConstant(true));
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&failed);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Return(m.BooleanConstant(false));
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Factory* factory = isolate->factory();
|
2019-11-15 10:39:28 +00:00
|
|
|
Handle<Object> smi0(Smi::zero(), isolate);
|
2016-06-02 15:02:08 +00:00
|
|
|
Handle<Object> smi1(Smi::FromInt(1), isolate);
|
|
|
|
Handle<Object> smi7(Smi::FromInt(7), isolate);
|
|
|
|
Handle<Object> smi13(Smi::FromInt(13), isolate);
|
|
|
|
Handle<Object> smi42(Smi::FromInt(42), isolate);
|
|
|
|
|
|
|
|
Handle<Object> expect_found(Smi::FromInt(kFound), isolate);
|
2017-03-24 14:12:14 +00:00
|
|
|
Handle<Object> expect_absent(Smi::FromInt(kAbsent), isolate);
|
2016-06-02 15:02:08 +00:00
|
|
|
Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate);
|
|
|
|
Handle<Object> expect_bailout(Smi::FromInt(kBailout), isolate);
|
|
|
|
|
|
|
|
#define CHECK_FOUND(object, index) \
|
|
|
|
CHECK(JSReceiver::HasElement(object, index).FromJust()); \
|
|
|
|
ft.CheckTrue(object, smi##index, expect_found);
|
|
|
|
|
|
|
|
#define CHECK_NOT_FOUND(object, index) \
|
|
|
|
CHECK(!JSReceiver::HasElement(object, index).FromJust()); \
|
|
|
|
ft.CheckTrue(object, smi##index, expect_not_found);
|
|
|
|
|
2020-01-09 17:50:43 +00:00
|
|
|
#define CHECK_ABSENT(object, index) \
|
|
|
|
{ \
|
|
|
|
Handle<Smi> smi(Smi::FromInt(index), isolate); \
|
2021-06-23 09:11:18 +00:00
|
|
|
PropertyKey key(isolate, smi); \
|
2020-01-09 17:50:43 +00:00
|
|
|
LookupIterator it(isolate, object, key); \
|
|
|
|
CHECK(!JSReceiver::HasProperty(&it).FromJust()); \
|
|
|
|
ft.CheckTrue(object, smi, expect_absent); \
|
2017-03-24 14:12:14 +00:00
|
|
|
}
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
{
|
2017-06-30 11:26:14 +00:00
|
|
|
Handle<JSArray> object = factory->NewJSArray(0, PACKED_SMI_ELEMENTS);
|
2016-06-02 15:02:08 +00:00
|
|
|
AddElement(object, 0, smi0);
|
|
|
|
AddElement(object, 1, smi0);
|
2017-06-30 11:26:14 +00:00
|
|
|
CHECK_EQ(PACKED_SMI_ELEMENTS, object->map().elements_kind());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
CHECK_FOUND(object, 0);
|
|
|
|
CHECK_FOUND(object, 1);
|
|
|
|
CHECK_NOT_FOUND(object, 7);
|
|
|
|
CHECK_NOT_FOUND(object, 13);
|
|
|
|
CHECK_NOT_FOUND(object, 42);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2017-06-30 11:26:14 +00:00
|
|
|
Handle<JSArray> object = factory->NewJSArray(0, HOLEY_SMI_ELEMENTS);
|
2016-06-02 15:02:08 +00:00
|
|
|
AddElement(object, 0, smi0);
|
|
|
|
AddElement(object, 13, smi0);
|
2017-06-30 11:26:14 +00:00
|
|
|
CHECK_EQ(HOLEY_SMI_ELEMENTS, object->map().elements_kind());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
CHECK_FOUND(object, 0);
|
|
|
|
CHECK_NOT_FOUND(object, 1);
|
|
|
|
CHECK_NOT_FOUND(object, 7);
|
|
|
|
CHECK_FOUND(object, 13);
|
|
|
|
CHECK_NOT_FOUND(object, 42);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2017-06-30 11:26:14 +00:00
|
|
|
Handle<JSArray> object = factory->NewJSArray(0, PACKED_ELEMENTS);
|
2016-06-02 15:02:08 +00:00
|
|
|
AddElement(object, 0, smi0);
|
|
|
|
AddElement(object, 1, smi0);
|
2017-06-30 11:26:14 +00:00
|
|
|
CHECK_EQ(PACKED_ELEMENTS, object->map().elements_kind());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
CHECK_FOUND(object, 0);
|
|
|
|
CHECK_FOUND(object, 1);
|
|
|
|
CHECK_NOT_FOUND(object, 7);
|
|
|
|
CHECK_NOT_FOUND(object, 13);
|
|
|
|
CHECK_NOT_FOUND(object, 42);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2017-06-30 11:26:14 +00:00
|
|
|
Handle<JSArray> object = factory->NewJSArray(0, HOLEY_ELEMENTS);
|
2016-06-02 15:02:08 +00:00
|
|
|
AddElement(object, 0, smi0);
|
|
|
|
AddElement(object, 13, smi0);
|
2017-06-30 11:26:14 +00:00
|
|
|
CHECK_EQ(HOLEY_ELEMENTS, object->map().elements_kind());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
CHECK_FOUND(object, 0);
|
|
|
|
CHECK_NOT_FOUND(object, 1);
|
|
|
|
CHECK_NOT_FOUND(object, 7);
|
|
|
|
CHECK_FOUND(object, 13);
|
|
|
|
CHECK_NOT_FOUND(object, 42);
|
|
|
|
}
|
|
|
|
|
2017-03-24 14:12:14 +00:00
|
|
|
{
|
Reland "[typedarray] Move external/data pointer to JSTypedArray."
This is a reland of 4b86fea5308b12fa369038dc60c0aabd13870ec5 with
copy&paste typo in CodeStubAssembler::AllocateByteArray() fixed
(bug led to holes in new space, which was crashing reproducibly
on the ia32 bot).
Original change's description:
> [typedarray] Move external/data pointer to JSTypedArray.
>
> As the next step in supporting huge typed arrays in V8, this moves the
> external/data pointer from the FixedTypedArrayBase backing store to the
> JSTypedArray instance itself, and replaces the special backing stores
> with a plain ByteArray (removing all the code for the FixedTypedArrayBase
> class hierarchy). By doing so, we can drastically simplify the system
> around typed arrays.
>
> Note: Several places in the code base used to check the instance type
> of the elements backing store of a JSTypedArray instead of checking the
> elements kind on the JSTypedArray map directly. Those had to be fixed,
> since the backing store is now always a ByteArray.
>
> Drive-by-fix: Move all the typed elements access related code into the
> elements.cc file to properly encapsulate the accesses.
>
> Doc: http://doc/1Z-wM2qwvAuxH46e9ivtkYvKzzwYZg8ymm0x0wJaomow
> Bug: chromium:951196, chromium:965583, v8:4153, v8:7881, v8:9183
> Change-Id: I8cc06b190c53e34155000b4560f5f3ef40621646
> Cq-Include-Trybots: luci.chromium.try:linux-rel,win7-rel
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1627535
> Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
> Reviewed-by: Peter Marshall <petermarshall@chromium.org>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Simon Zünd <szuend@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#61855}
Tbr: petermarshall@chromium.org
Bug: chromium:951196, chromium:965583, v8:4153, v8:7881, v8:9183
Change-Id: I87fcdb28532c5f08cc227332a4d59546cb423810
Cq-Include-Trybots: luci.chromium.try:linux-rel, win7-rel
Cq-Include-Trybots: luci.v8.try:v8_linux_shared_compile_rel
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1631592
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61864}
2019-05-27 17:01:01 +00:00
|
|
|
v8::Local<v8::ArrayBuffer> buffer =
|
|
|
|
v8::ArrayBuffer::New(reinterpret_cast<v8::Isolate*>(isolate), 8);
|
|
|
|
Handle<JSTypedArray> object = factory->NewJSTypedArray(
|
|
|
|
kExternalInt32Array, v8::Utils::OpenHandle(*buffer), 0, 2);
|
2017-03-24 14:12:14 +00:00
|
|
|
|
|
|
|
CHECK_EQ(INT32_ELEMENTS, object->map().elements_kind());
|
|
|
|
|
|
|
|
CHECK_FOUND(object, 0);
|
|
|
|
CHECK_FOUND(object, 1);
|
|
|
|
CHECK_ABSENT(object, -10);
|
|
|
|
CHECK_ABSENT(object, 13);
|
|
|
|
CHECK_ABSENT(object, 42);
|
|
|
|
|
2019-10-29 19:00:28 +00:00
|
|
|
{
|
|
|
|
std::shared_ptr<v8::BackingStore> backing_store =
|
|
|
|
buffer->GetBackingStore();
|
|
|
|
buffer->Detach();
|
|
|
|
}
|
2017-03-24 14:12:14 +00:00
|
|
|
CHECK_ABSENT(object, 0);
|
|
|
|
CHECK_ABSENT(object, 1);
|
|
|
|
CHECK_ABSENT(object, -10);
|
|
|
|
CHECK_ABSENT(object, 13);
|
|
|
|
CHECK_ABSENT(object, 42);
|
|
|
|
}
|
|
|
|
|
2016-06-02 15:02:08 +00:00
|
|
|
{
|
|
|
|
Handle<JSFunction> constructor = isolate->string_function();
|
|
|
|
Handle<JSObject> object = factory->NewJSObject(constructor);
|
|
|
|
Handle<String> str = factory->InternalizeUtf8String("ab");
|
2019-06-24 13:13:34 +00:00
|
|
|
Handle<JSPrimitiveWrapper>::cast(object)->set_value(*str);
|
2016-06-02 15:02:08 +00:00
|
|
|
AddElement(object, 13, smi0);
|
|
|
|
CHECK_EQ(FAST_STRING_WRAPPER_ELEMENTS, object->map().elements_kind());
|
|
|
|
|
|
|
|
CHECK_FOUND(object, 0);
|
|
|
|
CHECK_FOUND(object, 1);
|
|
|
|
CHECK_NOT_FOUND(object, 7);
|
|
|
|
CHECK_FOUND(object, 13);
|
|
|
|
CHECK_NOT_FOUND(object, 42);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Handle<JSFunction> constructor = isolate->string_function();
|
|
|
|
Handle<JSObject> object = factory->NewJSObject(constructor);
|
|
|
|
Handle<String> str = factory->InternalizeUtf8String("ab");
|
2019-06-24 13:13:34 +00:00
|
|
|
Handle<JSPrimitiveWrapper>::cast(object)->set_value(*str);
|
2016-06-02 15:02:08 +00:00
|
|
|
AddElement(object, 13, smi0);
|
|
|
|
JSObject::NormalizeElements(object);
|
|
|
|
CHECK_EQ(SLOW_STRING_WRAPPER_ELEMENTS, object->map().elements_kind());
|
|
|
|
|
|
|
|
CHECK_FOUND(object, 0);
|
|
|
|
CHECK_FOUND(object, 1);
|
|
|
|
CHECK_NOT_FOUND(object, 7);
|
|
|
|
CHECK_FOUND(object, 13);
|
|
|
|
CHECK_NOT_FOUND(object, 42);
|
|
|
|
}
|
|
|
|
|
2019-08-26 13:29:57 +00:00
|
|
|
// TODO(ishell): uncomment once NO_ELEMENTS kind is supported.
|
|
|
|
// {
|
|
|
|
// Handle<Map> map = Map::Create(isolate, 0);
|
|
|
|
// map->set_elements_kind(NO_ELEMENTS);
|
|
|
|
// Handle<JSObject> object = factory->NewJSObjectFromMap(map);
|
|
|
|
// CHECK_EQ(NO_ELEMENTS, object->map()->elements_kind());
|
|
|
|
//
|
|
|
|
// CHECK_NOT_FOUND(object, 0);
|
|
|
|
// CHECK_NOT_FOUND(object, 1);
|
|
|
|
// CHECK_NOT_FOUND(object, 7);
|
|
|
|
// CHECK_NOT_FOUND(object, 13);
|
|
|
|
// CHECK_NOT_FOUND(object, 42);
|
|
|
|
// }
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
#undef CHECK_FOUND
|
|
|
|
#undef CHECK_NOT_FOUND
|
2020-01-09 17:50:43 +00:00
|
|
|
#undef CHECK_ABSENT
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
Handle<JSArray> handler = factory->NewJSArray(0);
|
2017-11-08 12:56:08 +00:00
|
|
|
Handle<JSFunction> function =
|
2020-11-10 11:22:49 +00:00
|
|
|
factory->NewFunctionForTesting(factory->empty_string());
|
2016-06-02 15:02:08 +00:00
|
|
|
Handle<JSProxy> object = factory->NewJSProxy(function, handler);
|
|
|
|
CHECK_EQ(JS_PROXY_TYPE, object->map().instance_type());
|
|
|
|
ft.CheckTrue(object, smi0, expect_bailout);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Handle<JSObject> object = isolate->global_object();
|
|
|
|
CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map().instance_type());
|
|
|
|
ft.CheckTrue(object, smi0, expect_bailout);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Handle<JSObject> object = isolate->global_proxy();
|
|
|
|
CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map().instance_type());
|
|
|
|
ft.CheckTrue(object, smi0, expect_bailout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-19 11:33:30 +00:00
|
|
|
TEST(AllocateJSObjectFromMap) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
|
|
|
|
const int kNumParams = 3;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-10-19 11:33:30 +00:00
|
|
|
|
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
auto map = m.Parameter<Map>(1);
|
|
|
|
auto properties = m.Parameter<HeapObject>(2);
|
|
|
|
auto elements = m.Parameter<FixedArray>(3);
|
2016-10-19 11:33:30 +00:00
|
|
|
|
2019-08-22 09:56:32 +00:00
|
|
|
TNode<JSObject> result =
|
|
|
|
m.AllocateJSObjectFromMap(map, properties, elements);
|
2016-10-19 11:33:30 +00:00
|
|
|
|
2019-06-17 17:56:48 +00:00
|
|
|
CodeStubAssembler::Label done(&m);
|
|
|
|
m.GotoIfNot(m.IsJSArrayMap(map), &done);
|
|
|
|
|
|
|
|
// JS array verification requires the length field to be set.
|
|
|
|
m.StoreObjectFieldNoWriteBarrier(result, JSArray::kLengthOffset,
|
|
|
|
m.SmiConstant(0));
|
|
|
|
m.Goto(&done);
|
|
|
|
|
|
|
|
m.Bind(&done);
|
2016-10-19 11:33:30 +00:00
|
|
|
m.Return(result);
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-10-19 11:33:30 +00:00
|
|
|
|
|
|
|
Handle<Map> maps[] = {
|
|
|
|
handle(isolate->object_function()->initial_map(), isolate),
|
|
|
|
handle(isolate->array_function()->initial_map(), isolate),
|
|
|
|
};
|
|
|
|
|
|
|
|
{
|
2017-07-17 23:30:32 +00:00
|
|
|
Handle<FixedArray> empty_fixed_array = factory->empty_fixed_array();
|
|
|
|
Handle<PropertyArray> empty_property_array =
|
|
|
|
factory->empty_property_array();
|
2016-11-10 12:54:01 +00:00
|
|
|
for (size_t i = 0; i < arraysize(maps); i++) {
|
2016-10-19 11:33:30 +00:00
|
|
|
Handle<Map> map = maps[i];
|
|
|
|
Handle<JSObject> result = Handle<JSObject>::cast(
|
|
|
|
ft.Call(map, empty_fixed_array, empty_fixed_array).ToHandleChecked());
|
2017-07-17 23:30:32 +00:00
|
|
|
CHECK_EQ(result->map(), *map);
|
|
|
|
CHECK_EQ(result->property_array(), *empty_property_array);
|
|
|
|
CHECK_EQ(result->elements(), *empty_fixed_array);
|
2016-10-25 08:30:37 +00:00
|
|
|
CHECK(result->HasFastProperties());
|
2016-10-19 11:33:30 +00:00
|
|
|
#ifdef VERIFY_HEAP
|
|
|
|
isolate->heap()->Verify();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// TODO(cbruni): handle in-object properties
|
|
|
|
Handle<JSObject> object = Handle<JSObject>::cast(
|
|
|
|
v8::Utils::OpenHandle(*CompileRun("var object = {a:1,b:2, 1:1, 2:2}; "
|
|
|
|
"object")));
|
2019-06-06 19:39:54 +00:00
|
|
|
JSObject::NormalizeProperties(isolate, object, KEEP_INOBJECT_PROPERTIES, 0,
|
2016-10-19 11:33:30 +00:00
|
|
|
"Normalize");
|
2021-03-05 13:53:15 +00:00
|
|
|
Handle<HeapObject> properties =
|
2021-03-25 23:14:31 +00:00
|
|
|
V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
|
2021-03-05 13:53:15 +00:00
|
|
|
? Handle<HeapObject>(object->property_dictionary_swiss(), isolate)
|
|
|
|
: handle(object->property_dictionary(), isolate);
|
2017-07-17 23:30:32 +00:00
|
|
|
Handle<JSObject> result = Handle<JSObject>::cast(
|
2021-03-05 13:53:15 +00:00
|
|
|
ft.Call(handle(object->map(), isolate), properties,
|
2017-07-17 23:30:32 +00:00
|
|
|
handle(object->elements(), isolate))
|
|
|
|
.ToHandleChecked());
|
|
|
|
CHECK_EQ(result->map(), object->map());
|
2021-03-25 23:14:31 +00:00
|
|
|
if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
|
2021-03-05 13:53:15 +00:00
|
|
|
CHECK_EQ(result->property_dictionary_swiss(),
|
|
|
|
object->property_dictionary_swiss());
|
|
|
|
} else {
|
|
|
|
CHECK_EQ(result->property_dictionary(), object->property_dictionary());
|
|
|
|
}
|
2016-10-25 08:30:37 +00:00
|
|
|
CHECK(!result->HasFastProperties());
|
2016-10-19 11:33:30 +00:00
|
|
|
#ifdef VERIFY_HEAP
|
|
|
|
isolate->heap()->Verify();
|
|
|
|
#endif
|
|
|
|
}
|
2016-10-25 08:30:37 +00:00
|
|
|
}
|
|
|
|
|
2020-11-13 09:59:08 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
template <typename Dictionary>
|
|
|
|
using CSAAllocator =
|
|
|
|
std::function<TNode<Dictionary>(CodeStubAssembler&, TNode<IntPtrT>)> const&;
|
|
|
|
|
|
|
|
template <typename Dictionary>
|
|
|
|
using Allocator = std::function<Handle<Dictionary>(Isolate*, int)> const&;
|
|
|
|
|
|
|
|
// Tests that allocation code emitted by {csa_alloc} yields ordered hash tables
|
|
|
|
// identical to those produced by {alloc}.
|
|
|
|
template <typename Dictionary>
|
|
|
|
void TestDictionaryAllocation(CSAAllocator<Dictionary> csa_alloc,
|
|
|
|
Allocator<Dictionary> alloc, int max_capacity) {
|
2016-10-25 08:30:37 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-10-25 08:30:37 +00:00
|
|
|
|
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
auto capacity = m.Parameter<Smi>(1);
|
2020-11-13 09:59:08 +00:00
|
|
|
TNode<Dictionary> result = csa_alloc(m, m.SmiUntag(capacity));
|
2016-10-25 08:30:37 +00:00
|
|
|
m.Return(result);
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-10-25 08:30:37 +00:00
|
|
|
|
|
|
|
{
|
2020-11-13 09:59:08 +00:00
|
|
|
for (int i = 0; i < max_capacity; i = i * 1.1 + 1) {
|
2019-02-14 13:01:52 +00:00
|
|
|
Handle<HeapObject> result = Handle<HeapObject>::cast(
|
|
|
|
ft.Call(handle(Smi::FromInt(i), isolate)).ToHandleChecked());
|
2020-11-13 09:59:08 +00:00
|
|
|
Handle<Dictionary> dict = alloc(isolate, i);
|
2016-10-25 08:30:37 +00:00
|
|
|
// Both dictionaries should be memory equal.
|
2019-02-14 13:01:52 +00:00
|
|
|
int size = dict->Size();
|
|
|
|
CHECK_EQ(0, memcmp(reinterpret_cast<void*>(dict->address()),
|
|
|
|
reinterpret_cast<void*>(result->address()), size));
|
2016-10-25 08:30:37 +00:00
|
|
|
}
|
|
|
|
}
|
2016-10-19 11:33:30 +00:00
|
|
|
}
|
|
|
|
|
2020-11-13 09:59:08 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST(AllocateNameDictionary) {
|
|
|
|
auto csa_alloc = [](CodeStubAssembler& m, TNode<IntPtrT> cap) {
|
|
|
|
return m.AllocateNameDictionary(cap);
|
|
|
|
};
|
|
|
|
auto alloc = [](Isolate* isolate, int capacity) {
|
|
|
|
return NameDictionary::New(isolate, capacity);
|
|
|
|
};
|
|
|
|
TestDictionaryAllocation<NameDictionary>(csa_alloc, alloc, 256);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(AllocateOrderedNameDictionary) {
|
|
|
|
auto csa_alloc = [](CodeStubAssembler& m, TNode<IntPtrT> cap) {
|
|
|
|
return m.AllocateOrderedNameDictionary(cap);
|
|
|
|
};
|
|
|
|
auto alloc = [](Isolate* isolate, int capacity) {
|
|
|
|
return OrderedNameDictionary::Allocate(isolate, capacity).ToHandleChecked();
|
|
|
|
};
|
|
|
|
TestDictionaryAllocation<OrderedNameDictionary>(csa_alloc, alloc, 256);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(AllocateOrderedHashSet) {
|
|
|
|
// ignoring capacitites, as the API cannot take them
|
|
|
|
auto csa_alloc = [](CodeStubAssembler& m, TNode<IntPtrT> cap) {
|
|
|
|
return m.AllocateOrderedHashSet();
|
|
|
|
};
|
|
|
|
auto alloc = [](Isolate* isolate, int capacity) {
|
|
|
|
return OrderedHashSet::Allocate(isolate, OrderedHashSet::kInitialCapacity)
|
|
|
|
.ToHandleChecked();
|
|
|
|
};
|
|
|
|
TestDictionaryAllocation<OrderedHashSet>(csa_alloc, alloc, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(AllocateOrderedHashMap) {
|
|
|
|
// ignoring capacities, as the API cannot take them
|
|
|
|
auto csa_alloc = [](CodeStubAssembler& m, TNode<IntPtrT> cap) {
|
|
|
|
return m.AllocateOrderedHashMap();
|
|
|
|
};
|
|
|
|
auto alloc = [](Isolate* isolate, int capacity) {
|
|
|
|
return OrderedHashMap::Allocate(isolate, OrderedHashMap::kInitialCapacity)
|
|
|
|
.ToHandleChecked();
|
|
|
|
};
|
|
|
|
TestDictionaryAllocation<OrderedHashMap>(csa_alloc, alloc, 1);
|
|
|
|
}
|
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
TEST(PopAndReturnFromJSBuiltinWithStackParameters) {
|
2020-10-13 11:56:01 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
const int kNumStackParams = 1;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumStackParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
m.PopAndReturn(m.SmiUntag(m.Parameter<Smi>(0)),
|
|
|
|
m.SmiConstant(Smi::FromInt(1234)));
|
|
|
|
}
|
2020-10-13 11:56:01 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
// Attempt to generate code must trigger CHECK failure in RawMachineAssebler.
|
|
|
|
// PopAndReturn is not allowed in builtins with JS linkage and declared stack
|
|
|
|
// parameters.
|
|
|
|
asm_tester.GenerateCode();
|
|
|
|
}
|
2020-10-12 20:25:28 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
TEST(PopAndReturnFromTFCBuiltinWithStackParameters) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
// Setup CSA for creating TFC-style builtin with stack arguments.
|
|
|
|
// For the testing purposes we need any interface descriptor that has at
|
|
|
|
// least one argument passed on stack.
|
|
|
|
using Descriptor = FlatMapIntoArrayDescriptor;
|
|
|
|
Descriptor descriptor;
|
Reland "[codegen] Add static interface descriptors"
This is a reland of ae0752df1b84d8c53cc7b2af71013a9e678a9c6e
Reland fixes:
* Remove UNREACHABLE() from constexpr switch, since we don't have a
CONSTEXPR_UNREACHABLE() (it's ok, the switch is exhaustive for the
enum anyway).
* Fix IsRegisterArray trait to use public inheritance and size_t for
std::array size.
Original change's description:
> [codegen] Add static interface descriptors
>
> Add a new CRTP StaticCallInterfaceDescriptor class, which provides
> static constexpr getters for a descriptor's registers, parameter counts,
> and so on. Each CallInterfaceDescriptor subclass is changed to extend
> StaticCallInterfaceDescriptor, with StaticCallInterfaceDescriptor itself
> extending CallInterfaceDescriptor to still provide a dynamic lookup
> where needed.
>
> StaticCallInterfaceDescriptor provides a couple of customisation points,
> where it reads its CRTP derived descriptor's static fields and
> functions, with default fallbacks where appropriate. With these
> customisation points, the definition of CallInterfaceDescriptor
> subclasses is simplified to:
>
> a) Providing parameter names (as before)
> b) Providing parameter types (as before)
> c) Optionally setting flags (like kNoContext or kAllowVarArgs) as
> static booleans on the class.
> d) Optionally providing a `registers()` method that returns a
> std::array<Register, N> of registers that may be used for
> parameters (if not provided, this defaults to the implementation
> specific default register set).
>
> Parameter registers (and register count) are automagically set based on
> the number of parameters and number of given registers, with extra magic
> to ignore no_reg registers (to reduce ia32 special casing). The
> CallInterfaceDescriptorData is initialized based on these static
> functions, rather than manual per-descriptor initializers.
>
> This allows us to skip loading descriptors dynamically for CallBuiltin
> in Sparkplug, and instead lets us use a bit of template magic to
> statically set up arguments for the calls. Any other users of statically
> known descriptors will also benefit, thanks to C++ picking the static
> methods over the dynamic methods on the base class when available.
>
> Because we can remove various virtual functions and trigger heavier
> inlining of constantly known values, binary size slightly decreases with
> this change.
>
> Note that torque-generated descriptors are changed to use the same magic,
> rather than having Torque-specific magic, for consistency.
>
> Bug: v8:11420
> Change-Id: Icc5e238b6313a08734feb564204a13226b450c22
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2814518
> Auto-Submit: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
> Reviewed-by: Clemens Backes <clemensb@chromium.org>
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Reviewed-by: Jakob Gruber <jgruber@chromium.org>
> Commit-Queue: Clemens Backes <clemensb@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#73996}
TBR=nicohartmann@chromium.org,clemensb@chromium.org,ishell@chromium.org,clemensb@chromium.org
Bug: v8:11420
Change-Id: Icd1f6cdb3c178e74460044b1e9623139929ceba8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2831872
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74010}
2021-04-16 14:52:06 +00:00
|
|
|
CHECK_LT(0, Descriptor::GetStackParameterCount());
|
2020-10-13 15:44:09 +00:00
|
|
|
|
|
|
|
CodeAssemblerTester asm_tester(isolate, Descriptor());
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
m.PopAndReturn(m.SmiUntag(m.Parameter<Smi>(0)),
|
|
|
|
m.SmiConstant(Smi::FromInt(1234)));
|
2020-10-12 20:25:28 +00:00
|
|
|
}
|
2020-10-13 15:44:09 +00:00
|
|
|
|
|
|
|
// Attempt to generate code must trigger CHECK failure in RawMachineAssebler.
|
|
|
|
// PopAndReturn is not allowed in builtins with JS linkage and declared stack
|
|
|
|
// parameters.
|
|
|
|
asm_tester.GenerateCode();
|
2020-10-12 16:57:10 +00:00
|
|
|
}
|
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
namespace {
|
2020-10-13 11:56:01 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
TNode<Object> MakeConstantNode(CodeStubAssembler& m, Handle<Object> value) {
|
|
|
|
if (value->IsSmi()) {
|
|
|
|
return m.SmiConstant(Smi::ToInt(*value));
|
|
|
|
}
|
|
|
|
return m.HeapConstant(Handle<HeapObject>::cast(value));
|
|
|
|
}
|
2020-10-13 11:56:01 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
// Buids a CSA function that calls |target| function with given arguments
|
|
|
|
// |number_of_iterations| times and checks that the stack pointer values before
|
|
|
|
// the calls and after the calls are the same.
|
|
|
|
// Then this new function is called multiple times.
|
|
|
|
template <typename... Args>
|
|
|
|
void CallFunctionWithStackPointerChecks(Isolate* isolate,
|
|
|
|
Handle<Object> expected_result,
|
|
|
|
Handle<Object> target,
|
|
|
|
Handle<Object> receiver, Args... args) {
|
|
|
|
// Setup CSA for creating TFJ-style builtin.
|
|
|
|
using Descriptor = JSTrampolineDescriptor;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, Descriptor());
|
|
|
|
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
TNode<Context> context = m.Parameter<Context>(Descriptor::kContext);
|
|
|
|
|
|
|
|
#ifdef V8_CC_GNU
|
|
|
|
// GetStackPointer is available only when V8_CC_GNU is defined.
|
|
|
|
const TNode<ExternalReference> get_stack_ptr = m.ExternalConstant(
|
|
|
|
ExternalReference::Create(reinterpret_cast<Address>(GetStackPointer)));
|
|
|
|
|
|
|
|
// CSA doesn't have instructions for reading current stack pointer value,
|
|
|
|
// so we use a C function that returns address of its local variable.
|
|
|
|
// This is a good-enough approximation for the stack pointer.
|
|
|
|
MachineType type_intptr = MachineType::IntPtr();
|
|
|
|
TNode<WordT> stack_pointer0 =
|
|
|
|
m.UncheckedCast<WordT>(m.CallCFunction(get_stack_ptr, type_intptr));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// CSA::CallCFunction() aligns stack pointer before the call, so off-by one
|
|
|
|
// errors will not be detected. In order to handle this we do the calls in a
|
|
|
|
// loop in order to exaggerate the effect of potentially broken stack
|
|
|
|
// pointer so that the GetStackPointer function will be able to notice it.
|
|
|
|
m.BuildFastLoop<IntPtrT>(
|
|
|
|
m.IntPtrConstant(0), m.IntPtrConstant(153),
|
|
|
|
[&](TNode<IntPtrT> index) {
|
|
|
|
TNode<Object> result = m.Call(context, MakeConstantNode(m, target),
|
|
|
|
MakeConstantNode(m, receiver),
|
|
|
|
MakeConstantNode(m, args)...);
|
|
|
|
CSA_CHECK(
|
|
|
|
&m, m.TaggedEqual(result, MakeConstantNode(m, expected_result)));
|
|
|
|
},
|
|
|
|
1, CodeStubAssembler::IndexAdvanceMode::kPost);
|
|
|
|
|
|
|
|
#ifdef V8_CC_GNU
|
|
|
|
TNode<WordT> stack_pointer1 =
|
|
|
|
m.UncheckedCast<WordT>(m.CallCFunction(get_stack_ptr, type_intptr));
|
|
|
|
CSA_CHECK(&m, m.WordEqual(stack_pointer0, stack_pointer1));
|
|
|
|
#endif
|
|
|
|
m.Return(m.SmiConstant(42));
|
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), 1); // Include receiver.
|
2020-10-13 14:55:43 +00:00
|
|
|
|
|
|
|
Handle<Object> result;
|
|
|
|
for (int test_count = 0; test_count < 100; ++test_count) {
|
2020-10-13 15:44:09 +00:00
|
|
|
result = ft.Call().ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::FromInt(42), *result);
|
2020-10-13 14:55:43 +00:00
|
|
|
}
|
2020-10-13 11:56:01 +00:00
|
|
|
}
|
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST(PopAndReturnConstant) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
// Setup CSA for creating TFJ-style builtin.
|
|
|
|
using Descriptor = JSTrampolineDescriptor;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, Descriptor());
|
|
|
|
|
|
|
|
const int kNumParams = 4; // Not including receiver
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
TNode<Int32T> argc =
|
|
|
|
m.UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
|
|
|
|
CSA_CHECK(&m, m.Word32Equal(argc, m.Int32Constant(kNumParams)));
|
|
|
|
|
|
|
|
m.PopAndReturn(m.IntPtrConstant(kNumParams + 1), // Include receiver.
|
|
|
|
m.SmiConstant(1234));
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), 0);
|
|
|
|
ft.function->shared().DontAdaptArguments();
|
|
|
|
|
|
|
|
// Now call this function multiple time also checking that the stack pointer
|
|
|
|
// didn't change after the calls.
|
|
|
|
Handle<Object> receiver = isolate->factory()->undefined_value();
|
|
|
|
Handle<Smi> expected_result(Smi::FromInt(1234), isolate);
|
|
|
|
CallFunctionWithStackPointerChecks(isolate, expected_result, ft.function,
|
|
|
|
receiver,
|
|
|
|
// Pass kNumParams arguments.
|
|
|
|
Handle<Smi>(Smi::FromInt(1), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(2), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(3), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(4), isolate));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(PopAndReturnVariable) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
// Setup CSA for creating TFJ-style builtin.
|
|
|
|
using Descriptor = JSTrampolineDescriptor;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, Descriptor());
|
|
|
|
|
|
|
|
const int kNumParams = 4; // Not including receiver
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
TNode<Int32T> argc =
|
|
|
|
m.UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
|
|
|
|
CSA_CHECK(&m, m.Word32Equal(argc, m.Int32Constant(kNumParams)));
|
|
|
|
|
|
|
|
TNode<Int32T> argc_with_receiver = m.Int32Add(argc, m.Int32Constant(1));
|
|
|
|
m.PopAndReturn(m.ChangeInt32ToIntPtr(argc_with_receiver),
|
|
|
|
m.SmiConstant(1234));
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), 0);
|
|
|
|
ft.function->shared().DontAdaptArguments();
|
|
|
|
|
|
|
|
// Now call this function multiple time also checking that the stack pointer
|
|
|
|
// didn't change after the calls.
|
|
|
|
Handle<Object> receiver = isolate->factory()->undefined_value();
|
|
|
|
Handle<Smi> expected_result(Smi::FromInt(1234), isolate);
|
|
|
|
CallFunctionWithStackPointerChecks(isolate, expected_result, ft.function,
|
|
|
|
receiver,
|
|
|
|
// Pass kNumParams arguments.
|
|
|
|
Handle<Smi>(Smi::FromInt(1), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(2), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(3), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(4), isolate));
|
|
|
|
}
|
|
|
|
|
2016-11-02 13:18:50 +00:00
|
|
|
TEST(OneToTwoByteStringCopy) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2016-11-16 11:48:07 +00:00
|
|
|
const int kNumParams = 2;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2019-09-24 15:43:00 +00:00
|
|
|
StringBuiltinsAssembler m(asm_tester.state());
|
2016-11-02 13:18:50 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
m.CopyStringCharacters<String>(m.Parameter<String>(1), m.Parameter<String>(2),
|
2019-11-11 13:00:10 +00:00
|
|
|
m.IntPtrConstant(0), m.IntPtrConstant(0),
|
|
|
|
m.IntPtrConstant(5), String::ONE_BYTE_ENCODING,
|
|
|
|
String::TWO_BYTE_ENCODING);
|
2016-11-02 13:18:50 +00:00
|
|
|
m.Return(m.SmiConstant(Smi::FromInt(0)));
|
|
|
|
|
|
|
|
Handle<String> string1 = isolate->factory()->InternalizeUtf8String("abcde");
|
2021-06-24 13:32:01 +00:00
|
|
|
base::uc16 array[] = {1000, 1001, 1002, 1003, 1004};
|
2019-04-23 14:19:00 +00:00
|
|
|
Handle<String> string2 = isolate->factory()
|
2021-06-17 15:43:55 +00:00
|
|
|
->NewStringFromTwoByte(base::ArrayVector(array))
|
2019-04-23 14:19:00 +00:00
|
|
|
.ToHandleChecked();
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-11-02 13:18:50 +00:00
|
|
|
ft.Call(string1, string2);
|
2020-11-20 16:57:36 +00:00
|
|
|
DisallowGarbageCollection no_gc;
|
2018-11-30 12:40:36 +00:00
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars(no_gc)[0],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars(no_gc)[0]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars(no_gc)[1],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars(no_gc)[1]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars(no_gc)[2],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars(no_gc)[2]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars(no_gc)[3],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars(no_gc)[3]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars(no_gc)[4],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars(no_gc)[4]);
|
2016-11-02 13:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(OneToOneByteStringCopy) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2016-11-16 11:48:07 +00:00
|
|
|
const int kNumParams = 2;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2019-09-24 15:43:00 +00:00
|
|
|
StringBuiltinsAssembler m(asm_tester.state());
|
2016-11-02 13:18:50 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
m.CopyStringCharacters<String>(m.Parameter<String>(1), m.Parameter<String>(2),
|
2019-11-11 13:00:10 +00:00
|
|
|
m.IntPtrConstant(0), m.IntPtrConstant(0),
|
|
|
|
m.IntPtrConstant(5), String::ONE_BYTE_ENCODING,
|
|
|
|
String::ONE_BYTE_ENCODING);
|
2016-11-02 13:18:50 +00:00
|
|
|
m.Return(m.SmiConstant(Smi::FromInt(0)));
|
|
|
|
|
|
|
|
Handle<String> string1 = isolate->factory()->InternalizeUtf8String("abcde");
|
|
|
|
uint8_t array[] = {100, 101, 102, 103, 104};
|
2019-04-23 14:19:00 +00:00
|
|
|
Handle<String> string2 = isolate->factory()
|
2021-06-17 15:43:55 +00:00
|
|
|
->NewStringFromOneByte(base::ArrayVector(array))
|
2019-04-23 14:19:00 +00:00
|
|
|
.ToHandleChecked();
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-11-02 13:18:50 +00:00
|
|
|
ft.Call(string1, string2);
|
2020-11-20 16:57:36 +00:00
|
|
|
DisallowGarbageCollection no_gc;
|
2018-11-30 12:40:36 +00:00
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars(no_gc)[0],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars(no_gc)[0]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars(no_gc)[1],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars(no_gc)[1]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars(no_gc)[2],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars(no_gc)[2]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars(no_gc)[3],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars(no_gc)[3]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars(no_gc)[4],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars(no_gc)[4]);
|
2016-11-02 13:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(OneToOneByteStringCopyNonZeroStart) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2016-11-16 11:48:07 +00:00
|
|
|
const int kNumParams = 2;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2019-09-24 15:43:00 +00:00
|
|
|
StringBuiltinsAssembler m(asm_tester.state());
|
2016-11-02 13:18:50 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
m.CopyStringCharacters<String>(m.Parameter<String>(1), m.Parameter<String>(2),
|
2019-11-11 13:00:10 +00:00
|
|
|
m.IntPtrConstant(0), m.IntPtrConstant(3),
|
|
|
|
m.IntPtrConstant(2), String::ONE_BYTE_ENCODING,
|
|
|
|
String::ONE_BYTE_ENCODING);
|
2016-11-02 13:18:50 +00:00
|
|
|
m.Return(m.SmiConstant(Smi::FromInt(0)));
|
|
|
|
|
|
|
|
Handle<String> string1 = isolate->factory()->InternalizeUtf8String("abcde");
|
|
|
|
uint8_t array[] = {100, 101, 102, 103, 104};
|
2019-04-23 14:19:00 +00:00
|
|
|
Handle<String> string2 = isolate->factory()
|
2021-06-17 15:43:55 +00:00
|
|
|
->NewStringFromOneByte(base::ArrayVector(array))
|
2019-04-23 14:19:00 +00:00
|
|
|
.ToHandleChecked();
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-11-02 13:18:50 +00:00
|
|
|
ft.Call(string1, string2);
|
2020-11-20 16:57:36 +00:00
|
|
|
DisallowGarbageCollection no_gc;
|
2018-11-30 12:40:36 +00:00
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars(no_gc)[0],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars(no_gc)[3]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars(no_gc)[1],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars(no_gc)[4]);
|
|
|
|
CHECK_EQ(100, Handle<SeqOneByteString>::cast(string2)->GetChars(no_gc)[0]);
|
|
|
|
CHECK_EQ(101, Handle<SeqOneByteString>::cast(string2)->GetChars(no_gc)[1]);
|
|
|
|
CHECK_EQ(102, Handle<SeqOneByteString>::cast(string2)->GetChars(no_gc)[2]);
|
2016-11-02 13:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(TwoToTwoByteStringCopy) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2016-11-16 11:48:07 +00:00
|
|
|
const int kNumParams = 2;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2019-09-24 15:43:00 +00:00
|
|
|
StringBuiltinsAssembler m(asm_tester.state());
|
2016-11-02 13:18:50 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
m.CopyStringCharacters<String>(m.Parameter<String>(1), m.Parameter<String>(2),
|
2019-11-11 13:00:10 +00:00
|
|
|
m.IntPtrConstant(0), m.IntPtrConstant(0),
|
|
|
|
m.IntPtrConstant(5), String::TWO_BYTE_ENCODING,
|
|
|
|
String::TWO_BYTE_ENCODING);
|
2016-11-02 13:18:50 +00:00
|
|
|
m.Return(m.SmiConstant(Smi::FromInt(0)));
|
|
|
|
|
2021-06-24 13:32:01 +00:00
|
|
|
base::uc16 array1[] = {2000, 2001, 2002, 2003, 2004};
|
2019-04-23 14:19:00 +00:00
|
|
|
Handle<String> string1 = isolate->factory()
|
2021-06-17 15:43:55 +00:00
|
|
|
->NewStringFromTwoByte(base::ArrayVector(array1))
|
2019-04-23 14:19:00 +00:00
|
|
|
.ToHandleChecked();
|
2021-06-24 13:32:01 +00:00
|
|
|
base::uc16 array2[] = {1000, 1001, 1002, 1003, 1004};
|
2019-04-23 14:19:00 +00:00
|
|
|
Handle<String> string2 = isolate->factory()
|
2021-06-17 15:43:55 +00:00
|
|
|
->NewStringFromTwoByte(base::ArrayVector(array2))
|
2019-04-23 14:19:00 +00:00
|
|
|
.ToHandleChecked();
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-11-02 13:18:50 +00:00
|
|
|
ft.Call(string1, string2);
|
2020-11-20 16:57:36 +00:00
|
|
|
DisallowGarbageCollection no_gc;
|
2018-11-30 12:40:36 +00:00
|
|
|
CHECK_EQ(Handle<SeqTwoByteString>::cast(string1)->GetChars(no_gc)[0],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars(no_gc)[0]);
|
|
|
|
CHECK_EQ(Handle<SeqTwoByteString>::cast(string1)->GetChars(no_gc)[1],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars(no_gc)[1]);
|
|
|
|
CHECK_EQ(Handle<SeqTwoByteString>::cast(string1)->GetChars(no_gc)[2],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars(no_gc)[2]);
|
|
|
|
CHECK_EQ(Handle<SeqTwoByteString>::cast(string1)->GetChars(no_gc)[3],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars(no_gc)[3]);
|
|
|
|
CHECK_EQ(Handle<SeqTwoByteString>::cast(string1)->GetChars(no_gc)[4],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars(no_gc)[4]);
|
2016-11-02 13:18:50 +00:00
|
|
|
}
|
|
|
|
|
2016-11-03 12:53:24 +00:00
|
|
|
TEST(Arguments) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
// Setup CSA for creating TFJ-style builtin.
|
|
|
|
using Descriptor = JSTrampolineDescriptor;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, Descriptor());
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
TNode<Int32T> argc =
|
|
|
|
m.UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
|
|
|
|
CodeStubArguments arguments(&m, argc);
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
CSA_CHECK(&m, m.TaggedEqual(arguments.AtIndex(0), m.SmiConstant(12)));
|
|
|
|
CSA_CHECK(&m, m.TaggedEqual(arguments.AtIndex(1), m.SmiConstant(13)));
|
|
|
|
CSA_CHECK(&m, m.TaggedEqual(arguments.AtIndex(2), m.SmiConstant(14)));
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
arguments.PopAndReturn(arguments.GetReceiver());
|
|
|
|
}
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), 0);
|
|
|
|
ft.function->shared().DontAdaptArguments();
|
|
|
|
|
|
|
|
Handle<Object> result;
|
|
|
|
result = ft.Call(Handle<Smi>(Smi::FromInt(12), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(13), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(14), isolate))
|
|
|
|
.ToHandleChecked();
|
2020-07-15 11:03:22 +00:00
|
|
|
// When calling with undefined object as the receiver, the CallFunction
|
|
|
|
// builtin swaps it to the global proxy object.
|
|
|
|
CHECK_EQ(*isolate->global_proxy(), *result);
|
2020-10-13 15:44:09 +00:00
|
|
|
|
|
|
|
result = ft.Call(Handle<Smi>(Smi::FromInt(12), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(13), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(14), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(15), isolate))
|
|
|
|
.ToHandleChecked();
|
|
|
|
CHECK_EQ(*isolate->global_proxy(), *result);
|
|
|
|
|
|
|
|
result = ft.Call(Handle<Smi>(Smi::FromInt(12), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(13), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(14), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(15), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(16), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(17), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(18), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(19), isolate))
|
|
|
|
.ToHandleChecked();
|
|
|
|
CHECK_EQ(*isolate->global_proxy(), *result);
|
2016-11-03 12:53:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ArgumentsForEach) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
// Setup CSA for creating TFJ-style builtin.
|
|
|
|
using Descriptor = JSTrampolineDescriptor;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, Descriptor());
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
TNode<Int32T> argc =
|
|
|
|
m.UncheckedParameter<Int32T>(Descriptor::kActualArgumentsCount);
|
|
|
|
CodeStubArguments arguments(&m, argc);
|
2020-10-12 16:57:10 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
TVariable<Smi> sum(&m);
|
|
|
|
CodeAssemblerVariableList list({&sum}, m.zone());
|
2020-10-12 16:57:10 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
sum = m.SmiConstant(0);
|
2020-10-13 11:56:01 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
arguments.ForEach(list, [&](TNode<Object> arg) {
|
|
|
|
sum = m.SmiAdd(sum.value(), m.CAST(arg));
|
|
|
|
});
|
2020-10-13 11:56:01 +00:00
|
|
|
|
2020-10-13 15:44:09 +00:00
|
|
|
arguments.PopAndReturn(sum.value());
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), 0);
|
|
|
|
ft.function->shared().DontAdaptArguments();
|
|
|
|
|
|
|
|
Handle<Object> result;
|
|
|
|
result = ft.Call(Handle<Smi>(Smi::FromInt(12), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(13), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(14), isolate))
|
|
|
|
.ToHandleChecked();
|
2016-11-03 12:53:24 +00:00
|
|
|
CHECK_EQ(Smi::FromInt(12 + 13 + 14), *result);
|
2020-10-13 15:44:09 +00:00
|
|
|
|
|
|
|
result = ft.Call(Handle<Smi>(Smi::FromInt(12), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(13), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(14), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(15), isolate))
|
|
|
|
.ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::FromInt(12 + 13 + 14 + 15), *result);
|
|
|
|
|
|
|
|
result = ft.Call(Handle<Smi>(Smi::FromInt(12), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(13), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(14), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(15), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(16), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(17), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(18), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(19), isolate))
|
|
|
|
.ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::FromInt(12 + 13 + 14 + 15 + 16 + 17 + 18 + 19), *result);
|
2016-11-03 12:53:24 +00:00
|
|
|
}
|
|
|
|
|
2016-11-20 17:56:51 +00:00
|
|
|
TEST(IsDebugActive) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2020-07-15 11:03:22 +00:00
|
|
|
const int kNumParams = 0;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-11-20 17:56:51 +00:00
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
Label if_active(&m), if_not_active(&m);
|
2016-11-20 17:56:51 +00:00
|
|
|
|
|
|
|
m.Branch(m.IsDebugActive(), &if_active, &if_not_active);
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_active);
|
2016-11-20 17:56:51 +00:00
|
|
|
m.Return(m.TrueConstant());
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_not_active);
|
2016-11-20 17:56:51 +00:00
|
|
|
m.Return(m.FalseConstant());
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2017-02-07 14:20:02 +00:00
|
|
|
CHECK(!isolate->debug()->is_active());
|
2016-11-20 17:56:51 +00:00
|
|
|
Handle<Object> result =
|
|
|
|
ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).false_value(), *result);
|
2016-11-20 17:56:51 +00:00
|
|
|
|
|
|
|
bool* debug_is_active = reinterpret_cast<bool*>(
|
|
|
|
ExternalReference::debug_is_active_address(isolate).address());
|
|
|
|
|
|
|
|
// Cheat to enable debug (TODO: do this properly).
|
|
|
|
*debug_is_active = true;
|
|
|
|
|
2020-07-15 11:03:22 +00:00
|
|
|
result = ft.Call().ToHandleChecked();
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).true_value(), *result);
|
2016-11-20 17:56:51 +00:00
|
|
|
|
|
|
|
// Reset debug mode.
|
|
|
|
*debug_is_active = false;
|
|
|
|
}
|
|
|
|
|
2021-03-24 12:32:59 +00:00
|
|
|
// Ensure that the kShortBuiltinCallsOldSpaceSizeThreshold constant can be used
|
|
|
|
// for detecting whether the machine has >= 4GB of physical memory by checking
|
|
|
|
// the max old space size.
|
|
|
|
TEST(ShortBuiltinCallsThreshold) {
|
|
|
|
if (!V8_SHORT_BUILTIN_CALLS_BOOL) return;
|
|
|
|
|
|
|
|
const uint64_t kPhysicalMemoryThreshold = size_t{4} * GB;
|
|
|
|
|
|
|
|
size_t heap_size, old, young;
|
|
|
|
|
|
|
|
// If the physical memory is < kPhysicalMemoryThreshold then the old space
|
|
|
|
// size must be below the kShortBuiltinCallsOldSpaceThreshold.
|
|
|
|
heap_size = Heap::HeapSizeFromPhysicalMemory(kPhysicalMemoryThreshold - MB);
|
|
|
|
i::Heap::GenerationSizesFromHeapSize(heap_size, &young, &old);
|
|
|
|
CHECK_LT(old, kShortBuiltinCallsOldSpaceSizeThreshold);
|
|
|
|
|
|
|
|
// If the physical memory is >= kPhysicalMemoryThreshold then the old space
|
|
|
|
// size must be below the kShortBuiltinCallsOldSpaceThreshold.
|
|
|
|
heap_size = Heap::HeapSizeFromPhysicalMemory(kPhysicalMemoryThreshold);
|
|
|
|
i::Heap::GenerationSizesFromHeapSize(heap_size, &young, &old);
|
|
|
|
CHECK_GE(old, kShortBuiltinCallsOldSpaceSizeThreshold);
|
|
|
|
|
|
|
|
heap_size = Heap::HeapSizeFromPhysicalMemory(kPhysicalMemoryThreshold + MB);
|
|
|
|
i::Heap::GenerationSizesFromHeapSize(heap_size, &young, &old);
|
|
|
|
CHECK_GE(old, kShortBuiltinCallsOldSpaceSizeThreshold);
|
|
|
|
}
|
|
|
|
|
2021-03-17 09:31:08 +00:00
|
|
|
TEST(CallBuiltin) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 2;
|
|
|
|
CodeAssemblerTester asm_tester(isolate,
|
|
|
|
kNumParams + 1); // Include receiver.
|
|
|
|
PromiseBuiltinsAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
{
|
|
|
|
auto receiver = m.Parameter<Object>(1);
|
|
|
|
auto name = m.Parameter<Name>(2);
|
|
|
|
auto context = m.Parameter<Context>(kNumParams + 3);
|
|
|
|
|
2021-06-07 15:24:12 +00:00
|
|
|
auto value = m.CallBuiltin(Builtin::kGetProperty, context, receiver, name);
|
2021-03-17 09:31:08 +00:00
|
|
|
m.Return(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
Handle<Name> name = factory->InternalizeUtf8String("a");
|
|
|
|
Handle<Object> value(Smi::FromInt(153), isolate);
|
|
|
|
Handle<JSObject> object = factory->NewJSObjectWithNullProto();
|
|
|
|
JSObject::AddProperty(isolate, object, name, value, NONE);
|
|
|
|
|
|
|
|
Handle<Object> result = ft.Call(object, name).ToHandleChecked();
|
|
|
|
CHECK_EQ(*value, *result);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(TailCallBuiltin) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 2;
|
|
|
|
CodeAssemblerTester asm_tester(isolate,
|
|
|
|
kNumParams + 1); // Include receiver.
|
|
|
|
PromiseBuiltinsAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
{
|
|
|
|
auto receiver = m.Parameter<Object>(1);
|
|
|
|
auto name = m.Parameter<Name>(2);
|
|
|
|
auto context = m.Parameter<Context>(kNumParams + 3);
|
|
|
|
|
2021-06-07 15:24:12 +00:00
|
|
|
m.TailCallBuiltin(Builtin::kGetProperty, context, receiver, name);
|
2021-03-17 09:31:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
Handle<Name> name = factory->InternalizeUtf8String("a");
|
|
|
|
Handle<Object> value(Smi::FromInt(153), isolate);
|
|
|
|
Handle<JSObject> object = factory->NewJSObjectWithNullProto();
|
|
|
|
JSObject::AddProperty(isolate, object, name, value, NONE);
|
|
|
|
|
|
|
|
Handle<Object> result = ft.Call(object, name).ToHandleChecked();
|
|
|
|
CHECK_EQ(*value, *result);
|
|
|
|
}
|
|
|
|
|
2016-11-29 16:57:58 +00:00
|
|
|
class AppendJSArrayCodeStubAssembler : public CodeStubAssembler {
|
|
|
|
public:
|
|
|
|
AppendJSArrayCodeStubAssembler(compiler::CodeAssemblerState* state,
|
|
|
|
ElementsKind kind)
|
|
|
|
: CodeStubAssembler(state), kind_(kind) {}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
void TestAppendJSArrayImpl(Isolate* isolate, CodeAssemblerTester* csa_tester,
|
2020-02-11 13:18:49 +00:00
|
|
|
Handle<Object> o1, Handle<Object> o2,
|
|
|
|
Handle<Object> o3, Handle<Object> o4,
|
2016-11-29 16:57:58 +00:00
|
|
|
int initial_size, int result_size) {
|
|
|
|
Handle<JSArray> array = isolate->factory()->NewJSArray(
|
|
|
|
kind_, 2, initial_size, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
|
2018-12-08 02:59:17 +00:00
|
|
|
Object::SetElement(isolate, array, 0, Handle<Smi>(Smi::FromInt(1), isolate),
|
2019-01-23 17:13:08 +00:00
|
|
|
kDontThrow)
|
2016-11-29 16:57:58 +00:00
|
|
|
.Check();
|
2018-12-08 02:59:17 +00:00
|
|
|
Object::SetElement(isolate, array, 1, Handle<Smi>(Smi::FromInt(2), isolate),
|
2019-01-23 17:13:08 +00:00
|
|
|
kDontThrow)
|
2016-11-29 16:57:58 +00:00
|
|
|
.Check();
|
2017-01-27 11:20:07 +00:00
|
|
|
CodeStubArguments args(this, IntPtrConstant(kNumParams));
|
2017-08-03 14:27:11 +00:00
|
|
|
TVariable<IntPtrT> arg_index(this);
|
2016-11-29 16:57:58 +00:00
|
|
|
Label bailout(this);
|
2017-08-03 14:27:11 +00:00
|
|
|
arg_index = IntPtrConstant(0);
|
2019-10-01 10:06:22 +00:00
|
|
|
TNode<Smi> length = BuildAppendJSArray(kind_, HeapConstant(array), &args,
|
|
|
|
&arg_index, &bailout);
|
2016-11-29 16:57:58 +00:00
|
|
|
Return(length);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
BIND(&bailout);
|
2018-02-09 15:24:14 +00:00
|
|
|
Return(SmiTag(IntPtrAdd(arg_index.value(), IntPtrConstant(2))));
|
2016-11-29 16:57:58 +00:00
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(csa_tester->GenerateCode(), kNumParams);
|
2016-11-29 16:57:58 +00:00
|
|
|
|
2020-02-11 13:18:49 +00:00
|
|
|
Handle<Object> result = ft.Call(o1, o2, o3, o4).ToHandleChecked();
|
2016-11-29 16:57:58 +00:00
|
|
|
|
|
|
|
CHECK_EQ(kind_, array->GetElementsKind());
|
|
|
|
CHECK_EQ(result_size, Handle<Smi>::cast(result)->value());
|
2017-07-10 12:58:27 +00:00
|
|
|
CHECK_EQ(result_size, Smi::ToInt(array->length()));
|
2020-02-11 13:18:49 +00:00
|
|
|
Handle<Object> obj =
|
|
|
|
JSObject::GetElement(isolate, array, 2).ToHandleChecked();
|
|
|
|
Handle<HeapObject> undefined_value =
|
|
|
|
Handle<HeapObject>(ReadOnlyRoots(isolate).undefined_value(), isolate);
|
|
|
|
CHECK_EQ(result_size < 3 ? *undefined_value : *o1, *obj);
|
|
|
|
obj = JSObject::GetElement(isolate, array, 3).ToHandleChecked();
|
|
|
|
CHECK_EQ(result_size < 4 ? *undefined_value : *o2, *obj);
|
|
|
|
obj = JSObject::GetElement(isolate, array, 4).ToHandleChecked();
|
|
|
|
CHECK_EQ(result_size < 5 ? *undefined_value : *o3, *obj);
|
|
|
|
obj = JSObject::GetElement(isolate, array, 5).ToHandleChecked();
|
|
|
|
CHECK_EQ(result_size < 6 ? *undefined_value : *o4, *obj);
|
2016-11-29 16:57:58 +00:00
|
|
|
}
|
|
|
|
|
2018-12-25 00:19:47 +00:00
|
|
|
static void TestAppendJSArray(Isolate* isolate, ElementsKind kind, Object o1,
|
|
|
|
Object o2, Object o3, Object o4,
|
2016-11-29 16:57:58 +00:00
|
|
|
int initial_size, int result_size) {
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
AppendJSArrayCodeStubAssembler m(asm_tester.state(), kind);
|
2020-02-11 13:18:49 +00:00
|
|
|
m.TestAppendJSArrayImpl(
|
|
|
|
isolate, &asm_tester, Handle<Object>(o1, isolate),
|
|
|
|
Handle<Object>(o2, isolate), Handle<Object>(o3, isolate),
|
|
|
|
Handle<Object>(o4, isolate), initial_size, result_size);
|
2016-11-29 16:57:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static const int kNumParams = 4;
|
|
|
|
ElementsKind kind_;
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST(BuildAppendJSArrayFastElement) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
AppendJSArrayCodeStubAssembler::TestAppendJSArray(
|
2017-06-30 11:26:14 +00:00
|
|
|
isolate, PACKED_ELEMENTS, Smi::FromInt(3), Smi::FromInt(4),
|
|
|
|
Smi::FromInt(5), Smi::FromInt(6), 6, 6);
|
2016-11-29 16:57:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BuildAppendJSArrayFastElementGrow) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
AppendJSArrayCodeStubAssembler::TestAppendJSArray(
|
2017-06-30 11:26:14 +00:00
|
|
|
isolate, PACKED_ELEMENTS, Smi::FromInt(3), Smi::FromInt(4),
|
|
|
|
Smi::FromInt(5), Smi::FromInt(6), 2, 6);
|
2016-11-29 16:57:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BuildAppendJSArrayFastSmiElement) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
AppendJSArrayCodeStubAssembler::TestAppendJSArray(
|
2017-06-30 11:26:14 +00:00
|
|
|
isolate, PACKED_SMI_ELEMENTS, Smi::FromInt(3), Smi::FromInt(4),
|
2016-11-29 16:57:58 +00:00
|
|
|
Smi::FromInt(5), Smi::FromInt(6), 6, 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BuildAppendJSArrayFastSmiElementGrow) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
AppendJSArrayCodeStubAssembler::TestAppendJSArray(
|
2017-06-30 11:26:14 +00:00
|
|
|
isolate, PACKED_SMI_ELEMENTS, Smi::FromInt(3), Smi::FromInt(4),
|
2016-11-29 16:57:58 +00:00
|
|
|
Smi::FromInt(5), Smi::FromInt(6), 2, 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BuildAppendJSArrayFastSmiElementObject) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
AppendJSArrayCodeStubAssembler::TestAppendJSArray(
|
2017-06-30 11:26:14 +00:00
|
|
|
isolate, PACKED_SMI_ELEMENTS, Smi::FromInt(3), Smi::FromInt(4),
|
2018-07-04 09:10:05 +00:00
|
|
|
ReadOnlyRoots(isolate).undefined_value(), Smi::FromInt(6), 6, 4);
|
2016-11-29 16:57:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BuildAppendJSArrayFastSmiElementObjectGrow) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
AppendJSArrayCodeStubAssembler::TestAppendJSArray(
|
2017-06-30 11:26:14 +00:00
|
|
|
isolate, PACKED_SMI_ELEMENTS, Smi::FromInt(3), Smi::FromInt(4),
|
2018-07-04 09:10:05 +00:00
|
|
|
ReadOnlyRoots(isolate).undefined_value(), Smi::FromInt(6), 2, 4);
|
2016-11-29 16:57:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BuildAppendJSArrayFastDoubleElements) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
AppendJSArrayCodeStubAssembler::TestAppendJSArray(
|
2017-06-30 11:26:14 +00:00
|
|
|
isolate, PACKED_DOUBLE_ELEMENTS, Smi::FromInt(3), Smi::FromInt(4),
|
2016-11-29 16:57:58 +00:00
|
|
|
Smi::FromInt(5), Smi::FromInt(6), 6, 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BuildAppendJSArrayFastDoubleElementsGrow) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
AppendJSArrayCodeStubAssembler::TestAppendJSArray(
|
2017-06-30 11:26:14 +00:00
|
|
|
isolate, PACKED_DOUBLE_ELEMENTS, Smi::FromInt(3), Smi::FromInt(4),
|
2016-11-29 16:57:58 +00:00
|
|
|
Smi::FromInt(5), Smi::FromInt(6), 2, 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BuildAppendJSArrayFastDoubleElementsObject) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
AppendJSArrayCodeStubAssembler::TestAppendJSArray(
|
2017-06-30 11:26:14 +00:00
|
|
|
isolate, PACKED_DOUBLE_ELEMENTS, Smi::FromInt(3), Smi::FromInt(4),
|
2018-07-04 09:10:05 +00:00
|
|
|
ReadOnlyRoots(isolate).undefined_value(), Smi::FromInt(6), 6, 4);
|
2016-11-29 16:57:58 +00:00
|
|
|
}
|
|
|
|
|
2016-12-07 10:40:45 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
template <typename Stub, typename... Args>
|
|
|
|
void Recompile(Args... args) {
|
|
|
|
Stub stub(args...);
|
|
|
|
stub.DeleteStubFromCacheForTesting();
|
|
|
|
stub.GetCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2016-12-16 19:17:16 +00:00
|
|
|
void CustomPromiseHook(v8::PromiseHookType type, v8::Local<v8::Promise> promise,
|
|
|
|
v8::Local<v8::Value> parentPromise) {}
|
|
|
|
|
2016-12-09 06:56:43 +00:00
|
|
|
TEST(IsPromiseHookEnabled) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-12-09 06:56:43 +00:00
|
|
|
|
2018-06-05 14:16:34 +00:00
|
|
|
m.Return(
|
2021-04-14 22:44:39 +00:00
|
|
|
m.SelectBooleanConstant(
|
|
|
|
m.IsIsolatePromiseHookEnabledOrHasAsyncEventDelegate()));
|
2016-12-09 06:56:43 +00:00
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-12-09 06:56:43 +00:00
|
|
|
Handle<Object> result =
|
|
|
|
ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).false_value(), *result);
|
2016-12-09 06:56:43 +00:00
|
|
|
|
2016-12-16 19:17:16 +00:00
|
|
|
isolate->SetPromiseHook(CustomPromiseHook);
|
2016-12-09 06:56:43 +00:00
|
|
|
result = ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).true_value(), *result);
|
2016-12-09 06:56:43 +00:00
|
|
|
|
2016-12-16 19:17:16 +00:00
|
|
|
isolate->SetPromiseHook(nullptr);
|
2016-12-09 06:56:43 +00:00
|
|
|
result = ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).false_value(), *result);
|
2016-12-09 06:56:43 +00:00
|
|
|
}
|
|
|
|
|
2020-01-23 16:50:05 +00:00
|
|
|
TEST(NewJSPromise) {
|
2016-12-13 02:14:07 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
PromiseBuiltinsAssembler m(asm_tester.state());
|
2016-12-13 02:14:07 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
auto context = m.Parameter<Context>(kNumParams + 2);
|
|
|
|
const TNode<JSPromise> promise = m.NewJSPromise(context);
|
2016-12-13 02:14:07 +00:00
|
|
|
m.Return(promise);
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-12-13 02:14:07 +00:00
|
|
|
Handle<Object> result =
|
|
|
|
ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
|
|
|
CHECK(result->IsJSPromise());
|
|
|
|
}
|
|
|
|
|
2020-01-23 16:50:05 +00:00
|
|
|
TEST(NewJSPromise2) {
|
2016-12-13 02:14:07 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
PromiseBuiltinsAssembler m(asm_tester.state());
|
2016-12-13 02:14:07 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
auto context = m.Parameter<Context>(kNumParams + 2);
|
2020-01-23 16:50:05 +00:00
|
|
|
const TNode<JSPromise> promise =
|
2020-09-30 17:40:39 +00:00
|
|
|
m.NewJSPromise(context, v8::Promise::kRejected, m.SmiConstant(1));
|
2016-12-13 02:14:07 +00:00
|
|
|
m.Return(promise);
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-12-13 02:14:07 +00:00
|
|
|
Handle<Object> result =
|
|
|
|
ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
|
|
|
CHECK(result->IsJSPromise());
|
|
|
|
Handle<JSPromise> js_promise = Handle<JSPromise>::cast(result);
|
2017-08-27 00:47:50 +00:00
|
|
|
CHECK_EQ(v8::Promise::kRejected, js_promise->status());
|
2016-12-13 02:14:07 +00:00
|
|
|
CHECK_EQ(Smi::FromInt(1), js_promise->result());
|
|
|
|
CHECK(!js_promise->has_handler());
|
|
|
|
}
|
|
|
|
|
2016-12-13 23:12:13 +00:00
|
|
|
TEST(IsSymbol) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-12-13 23:12:13 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
auto symbol = m.Parameter<HeapObject>(1);
|
2016-12-13 23:12:13 +00:00
|
|
|
m.Return(m.SelectBooleanConstant(m.IsSymbol(symbol)));
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-12-13 23:12:13 +00:00
|
|
|
Handle<Object> result =
|
|
|
|
ft.Call(isolate->factory()->NewSymbol()).ToHandleChecked();
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).true_value(), *result);
|
2016-12-13 23:12:13 +00:00
|
|
|
|
|
|
|
result = ft.Call(isolate->factory()->empty_string()).ToHandleChecked();
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).false_value(), *result);
|
2016-12-13 23:12:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(IsPrivateSymbol) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-12-13 23:12:13 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
auto symbol = m.Parameter<HeapObject>(1);
|
2016-12-13 23:12:13 +00:00
|
|
|
m.Return(m.SelectBooleanConstant(m.IsPrivateSymbol(symbol)));
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-12-13 23:12:13 +00:00
|
|
|
Handle<Object> result =
|
|
|
|
ft.Call(isolate->factory()->NewSymbol()).ToHandleChecked();
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).false_value(), *result);
|
2016-12-13 23:12:13 +00:00
|
|
|
|
|
|
|
result = ft.Call(isolate->factory()->empty_string()).ToHandleChecked();
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).false_value(), *result);
|
2016-12-13 23:12:13 +00:00
|
|
|
|
|
|
|
result = ft.Call(isolate->factory()->NewPrivateSymbol()).ToHandleChecked();
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).true_value(), *result);
|
2016-12-13 23:12:13 +00:00
|
|
|
}
|
|
|
|
|
2016-12-19 17:14:36 +00:00
|
|
|
TEST(PromiseHasHandler) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
PromiseBuiltinsAssembler m(asm_tester.state());
|
2016-12-19 17:14:36 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
auto context = m.Parameter<Context>(kNumParams + 2);
|
2019-10-30 17:54:06 +00:00
|
|
|
const TNode<JSPromise> promise =
|
2020-09-30 17:40:39 +00:00
|
|
|
m.NewJSPromise(context, m.UndefinedConstant());
|
2016-12-19 17:14:36 +00:00
|
|
|
m.Return(m.SelectBooleanConstant(m.PromiseHasHandler(promise)));
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-12-19 17:14:36 +00:00
|
|
|
Handle<Object> result =
|
|
|
|
ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).false_value(), *result);
|
2016-12-19 17:14:36 +00:00
|
|
|
}
|
|
|
|
|
2016-12-19 22:21:35 +00:00
|
|
|
TEST(CreatePromiseResolvingFunctionsContext) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2020-07-15 11:03:22 +00:00
|
|
|
const int kNumParams = 0;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
PromiseBuiltinsAssembler m(asm_tester.state());
|
2016-12-19 22:21:35 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
const auto context = m.Parameter<Context>(kNumParams + 3);
|
2019-10-30 17:54:06 +00:00
|
|
|
const TNode<NativeContext> native_context = m.LoadNativeContext(context);
|
2019-09-19 09:22:35 +00:00
|
|
|
const TNode<JSPromise> promise =
|
2020-01-23 16:50:05 +00:00
|
|
|
m.NewJSPromise(context, m.UndefinedConstant());
|
2019-10-30 17:54:06 +00:00
|
|
|
const TNode<Context> promise_context =
|
2019-10-01 10:06:22 +00:00
|
|
|
m.CreatePromiseResolvingFunctionsContext(
|
2020-01-21 15:15:35 +00:00
|
|
|
context, promise, m.BooleanConstant(false), native_context);
|
2016-12-19 22:21:35 +00:00
|
|
|
m.Return(promise_context);
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2020-07-15 11:03:22 +00:00
|
|
|
Handle<Object> result = ft.Call().ToHandleChecked();
|
2016-12-19 22:21:35 +00:00
|
|
|
CHECK(result->IsContext());
|
|
|
|
Handle<Context> context_js = Handle<Context>::cast(result);
|
2020-07-01 13:32:55 +00:00
|
|
|
CHECK_EQ(isolate->root(RootIndex::kEmptyScopeInfo), context_js->scope_info());
|
2016-12-19 22:21:35 +00:00
|
|
|
CHECK_EQ(*isolate->native_context(), context_js->native_context());
|
2018-12-13 09:46:59 +00:00
|
|
|
CHECK(context_js->get(PromiseBuiltins::kPromiseSlot).IsJSPromise());
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).false_value(),
|
2018-12-13 09:46:59 +00:00
|
|
|
context_js->get(PromiseBuiltins::kDebugEventSlot));
|
2016-12-19 22:21:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CreatePromiseResolvingFunctions) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
PromiseBuiltinsAssembler m(asm_tester.state());
|
2016-12-19 22:21:35 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
auto context = m.Parameter<Context>(kNumParams + 2);
|
2019-10-30 17:54:06 +00:00
|
|
|
const TNode<NativeContext> native_context = m.LoadNativeContext(context);
|
2019-09-19 09:22:35 +00:00
|
|
|
const TNode<JSPromise> promise =
|
2020-09-30 17:40:39 +00:00
|
|
|
m.NewJSPromise(context, m.UndefinedConstant());
|
2019-10-30 16:35:38 +00:00
|
|
|
PromiseResolvingFunctions funcs = m.CreatePromiseResolvingFunctions(
|
2020-09-30 17:40:39 +00:00
|
|
|
context, promise, m.BooleanConstant(false), native_context);
|
2021-02-12 15:15:52 +00:00
|
|
|
TNode<JSFunction> resolve = funcs.resolve;
|
|
|
|
TNode<JSFunction> reject = funcs.reject;
|
2019-08-22 09:56:32 +00:00
|
|
|
TNode<IntPtrT> const kSize = m.IntPtrConstant(2);
|
2018-08-13 15:08:55 +00:00
|
|
|
TNode<FixedArray> const arr =
|
|
|
|
m.Cast(m.AllocateFixedArray(PACKED_ELEMENTS, kSize));
|
2016-12-19 22:21:35 +00:00
|
|
|
m.StoreFixedArrayElement(arr, 0, resolve);
|
|
|
|
m.StoreFixedArrayElement(arr, 1, reject);
|
|
|
|
m.Return(arr);
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-12-19 22:21:35 +00:00
|
|
|
Handle<Object> result_obj =
|
|
|
|
ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
|
|
|
CHECK(result_obj->IsFixedArray());
|
|
|
|
Handle<FixedArray> result_arr = Handle<FixedArray>::cast(result_obj);
|
|
|
|
CHECK(result_arr->get(0).IsJSFunction());
|
|
|
|
CHECK(result_arr->get(1).IsJSFunction());
|
|
|
|
}
|
|
|
|
|
2017-01-10 01:48:11 +00:00
|
|
|
TEST(NewElementsCapacity) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, 2);
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.SmiTag(
|
|
|
|
m.CalculateNewElementsCapacity(m.SmiUntag(m.Parameter<Smi>(1)))));
|
2017-07-18 13:45:08 +00:00
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), 1);
|
2020-07-15 11:03:22 +00:00
|
|
|
Handle<Smi> test_value = Handle<Smi>(Smi::FromInt(1), isolate);
|
2017-07-18 13:45:08 +00:00
|
|
|
Handle<Smi> result_obj = ft.CallChecked<Smi>(test_value);
|
2017-01-10 01:48:11 +00:00
|
|
|
CHECK_EQ(
|
|
|
|
result_obj->value(),
|
|
|
|
static_cast<int>(JSObject::NewElementsCapacity(test_value->value())));
|
|
|
|
test_value = Handle<Smi>(Smi::FromInt(1), isolate);
|
2017-07-18 13:45:08 +00:00
|
|
|
result_obj = ft.CallChecked<Smi>(test_value);
|
2017-01-10 01:48:11 +00:00
|
|
|
CHECK_EQ(
|
|
|
|
result_obj->value(),
|
|
|
|
static_cast<int>(JSObject::NewElementsCapacity(test_value->value())));
|
|
|
|
test_value = Handle<Smi>(Smi::FromInt(2), isolate);
|
2017-07-18 13:45:08 +00:00
|
|
|
result_obj = ft.CallChecked<Smi>(test_value);
|
2017-01-10 01:48:11 +00:00
|
|
|
CHECK_EQ(
|
|
|
|
result_obj->value(),
|
|
|
|
static_cast<int>(JSObject::NewElementsCapacity(test_value->value())));
|
|
|
|
test_value = Handle<Smi>(Smi::FromInt(1025), isolate);
|
2017-07-18 13:45:08 +00:00
|
|
|
result_obj = ft.CallChecked<Smi>(test_value);
|
2017-01-10 01:48:11 +00:00
|
|
|
CHECK_EQ(
|
|
|
|
result_obj->value(),
|
|
|
|
static_cast<int>(JSObject::NewElementsCapacity(test_value->value())));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(NewElementsCapacitySmi) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, 2);
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.CalculateNewElementsCapacity(m.UncheckedParameter<Smi>(1)));
|
2017-07-18 13:45:08 +00:00
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), 1);
|
2017-01-10 01:48:11 +00:00
|
|
|
Handle<Smi> test_value = Handle<Smi>(Smi::FromInt(0), isolate);
|
2017-07-18 13:45:08 +00:00
|
|
|
Handle<Smi> result_obj = ft.CallChecked<Smi>(test_value);
|
2017-01-10 01:48:11 +00:00
|
|
|
CHECK_EQ(
|
|
|
|
result_obj->value(),
|
|
|
|
static_cast<int>(JSObject::NewElementsCapacity(test_value->value())));
|
|
|
|
test_value = Handle<Smi>(Smi::FromInt(1), isolate);
|
2017-07-18 13:45:08 +00:00
|
|
|
result_obj = ft.CallChecked<Smi>(test_value);
|
2017-01-10 01:48:11 +00:00
|
|
|
CHECK_EQ(
|
|
|
|
result_obj->value(),
|
|
|
|
static_cast<int>(JSObject::NewElementsCapacity(test_value->value())));
|
|
|
|
test_value = Handle<Smi>(Smi::FromInt(2), isolate);
|
2017-07-18 13:45:08 +00:00
|
|
|
result_obj = ft.CallChecked<Smi>(test_value);
|
2017-01-10 01:48:11 +00:00
|
|
|
CHECK_EQ(
|
|
|
|
result_obj->value(),
|
|
|
|
static_cast<int>(JSObject::NewElementsCapacity(test_value->value())));
|
|
|
|
test_value = Handle<Smi>(Smi::FromInt(1025), isolate);
|
2017-07-18 13:45:08 +00:00
|
|
|
result_obj = ft.CallChecked<Smi>(test_value);
|
2017-01-10 01:48:11 +00:00
|
|
|
CHECK_EQ(
|
|
|
|
result_obj->value(),
|
|
|
|
static_cast<int>(JSObject::NewElementsCapacity(test_value->value())));
|
|
|
|
}
|
|
|
|
|
2016-12-19 22:21:35 +00:00
|
|
|
TEST(AllocateFunctionWithMapAndContext) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
PromiseBuiltinsAssembler m(asm_tester.state());
|
2016-12-19 22:21:35 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
const auto context = m.Parameter<Context>(kNumParams + 2);
|
2019-10-30 17:54:06 +00:00
|
|
|
const TNode<NativeContext> native_context = m.LoadNativeContext(context);
|
2019-09-19 09:22:35 +00:00
|
|
|
const TNode<JSPromise> promise =
|
2020-01-23 16:50:05 +00:00
|
|
|
m.NewJSPromise(context, m.UndefinedConstant());
|
2019-10-01 10:06:22 +00:00
|
|
|
TNode<Context> promise_context = m.CreatePromiseResolvingFunctionsContext(
|
2020-01-21 15:15:35 +00:00
|
|
|
context, promise, m.BooleanConstant(false), native_context);
|
2020-05-12 07:17:49 +00:00
|
|
|
TNode<Object> resolve_info =
|
|
|
|
m.PromiseCapabilityDefaultResolveSharedFunConstant();
|
2019-10-30 17:54:06 +00:00
|
|
|
const TNode<Object> map = m.LoadContextElement(
|
2016-12-19 22:21:35 +00:00
|
|
|
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
|
2019-10-30 17:54:06 +00:00
|
|
|
const TNode<JSFunction> resolve = m.AllocateFunctionWithMapAndContext(
|
2019-10-01 10:06:22 +00:00
|
|
|
m.CAST(map), m.CAST(resolve_info), promise_context);
|
2016-12-19 22:21:35 +00:00
|
|
|
m.Return(resolve);
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-12-19 22:21:35 +00:00
|
|
|
Handle<Object> result_obj =
|
|
|
|
ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
|
|
|
CHECK(result_obj->IsJSFunction());
|
|
|
|
Handle<JSFunction> fun = Handle<JSFunction>::cast(result_obj);
|
2018-07-04 09:10:05 +00:00
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).empty_property_array(),
|
|
|
|
fun->property_array());
|
|
|
|
CHECK_EQ(ReadOnlyRoots(isolate).empty_fixed_array(), fun->elements());
|
2018-12-05 17:31:16 +00:00
|
|
|
CHECK_EQ(isolate->heap()->many_closures_cell(), fun->raw_feedback_cell());
|
2017-10-12 15:37:46 +00:00
|
|
|
CHECK(!fun->has_prototype_slot());
|
2020-05-12 07:17:49 +00:00
|
|
|
CHECK_EQ(*isolate->factory()->promise_capability_default_resolve_shared_fun(),
|
[builtins] Refactor the promise resolution and rejection logic.
This introduces dedicated builtins
- FulfillPromise,
- RejectPromise, and
- ResolvePromise,
which perform the corresponding operations from the language
specification, and removes the redundant entry points and the
excessive inlining of these operations into other builtins. We
also add the same logic on the C++ side, so that we don't need
to go into JavaScript land when resolving/rejecting from the
API.
The C++ side has a complete implementation, including full support
for the debugger and the current PromiseHook machinery. This is to
avoid constantly crossing the boundary for those cases, and to also
simplify the CSA side (and soon the TurboFan side), where we only
do the fast-path and bail out to the runtime for the general handling.
On top of this we introduce %_RejectPromise and %_ResolvePromise,
which are entry points used by the bytecode and parser desugarings
for async functions, and also used by the V8 Extras API. Thanks to
this we can uniformly optimize these in TurboFan, where we have
corresponding operators JSRejectPromise and JSResolvePromise, which
currently just call into the builtins, but middle-term can be further
optimized, i.e. to skip the "then" lookup for JSResolvePromise when
we know something about the resolution.
In TurboFan we can also already inline the default PromiseCapability
[[Reject]] and [[Resolve]] functions, although this is not as effective
as it can be right now, until we have inlining support for the Promise
constructor (being worked on by petermarshall@ right now) and/or SFI
based CALL_IC feedback.
Overall this change is meant as a refactoring without significant
performance impact anywhere; it seems to improve performance of
simple async functions a bit, but otherwise is neutral.
Bug: v8:7253
Change-Id: Id0b979f9b2843560e38cd8df4b02627dad4b6d8c
Reviewed-on: https://chromium-review.googlesource.com/911632
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51260}
2018-02-12 19:10:29 +00:00
|
|
|
fun->shared());
|
2020-05-12 07:17:49 +00:00
|
|
|
CHECK_EQ(isolate->factory()
|
|
|
|
->promise_capability_default_resolve_shared_fun()
|
|
|
|
->GetCode(),
|
[builtins] Refactor the promise resolution and rejection logic.
This introduces dedicated builtins
- FulfillPromise,
- RejectPromise, and
- ResolvePromise,
which perform the corresponding operations from the language
specification, and removes the redundant entry points and the
excessive inlining of these operations into other builtins. We
also add the same logic on the C++ side, so that we don't need
to go into JavaScript land when resolving/rejecting from the
API.
The C++ side has a complete implementation, including full support
for the debugger and the current PromiseHook machinery. This is to
avoid constantly crossing the boundary for those cases, and to also
simplify the CSA side (and soon the TurboFan side), where we only
do the fast-path and bail out to the runtime for the general handling.
On top of this we introduce %_RejectPromise and %_ResolvePromise,
which are entry points used by the bytecode and parser desugarings
for async functions, and also used by the V8 Extras API. Thanks to
this we can uniformly optimize these in TurboFan, where we have
corresponding operators JSRejectPromise and JSResolvePromise, which
currently just call into the builtins, but middle-term can be further
optimized, i.e. to skip the "then" lookup for JSResolvePromise when
we know something about the resolution.
In TurboFan we can also already inline the default PromiseCapability
[[Reject]] and [[Resolve]] functions, although this is not as effective
as it can be right now, until we have inlining support for the Promise
constructor (being worked on by petermarshall@ right now) and/or SFI
based CALL_IC feedback.
Overall this change is meant as a refactoring without significant
performance impact anywhere; it seems to improve performance of
simple async functions a bit, but otherwise is neutral.
Bug: v8:7253
Change-Id: Id0b979f9b2843560e38cd8df4b02627dad4b6d8c
Reviewed-on: https://chromium-review.googlesource.com/911632
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51260}
2018-02-12 19:10:29 +00:00
|
|
|
fun->code());
|
2016-12-19 22:21:35 +00:00
|
|
|
}
|
|
|
|
|
2017-01-02 17:22:30 +00:00
|
|
|
TEST(CreatePromiseGetCapabilitiesExecutorContext) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
PromiseBuiltinsAssembler m(asm_tester.state());
|
2017-01-02 17:22:30 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
auto context = m.Parameter<Context>(kNumParams + 2);
|
2019-11-14 00:46:24 +00:00
|
|
|
TNode<NativeContext> native_context = m.LoadNativeContext(context);
|
2017-01-02 17:22:30 +00:00
|
|
|
|
2019-11-14 00:46:24 +00:00
|
|
|
TNode<PromiseCapability> capability = m.CreatePromiseCapability(
|
|
|
|
m.UndefinedConstant(), m.UndefinedConstant(), m.UndefinedConstant());
|
|
|
|
TNode<Context> executor_context =
|
|
|
|
m.CreatePromiseCapabilitiesExecutorContext(native_context, capability);
|
2017-01-02 17:22:30 +00:00
|
|
|
m.Return(executor_context);
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2017-01-02 17:22:30 +00:00
|
|
|
Handle<Object> result_obj =
|
|
|
|
ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
|
|
|
CHECK(result_obj->IsContext());
|
|
|
|
Handle<Context> context_js = Handle<Context>::cast(result_obj);
|
2018-12-13 09:46:59 +00:00
|
|
|
CHECK_EQ(PromiseBuiltins::kCapabilitiesContextLength, context_js->length());
|
2020-07-01 13:32:55 +00:00
|
|
|
CHECK_EQ(isolate->root(RootIndex::kEmptyScopeInfo), context_js->scope_info());
|
2017-01-02 17:22:30 +00:00
|
|
|
CHECK_EQ(*isolate->native_context(), context_js->native_context());
|
2018-12-13 09:46:59 +00:00
|
|
|
CHECK(
|
|
|
|
context_js->get(PromiseBuiltins::kCapabilitySlot).IsPromiseCapability());
|
2017-01-02 17:22:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(NewPromiseCapability) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
{ // Builtin Promise
|
2020-07-15 11:03:22 +00:00
|
|
|
const int kNumParams = 0;
|
|
|
|
CodeAssemblerTester asm_tester(isolate,
|
|
|
|
kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
PromiseBuiltinsAssembler m(asm_tester.state());
|
2017-01-02 17:22:30 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
auto context = m.Parameter<Context>(kNumParams + 3);
|
2019-10-30 17:54:06 +00:00
|
|
|
const TNode<NativeContext> native_context = m.LoadNativeContext(context);
|
|
|
|
const TNode<Object> promise_constructor =
|
2017-01-02 17:22:30 +00:00
|
|
|
m.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
|
|
|
|
|
2019-10-30 17:54:06 +00:00
|
|
|
const TNode<Oddball> debug_event = m.TrueConstant();
|
|
|
|
const TNode<Object> capability =
|
2021-06-07 15:24:12 +00:00
|
|
|
m.CallBuiltin(Builtin::kNewPromiseCapability, context,
|
2018-02-08 16:36:52 +00:00
|
|
|
promise_constructor, debug_event);
|
2017-01-02 17:22:30 +00:00
|
|
|
m.Return(capability);
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2017-01-02 17:22:30 +00:00
|
|
|
|
2020-07-15 11:03:22 +00:00
|
|
|
Handle<Object> result_obj = ft.Call().ToHandleChecked();
|
2017-08-30 17:03:38 +00:00
|
|
|
CHECK(result_obj->IsPromiseCapability());
|
|
|
|
Handle<PromiseCapability> result =
|
|
|
|
Handle<PromiseCapability>::cast(result_obj);
|
2017-01-02 17:22:30 +00:00
|
|
|
|
|
|
|
CHECK(result->promise().IsJSPromise());
|
|
|
|
CHECK(result->resolve().IsJSFunction());
|
|
|
|
CHECK(result->reject().IsJSFunction());
|
2020-05-12 07:17:49 +00:00
|
|
|
CHECK_EQ(
|
|
|
|
*isolate->factory()->promise_capability_default_reject_shared_fun(),
|
|
|
|
JSFunction::cast(result->reject()).shared());
|
|
|
|
CHECK_EQ(
|
|
|
|
*isolate->factory()->promise_capability_default_resolve_shared_fun(),
|
|
|
|
JSFunction::cast(result->resolve()).shared());
|
2017-01-02 17:22:30 +00:00
|
|
|
|
|
|
|
Handle<JSFunction> callbacks[] = {
|
2018-06-11 09:53:20 +00:00
|
|
|
handle(JSFunction::cast(result->resolve()), isolate),
|
|
|
|
handle(JSFunction::cast(result->reject()), isolate)};
|
2017-01-02 17:22:30 +00:00
|
|
|
|
|
|
|
for (auto&& callback : callbacks) {
|
2018-06-23 09:05:50 +00:00
|
|
|
Handle<Context> context(Context::cast(callback->context()), isolate);
|
2020-07-01 13:32:55 +00:00
|
|
|
CHECK_EQ(isolate->root(RootIndex::kEmptyScopeInfo),
|
|
|
|
context->scope_info());
|
2017-01-02 17:22:30 +00:00
|
|
|
CHECK_EQ(*isolate->native_context(), context->native_context());
|
2018-12-13 09:46:59 +00:00
|
|
|
CHECK_EQ(PromiseBuiltins::kPromiseContextLength, context->length());
|
|
|
|
CHECK_EQ(context->get(PromiseBuiltins::kPromiseSlot), result->promise());
|
2017-01-02 17:22:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{ // Custom Promise
|
2020-07-15 11:03:22 +00:00
|
|
|
const int kNumParams = 1;
|
|
|
|
CodeAssemblerTester asm_tester(isolate,
|
|
|
|
kNumParams + 1); // Include receiver.
|
2017-07-18 13:45:08 +00:00
|
|
|
PromiseBuiltinsAssembler m(asm_tester.state());
|
2017-01-02 17:22:30 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
auto context = m.Parameter<Context>(kNumParams + 3);
|
2017-01-02 17:22:30 +00:00
|
|
|
|
2020-09-30 17:40:39 +00:00
|
|
|
auto constructor = m.Parameter<Object>(1);
|
2019-10-30 17:54:06 +00:00
|
|
|
const TNode<Oddball> debug_event = m.TrueConstant();
|
|
|
|
const TNode<Object> capability = m.CallBuiltin(
|
2021-06-07 15:24:12 +00:00
|
|
|
Builtin::kNewPromiseCapability, context, constructor, debug_event);
|
2017-01-02 17:22:30 +00:00
|
|
|
m.Return(capability);
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2017-01-02 17:22:30 +00:00
|
|
|
|
|
|
|
Handle<JSFunction> constructor_fn =
|
|
|
|
Handle<JSFunction>::cast(v8::Utils::OpenHandle(*CompileRun(
|
|
|
|
"(function FakePromise(executor) {"
|
|
|
|
" var self = this;"
|
|
|
|
" function resolve(value) { self.resolvedValue = value; }"
|
|
|
|
" function reject(reason) { self.rejectedReason = reason; }"
|
|
|
|
" executor(resolve, reject);"
|
|
|
|
"})")));
|
|
|
|
|
2020-07-15 11:03:22 +00:00
|
|
|
Handle<Object> result_obj = ft.Call(constructor_fn).ToHandleChecked();
|
2017-08-30 17:03:38 +00:00
|
|
|
CHECK(result_obj->IsPromiseCapability());
|
|
|
|
Handle<PromiseCapability> result =
|
|
|
|
Handle<PromiseCapability>::cast(result_obj);
|
2017-01-02 17:22:30 +00:00
|
|
|
|
|
|
|
CHECK(result->promise().IsJSObject());
|
2018-06-23 09:05:50 +00:00
|
|
|
Handle<JSObject> promise(JSObject::cast(result->promise()), isolate);
|
2021-04-27 10:36:45 +00:00
|
|
|
CHECK_EQ(constructor_fn->prototype_or_initial_map(kAcquireLoad),
|
|
|
|
promise->map());
|
2017-01-02 17:22:30 +00:00
|
|
|
CHECK(result->resolve().IsJSFunction());
|
|
|
|
CHECK(result->reject().IsJSFunction());
|
|
|
|
|
|
|
|
Handle<String> resolved_str =
|
|
|
|
isolate->factory()->NewStringFromAsciiChecked("resolvedStr");
|
|
|
|
Handle<String> rejected_str =
|
|
|
|
isolate->factory()->NewStringFromAsciiChecked("rejectedStr");
|
|
|
|
|
|
|
|
Handle<Object> argv1[] = {resolved_str};
|
|
|
|
Handle<Object> ret =
|
|
|
|
Execution::Call(isolate, handle(result->resolve(), isolate),
|
|
|
|
isolate->factory()->undefined_value(), 1, argv1)
|
|
|
|
.ToHandleChecked();
|
|
|
|
|
|
|
|
Handle<Object> prop1 =
|
|
|
|
JSReceiver::GetProperty(isolate, promise, "resolvedValue")
|
|
|
|
.ToHandleChecked();
|
|
|
|
CHECK_EQ(*resolved_str, *prop1);
|
|
|
|
|
|
|
|
Handle<Object> argv2[] = {rejected_str};
|
|
|
|
ret = Execution::Call(isolate, handle(result->reject(), isolate),
|
|
|
|
isolate->factory()->undefined_value(), 1, argv2)
|
|
|
|
.ToHandleChecked();
|
|
|
|
Handle<Object> prop2 =
|
|
|
|
JSReceiver::GetProperty(isolate, promise, "rejectedReason")
|
|
|
|
.ToHandleChecked();
|
|
|
|
CHECK_EQ(*rejected_str, *prop2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-13 23:34:36 +00:00
|
|
|
TEST(DirectMemoryTest8BitWord32Immediate) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 0;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-01-13 23:34:36 +00:00
|
|
|
int8_t buffer[] = {1, 2, 4, 8, 17, 33, 65, 127};
|
|
|
|
const int element_count = 8;
|
|
|
|
Label bad(&m);
|
|
|
|
|
2020-01-07 13:54:09 +00:00
|
|
|
TNode<RawPtrT> buffer_node = m.PointerConstant(buffer);
|
2017-01-13 23:34:36 +00:00
|
|
|
for (size_t i = 0; i < element_count; ++i) {
|
|
|
|
for (size_t j = 0; j < element_count; ++j) {
|
2020-01-07 13:54:09 +00:00
|
|
|
TNode<Uint8T> loaded =
|
|
|
|
m.LoadBufferData<Uint8T>(buffer_node, static_cast<int>(i));
|
2019-08-22 09:56:32 +00:00
|
|
|
TNode<Word32T> masked = m.Word32And(loaded, m.Int32Constant(buffer[j]));
|
2017-01-13 23:34:36 +00:00
|
|
|
if ((buffer[j] & buffer[i]) != 0) {
|
|
|
|
m.GotoIf(m.Word32Equal(masked, m.Int32Constant(0)), &bad);
|
|
|
|
} else {
|
|
|
|
m.GotoIf(m.Word32NotEqual(masked, m.Int32Constant(0)), &bad);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m.Return(m.SmiConstant(1));
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&bad);
|
2017-01-13 23:34:36 +00:00
|
|
|
m.Return(m.SmiConstant(0));
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
CHECK_EQ(1, ft.CallChecked<Smi>()->value());
|
2017-01-13 23:34:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(DirectMemoryTest16BitWord32Immediate) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 0;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-01-13 23:34:36 +00:00
|
|
|
int16_t buffer[] = {156, 2234, 4544, 8444, 1723, 3888, 658, 1278};
|
|
|
|
const int element_count = 8;
|
|
|
|
Label bad(&m);
|
|
|
|
|
2020-01-07 13:54:09 +00:00
|
|
|
TNode<RawPtrT> buffer_node = m.PointerConstant(buffer);
|
2017-01-13 23:34:36 +00:00
|
|
|
for (size_t i = 0; i < element_count; ++i) {
|
|
|
|
for (size_t j = 0; j < element_count; ++j) {
|
2020-01-07 13:54:09 +00:00
|
|
|
TNode<Uint16T> loaded = m.LoadBufferData<Uint16T>(
|
|
|
|
buffer_node, static_cast<int>(i * sizeof(int16_t)));
|
2019-08-22 09:56:32 +00:00
|
|
|
TNode<Word32T> masked = m.Word32And(loaded, m.Int32Constant(buffer[j]));
|
2017-01-13 23:34:36 +00:00
|
|
|
if ((buffer[j] & buffer[i]) != 0) {
|
|
|
|
m.GotoIf(m.Word32Equal(masked, m.Int32Constant(0)), &bad);
|
|
|
|
} else {
|
|
|
|
m.GotoIf(m.Word32NotEqual(masked, m.Int32Constant(0)), &bad);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m.Return(m.SmiConstant(1));
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&bad);
|
2017-01-13 23:34:36 +00:00
|
|
|
m.Return(m.SmiConstant(0));
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
CHECK_EQ(1, ft.CallChecked<Smi>()->value());
|
2017-01-13 23:34:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(DirectMemoryTest8BitWord32) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 0;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-01-13 23:34:36 +00:00
|
|
|
int8_t buffer[] = {1, 2, 4, 8, 17, 33, 65, 127, 67, 38};
|
|
|
|
const int element_count = 10;
|
|
|
|
Label bad(&m);
|
2020-01-07 13:54:09 +00:00
|
|
|
TNode<Uint32T> constants[element_count];
|
2017-01-13 23:34:36 +00:00
|
|
|
|
2020-01-07 13:54:09 +00:00
|
|
|
TNode<RawPtrT> buffer_node = m.PointerConstant(buffer);
|
2017-01-13 23:34:36 +00:00
|
|
|
for (size_t i = 0; i < element_count; ++i) {
|
2020-01-07 13:54:09 +00:00
|
|
|
constants[i] = m.LoadBufferData<Uint8T>(buffer_node, static_cast<int>(i));
|
2017-01-13 23:34:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < element_count; ++i) {
|
|
|
|
for (size_t j = 0; j < element_count; ++j) {
|
2020-01-07 13:54:09 +00:00
|
|
|
TNode<Uint8T> loaded =
|
|
|
|
m.LoadBufferData<Uint8T>(buffer_node, static_cast<int>(i));
|
2019-08-22 09:56:32 +00:00
|
|
|
TNode<Word32T> masked = m.Word32And(loaded, constants[j]);
|
2017-01-13 23:34:36 +00:00
|
|
|
if ((buffer[j] & buffer[i]) != 0) {
|
|
|
|
m.GotoIf(m.Word32Equal(masked, m.Int32Constant(0)), &bad);
|
|
|
|
} else {
|
|
|
|
m.GotoIf(m.Word32NotEqual(masked, m.Int32Constant(0)), &bad);
|
|
|
|
}
|
|
|
|
|
|
|
|
masked = m.Word32And(constants[i], constants[j]);
|
|
|
|
if ((buffer[j] & buffer[i]) != 0) {
|
|
|
|
m.GotoIf(m.Word32Equal(masked, m.Int32Constant(0)), &bad);
|
|
|
|
} else {
|
|
|
|
m.GotoIf(m.Word32NotEqual(masked, m.Int32Constant(0)), &bad);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m.Return(m.SmiConstant(1));
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&bad);
|
2017-01-13 23:34:36 +00:00
|
|
|
m.Return(m.SmiConstant(0));
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
CHECK_EQ(1, ft.CallChecked<Smi>()->value());
|
2017-01-13 23:34:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(DirectMemoryTest16BitWord32) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 0;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-01-13 23:34:36 +00:00
|
|
|
int16_t buffer[] = {1, 2, 4, 8, 12345, 33, 65, 255, 67, 3823};
|
|
|
|
const int element_count = 10;
|
|
|
|
Label bad(&m);
|
2020-01-07 13:54:09 +00:00
|
|
|
TNode<Uint32T> constants[element_count];
|
2017-01-13 23:34:36 +00:00
|
|
|
|
2020-01-07 13:54:09 +00:00
|
|
|
TNode<RawPtrT> buffer_node1 = m.PointerConstant(buffer);
|
2017-01-13 23:34:36 +00:00
|
|
|
for (size_t i = 0; i < element_count; ++i) {
|
2020-01-07 13:54:09 +00:00
|
|
|
constants[i] = m.LoadBufferData<Uint16T>(
|
|
|
|
buffer_node1, static_cast<int>(i * sizeof(int16_t)));
|
2017-01-13 23:34:36 +00:00
|
|
|
}
|
2020-01-07 13:54:09 +00:00
|
|
|
TNode<RawPtrT> buffer_node2 = m.PointerConstant(buffer);
|
2017-01-13 23:34:36 +00:00
|
|
|
|
|
|
|
for (size_t i = 0; i < element_count; ++i) {
|
|
|
|
for (size_t j = 0; j < element_count; ++j) {
|
2021-03-01 18:05:53 +00:00
|
|
|
TNode<Uint16T> loaded = m.LoadBufferData<Uint16T>(
|
2020-01-07 13:54:09 +00:00
|
|
|
buffer_node1, static_cast<int>(i * sizeof(int16_t)));
|
2019-08-22 09:56:32 +00:00
|
|
|
TNode<Word32T> masked = m.Word32And(loaded, constants[j]);
|
2017-01-13 23:34:36 +00:00
|
|
|
if ((buffer[j] & buffer[i]) != 0) {
|
|
|
|
m.GotoIf(m.Word32Equal(masked, m.Int32Constant(0)), &bad);
|
|
|
|
} else {
|
|
|
|
m.GotoIf(m.Word32NotEqual(masked, m.Int32Constant(0)), &bad);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Force a memory access relative to a high-number register.
|
2020-01-07 13:54:09 +00:00
|
|
|
loaded = m.LoadBufferData<Uint16T>(buffer_node2,
|
|
|
|
static_cast<int>(i * sizeof(int16_t)));
|
2017-01-13 23:34:36 +00:00
|
|
|
masked = m.Word32And(loaded, constants[j]);
|
|
|
|
if ((buffer[j] & buffer[i]) != 0) {
|
|
|
|
m.GotoIf(m.Word32Equal(masked, m.Int32Constant(0)), &bad);
|
|
|
|
} else {
|
|
|
|
m.GotoIf(m.Word32NotEqual(masked, m.Int32Constant(0)), &bad);
|
|
|
|
}
|
|
|
|
|
|
|
|
masked = m.Word32And(constants[i], constants[j]);
|
|
|
|
if ((buffer[j] & buffer[i]) != 0) {
|
|
|
|
m.GotoIf(m.Word32Equal(masked, m.Int32Constant(0)), &bad);
|
|
|
|
} else {
|
|
|
|
m.GotoIf(m.Word32NotEqual(masked, m.Int32Constant(0)), &bad);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m.Return(m.SmiConstant(1));
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&bad);
|
2017-01-13 23:34:36 +00:00
|
|
|
m.Return(m.SmiConstant(0));
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
CHECK_EQ(1, ft.CallChecked<Smi>()->value());
|
2017-01-13 23:34:36 +00:00
|
|
|
}
|
|
|
|
|
2017-07-24 12:12:34 +00:00
|
|
|
TEST(LoadJSArrayElementsMap) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-07-24 12:12:34 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
auto context = m.Parameter<Context>(kNumParams + 3);
|
2019-09-04 08:50:59 +00:00
|
|
|
TNode<NativeContext> native_context = m.LoadNativeContext(context);
|
2020-09-30 17:40:39 +00:00
|
|
|
TNode<Int32T> kind = m.SmiToInt32(m.Parameter<Smi>(1));
|
2017-07-24 12:12:34 +00:00
|
|
|
m.Return(m.LoadJSArrayElementsMap(kind, native_context));
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
for (int kind = 0; kind <= HOLEY_DOUBLE_ELEMENTS; kind++) {
|
|
|
|
Handle<Map> csa_result =
|
|
|
|
ft.CallChecked<Map>(handle(Smi::FromInt(kind), isolate));
|
|
|
|
ElementsKind elements_kind = static_cast<ElementsKind>(kind);
|
|
|
|
Handle<Map> result(
|
2018-06-23 09:05:50 +00:00
|
|
|
isolate->native_context()->GetInitialJSArrayMap(elements_kind),
|
|
|
|
isolate);
|
2017-07-24 12:12:34 +00:00
|
|
|
CHECK_EQ(*csa_result, *result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-05 20:29:59 +00:00
|
|
|
TEST(IsWhiteSpaceOrLineTerminator) {
|
2017-09-05 02:19:29 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-09-05 02:19:29 +00:00
|
|
|
|
|
|
|
{ // Returns true if whitespace, false otherwise.
|
2020-11-05 20:29:59 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
Label if_true(&m), if_false(&m);
|
2020-12-04 09:57:13 +00:00
|
|
|
m.Branch(m.IsWhiteSpaceOrLineTerminator(
|
|
|
|
m.UncheckedCast<Uint16T>(m.SmiToInt32(m.Parameter<Smi>(1)))),
|
2020-11-05 20:29:59 +00:00
|
|
|
&if_true, &if_false);
|
|
|
|
m.BIND(&if_true);
|
2017-09-05 02:19:29 +00:00
|
|
|
m.Return(m.TrueConstant());
|
2020-11-05 20:29:59 +00:00
|
|
|
m.BIND(&if_false);
|
2017-09-05 02:19:29 +00:00
|
|
|
m.Return(m.FalseConstant());
|
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<Object> true_value = ft.true_value();
|
|
|
|
Handle<Object> false_value = ft.false_value();
|
|
|
|
|
2021-06-24 13:32:01 +00:00
|
|
|
for (base::uc16 c = 0; c < 0xFFFF; c++) {
|
2017-09-05 02:19:29 +00:00
|
|
|
Handle<Object> expected_value =
|
2018-11-14 14:14:58 +00:00
|
|
|
IsWhiteSpaceOrLineTerminator(c) ? true_value : false_value;
|
2017-09-05 02:19:29 +00:00
|
|
|
ft.CheckCall(expected_value, handle(Smi::FromInt(c), isolate));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-13 00:12:10 +00:00
|
|
|
TEST(BranchIfNumberRelationalComparison) {
|
2017-09-15 12:07:23 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
Factory* f = isolate->factory();
|
|
|
|
const int kNumParams = 2;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-09-15 12:07:23 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
Label return_true(&m), return_false(&m);
|
2020-09-30 17:40:39 +00:00
|
|
|
m.BranchIfNumberRelationalComparison(
|
|
|
|
Operation::kGreaterThanOrEqual, m.Parameter<Number>(1),
|
|
|
|
m.Parameter<Number>(2), &return_true, &return_false);
|
2017-09-15 12:07:23 +00:00
|
|
|
m.BIND(&return_true);
|
|
|
|
m.Return(m.BooleanConstant(true));
|
|
|
|
m.BIND(&return_false);
|
|
|
|
m.Return(m.BooleanConstant(false));
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
ft.CheckTrue(f->NewNumber(0), f->NewNumber(0));
|
|
|
|
ft.CheckTrue(f->NewNumber(1), f->NewNumber(0));
|
|
|
|
ft.CheckTrue(f->NewNumber(1), f->NewNumber(1));
|
|
|
|
ft.CheckFalse(f->NewNumber(0), f->NewNumber(1));
|
|
|
|
ft.CheckFalse(f->NewNumber(-1), f->NewNumber(0));
|
|
|
|
ft.CheckTrue(f->NewNumber(-1), f->NewNumber(-1));
|
|
|
|
|
|
|
|
ft.CheckTrue(f->NewNumber(-1), f->NewNumber(-1.5));
|
|
|
|
ft.CheckFalse(f->NewNumber(-1.5), f->NewNumber(-1));
|
|
|
|
ft.CheckTrue(f->NewNumber(-1.5), f->NewNumber(-1.5));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(IsNumberArrayIndex) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-09-15 12:07:23 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
auto number = m.Parameter<Number>(1);
|
2018-06-13 14:56:16 +00:00
|
|
|
m.Return(
|
|
|
|
m.SmiFromInt32(m.UncheckedCast<Int32T>(m.IsNumberArrayIndex(number))));
|
2017-09-15 12:07:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
double indices[] = {Smi::kMinValue,
|
|
|
|
-11,
|
|
|
|
-1,
|
|
|
|
0,
|
|
|
|
1,
|
|
|
|
2,
|
|
|
|
Smi::kMaxValue,
|
|
|
|
-11.0,
|
|
|
|
-11.1,
|
|
|
|
-2.0,
|
|
|
|
-1.0,
|
|
|
|
-0.0,
|
|
|
|
0.0,
|
|
|
|
0.00001,
|
|
|
|
0.1,
|
|
|
|
1,
|
|
|
|
2,
|
|
|
|
Smi::kMinValue - 1.0,
|
|
|
|
Smi::kMinValue + 1.0,
|
|
|
|
Smi::kMinValue + 1.2,
|
|
|
|
kMaxInt + 1.2,
|
|
|
|
kMaxInt - 10.0,
|
|
|
|
kMaxInt - 1.0,
|
|
|
|
kMaxInt,
|
|
|
|
kMaxInt + 1.0,
|
|
|
|
kMaxInt + 10.0};
|
|
|
|
|
|
|
|
for (size_t i = 0; i < arraysize(indices); i++) {
|
|
|
|
Handle<Object> index = isolate->factory()->NewNumber(indices[i]);
|
|
|
|
uint32_t array_index;
|
|
|
|
CHECK_EQ(index->ToArrayIndex(&array_index),
|
|
|
|
(ft.CallChecked<Smi>(index)->value() == 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-05 07:58:19 +00:00
|
|
|
TEST(NumberMinMax) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 2;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester_min(isolate,
|
|
|
|
kNumParams + 1); // Include receiver.
|
2017-10-05 07:58:19 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester_min.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.NumberMin(m.Parameter<Number>(1), m.Parameter<Number>(2)));
|
2017-10-05 07:58:19 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft_min(asm_tester_min.GenerateCode(), kNumParams);
|
|
|
|
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester_max(isolate,
|
|
|
|
kNumParams + 1); // Include receiver.
|
2017-10-05 07:58:19 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester_max.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.NumberMax(m.Parameter<Number>(1), m.Parameter<Number>(2)));
|
2017-10-05 07:58:19 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft_max(asm_tester_max.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
// Test smi values.
|
|
|
|
Handle<Smi> smi_1(Smi::FromInt(1), isolate);
|
|
|
|
Handle<Smi> smi_2(Smi::FromInt(2), isolate);
|
|
|
|
Handle<Smi> smi_5(Smi::FromInt(5), isolate);
|
|
|
|
CHECK_EQ(ft_min.CallChecked<Smi>(smi_1, smi_2)->value(), 1);
|
|
|
|
CHECK_EQ(ft_min.CallChecked<Smi>(smi_2, smi_1)->value(), 1);
|
|
|
|
CHECK_EQ(ft_max.CallChecked<Smi>(smi_1, smi_2)->value(), 2);
|
|
|
|
CHECK_EQ(ft_max.CallChecked<Smi>(smi_2, smi_1)->value(), 2);
|
|
|
|
|
|
|
|
// Test double values.
|
|
|
|
Handle<Object> double_a = isolate->factory()->NewNumber(2.5);
|
|
|
|
Handle<Object> double_b = isolate->factory()->NewNumber(3.5);
|
|
|
|
Handle<Object> nan =
|
|
|
|
isolate->factory()->NewNumber(std::numeric_limits<double>::quiet_NaN());
|
|
|
|
Handle<Object> infinity = isolate->factory()->NewNumber(V8_INFINITY);
|
|
|
|
|
|
|
|
CHECK_EQ(ft_min.CallChecked<HeapNumber>(double_a, double_b)->value(), 2.5);
|
|
|
|
CHECK_EQ(ft_min.CallChecked<HeapNumber>(double_b, double_a)->value(), 2.5);
|
|
|
|
CHECK_EQ(ft_min.CallChecked<HeapNumber>(infinity, double_a)->value(), 2.5);
|
|
|
|
CHECK_EQ(ft_min.CallChecked<HeapNumber>(double_a, infinity)->value(), 2.5);
|
|
|
|
CHECK(std::isnan(ft_min.CallChecked<HeapNumber>(nan, double_a)->value()));
|
|
|
|
CHECK(std::isnan(ft_min.CallChecked<HeapNumber>(double_a, nan)->value()));
|
|
|
|
|
|
|
|
CHECK_EQ(ft_max.CallChecked<HeapNumber>(double_a, double_b)->value(), 3.5);
|
|
|
|
CHECK_EQ(ft_max.CallChecked<HeapNumber>(double_b, double_a)->value(), 3.5);
|
|
|
|
CHECK_EQ(ft_max.CallChecked<HeapNumber>(infinity, double_a)->value(),
|
|
|
|
V8_INFINITY);
|
|
|
|
CHECK_EQ(ft_max.CallChecked<HeapNumber>(double_a, infinity)->value(),
|
|
|
|
V8_INFINITY);
|
|
|
|
CHECK(std::isnan(ft_max.CallChecked<HeapNumber>(nan, double_a)->value()));
|
|
|
|
CHECK(std::isnan(ft_max.CallChecked<HeapNumber>(double_a, nan)->value()));
|
|
|
|
|
|
|
|
// Mixed smi/double values.
|
|
|
|
CHECK_EQ(ft_max.CallChecked<HeapNumber>(smi_1, double_b)->value(), 3.5);
|
|
|
|
CHECK_EQ(ft_max.CallChecked<HeapNumber>(double_b, smi_1)->value(), 3.5);
|
|
|
|
CHECK_EQ(ft_min.CallChecked<HeapNumber>(smi_5, double_b)->value(), 3.5);
|
|
|
|
CHECK_EQ(ft_min.CallChecked<HeapNumber>(double_b, smi_5)->value(), 3.5);
|
|
|
|
}
|
|
|
|
|
2017-10-06 06:36:02 +00:00
|
|
|
TEST(NumberAddSub) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 2;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester_add(isolate,
|
|
|
|
kNumParams + 1); // Include receiver.
|
2017-10-06 06:36:02 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester_add.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.NumberAdd(m.Parameter<Number>(1), m.Parameter<Number>(2)));
|
2017-10-06 06:36:02 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft_add(asm_tester_add.GenerateCode(), kNumParams);
|
|
|
|
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester_sub(isolate,
|
|
|
|
kNumParams + 1); // Include receiver.
|
2017-10-06 06:36:02 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester_sub.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.NumberSub(m.Parameter<Number>(1), m.Parameter<Number>(2)));
|
2017-10-06 06:36:02 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft_sub(asm_tester_sub.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
// Test smi values.
|
|
|
|
Handle<Smi> smi_1(Smi::FromInt(1), isolate);
|
|
|
|
Handle<Smi> smi_2(Smi::FromInt(2), isolate);
|
|
|
|
CHECK_EQ(ft_add.CallChecked<Smi>(smi_1, smi_2)->value(), 3);
|
|
|
|
CHECK_EQ(ft_sub.CallChecked<Smi>(smi_2, smi_1)->value(), 1);
|
|
|
|
|
|
|
|
// Test double values.
|
|
|
|
Handle<Object> double_a = isolate->factory()->NewNumber(2.5);
|
|
|
|
Handle<Object> double_b = isolate->factory()->NewNumber(3.0);
|
|
|
|
CHECK_EQ(ft_add.CallChecked<HeapNumber>(double_a, double_b)->value(), 5.5);
|
|
|
|
CHECK_EQ(ft_sub.CallChecked<HeapNumber>(double_a, double_b)->value(), -.5);
|
|
|
|
|
|
|
|
// Test overflow.
|
|
|
|
Handle<Smi> smi_max(Smi::FromInt(Smi::kMaxValue), isolate);
|
|
|
|
Handle<Smi> smi_min(Smi::FromInt(Smi::kMinValue), isolate);
|
|
|
|
CHECK_EQ(ft_add.CallChecked<HeapNumber>(smi_max, smi_1)->value(),
|
|
|
|
static_cast<double>(Smi::kMaxValue) + 1);
|
|
|
|
CHECK_EQ(ft_sub.CallChecked<HeapNumber>(smi_min, smi_1)->value(),
|
|
|
|
static_cast<double>(Smi::kMinValue) - 1);
|
|
|
|
|
|
|
|
// Test mixed smi/double values.
|
|
|
|
CHECK_EQ(ft_add.CallChecked<HeapNumber>(smi_1, double_a)->value(), 3.5);
|
|
|
|
CHECK_EQ(ft_add.CallChecked<HeapNumber>(double_a, smi_1)->value(), 3.5);
|
|
|
|
CHECK_EQ(ft_sub.CallChecked<HeapNumber>(smi_1, double_a)->value(), -1.5);
|
|
|
|
CHECK_EQ(ft_sub.CallChecked<HeapNumber>(double_a, smi_1)->value(), 1.5);
|
|
|
|
}
|
|
|
|
|
2017-10-17 06:54:48 +00:00
|
|
|
TEST(CloneEmptyFixedArray) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-10-17 06:54:48 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.CloneFixedArray(m.Parameter<FixedArrayBase>(1)));
|
2017-10-17 06:54:48 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<FixedArray> source(isolate->factory()->empty_fixed_array());
|
|
|
|
Handle<Object> result_raw = ft.Call(source).ToHandleChecked();
|
2018-11-25 02:24:43 +00:00
|
|
|
FixedArray result(FixedArray::cast(*result_raw));
|
2017-10-17 06:54:48 +00:00
|
|
|
CHECK_EQ(0, result.length());
|
|
|
|
CHECK_EQ(*(isolate->factory()->empty_fixed_array()), result);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CloneFixedArray) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-10-17 06:54:48 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.CloneFixedArray(m.Parameter<FixedArrayBase>(1)));
|
2017-10-17 06:54:48 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<FixedArray> source(isolate->factory()->NewFixedArrayWithHoles(5));
|
|
|
|
source->set(1, Smi::FromInt(1234));
|
|
|
|
Handle<Object> result_raw = ft.Call(source).ToHandleChecked();
|
2018-11-25 02:24:43 +00:00
|
|
|
FixedArray result(FixedArray::cast(*result_raw));
|
2017-10-17 06:54:48 +00:00
|
|
|
CHECK_EQ(5, result.length());
|
|
|
|
CHECK(result.get(0).IsTheHole(isolate));
|
|
|
|
CHECK_EQ(Smi::cast(result.get(1)).value(), 1234);
|
|
|
|
CHECK(result.get(2).IsTheHole(isolate));
|
|
|
|
CHECK(result.get(3).IsTheHole(isolate));
|
|
|
|
CHECK(result.get(4).IsTheHole(isolate));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CloneFixedArrayCOW) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-10-17 06:54:48 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.CloneFixedArray(m.Parameter<FixedArrayBase>(1)));
|
2017-10-17 06:54:48 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<FixedArray> source(isolate->factory()->NewFixedArrayWithHoles(5));
|
|
|
|
source->set(1, Smi::FromInt(1234));
|
2018-07-04 09:10:05 +00:00
|
|
|
source->set_map(ReadOnlyRoots(isolate).fixed_cow_array_map());
|
2017-10-17 06:54:48 +00:00
|
|
|
Handle<Object> result_raw = ft.Call(source).ToHandleChecked();
|
2018-11-25 02:24:43 +00:00
|
|
|
FixedArray result(FixedArray::cast(*result_raw));
|
2017-10-17 06:54:48 +00:00
|
|
|
CHECK_EQ(*source, result);
|
|
|
|
}
|
|
|
|
|
2017-10-19 14:17:56 +00:00
|
|
|
TEST(ExtractFixedArrayCOWForceCopy) {
|
2017-10-17 06:54:48 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-10-17 06:54:48 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
CodeStubAssembler::ExtractFixedArrayFlags flags;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kAllFixedArrays;
|
2020-07-29 08:59:45 +00:00
|
|
|
base::Optional<TNode<Smi>> constant(m.SmiConstant(0));
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.ExtractFixedArray(m.Parameter<FixedArrayBase>(1), constant,
|
2020-07-29 08:59:45 +00:00
|
|
|
base::Optional<TNode<Smi>>(base::nullopt),
|
|
|
|
base::Optional<TNode<Smi>>(base::nullopt),
|
|
|
|
flags));
|
2017-10-17 06:54:48 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<FixedArray> source(isolate->factory()->NewFixedArrayWithHoles(5));
|
|
|
|
source->set(1, Smi::FromInt(1234));
|
2018-07-04 09:10:05 +00:00
|
|
|
source->set_map(ReadOnlyRoots(isolate).fixed_cow_array_map());
|
2017-10-17 06:54:48 +00:00
|
|
|
Handle<Object> result_raw = ft.Call(source).ToHandleChecked();
|
2018-11-25 02:24:43 +00:00
|
|
|
FixedArray result(FixedArray::cast(*result_raw));
|
2017-10-17 06:54:48 +00:00
|
|
|
CHECK_NE(*source, result);
|
|
|
|
CHECK_EQ(5, result.length());
|
|
|
|
CHECK(result.get(0).IsTheHole(isolate));
|
|
|
|
CHECK_EQ(Smi::cast(result.get(1)).value(), 1234);
|
|
|
|
CHECK(result.get(2).IsTheHole(isolate));
|
|
|
|
CHECK(result.get(3).IsTheHole(isolate));
|
|
|
|
CHECK(result.get(4).IsTheHole(isolate));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ExtractFixedArraySimple) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 3;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-10-17 06:54:48 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-10-19 14:17:56 +00:00
|
|
|
CodeStubAssembler::ExtractFixedArrayFlags flags;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kAllFixedArrays;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kDontCopyCOW;
|
2020-09-30 17:40:39 +00:00
|
|
|
base::Optional<TNode<IntPtrT>> p1_untagged(m.SmiUntag(m.Parameter<Smi>(2)));
|
|
|
|
base::Optional<TNode<IntPtrT>> p2_untagged(m.SmiUntag(m.Parameter<Smi>(3)));
|
2020-07-29 08:59:45 +00:00
|
|
|
m.Return(m.ExtractFixedArray(
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Parameter<FixedArrayBase>(1), p1_untagged, p2_untagged,
|
2020-07-29 08:59:45 +00:00
|
|
|
base::Optional<TNode<IntPtrT>>(base::nullopt), flags));
|
2017-10-17 06:54:48 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<FixedArray> source(isolate->factory()->NewFixedArrayWithHoles(5));
|
|
|
|
source->set(1, Smi::FromInt(1234));
|
|
|
|
Handle<Object> result_raw =
|
|
|
|
ft.Call(source, Handle<Smi>(Smi::FromInt(1), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(2), isolate))
|
|
|
|
.ToHandleChecked();
|
2018-11-25 02:24:43 +00:00
|
|
|
FixedArray result(FixedArray::cast(*result_raw));
|
2017-10-17 06:54:48 +00:00
|
|
|
CHECK_EQ(2, result.length());
|
|
|
|
CHECK_EQ(Smi::cast(result.get(0)).value(), 1234);
|
|
|
|
CHECK(result.get(1).IsTheHole(isolate));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ExtractFixedArraySimpleSmiConstant) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-10-17 06:54:48 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-10-19 14:17:56 +00:00
|
|
|
CodeStubAssembler::ExtractFixedArrayFlags flags;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kAllFixedArrays;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kDontCopyCOW;
|
2020-07-29 08:59:45 +00:00
|
|
|
base::Optional<TNode<Smi>> constant_1(m.SmiConstant(1));
|
|
|
|
base::Optional<TNode<Smi>> constant_2(m.SmiConstant(2));
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.ExtractFixedArray(
|
|
|
|
m.Parameter<FixedArrayBase>(1), constant_1, constant_2,
|
|
|
|
base::Optional<TNode<Smi>>(base::nullopt), flags));
|
2017-10-17 06:54:48 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<FixedArray> source(isolate->factory()->NewFixedArrayWithHoles(5));
|
|
|
|
source->set(1, Smi::FromInt(1234));
|
|
|
|
Handle<Object> result_raw = ft.Call(source).ToHandleChecked();
|
2018-11-25 02:24:43 +00:00
|
|
|
FixedArray result(FixedArray::cast(*result_raw));
|
2017-10-17 06:54:48 +00:00
|
|
|
CHECK_EQ(2, result.length());
|
|
|
|
CHECK_EQ(Smi::cast(result.get(0)).value(), 1234);
|
|
|
|
CHECK(result.get(1).IsTheHole(isolate));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ExtractFixedArraySimpleIntPtrConstant) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-10-17 06:54:48 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-10-19 14:17:56 +00:00
|
|
|
CodeStubAssembler::ExtractFixedArrayFlags flags;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kAllFixedArrays;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kDontCopyCOW;
|
2020-07-29 08:59:45 +00:00
|
|
|
base::Optional<TNode<IntPtrT>> constant_1(m.IntPtrConstant(1));
|
|
|
|
base::Optional<TNode<IntPtrT>> constant_2(m.IntPtrConstant(2));
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Return(m.ExtractFixedArray(
|
|
|
|
m.Parameter<FixedArrayBase>(1), constant_1, constant_2,
|
|
|
|
base::Optional<TNode<IntPtrT>>(base::nullopt), flags));
|
2017-10-17 06:54:48 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<FixedArray> source(isolate->factory()->NewFixedArrayWithHoles(5));
|
|
|
|
source->set(1, Smi::FromInt(1234));
|
|
|
|
Handle<Object> result_raw = ft.Call(source).ToHandleChecked();
|
2018-11-25 02:24:43 +00:00
|
|
|
FixedArray result(FixedArray::cast(*result_raw));
|
2017-10-17 06:54:48 +00:00
|
|
|
CHECK_EQ(2, result.length());
|
|
|
|
CHECK_EQ(Smi::cast(result.get(0)).value(), 1234);
|
|
|
|
CHECK(result.get(1).IsTheHole(isolate));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ExtractFixedArraySimpleIntPtrConstantNoDoubles) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-10-17 06:54:48 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-07-29 08:59:45 +00:00
|
|
|
base::Optional<TNode<IntPtrT>> constant_1(m.IntPtrConstant(1));
|
|
|
|
base::Optional<TNode<IntPtrT>> constant_2(m.IntPtrConstant(2));
|
2017-10-17 06:54:48 +00:00
|
|
|
m.Return(m.ExtractFixedArray(
|
2020-09-30 17:40:39 +00:00
|
|
|
m.Parameter<FixedArrayBase>(1), constant_1, constant_2,
|
2020-07-29 08:59:45 +00:00
|
|
|
base::Optional<TNode<IntPtrT>>(base::nullopt),
|
|
|
|
CodeStubAssembler::ExtractFixedArrayFlag::kFixedArrays));
|
2017-10-17 06:54:48 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<FixedArray> source(isolate->factory()->NewFixedArrayWithHoles(5));
|
|
|
|
source->set(1, Smi::FromInt(1234));
|
|
|
|
Handle<Object> result_raw = ft.Call(source).ToHandleChecked();
|
2018-11-25 02:24:43 +00:00
|
|
|
FixedArray result(FixedArray::cast(*result_raw));
|
2017-10-17 06:54:48 +00:00
|
|
|
CHECK_EQ(2, result.length());
|
|
|
|
CHECK_EQ(Smi::cast(result.get(0)).value(), 1234);
|
|
|
|
CHECK(result.get(1).IsTheHole(isolate));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ExtractFixedArraySimpleIntPtrParameters) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 3;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2017-10-17 06:54:48 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
base::Optional<TNode<IntPtrT>> p1_untagged(m.SmiUntag(m.Parameter<Smi>(2)));
|
|
|
|
base::Optional<TNode<IntPtrT>> p2_untagged(m.SmiUntag(m.Parameter<Smi>(3)));
|
|
|
|
m.Return(m.ExtractFixedArray(m.Parameter<FixedArrayBase>(1), p1_untagged,
|
|
|
|
p2_untagged));
|
2017-10-17 06:54:48 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<FixedArray> source(isolate->factory()->NewFixedArrayWithHoles(5));
|
|
|
|
source->set(1, Smi::FromInt(1234));
|
|
|
|
Handle<Object> result_raw =
|
|
|
|
ft.Call(source, Handle<Smi>(Smi::FromInt(1), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(2), isolate))
|
|
|
|
.ToHandleChecked();
|
2018-11-25 02:24:43 +00:00
|
|
|
FixedArray result(FixedArray::cast(*result_raw));
|
2017-10-17 06:54:48 +00:00
|
|
|
CHECK_EQ(2, result.length());
|
|
|
|
CHECK_EQ(Smi::cast(result.get(0)).value(), 1234);
|
|
|
|
CHECK(result.get(1).IsTheHole(isolate));
|
|
|
|
|
2018-04-09 19:11:22 +00:00
|
|
|
Handle<FixedDoubleArray> source_double = Handle<FixedDoubleArray>::cast(
|
|
|
|
isolate->factory()->NewFixedDoubleArray(5));
|
2017-10-17 06:54:48 +00:00
|
|
|
source_double->set(0, 10);
|
|
|
|
source_double->set(1, 11);
|
|
|
|
source_double->set(2, 12);
|
|
|
|
source_double->set(3, 13);
|
|
|
|
source_double->set(4, 14);
|
|
|
|
Handle<Object> double_result_raw =
|
|
|
|
ft.Call(source_double, Handle<Smi>(Smi::FromInt(1), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(2), isolate))
|
|
|
|
.ToHandleChecked();
|
2018-11-24 02:42:52 +00:00
|
|
|
FixedDoubleArray double_result = FixedDoubleArray::cast(*double_result_raw);
|
2017-10-17 06:54:48 +00:00
|
|
|
CHECK_EQ(2, double_result.length());
|
|
|
|
CHECK_EQ(double_result.get_scalar(0), 11);
|
|
|
|
CHECK_EQ(double_result.get_scalar(1), 12);
|
|
|
|
}
|
|
|
|
|
2018-03-20 10:29:37 +00:00
|
|
|
TEST(SingleInputPhiElimination) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 2;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-07-10 13:52:47 +00:00
|
|
|
TVariable<Smi> temp1(&m);
|
|
|
|
TVariable<Smi> temp2(&m);
|
2018-03-20 10:29:37 +00:00
|
|
|
Label temp_label(&m, {&temp1, &temp2});
|
|
|
|
Label end_label(&m, {&temp1, &temp2});
|
2020-09-30 17:40:39 +00:00
|
|
|
temp1 = m.Parameter<Smi>(1);
|
|
|
|
temp2 = m.Parameter<Smi>(1);
|
|
|
|
m.Branch(m.TaggedEqual(m.UncheckedParameter<Object>(0),
|
|
|
|
m.UncheckedParameter<Object>(1)),
|
2019-08-23 12:40:12 +00:00
|
|
|
&end_label, &temp_label);
|
2018-03-20 10:29:37 +00:00
|
|
|
m.BIND(&temp_label);
|
2020-09-30 17:40:39 +00:00
|
|
|
temp1 = m.Parameter<Smi>(2);
|
|
|
|
temp2 = m.Parameter<Smi>(2);
|
2018-03-20 10:29:37 +00:00
|
|
|
m.Goto(&end_label);
|
|
|
|
m.BIND(&end_label);
|
2019-11-27 17:32:26 +00:00
|
|
|
m.Return(m.UncheckedCast<Object>(temp1.value()));
|
2018-03-20 10:29:37 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
// Generating code without an assert is enough to make sure that the
|
|
|
|
// single-input phi is properly eliminated.
|
|
|
|
}
|
|
|
|
|
2018-06-27 16:52:37 +00:00
|
|
|
TEST(SmallOrderedHashMapAllocate) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2018-06-27 16:52:37 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
auto capacity = m.Parameter<Smi>(1);
|
2019-12-20 11:45:14 +00:00
|
|
|
m.Return(m.AllocateSmallOrderedHashMap(m.SmiToIntPtr(capacity)));
|
2018-06-27 16:52:37 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
int capacity = SmallOrderedHashMap::kMinCapacity;
|
|
|
|
while (capacity <= SmallOrderedHashMap::kMaxCapacity) {
|
|
|
|
Handle<SmallOrderedHashMap> expected =
|
|
|
|
factory->NewSmallOrderedHashMap(capacity);
|
|
|
|
Handle<Object> result_raw =
|
|
|
|
ft.Call(Handle<Smi>(Smi::FromInt(capacity), isolate)).ToHandleChecked();
|
|
|
|
Handle<SmallOrderedHashMap> actual = Handle<SmallOrderedHashMap>(
|
|
|
|
SmallOrderedHashMap::cast(*result_raw), isolate);
|
|
|
|
CHECK_EQ(capacity, actual->Capacity());
|
|
|
|
CHECK_EQ(0, actual->NumberOfElements());
|
|
|
|
CHECK_EQ(0, actual->NumberOfDeletedElements());
|
|
|
|
CHECK_EQ(capacity / SmallOrderedHashMap::kLoadFactor,
|
|
|
|
actual->NumberOfBuckets());
|
2018-07-18 20:17:21 +00:00
|
|
|
CHECK_EQ(0, memcmp(reinterpret_cast<void*>(expected->address()),
|
|
|
|
reinterpret_cast<void*>(actual->address()),
|
|
|
|
SmallOrderedHashMap::SizeFor(capacity)));
|
2018-06-27 16:52:37 +00:00
|
|
|
#ifdef VERIFY_HEAP
|
2019-04-04 08:51:47 +00:00
|
|
|
actual->SmallOrderedHashMapVerify(isolate);
|
2018-06-27 16:52:37 +00:00
|
|
|
#endif
|
|
|
|
capacity = capacity << 1;
|
|
|
|
}
|
|
|
|
#ifdef VERIFY_HEAP
|
|
|
|
isolate->heap()->Verify();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SmallOrderedHashSetAllocate) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2018-06-27 16:52:37 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
auto capacity = m.Parameter<Smi>(1);
|
2019-12-20 11:45:14 +00:00
|
|
|
m.Return(m.AllocateSmallOrderedHashSet(m.SmiToIntPtr(capacity)));
|
2018-06-27 16:52:37 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
int capacity = SmallOrderedHashSet::kMinCapacity;
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
while (capacity <= SmallOrderedHashSet::kMaxCapacity) {
|
|
|
|
Handle<SmallOrderedHashSet> expected =
|
|
|
|
factory->NewSmallOrderedHashSet(capacity);
|
|
|
|
Handle<Object> result_raw =
|
|
|
|
ft.Call(Handle<Smi>(Smi::FromInt(capacity), isolate)).ToHandleChecked();
|
|
|
|
Handle<SmallOrderedHashSet> actual = Handle<SmallOrderedHashSet>(
|
|
|
|
SmallOrderedHashSet::cast(*result_raw), isolate);
|
|
|
|
CHECK_EQ(capacity, actual->Capacity());
|
|
|
|
CHECK_EQ(0, actual->NumberOfElements());
|
|
|
|
CHECK_EQ(0, actual->NumberOfDeletedElements());
|
|
|
|
CHECK_EQ(capacity / SmallOrderedHashSet::kLoadFactor,
|
|
|
|
actual->NumberOfBuckets());
|
2018-07-18 20:17:21 +00:00
|
|
|
CHECK_EQ(0, memcmp(reinterpret_cast<void*>(expected->address()),
|
|
|
|
reinterpret_cast<void*>(actual->address()),
|
|
|
|
SmallOrderedHashSet::SizeFor(capacity)));
|
2018-06-27 16:52:37 +00:00
|
|
|
#ifdef VERIFY_HEAP
|
2019-04-04 08:51:47 +00:00
|
|
|
actual->SmallOrderedHashSetVerify(isolate);
|
2018-06-27 16:52:37 +00:00
|
|
|
#endif
|
|
|
|
capacity = capacity << 1;
|
|
|
|
}
|
|
|
|
#ifdef VERIFY_HEAP
|
|
|
|
isolate->heap()->Verify();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-06-12 11:11:44 +00:00
|
|
|
TEST(IsDoubleElementsKind) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 2;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester ft_tester(isolate, kNumParams + 1); // Include receiver.
|
2018-06-12 11:11:44 +00:00
|
|
|
{
|
|
|
|
CodeStubAssembler m(ft_tester.state());
|
|
|
|
m.Return(m.SmiFromInt32(m.UncheckedCast<Int32T>(
|
2020-09-30 17:40:39 +00:00
|
|
|
m.IsDoubleElementsKind(m.SmiToInt32(m.Parameter<Smi>(1))))));
|
2018-06-12 11:11:44 +00:00
|
|
|
}
|
|
|
|
FunctionTester ft(ft_tester.GenerateCode(), kNumParams);
|
|
|
|
CHECK_EQ(
|
|
|
|
(*Handle<Smi>::cast(
|
|
|
|
ft.Call(Handle<Smi>(Smi::FromInt(PACKED_DOUBLE_ELEMENTS), isolate))
|
|
|
|
.ToHandleChecked()))
|
|
|
|
.value(),
|
|
|
|
1);
|
|
|
|
CHECK_EQ(
|
|
|
|
(*Handle<Smi>::cast(
|
|
|
|
ft.Call(Handle<Smi>(Smi::FromInt(HOLEY_DOUBLE_ELEMENTS), isolate))
|
|
|
|
.ToHandleChecked()))
|
|
|
|
.value(),
|
|
|
|
1);
|
|
|
|
CHECK_EQ((*Handle<Smi>::cast(
|
|
|
|
ft.Call(Handle<Smi>(Smi::FromInt(HOLEY_ELEMENTS), isolate))
|
|
|
|
.ToHandleChecked()))
|
|
|
|
.value(),
|
|
|
|
0);
|
|
|
|
CHECK_EQ((*Handle<Smi>::cast(
|
|
|
|
ft.Call(Handle<Smi>(Smi::FromInt(PACKED_ELEMENTS), isolate))
|
|
|
|
.ToHandleChecked()))
|
|
|
|
.value(),
|
|
|
|
0);
|
|
|
|
CHECK_EQ((*Handle<Smi>::cast(
|
|
|
|
ft.Call(Handle<Smi>(Smi::FromInt(PACKED_SMI_ELEMENTS), isolate))
|
|
|
|
.ToHandleChecked()))
|
|
|
|
.value(),
|
|
|
|
0);
|
|
|
|
CHECK_EQ((*Handle<Smi>::cast(
|
|
|
|
ft.Call(Handle<Smi>(Smi::FromInt(HOLEY_SMI_ELEMENTS), isolate))
|
|
|
|
.ToHandleChecked()))
|
|
|
|
.value(),
|
|
|
|
0);
|
|
|
|
CHECK_EQ((*Handle<Smi>::cast(
|
|
|
|
ft.Call(Handle<Smi>(Smi::FromInt(DICTIONARY_ELEMENTS), isolate))
|
|
|
|
.ToHandleChecked()))
|
|
|
|
.value(),
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
2018-08-02 11:16:52 +00:00
|
|
|
TEST(TestCallBuiltinInlineTrampoline) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2018-08-02 11:16:52 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
2020-07-15 11:03:22 +00:00
|
|
|
const int kContextOffset = 3;
|
2020-09-30 17:40:39 +00:00
|
|
|
auto str = m.Parameter<String>(1);
|
|
|
|
auto context = m.Parameter<Context>(kNumParams + kContextOffset);
|
2018-08-02 11:16:52 +00:00
|
|
|
|
2019-08-22 09:56:32 +00:00
|
|
|
TNode<Smi> index = m.SmiConstant(2);
|
2018-08-02 11:16:52 +00:00
|
|
|
|
2021-06-07 15:24:12 +00:00
|
|
|
m.Return(m.CallStub(Builtins::CallableFor(isolate, Builtin::kStringRepeat),
|
2018-08-02 11:16:52 +00:00
|
|
|
context, str, index));
|
|
|
|
AssemblerOptions options = AssemblerOptions::Default(isolate);
|
|
|
|
options.inline_offheap_trampolines = true;
|
|
|
|
options.use_pc_relative_calls_and_jumps = false;
|
|
|
|
options.isolate_independent_code = false;
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(options), kNumParams);
|
2020-05-26 11:17:38 +00:00
|
|
|
MaybeHandle<Object> result = ft.Call(CcTest::MakeString("abcdef"));
|
|
|
|
CHECK(String::Equals(isolate, CcTest::MakeString("abcdefabcdef"),
|
2018-08-02 11:16:52 +00:00
|
|
|
Handle<String>::cast(result.ToHandleChecked())));
|
|
|
|
}
|
|
|
|
|
2019-11-04 10:01:19 +00:00
|
|
|
// TODO(v8:9821): Remove the option to disable inlining off-heap trampolines
|
|
|
|
// along with this test.
|
|
|
|
DISABLED_TEST(TestCallBuiltinIndirectLoad) {
|
2018-08-02 11:16:52 +00:00
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
const int kContextOffset = 2;
|
2020-09-30 17:40:39 +00:00
|
|
|
auto str = m.Parameter<String>(0);
|
|
|
|
auto context = m.Parameter<Context>(kNumParams + kContextOffset);
|
2018-08-02 11:16:52 +00:00
|
|
|
|
2019-08-22 09:56:32 +00:00
|
|
|
TNode<Smi> index = m.SmiConstant(2);
|
2018-08-02 11:16:52 +00:00
|
|
|
|
2021-06-07 15:24:12 +00:00
|
|
|
m.Return(m.CallStub(Builtins::CallableFor(isolate, Builtin::kStringRepeat),
|
2018-08-02 11:16:52 +00:00
|
|
|
context, str, index));
|
|
|
|
AssemblerOptions options = AssemblerOptions::Default(isolate);
|
|
|
|
options.inline_offheap_trampolines = false;
|
|
|
|
options.use_pc_relative_calls_and_jumps = false;
|
|
|
|
options.isolate_independent_code = true;
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(options), kNumParams);
|
2020-05-26 11:17:38 +00:00
|
|
|
MaybeHandle<Object> result = ft.Call(CcTest::MakeString("abcdef"));
|
|
|
|
CHECK(String::Equals(isolate, CcTest::MakeString("abcdefabcdef"),
|
2018-08-02 11:16:52 +00:00
|
|
|
Handle<String>::cast(result.ToHandleChecked())));
|
|
|
|
}
|
|
|
|
|
2019-10-18 09:20:52 +00:00
|
|
|
TEST(InstructionSchedulingCallerSavedRegisters) {
|
|
|
|
// This is a regression test for v8:9775, where TF's instruction scheduler
|
|
|
|
// incorrectly moved pure operations in between a ArchSaveCallerRegisters and
|
|
|
|
// a ArchRestoreCallerRegisters instruction.
|
|
|
|
bool old_turbo_instruction_scheduling = FLAG_turbo_instruction_scheduling;
|
|
|
|
FLAG_turbo_instruction_scheduling = true;
|
|
|
|
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2019-10-18 09:20:52 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
{
|
2021-02-22 16:56:41 +00:00
|
|
|
TNode<IntPtrT> x = m.SmiUntag(m.Parameter<Smi>(1));
|
|
|
|
TNode<WordT> y = m.WordOr(m.WordShr(x, 1), m.IntPtrConstant(1));
|
2019-10-18 09:20:52 +00:00
|
|
|
TNode<ExternalReference> isolate_ptr =
|
|
|
|
m.ExternalConstant(ExternalReference::isolate_address(isolate));
|
|
|
|
m.CallCFunctionWithCallerSavedRegisters(
|
|
|
|
m.ExternalConstant(
|
|
|
|
ExternalReference::smi_lexicographic_compare_function()),
|
2021-05-11 09:03:52 +00:00
|
|
|
MachineType::Int32(), SaveFPRegsMode::kSave,
|
2019-10-18 09:20:52 +00:00
|
|
|
std::make_pair(MachineType::Pointer(), isolate_ptr),
|
|
|
|
std::make_pair(MachineType::TaggedSigned(), m.SmiConstant(0)),
|
|
|
|
std::make_pair(MachineType::TaggedSigned(), m.SmiConstant(0)));
|
|
|
|
m.Return(m.SmiTag(m.Signed(m.WordOr(x, y))));
|
|
|
|
}
|
|
|
|
|
|
|
|
AssemblerOptions options = AssemblerOptions::Default(isolate);
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(options), kNumParams);
|
|
|
|
Handle<Object> input = isolate->factory()->NewNumber(8);
|
|
|
|
MaybeHandle<Object> result = ft.Call(input);
|
|
|
|
CHECK(result.ToHandleChecked()->IsSmi());
|
|
|
|
CHECK_EQ(result.ToHandleChecked()->Number(), 13);
|
|
|
|
|
|
|
|
FLAG_turbo_instruction_scheduling = old_turbo_instruction_scheduling;
|
|
|
|
}
|
|
|
|
|
Reland "[no-wasm] Exclude src/wasm from compilation"
This is a reland of 80f5dfda0147d6b078ae6c9d0eb947bd012bf72d. A condition
in pipeline.cc was inverted, which lead to a CSA verifier error.
Original change's description:
> [no-wasm] Exclude src/wasm from compilation
>
> This is the biggest chunk, including
> - all of src/wasm,
> - torque file for wasm objects,
> - torque file for wasm builtins,
> - wasm builtins,
> - wasm runtime functions,
> - int64 lowering,
> - simd scala lowering,
> - WasmGraphBuilder (TF graph construction for wasm),
> - wasm frame types,
> - wasm interrupts,
> - the JSWasmCall opcode,
> - wasm backing store allocation.
>
> Those components are all recursively entangled, so I found no way to
> split this change up further.
>
> Some includes that were recursively included by wasm headers needed to
> be added explicitly now.
>
> backing-store-unittest.cc is renamed to wasm-backing-store-unittest.cc
> because it only tests wasm backing stores. This file is excluded from
> no-wasm builds then.
>
> R=jkummerow@chromium.org, jgruber@chromium.org, mlippautz@chromium.org, petermarshall@chromium.org
>
> Bug: v8:11238
> Change-Id: I7558f2d12d2dd6c65128c4de7b79173668c80b2b
> Cq-Include-Trybots: luci.v8.try:v8_linux64_no_wasm_compile_rel
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2742955
> Commit-Queue: Clemens Backes <clemensb@chromium.org>
> Reviewed-by: Peter Marshall <petermarshall@chromium.org>
> Reviewed-by: Toon Verwaest <verwaest@chromium.org>
> Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Reviewed-by: Jakob Gruber <jgruber@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#73344}
TBR=jgruber@chromium.org
Bug: v8:11238
Change-Id: I20bd2847a59c68738b5a336cd42582b7b1499585
Cq-Include-Trybots: luci.v8.try:v8_linux64_no_wasm_compile_rel
Cq-Include-Trybots: luci.v8.try:v8_linux_verify_csa_rel_ng
Cq-Include-Trybots: luci.v8.try:v8_linux64_verify_csa_rel_ng
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2752867
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73348}
2021-03-11 13:42:01 +00:00
|
|
|
#if V8_ENABLE_WEBASSEMBLY
|
2020-04-21 18:39:11 +00:00
|
|
|
TEST(WasmInt32ToHeapNumber) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
int32_t test_values[] = {
|
|
|
|
// Smi values.
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
-1,
|
|
|
|
kSmiMaxValue,
|
|
|
|
kSmiMinValue,
|
|
|
|
// Test integers that can't be Smis (only possible if Smis are 31 bits).
|
|
|
|
#if defined(V8_HOST_ARCH_32_BIT) || defined(V8_31BIT_SMIS_ON_64BIT_ARCH)
|
|
|
|
kSmiMaxValue + 1,
|
|
|
|
kSmiMinValue - 1,
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
// FunctionTester can't handle Wasm type arguments, so for each test value,
|
|
|
|
// build a function with the arguments baked in, then generate a no-argument
|
|
|
|
// function to call.
|
|
|
|
const int kNumParams = 1;
|
|
|
|
for (size_t i = 0; i < arraysize(test_values); ++i) {
|
|
|
|
int32_t test_value = test_values[i];
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
const TNode<Int32T> arg = m.Int32Constant(test_value);
|
2020-10-02 16:56:55 +00:00
|
|
|
const TNode<Object> call_result = m.CallBuiltin(
|
2021-06-07 15:24:12 +00:00
|
|
|
Builtin::kWasmInt32ToHeapNumber, m.NoContextConstant(), arg);
|
2020-04-21 18:39:11 +00:00
|
|
|
m.Return(call_result);
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
Handle<Object> result = ft.Call().ToHandleChecked();
|
|
|
|
CHECK(result->IsNumber());
|
|
|
|
Handle<Object> expected(isolate->factory()->NewNumber(test_value));
|
|
|
|
CHECK(result->StrictEquals(*expected));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t NumberToInt32(Handle<Object> number) {
|
|
|
|
if (number->IsSmi()) {
|
|
|
|
return Smi::ToInt(*number);
|
|
|
|
}
|
|
|
|
if (number->IsHeapNumber()) {
|
|
|
|
double num = HeapNumber::cast(*number).value();
|
|
|
|
return DoubleToInt32(num);
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(WasmTaggedNonSmiToInt32) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
|
|
|
|
Handle<Object> test_values[] = {
|
|
|
|
// No Smis here; the builtin can't handle them correctly.
|
|
|
|
factory->NewNumber(-0.0),
|
|
|
|
factory->NewNumber(1.5),
|
|
|
|
factory->NewNumber(-1.5),
|
|
|
|
factory->NewNumber(2 * static_cast<double>(kSmiMaxValue)),
|
|
|
|
factory->NewNumber(2 * static_cast<double>(kSmiMinValue)),
|
|
|
|
factory->NewNumber(std::numeric_limits<double>::infinity()),
|
|
|
|
factory->NewNumber(-std::numeric_limits<double>::infinity()),
|
|
|
|
factory->NewNumber(-std::numeric_limits<double>::quiet_NaN()),
|
|
|
|
};
|
|
|
|
|
|
|
|
const int kNumParams = 2;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2020-04-21 18:39:11 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
auto context = m.Parameter<Context>(kNumParams + 3);
|
|
|
|
const auto arg = m.Parameter<Object>(1);
|
2020-04-21 18:39:11 +00:00
|
|
|
int32_t result = 0;
|
|
|
|
Node* base = m.IntPtrConstant(reinterpret_cast<intptr_t>(&result));
|
2021-06-07 15:24:12 +00:00
|
|
|
Node* value = m.CallBuiltin(Builtin::kWasmTaggedNonSmiToInt32, context, arg);
|
2020-04-21 18:39:11 +00:00
|
|
|
m.StoreNoWriteBarrier(MachineRepresentation::kWord32, base, value);
|
|
|
|
m.Return(m.UndefinedConstant());
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < arraysize(test_values); ++i) {
|
|
|
|
Handle<Object> test_value = test_values[i];
|
|
|
|
ft.Call(test_value);
|
|
|
|
int32_t expected = NumberToInt32(test_value);
|
|
|
|
CHECK_EQ(result, expected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-22 23:28:11 +00:00
|
|
|
TEST(WasmFloat32ToNumber) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
float test_values[] = {
|
|
|
|
// Smi values.
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
-1,
|
|
|
|
// Max and min Smis can't be represented as floats.
|
|
|
|
// Non-Smi values.
|
|
|
|
-0.0,
|
|
|
|
1.5,
|
|
|
|
std::numeric_limits<float>::quiet_NaN(),
|
|
|
|
std::numeric_limits<float>::infinity(),
|
|
|
|
};
|
|
|
|
|
|
|
|
// FunctionTester can't handle Wasm type arguments, so for each test value,
|
|
|
|
// build a function with the arguments baked in, then generate a no-argument
|
|
|
|
// function to call.
|
|
|
|
const int kNumParams = 1;
|
|
|
|
for (size_t i = 0; i < arraysize(test_values); ++i) {
|
|
|
|
double test_value = test_values[i];
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
const TNode<Float32T> arg = m.Float32Constant(test_value);
|
2020-10-02 16:56:55 +00:00
|
|
|
const TNode<Object> call_result = m.CallBuiltin(
|
2021-06-07 15:24:12 +00:00
|
|
|
Builtin::kWasmFloat32ToNumber, m.NoContextConstant(), arg);
|
2020-04-22 23:28:11 +00:00
|
|
|
m.Return(call_result);
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
Handle<Object> result = ft.Call().ToHandleChecked();
|
|
|
|
CHECK(result->IsNumber());
|
|
|
|
Handle<Object> expected(isolate->factory()->NewNumber(test_value));
|
|
|
|
CHECK(result->StrictEquals(*expected) ||
|
|
|
|
(std::isnan(test_value) && std::isnan(result->Number())));
|
|
|
|
CHECK_EQ(result->IsSmi(), expected->IsSmi());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:39:11 +00:00
|
|
|
TEST(WasmFloat64ToNumber) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
double test_values[] = {
|
|
|
|
// Smi values.
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
-1,
|
|
|
|
kSmiMaxValue,
|
|
|
|
kSmiMinValue,
|
|
|
|
// Non-Smi values.
|
|
|
|
-0.0,
|
|
|
|
1.5,
|
|
|
|
std::numeric_limits<double>::quiet_NaN(),
|
|
|
|
std::numeric_limits<double>::infinity(),
|
|
|
|
};
|
|
|
|
|
|
|
|
// FunctionTester can't handle Wasm type arguments, so for each test value,
|
|
|
|
// build a function with the arguments baked in, then generate a no-argument
|
|
|
|
// function to call.
|
|
|
|
const int kNumParams = 1;
|
|
|
|
for (size_t i = 0; i < arraysize(test_values); ++i) {
|
|
|
|
double test_value = test_values[i];
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
const TNode<Float64T> arg = m.Float64Constant(test_value);
|
2020-10-02 16:56:55 +00:00
|
|
|
const TNode<Object> call_result = m.CallBuiltin(
|
2021-06-07 15:24:12 +00:00
|
|
|
Builtin::kWasmFloat64ToNumber, m.NoContextConstant(), arg);
|
2020-04-21 18:39:11 +00:00
|
|
|
m.Return(call_result);
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
Handle<Object> result = ft.Call().ToHandleChecked();
|
|
|
|
CHECK(result->IsNumber());
|
|
|
|
Handle<Object> expected(isolate->factory()->NewNumber(test_value));
|
|
|
|
CHECK(result->StrictEquals(*expected) ||
|
|
|
|
(std::isnan(test_value) && std::isnan(result->Number())));
|
|
|
|
CHECK_EQ(result->IsSmi(), expected->IsSmi());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double NumberToFloat64(Handle<Object> number) {
|
|
|
|
if (number->IsSmi()) {
|
|
|
|
return Smi::ToInt(*number);
|
|
|
|
}
|
|
|
|
if (number->IsHeapNumber()) {
|
|
|
|
return HeapNumber::cast(*number).value();
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(WasmTaggedToFloat64) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
Factory* factory = isolate->factory();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
|
|
|
|
Handle<Object> test_values[] = {
|
2020-04-22 16:21:36 +00:00
|
|
|
// Smi values.
|
|
|
|
handle(Smi::FromInt(1), isolate),
|
|
|
|
handle(Smi::FromInt(0), isolate),
|
|
|
|
handle(Smi::FromInt(-1), isolate),
|
|
|
|
handle(Smi::FromInt(kSmiMaxValue), isolate),
|
|
|
|
handle(Smi::FromInt(kSmiMinValue), isolate),
|
|
|
|
// Test some non-Smis.
|
|
|
|
factory->NewNumber(-0.0),
|
|
|
|
factory->NewNumber(1.5),
|
|
|
|
factory->NewNumber(-1.5),
|
|
|
|
// Integer Overflows on platforms with 32 bit Smis.
|
|
|
|
#if defined(V8_HOST_ARCH_32_BIT) || defined(V8_31BIT_SMIS_ON_64BIT_ARCH)
|
|
|
|
factory->NewNumber(2 * kSmiMaxValue),
|
|
|
|
factory->NewNumber(2 * kSmiMinValue),
|
|
|
|
#endif
|
|
|
|
factory->NewNumber(std::numeric_limits<double>::infinity()),
|
|
|
|
factory->NewNumber(-std::numeric_limits<double>::infinity()),
|
|
|
|
factory->NewNumber(-std::numeric_limits<double>::quiet_NaN()),
|
2020-04-21 18:39:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
2020-07-15 11:03:22 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams + 1); // Include receiver.
|
2020-04-21 18:39:11 +00:00
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2020-09-30 17:40:39 +00:00
|
|
|
auto context = m.Parameter<Context>(kNumParams + 3);
|
|
|
|
const auto arg = m.Parameter<Object>(1);
|
2020-04-21 18:39:11 +00:00
|
|
|
double result = 0;
|
|
|
|
Node* base = m.IntPtrConstant(reinterpret_cast<intptr_t>(&result));
|
2021-06-07 15:24:12 +00:00
|
|
|
Node* value = m.CallBuiltin(Builtin::kWasmTaggedToFloat64, context, arg);
|
2020-04-21 18:39:11 +00:00
|
|
|
m.StoreNoWriteBarrier(MachineRepresentation::kFloat64, base, value);
|
|
|
|
m.Return(m.UndefinedConstant());
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < arraysize(test_values); ++i) {
|
|
|
|
Handle<Object> test_value = test_values[i];
|
|
|
|
ft.Call(test_value);
|
|
|
|
double expected = NumberToFloat64(test_value);
|
|
|
|
if (std::isnan(expected)) {
|
|
|
|
CHECK(std::isnan(result));
|
|
|
|
} else {
|
|
|
|
CHECK_EQ(result, expected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Reland "[no-wasm] Exclude src/wasm from compilation"
This is a reland of 80f5dfda0147d6b078ae6c9d0eb947bd012bf72d. A condition
in pipeline.cc was inverted, which lead to a CSA verifier error.
Original change's description:
> [no-wasm] Exclude src/wasm from compilation
>
> This is the biggest chunk, including
> - all of src/wasm,
> - torque file for wasm objects,
> - torque file for wasm builtins,
> - wasm builtins,
> - wasm runtime functions,
> - int64 lowering,
> - simd scala lowering,
> - WasmGraphBuilder (TF graph construction for wasm),
> - wasm frame types,
> - wasm interrupts,
> - the JSWasmCall opcode,
> - wasm backing store allocation.
>
> Those components are all recursively entangled, so I found no way to
> split this change up further.
>
> Some includes that were recursively included by wasm headers needed to
> be added explicitly now.
>
> backing-store-unittest.cc is renamed to wasm-backing-store-unittest.cc
> because it only tests wasm backing stores. This file is excluded from
> no-wasm builds then.
>
> R=jkummerow@chromium.org, jgruber@chromium.org, mlippautz@chromium.org, petermarshall@chromium.org
>
> Bug: v8:11238
> Change-Id: I7558f2d12d2dd6c65128c4de7b79173668c80b2b
> Cq-Include-Trybots: luci.v8.try:v8_linux64_no_wasm_compile_rel
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2742955
> Commit-Queue: Clemens Backes <clemensb@chromium.org>
> Reviewed-by: Peter Marshall <petermarshall@chromium.org>
> Reviewed-by: Toon Verwaest <verwaest@chromium.org>
> Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Reviewed-by: Jakob Gruber <jgruber@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#73344}
TBR=jgruber@chromium.org
Bug: v8:11238
Change-Id: I20bd2847a59c68738b5a336cd42582b7b1499585
Cq-Include-Trybots: luci.v8.try:v8_linux64_no_wasm_compile_rel
Cq-Include-Trybots: luci.v8.try:v8_linux_verify_csa_rel_ng
Cq-Include-Trybots: luci.v8.try:v8_linux64_verify_csa_rel_ng
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2752867
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73348}
2021-03-11 13:42:01 +00:00
|
|
|
#endif // V8_ENABLE_WEBASSEMBLY
|
2020-04-21 18:39:11 +00:00
|
|
|
|
2020-04-28 14:27:29 +00:00
|
|
|
TEST(SmiUntagLeftShiftOptimization) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
TNode<TaggedIndex> param = m.UncheckedParameter<TaggedIndex>(0);
|
2020-04-28 14:27:29 +00:00
|
|
|
TNode<WordT> unoptimized =
|
|
|
|
m.IntPtrMul(m.TaggedIndexToIntPtr(param), m.IntPtrConstant(8));
|
|
|
|
TNode<WordT> optimized = m.WordShl(
|
|
|
|
m.BitcastTaggedToWordForTagAndSmiBits(param), 3 - kSmiTagSize);
|
|
|
|
m.StaticAssert(m.WordEqual(unoptimized, optimized));
|
|
|
|
m.Return(m.UndefinedConstant());
|
|
|
|
}
|
|
|
|
|
|
|
|
AssemblerOptions options = AssemblerOptions::Default(isolate);
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(options), kNumParams);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SmiUntagComparisonOptimization) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 2;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
{
|
2020-09-30 17:40:39 +00:00
|
|
|
TNode<Smi> a = m.UncheckedParameter<Smi>(0);
|
|
|
|
TNode<Smi> b = m.UncheckedParameter<Smi>(1);
|
2020-04-28 14:27:29 +00:00
|
|
|
TNode<BoolT> unoptimized = m.UintPtrLessThan(m.SmiUntag(a), m.SmiUntag(b));
|
|
|
|
#ifdef V8_COMPRESS_POINTERS
|
|
|
|
TNode<BoolT> optimized = m.Uint32LessThan(
|
|
|
|
m.TruncateIntPtrToInt32(m.BitcastTaggedToWordForTagAndSmiBits(a)),
|
|
|
|
m.TruncateIntPtrToInt32(m.BitcastTaggedToWordForTagAndSmiBits(b)));
|
|
|
|
#else
|
|
|
|
TNode<BoolT> optimized =
|
|
|
|
m.UintPtrLessThan(m.BitcastTaggedToWordForTagAndSmiBits(a),
|
|
|
|
m.BitcastTaggedToWordForTagAndSmiBits(b));
|
|
|
|
#endif
|
|
|
|
m.StaticAssert(m.Word32Equal(unoptimized, optimized));
|
|
|
|
m.Return(m.UndefinedConstant());
|
|
|
|
}
|
|
|
|
|
|
|
|
AssemblerOptions options = AssemblerOptions::Default(isolate);
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(options), kNumParams);
|
|
|
|
}
|
|
|
|
|
2021-03-17 15:45:34 +00:00
|
|
|
TEST(PopCount) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
CodeAssemblerTester asm_tester(isolate);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
const std::vector<std::pair<uint32_t, int>> test_cases = {
|
|
|
|
{0, 0},
|
|
|
|
{1, 1},
|
|
|
|
{(1 << 31), 1},
|
|
|
|
{0b01010101010101010101010101010101, 16},
|
|
|
|
{0b10101010101010101010101010101010, 16},
|
|
|
|
{0b11100011100000011100011111000111, 17} // arbitrarily chosen
|
|
|
|
};
|
|
|
|
|
|
|
|
for (std::pair<uint32_t, int> test_case : test_cases) {
|
|
|
|
uint32_t value32 = test_case.first;
|
|
|
|
uint64_t value64 = (static_cast<uint64_t>(value32) << 32) | value32;
|
|
|
|
int expected_pop32 = test_case.second;
|
|
|
|
int expected_pop64 = 2 * expected_pop32;
|
|
|
|
|
2021-03-22 16:06:13 +00:00
|
|
|
TNode<Int32T> pop32 = m.PopulationCount32(m.Uint32Constant(value32));
|
2021-03-17 15:45:34 +00:00
|
|
|
CSA_CHECK(&m, m.Word32Equal(pop32, m.Int32Constant(expected_pop32)));
|
|
|
|
|
|
|
|
if (m.Is64()) {
|
|
|
|
// TODO(emrich): enable once 64-bit operations are supported on 32-bit
|
|
|
|
// architectures.
|
|
|
|
|
2021-03-22 16:06:13 +00:00
|
|
|
TNode<Int64T> pop64 = m.PopulationCount64(m.Uint64Constant(value64));
|
2021-03-17 15:45:34 +00:00
|
|
|
CSA_CHECK(&m, m.Word64Equal(pop64, m.Int64Constant(expected_pop64)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m.Return(m.UndefinedConstant());
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode());
|
|
|
|
ft.Call();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CountTrailingZeros) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
CodeAssemblerTester asm_tester(isolate);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
const std::vector<std::pair<uint32_t, int>> test_cases = {
|
|
|
|
{1, 0},
|
|
|
|
{2, 1},
|
|
|
|
{(0b0101010'0000'0000), 9},
|
|
|
|
{(1 << 31), 31},
|
|
|
|
{std::numeric_limits<uint32_t>::max(), 0},
|
|
|
|
};
|
|
|
|
|
|
|
|
for (std::pair<uint32_t, int> test_case : test_cases) {
|
|
|
|
uint32_t value32 = test_case.first;
|
|
|
|
uint64_t value64 = static_cast<uint64_t>(value32) << 32;
|
|
|
|
int expected_ctz32 = test_case.second;
|
|
|
|
int expected_ctz64 = expected_ctz32 + 32;
|
|
|
|
|
2021-03-22 16:06:13 +00:00
|
|
|
TNode<Int32T> pop32 = m.CountTrailingZeros32(m.Uint32Constant(value32));
|
2021-03-17 15:45:34 +00:00
|
|
|
CSA_CHECK(&m, m.Word32Equal(pop32, m.Int32Constant(expected_ctz32)));
|
|
|
|
|
|
|
|
if (m.Is64()) {
|
|
|
|
// TODO(emrich): enable once 64-bit operations are supported on 32-bit
|
|
|
|
// architectures.
|
|
|
|
|
|
|
|
TNode<Int64T> pop64_ext =
|
2021-03-22 16:06:13 +00:00
|
|
|
m.CountTrailingZeros64(m.Uint64Constant(value32));
|
|
|
|
TNode<Int64T> pop64 = m.CountTrailingZeros64(m.Uint64Constant(value64));
|
2021-03-17 15:45:34 +00:00
|
|
|
|
|
|
|
CSA_CHECK(&m, m.Word64Equal(pop64_ext, m.Int64Constant(expected_ctz32)));
|
|
|
|
CSA_CHECK(&m, m.Word64Equal(pop64, m.Int64Constant(expected_ctz64)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m.Return(m.UndefinedConstant());
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode());
|
|
|
|
ft.Call();
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
} // namespace compiler
|
2016-06-01 21:08:22 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|