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>
|
|
|
|
|
2017-02-23 11:46:29 +00:00
|
|
|
#include "src/api.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"
|
2017-09-05 02:19:29 +00:00
|
|
|
#include "src/builtins/builtins-string-gen.h"
|
|
|
|
#include "src/char-predicates.h"
|
2016-08-26 08:41:20 +00:00
|
|
|
#include "src/code-factory.h"
|
|
|
|
#include "src/code-stub-assembler.h"
|
|
|
|
#include "src/compiler/node.h"
|
2017-02-23 11:46:29 +00:00
|
|
|
#include "src/debug/debug.h"
|
2016-06-01 21:08:22 +00:00
|
|
|
#include "src/isolate.h"
|
2017-02-23 11:46:29 +00:00
|
|
|
#include "src/objects-inl.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 {
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
typedef CodeAssemblerLabel Label;
|
|
|
|
typedef CodeAssemblerVariable Variable;
|
|
|
|
|
2017-04-24 11:58:50 +00:00
|
|
|
int sum9(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
|
|
|
|
int a8) {
|
|
|
|
return a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|
|
|
TEST(CallCFunction9) {
|
|
|
|
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
|
|
|
|
|
|
|
{
|
|
|
|
Node* const fun_constant = m.ExternalConstant(
|
|
|
|
ExternalReference(reinterpret_cast<Address>(sum9), isolate));
|
|
|
|
|
|
|
|
MachineType type_intptr = MachineType::IntPtr();
|
|
|
|
|
|
|
|
Node* const result = m.CallCFunction9(
|
|
|
|
type_intptr, type_intptr, type_intptr, type_intptr, type_intptr,
|
|
|
|
type_intptr, type_intptr, type_intptr, type_intptr, type_intptr,
|
|
|
|
fun_constant, m.IntPtrConstant(0), m.IntPtrConstant(1),
|
|
|
|
m.IntPtrConstant(2), m.IntPtrConstant(3), m.IntPtrConstant(4),
|
|
|
|
m.IntPtrConstant(5), m.IntPtrConstant(6), m.IntPtrConstant(7),
|
|
|
|
m.IntPtrConstant(8));
|
|
|
|
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();
|
|
|
|
CHECK_EQ(36, Handle<Smi>::cast(result)->value());
|
|
|
|
}
|
|
|
|
|
2017-08-21 15:23:17 +00:00
|
|
|
TEST(CallCFunction3WithCallerSavedRegisters) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 0;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
{
|
|
|
|
Node* const fun_constant = m.ExternalConstant(
|
|
|
|
ExternalReference(reinterpret_cast<Address>(sum3), isolate));
|
|
|
|
|
|
|
|
MachineType type_intptr = MachineType::IntPtr();
|
|
|
|
|
|
|
|
Node* const result = m.CallCFunction3WithCallerSavedRegisters(
|
|
|
|
type_intptr, type_intptr, type_intptr, type_intptr, fun_constant,
|
2017-09-22 09:13:07 +00:00
|
|
|
m.IntPtrConstant(0), m.IntPtrConstant(1), m.IntPtrConstant(2),
|
|
|
|
kSaveFPRegs);
|
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());
|
|
|
|
}
|
|
|
|
|
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;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-04-07 12:50:15 +00:00
|
|
|
|
|
|
|
const int kContextOffset = 2;
|
|
|
|
Node* const context = m.Parameter(kNumParams + kContextOffset);
|
|
|
|
Node* const input = m.Parameter(0);
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
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),
|
2017-08-03 14:27:11 +00:00
|
|
|
m.SmiTag(m.IntPtrConstant(4)), 0,
|
2016-06-01 21:08:22 +00:00
|
|
|
CodeStubAssembler::SMI_PARAMETERS));
|
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);
|
2017-10-20 15:18:53 +00:00
|
|
|
m.Return(m.SmiFromWord32(m.Signed(
|
|
|
|
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();
|
2016-12-15 11:45:18 +00:00
|
|
|
m.Return(m.SmiFromWord32(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
|
|
|
|
|
|
|
class TestBitField : public 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) {
|
|
|
|
const int kNumParams = 3; // Receiver, left, right.
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-17 13:19:58 +00:00
|
|
|
m.Return(m.SmiFromWord32(m.Int32Add(m.SmiToWord32(m.Parameter(1)),
|
|
|
|
m.SmiToWord32(m.Parameter(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
|
|
|
|
2016-06-17 13:19:58 +00:00
|
|
|
MaybeHandle<Object> result = ft.Call(isolate->factory()->undefined_value(),
|
|
|
|
handle(Smi::FromInt(23), isolate),
|
|
|
|
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());
|
2016-06-17 13:19:58 +00:00
|
|
|
const int kNumParams = 2;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Return(m.SmiFromWord32(m.ComputeIntegerHash(
|
2016-12-15 11:45:18 +00:00
|
|
|
m.SmiUntag(m.Parameter(0)), m.SmiToWord32(m.Parameter(1)))));
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Handle<Smi> hash_seed = isolate->factory()->hash_seed();
|
|
|
|
|
|
|
|
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);
|
|
|
|
Handle<Object> result = ft.Call(key, hash_seed).ToHandleChecked();
|
|
|
|
|
|
|
|
uint32_t hash = ComputeIntegerHash(k, hash_seed->value());
|
|
|
|
Smi* expected = Smi::FromInt(hash & Smi::kMaxValue);
|
|
|
|
CHECK_EQ(expected, Smi::cast(*result));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-19 13:37:12 +00:00
|
|
|
TEST(ToString) {
|
|
|
|
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-10-19 13:37:12 +00:00
|
|
|
m.Return(m.ToString(m.Parameter(kNumParams + 2), m.Parameter(0)));
|
|
|
|
|
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);
|
|
|
|
oddball_test->set(0, isolate->heap()->undefined_value());
|
|
|
|
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) {
|
|
|
|
Handle<FixedArray> test = handle(FixedArray::cast(test_cases->get(i)));
|
|
|
|
Handle<Object> obj = handle(test->get(0), isolate);
|
|
|
|
Handle<String> expected = handle(String::cast(test->get(1)));
|
|
|
|
Handle<Object> result = ft.Call(obj).ToHandleChecked();
|
|
|
|
CHECK(result->IsString());
|
|
|
|
CHECK(String::Equals(Handle<String>::cast(result), expected));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
enum Result { kKeyIsIndex, kKeyIsUnique, kBailout };
|
|
|
|
{
|
|
|
|
Node* key = m.Parameter(0);
|
|
|
|
Node* expected_result = m.Parameter(1);
|
|
|
|
Node* expected_arg = m.Parameter(2);
|
|
|
|
|
|
|
|
Label passed(&m), failed(&m);
|
|
|
|
Label if_keyisindex(&m), if_keyisunique(&m), if_bailout(&m);
|
2017-01-19 13:27:59 +00:00
|
|
|
{
|
|
|
|
Variable var_index(&m, MachineType::PointerRepresentation());
|
|
|
|
Variable var_unique(&m, MachineRepresentation::kTagged);
|
|
|
|
|
|
|
|
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);
|
2017-02-17 16:25:07 +00:00
|
|
|
m.GotoIfNot(m.WordEqual(expected_result,
|
|
|
|
m.SmiConstant(Smi::FromInt(kKeyIsIndex))),
|
|
|
|
&failed);
|
2017-01-19 13:27:59 +00:00
|
|
|
m.Branch(m.WordEqual(m.SmiUntag(expected_arg), var_index.value()),
|
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_keyisunique);
|
2017-02-17 16:25:07 +00:00
|
|
|
m.GotoIfNot(m.WordEqual(expected_result,
|
|
|
|
m.SmiConstant(Smi::FromInt(kKeyIsUnique))),
|
|
|
|
&failed);
|
2017-01-19 13:27:59 +00:00
|
|
|
m.Branch(m.WordEqual(expected_arg, var_unique.value()), &passed, &failed);
|
|
|
|
}
|
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(
|
|
|
|
m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
|
|
|
|
&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.
|
2016-10-07 13:05:07 +00:00
|
|
|
Handle<Object> key(Smi::kZero, 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
|
|
|
{
|
|
|
|
// TryToName(<internalized uncacheable number string>) => bailout
|
|
|
|
Handle<Object> key =
|
|
|
|
isolate->factory()->InternalizeUtf8String("4294967294");
|
|
|
|
ft.CheckTrue(key, expect_bailout);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// TryToName(<number string without cached index>) => bailout.
|
|
|
|
Handle<String> key = isolate->factory()->NewStringFromAsciiChecked("153");
|
|
|
|
CHECK(!key->HasHashCode());
|
|
|
|
ft.CheckTrue(key, expect_bailout);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2017-01-31 06:41:14 +00:00
|
|
|
if (FLAG_thin_strings) {
|
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);
|
|
|
|
}
|
|
|
|
|
2017-01-31 06:41:14 +00:00
|
|
|
if (FLAG_thin_strings) {
|
2017-01-19 13:27:59 +00:00
|
|
|
// TryToName(<thin two-byte string>) => internalized version.
|
|
|
|
uc16 array1[] = {2001, 2002, 2003};
|
|
|
|
Vector<const uc16> str1(array1);
|
|
|
|
Handle<String> s =
|
|
|
|
isolate->factory()->NewStringFromTwoByte(str1).ToHandleChecked();
|
|
|
|
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;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-10-25 08:30:37 +00:00
|
|
|
{
|
|
|
|
Node* entry = m.SmiUntag(m.Parameter(0));
|
|
|
|
Node* result = m.EntryToIndex<Dictionary>(entry);
|
|
|
|
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();
|
2017-07-10 12:58:27 +00:00
|
|
|
CHECK_EQ(Dictionary::EntryToIndex(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;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
enum Result { kFound, kNotFound };
|
|
|
|
{
|
|
|
|
Node* dictionary = m.Parameter(0);
|
|
|
|
Node* unique_name = m.Parameter(1);
|
|
|
|
Node* expected_result = m.Parameter(2);
|
|
|
|
Node* expected_arg = m.Parameter(3);
|
|
|
|
|
|
|
|
Label passed(&m), failed(&m);
|
|
|
|
Label if_found(&m), if_not_found(&m);
|
2016-09-08 10:56:44 +00:00
|
|
|
Variable var_name_index(&m, MachineType::PointerRepresentation());
|
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(
|
2016-06-02 15:02:08 +00:00
|
|
|
m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
|
|
|
|
&failed);
|
2016-12-15 11:45:18 +00:00
|
|
|
m.Branch(m.WordEqual(m.SmiUntag(expected_arg), var_name_index.value()),
|
2016-06-02 15:02:08 +00:00
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_not_found);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(
|
|
|
|
m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
|
|
|
|
&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++) {
|
2017-06-27 11:57:13 +00:00
|
|
|
Handle<Object> value = factory->NewPropertyCell(keys[i]);
|
2016-06-02 15:02:08 +00:00
|
|
|
dictionary = Dictionary::Add(dictionary, keys[i], value, fake_details);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < arraysize(keys); i++) {
|
|
|
|
int entry = dictionary->FindEntry(keys[i]);
|
2016-06-27 12:26:57 +00:00
|
|
|
int name_index =
|
|
|
|
Dictionary::EntryToIndex(entry) + Dictionary::kEntryKeyIndex;
|
2016-06-02 15:02:08 +00:00
|
|
|
CHECK_NE(Dictionary::kNotFound, entry);
|
|
|
|
|
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++) {
|
|
|
|
int entry = dictionary->FindEntry(non_existing_keys[i]);
|
|
|
|
CHECK_EQ(Dictionary::kNotFound, entry);
|
|
|
|
|
|
|
|
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;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
enum Result { kFound, kNotFound };
|
|
|
|
{
|
|
|
|
Node* dictionary = m.Parameter(0);
|
2016-12-15 11:45:18 +00:00
|
|
|
Node* key = m.SmiUntag(m.Parameter(1));
|
2016-06-02 15:02:08 +00:00
|
|
|
Node* expected_result = m.Parameter(2);
|
|
|
|
Node* expected_arg = m.Parameter(3);
|
|
|
|
|
|
|
|
Label passed(&m), failed(&m);
|
|
|
|
Label if_found(&m), if_not_found(&m);
|
2016-09-08 10:56:44 +00:00
|
|
|
Variable var_entry(&m, MachineType::PointerRepresentation());
|
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(
|
2016-06-02 15:02:08 +00:00
|
|
|
m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
|
|
|
|
&failed);
|
2016-12-15 11:45:18 +00:00
|
|
|
m.Branch(m.WordEqual(m.SmiUntag(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(
|
|
|
|
m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
|
|
|
|
&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);
|
2017-11-07 09:35:59 +00:00
|
|
|
if (dictionary->FindEntry(keys[i]) != NumberDictionary::kNotFound) continue;
|
2016-06-02 15:02:08 +00:00
|
|
|
|
2017-11-07 09:35:59 +00:00
|
|
|
dictionary =
|
|
|
|
NumberDictionary::Add(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++) {
|
|
|
|
int entry = dictionary->FindEntry(keys[i]);
|
2017-11-07 09:35:59 +00:00
|
|
|
CHECK_NE(NumberDictionary::kNotFound, entry);
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
Handle<Object> key(Smi::FromInt(keys[i]), isolate);
|
|
|
|
Handle<Object> expected_entry(Smi::FromInt(entry), isolate);
|
|
|
|
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);
|
|
|
|
int entry = dictionary->FindEntry(random_key);
|
2017-11-07 09:35:59 +00:00
|
|
|
if (entry != NumberDictionary::kNotFound) 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2016-06-02 15:02:08 +00:00
|
|
|
JSObject::AddProperty(object, names[i], value, NONE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 {
|
|
|
|
JSObject::AddProperty(object, names[i], value, NONE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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());
|
|
|
|
|
2016-06-17 13:19:58 +00:00
|
|
|
const int kNumParams = 4;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-06-02 15:02:08 +00:00
|
|
|
|
|
|
|
enum Result { kFound, kNotFound, kBailout };
|
|
|
|
{
|
|
|
|
Node* object = m.Parameter(0);
|
|
|
|
Node* unique_name = m.Parameter(1);
|
|
|
|
Node* expected_result = m.Parameter(2);
|
|
|
|
|
|
|
|
Label passed(&m), failed(&m);
|
|
|
|
Label if_found(&m), if_not_found(&m), if_bailout(&m);
|
|
|
|
|
|
|
|
Node* map = m.LoadMap(object);
|
|
|
|
Node* instance_type = m.LoadMapInstanceType(map);
|
|
|
|
|
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);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
|
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_not_found);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(
|
|
|
|
m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
|
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_bailout);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(
|
|
|
|
m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
|
|
|
|
&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 =
|
|
|
|
factory->NewFunctionForTest(factory->empty_string());
|
2016-06-02 15:02:08 +00:00
|
|
|
Handle<JSObject> object = factory->NewJSObject(function);
|
|
|
|
AddProperties(object, names, arraysize(names));
|
|
|
|
JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, "test");
|
2016-06-27 12:26:57 +00:00
|
|
|
|
|
|
|
JSObject::AddProperty(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 =
|
|
|
|
factory->NewFunctionForTest(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
|
|
|
|
|
|
|
JSObject::AddProperty(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 =
|
|
|
|
factory->NewFunctionForTest(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;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
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();
|
|
|
|
{
|
|
|
|
Node* object = m.Parameter(0);
|
|
|
|
Node* unique_name = m.Parameter(1);
|
|
|
|
Node* context = m.Parameter(kNumParams + 2);
|
|
|
|
|
|
|
|
Variable var_value(&m, MachineRepresentation::kTagged);
|
|
|
|
Label if_found(&m), if_not_found(&m), if_bailout(&m);
|
|
|
|
|
|
|
|
Node* map = m.LoadMap(object);
|
|
|
|
Node* instance_type = m.LoadMapInstanceType(map);
|
|
|
|
|
|
|
|
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);
|
2016-06-27 12:26:57 +00:00
|
|
|
m.Return(var_value.value());
|
|
|
|
|
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[] = {
|
2017-11-08 12:56:08 +00:00
|
|
|
factory->NewFunctionForTest(factory->empty_string()),
|
2016-06-27 12:26:57 +00:00
|
|
|
factory->NewSymbol(),
|
|
|
|
factory->InternalizeUtf8String("a"),
|
|
|
|
CreateAccessorPair(&ft, "() => 188;", "() => 199;"),
|
2017-11-08 12:56:08 +00:00
|
|
|
factory->NewFunctionForTest(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(
|
|
|
|
factory->NewFunctionForTest(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 =
|
|
|
|
factory->NewFunctionForTest(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());
|
|
|
|
JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, "test");
|
|
|
|
|
|
|
|
JSObject::AddProperty(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());
|
|
|
|
|
|
|
|
JSObject::AddProperty(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 =
|
|
|
|
JSReceiver::GetProperty(object, name).ToHandleChecked();
|
|
|
|
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 =
|
|
|
|
JSReceiver::GetProperty(object, name).ToHandleChecked();
|
|
|
|
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 =
|
|
|
|
factory->NewFunctionForTest(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) {
|
|
|
|
JSObject::AddDataElement(object, index, value, attributes).ToHandleChecked();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST(TryLookupElement) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2016-06-27 12:26:57 +00:00
|
|
|
const int kNumParams = 3;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
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
|
|
|
{
|
|
|
|
Node* object = m.Parameter(0);
|
2016-12-15 11:45:18 +00:00
|
|
|
Node* index = m.SmiUntag(m.Parameter(1));
|
2016-06-02 15:02:08 +00:00
|
|
|
Node* expected_result = m.Parameter(2);
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
Node* map = m.LoadMap(object);
|
|
|
|
Node* instance_type = m.LoadMapInstanceType(map);
|
|
|
|
|
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);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))),
|
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_absent);
|
2017-03-24 14:12:14 +00:00
|
|
|
m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kAbsent))),
|
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_not_found);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(
|
|
|
|
m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))),
|
|
|
|
&passed, &failed);
|
|
|
|
|
2017-05-19 16:13:17 +00:00
|
|
|
m.BIND(&if_bailout);
|
2016-06-02 15:02:08 +00:00
|
|
|
m.Branch(
|
|
|
|
m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))),
|
|
|
|
&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();
|
2016-10-07 13:05:07 +00:00
|
|
|
Handle<Object> smi0(Smi::kZero, 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);
|
|
|
|
|
2017-03-24 14:12:14 +00:00
|
|
|
#define CHECK_ABSENT(object, index) \
|
|
|
|
{ \
|
|
|
|
bool success; \
|
|
|
|
Handle<Smi> smi(Smi::FromInt(index), isolate); \
|
|
|
|
LookupIterator it = \
|
|
|
|
LookupIterator::PropertyOrElement(isolate, object, smi, &success); \
|
|
|
|
CHECK(success); \
|
|
|
|
CHECK(!JSReceiver::HasProperty(&it).FromJust()); \
|
|
|
|
ft.CheckTrue(object, smi, expect_absent); \
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
Handle<JSTypedArray> object = factory->NewJSTypedArray(INT32_ELEMENTS, 2);
|
|
|
|
Local<v8::ArrayBuffer> buffer = Utils::ToLocal(object->GetBuffer());
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
v8::ArrayBuffer::Contents contents = buffer->Externalize();
|
|
|
|
buffer->Neuter();
|
|
|
|
isolate->array_buffer_allocator()->Free(contents.Data(),
|
|
|
|
contents.ByteLength());
|
|
|
|
|
|
|
|
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");
|
|
|
|
Handle<JSValue>::cast(object)->set_value(*str);
|
|
|
|
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");
|
|
|
|
Handle<JSValue>::cast(object)->set_value(*str);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
// }
|
|
|
|
|
|
|
|
#undef CHECK_FOUND
|
|
|
|
#undef CHECK_NOT_FOUND
|
|
|
|
|
|
|
|
{
|
|
|
|
Handle<JSArray> handler = factory->NewJSArray(0);
|
2017-11-08 12:56:08 +00:00
|
|
|
Handle<JSFunction> function =
|
|
|
|
factory->NewFunctionForTest(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;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-10-19 11:33:30 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
Node* map = m.Parameter(0);
|
|
|
|
Node* properties = m.Parameter(1);
|
|
|
|
Node* elements = m.Parameter(2);
|
|
|
|
|
|
|
|
Node* result = m.AllocateJSObjectFromMap(map, properties, elements);
|
|
|
|
|
|
|
|
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")));
|
|
|
|
JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
|
|
|
|
"Normalize");
|
2017-07-17 23:30:32 +00:00
|
|
|
Handle<JSObject> result = Handle<JSObject>::cast(
|
|
|
|
ft.Call(handle(object->map(), isolate),
|
|
|
|
handle(object->property_dictionary(), isolate),
|
|
|
|
handle(object->elements(), isolate))
|
|
|
|
.ToHandleChecked());
|
|
|
|
CHECK_EQ(result->map(), object->map());
|
|
|
|
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
|
|
|
#undef VERIFY
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(AllocateNameDictionary) {
|
|
|
|
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-10-25 08:30:37 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
Node* capacity = m.Parameter(0);
|
|
|
|
Node* result = m.AllocateNameDictionary(m.SmiUntag(capacity));
|
|
|
|
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
|
|
|
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 256; i = i * 1.1 + 1) {
|
|
|
|
Handle<Object> result =
|
|
|
|
ft.Call(handle(Smi::FromInt(i), isolate)).ToHandleChecked();
|
|
|
|
Handle<NameDictionary> dict = NameDictionary::New(isolate, i);
|
|
|
|
// Both dictionaries should be memory equal.
|
|
|
|
int size =
|
|
|
|
FixedArrayBase::kHeaderSize + (dict->length() - 1) * kPointerSize;
|
|
|
|
CHECK_EQ(0, memcmp(*dict, *result, size));
|
|
|
|
}
|
|
|
|
}
|
2016-10-19 11:33:30 +00:00
|
|
|
}
|
|
|
|
|
2016-11-02 13:15:39 +00:00
|
|
|
TEST(PopAndReturnConstant) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 4;
|
2016-11-16 11:48:07 +00:00
|
|
|
const int kNumProgrammaticParams = 2;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams - kNumProgrammaticParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-11-02 13:15:39 +00:00
|
|
|
|
|
|
|
// Call a function that return |kNumProgramaticParams| parameters in addition
|
|
|
|
// to those specified by the static descriptor. |kNumProgramaticParams| is
|
|
|
|
// specified as a constant.
|
2016-11-16 11:48:07 +00:00
|
|
|
m.PopAndReturn(m.Int32Constant(kNumProgrammaticParams),
|
2016-11-02 13:15:39 +00:00
|
|
|
m.SmiConstant(Smi::FromInt(1234)));
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-11-02 13:15:39 +00:00
|
|
|
Handle<Object> result;
|
|
|
|
for (int test_count = 0; test_count < 100; ++test_count) {
|
|
|
|
result = ft.Call(isolate->factory()->undefined_value(),
|
|
|
|
Handle<Smi>(Smi::FromInt(1234), isolate),
|
|
|
|
isolate->factory()->undefined_value(),
|
|
|
|
isolate->factory()->undefined_value())
|
|
|
|
.ToHandleChecked();
|
|
|
|
CHECK_EQ(1234, Handle<Smi>::cast(result)->value());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(PopAndReturnVariable) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 4;
|
2016-11-16 11:48:07 +00:00
|
|
|
const int kNumProgrammaticParams = 2;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams - kNumProgrammaticParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-11-02 13:15:39 +00:00
|
|
|
|
|
|
|
// Call a function that return |kNumProgramaticParams| parameters in addition
|
|
|
|
// to those specified by the static descriptor. |kNumProgramaticParams| is
|
|
|
|
// passed in as a parameter to the function so that it can't be recongized as
|
|
|
|
// a constant.
|
|
|
|
m.PopAndReturn(m.SmiUntag(m.Parameter(1)), m.SmiConstant(Smi::FromInt(1234)));
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-11-02 13:15:39 +00:00
|
|
|
Handle<Object> result;
|
|
|
|
for (int test_count = 0; test_count < 100; ++test_count) {
|
|
|
|
result = ft.Call(isolate->factory()->undefined_value(),
|
|
|
|
Handle<Smi>(Smi::FromInt(1234), isolate),
|
|
|
|
isolate->factory()->undefined_value(),
|
2016-11-16 11:48:07 +00:00
|
|
|
Handle<Smi>(Smi::FromInt(kNumProgrammaticParams), isolate))
|
2016-11-02 13:15:39 +00:00
|
|
|
.ToHandleChecked();
|
|
|
|
CHECK_EQ(1234, Handle<Smi>::cast(result)->value());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-11-02 13:18:50 +00:00
|
|
|
|
2017-11-15 12:30:07 +00:00
|
|
|
m.CopyStringCharacters(m.Parameter(0), m.Parameter(1), 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");
|
|
|
|
uc16 array[] = {1000, 1001, 1002, 1003, 1004};
|
|
|
|
Vector<const uc16> str(array);
|
|
|
|
Handle<String> string2 =
|
|
|
|
isolate->factory()->NewStringFromTwoByte(str).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);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars()[0],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars()[0]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars()[1],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars()[1]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars()[2],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars()[2]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars()[3],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars()[3]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars()[4],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars()[4]);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(OneToOneByteStringCopy) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2016-11-16 11:48:07 +00:00
|
|
|
const int kNumParams = 2;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-11-02 13:18:50 +00:00
|
|
|
|
2017-11-15 12:30:07 +00:00
|
|
|
m.CopyStringCharacters(m.Parameter(0), m.Parameter(1), 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};
|
|
|
|
Vector<const uint8_t> str(array);
|
|
|
|
Handle<String> string2 =
|
|
|
|
isolate->factory()->NewStringFromOneByte(str).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);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars()[0],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars()[0]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars()[1],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars()[1]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars()[2],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars()[2]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars()[3],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars()[3]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars()[4],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars()[4]);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(OneToOneByteStringCopyNonZeroStart) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2016-11-16 11:48:07 +00:00
|
|
|
const int kNumParams = 2;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-11-02 13:18:50 +00:00
|
|
|
|
2017-11-15 12:30:07 +00:00
|
|
|
m.CopyStringCharacters(m.Parameter(0), m.Parameter(1), 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};
|
|
|
|
Vector<const uint8_t> str(array);
|
|
|
|
Handle<String> string2 =
|
|
|
|
isolate->factory()->NewStringFromOneByte(str).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);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars()[0],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars()[3]);
|
|
|
|
CHECK_EQ(Handle<SeqOneByteString>::cast(string1)->GetChars()[1],
|
|
|
|
Handle<SeqOneByteString>::cast(string2)->GetChars()[4]);
|
|
|
|
CHECK_EQ(100, Handle<SeqOneByteString>::cast(string2)->GetChars()[0]);
|
|
|
|
CHECK_EQ(101, Handle<SeqOneByteString>::cast(string2)->GetChars()[1]);
|
|
|
|
CHECK_EQ(102, Handle<SeqOneByteString>::cast(string2)->GetChars()[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(TwoToTwoByteStringCopy) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
2016-11-16 11:48:07 +00:00
|
|
|
const int kNumParams = 2;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-11-02 13:18:50 +00:00
|
|
|
|
2017-11-15 12:30:07 +00:00
|
|
|
m.CopyStringCharacters(m.Parameter(0), m.Parameter(1), 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)));
|
|
|
|
|
|
|
|
uc16 array1[] = {2000, 2001, 2002, 2003, 2004};
|
|
|
|
Vector<const uc16> str1(array1);
|
|
|
|
Handle<String> string1 =
|
|
|
|
isolate->factory()->NewStringFromTwoByte(str1).ToHandleChecked();
|
|
|
|
uc16 array2[] = {1000, 1001, 1002, 1003, 1004};
|
|
|
|
Vector<const uc16> str2(array2);
|
|
|
|
Handle<String> string2 =
|
|
|
|
isolate->factory()->NewStringFromTwoByte(str2).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);
|
|
|
|
CHECK_EQ(Handle<SeqTwoByteString>::cast(string1)->GetChars()[0],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars()[0]);
|
|
|
|
CHECK_EQ(Handle<SeqTwoByteString>::cast(string1)->GetChars()[1],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars()[1]);
|
|
|
|
CHECK_EQ(Handle<SeqTwoByteString>::cast(string1)->GetChars()[2],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars()[2]);
|
|
|
|
CHECK_EQ(Handle<SeqTwoByteString>::cast(string1)->GetChars()[3],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars()[3]);
|
|
|
|
CHECK_EQ(Handle<SeqTwoByteString>::cast(string1)->GetChars()[4],
|
|
|
|
Handle<SeqTwoByteString>::cast(string2)->GetChars()[4]);
|
|
|
|
}
|
|
|
|
|
2016-11-03 12:53:24 +00:00
|
|
|
TEST(Arguments) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 4;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2017-01-27 11:20:07 +00:00
|
|
|
CodeStubArguments arguments(&m, m.IntPtrConstant(3));
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2016-11-09 18:22:06 +00:00
|
|
|
CSA_ASSERT(
|
|
|
|
&m, m.WordEqual(arguments.AtIndex(0), m.SmiConstant(Smi::FromInt(12))));
|
|
|
|
CSA_ASSERT(
|
|
|
|
&m, m.WordEqual(arguments.AtIndex(1), m.SmiConstant(Smi::FromInt(13))));
|
|
|
|
CSA_ASSERT(
|
|
|
|
&m, m.WordEqual(arguments.AtIndex(2), m.SmiConstant(Smi::FromInt(14))));
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2018-01-16 15:06:11 +00:00
|
|
|
arguments.PopAndReturn(arguments.GetReceiver());
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2018-01-10 08:47:56 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
Handle<Object> result = ft.Call(isolate->factory()->undefined_value(),
|
|
|
|
Handle<Smi>(Smi::FromInt(12), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(13), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(14), isolate))
|
|
|
|
.ToHandleChecked();
|
|
|
|
CHECK_EQ(*isolate->factory()->undefined_value(), *result);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ArgumentsWithSmiConstantIndices) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 4;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
CodeStubArguments arguments(&m, m.SmiConstant(3), nullptr,
|
|
|
|
CodeStubAssembler::SMI_PARAMETERS);
|
|
|
|
|
|
|
|
CSA_ASSERT(&m,
|
|
|
|
m.WordEqual(arguments.AtIndex(m.SmiConstant(0),
|
|
|
|
CodeStubAssembler::SMI_PARAMETERS),
|
|
|
|
m.SmiConstant(Smi::FromInt(12))));
|
|
|
|
CSA_ASSERT(&m,
|
|
|
|
m.WordEqual(arguments.AtIndex(m.SmiConstant(1),
|
|
|
|
CodeStubAssembler::SMI_PARAMETERS),
|
|
|
|
m.SmiConstant(Smi::FromInt(13))));
|
|
|
|
CSA_ASSERT(&m,
|
|
|
|
m.WordEqual(arguments.AtIndex(m.SmiConstant(2),
|
|
|
|
CodeStubAssembler::SMI_PARAMETERS),
|
|
|
|
m.SmiConstant(Smi::FromInt(14))));
|
|
|
|
|
2018-01-16 15:06:11 +00:00
|
|
|
arguments.PopAndReturn(arguments.GetReceiver());
|
2018-01-10 08:47:56 +00:00
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
Handle<Object> result = ft.Call(isolate->factory()->undefined_value(),
|
|
|
|
Handle<Smi>(Smi::FromInt(12), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(13), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(14), isolate))
|
|
|
|
.ToHandleChecked();
|
|
|
|
CHECK_EQ(*isolate->factory()->undefined_value(), *result);
|
|
|
|
}
|
|
|
|
|
|
|
|
TNode<Smi> NonConstantSmi(CodeStubAssembler* m, int value) {
|
|
|
|
// Generate a SMI with the given value and feed it through a Phi so it can't
|
|
|
|
// be inferred to be constant.
|
|
|
|
Variable var(m, MachineRepresentation::kTagged, m->SmiConstant(value));
|
|
|
|
Label dummy_done(m);
|
|
|
|
// Even though the Goto always executes, it will taint the variable and thus
|
|
|
|
// make it appear non-constant when used later.
|
|
|
|
m->GotoIf(m->Int32Constant(1), &dummy_done);
|
|
|
|
var.Bind(m->SmiConstant(value));
|
|
|
|
m->Goto(&dummy_done);
|
|
|
|
m->BIND(&dummy_done);
|
|
|
|
|
|
|
|
// Ensure that the above hackery actually created a non-constant SMI.
|
|
|
|
Smi* smi_constant;
|
|
|
|
CHECK(!m->ToSmiConstant(var.value(), smi_constant));
|
|
|
|
|
|
|
|
return m->UncheckedCast<Smi>(var.value());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ArgumentsWithSmiIndices) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 4;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
CodeStubArguments arguments(&m, m.SmiConstant(3), nullptr,
|
|
|
|
CodeStubAssembler::SMI_PARAMETERS);
|
|
|
|
|
|
|
|
CSA_ASSERT(&m,
|
|
|
|
m.WordEqual(arguments.AtIndex(NonConstantSmi(&m, 0),
|
|
|
|
CodeStubAssembler::SMI_PARAMETERS),
|
|
|
|
m.SmiConstant(Smi::FromInt(12))));
|
|
|
|
CSA_ASSERT(&m,
|
|
|
|
m.WordEqual(arguments.AtIndex(NonConstantSmi(&m, 1),
|
|
|
|
CodeStubAssembler::SMI_PARAMETERS),
|
|
|
|
m.SmiConstant(Smi::FromInt(13))));
|
|
|
|
CSA_ASSERT(&m,
|
|
|
|
m.WordEqual(arguments.AtIndex(NonConstantSmi(&m, 2),
|
|
|
|
CodeStubAssembler::SMI_PARAMETERS),
|
|
|
|
m.SmiConstant(Smi::FromInt(14))));
|
|
|
|
|
2018-01-16 15:06:11 +00:00
|
|
|
arguments.PopAndReturn(arguments.GetReceiver());
|
2018-01-10 08:47:56 +00:00
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-11-03 12:53:24 +00:00
|
|
|
Handle<Object> result = ft.Call(isolate->factory()->undefined_value(),
|
|
|
|
Handle<Smi>(Smi::FromInt(12), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(13), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(14), isolate))
|
|
|
|
.ToHandleChecked();
|
|
|
|
CHECK_EQ(*isolate->factory()->undefined_value(), *result);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ArgumentsForEach) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 4;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2017-01-27 11:20:07 +00:00
|
|
|
CodeStubArguments arguments(&m, m.IntPtrConstant(3));
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
Variable sum(&m, MachineRepresentation::kTagged);
|
2016-12-15 11:45:18 +00:00
|
|
|
CodeAssemblerVariableList list({&sum}, m.zone());
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2016-12-15 11:45:18 +00:00
|
|
|
sum.Bind(m.SmiConstant(0));
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2016-12-05 11:28:48 +00:00
|
|
|
arguments.ForEach(
|
2016-12-15 11:45:18 +00:00
|
|
|
list, [&m, &sum](Node* arg) { sum.Bind(m.SmiAdd(sum.value(), arg)); });
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2018-01-16 15:06:11 +00:00
|
|
|
arguments.PopAndReturn(sum.value());
|
2016-11-03 12:53:24 +00:00
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
2016-11-03 12:53:24 +00:00
|
|
|
Handle<Object> result = ft.Call(isolate->factory()->undefined_value(),
|
|
|
|
Handle<Smi>(Smi::FromInt(12), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(13), isolate),
|
|
|
|
Handle<Smi>(Smi::FromInt(14), isolate))
|
|
|
|
.ToHandleChecked();
|
|
|
|
CHECK_EQ(Smi::FromInt(12 + 13 + 14), *result);
|
|
|
|
}
|
|
|
|
|
2016-11-20 17:56:51 +00:00
|
|
|
TEST(IsDebugActive) {
|
|
|
|
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-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();
|
|
|
|
CHECK_EQ(isolate->heap()->false_value(), *result);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
result = ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
|
|
|
CHECK_EQ(isolate->heap()->true_value(), *result);
|
|
|
|
|
|
|
|
// Reset debug mode.
|
|
|
|
*debug_is_active = false;
|
|
|
|
}
|
|
|
|
|
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,
|
2016-11-29 16:57:58 +00:00
|
|
|
Object* o1, Object* o2, Object* o3, Object* o4,
|
|
|
|
int initial_size, int result_size) {
|
|
|
|
Handle<JSArray> array = isolate->factory()->NewJSArray(
|
|
|
|
kind_, 2, initial_size, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
|
|
|
|
JSObject::SetElement(isolate, array, 0,
|
2017-10-16 10:55:06 +00:00
|
|
|
Handle<Smi>(Smi::FromInt(1), isolate),
|
|
|
|
LanguageMode::kSloppy)
|
2016-11-29 16:57:58 +00:00
|
|
|
.Check();
|
|
|
|
JSObject::SetElement(isolate, array, 1,
|
2017-10-16 10:55:06 +00:00
|
|
|
Handle<Smi>(Smi::FromInt(2), isolate),
|
|
|
|
LanguageMode::kSloppy)
|
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);
|
|
|
|
Node* 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
|
|
|
|
|
|
|
Handle<Object> result =
|
|
|
|
ft.Call(Handle<Object>(o1, isolate), Handle<Object>(o2, isolate),
|
|
|
|
Handle<Object>(o3, isolate), Handle<Object>(o4, isolate))
|
|
|
|
.ToHandleChecked();
|
|
|
|
|
|
|
|
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()));
|
2016-11-29 16:57:58 +00:00
|
|
|
Object* obj = *JSObject::GetElement(isolate, array, 2).ToHandleChecked();
|
|
|
|
CHECK_EQ(result_size < 3 ? isolate->heap()->undefined_value() : o1, obj);
|
|
|
|
obj = *JSObject::GetElement(isolate, array, 3).ToHandleChecked();
|
|
|
|
CHECK_EQ(result_size < 4 ? isolate->heap()->undefined_value() : o2, obj);
|
|
|
|
obj = *JSObject::GetElement(isolate, array, 4).ToHandleChecked();
|
|
|
|
CHECK_EQ(result_size < 5 ? isolate->heap()->undefined_value() : o3, obj);
|
|
|
|
obj = *JSObject::GetElement(isolate, array, 5).ToHandleChecked();
|
|
|
|
CHECK_EQ(result_size < 6 ? isolate->heap()->undefined_value() : o4, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void TestAppendJSArray(Isolate* isolate, ElementsKind kind, Object* o1,
|
|
|
|
Object* o2, Object* o3, Object* o4,
|
|
|
|
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);
|
|
|
|
m.TestAppendJSArrayImpl(isolate, &asm_tester, o1, o2, o3, o4, initial_size,
|
2016-11-29 16:57:58 +00:00
|
|
|
result_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
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),
|
2016-11-29 16:57:58 +00:00
|
|
|
isolate->heap()->undefined_value(), Smi::FromInt(6), 6, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
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),
|
2016-11-29 16:57:58 +00:00
|
|
|
isolate->heap()->undefined_value(), Smi::FromInt(6), 2, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
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),
|
2016-11-29 16:57:58 +00:00
|
|
|
isolate->heap()->undefined_value(), Smi::FromInt(6), 6, 4);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
[inspector] change target promise for kDebugWillHandle & kDebugDidHandle
- kDebugPromiseCreated(task, parent_task)
This event occurs when promise is created (PromiseHookType::Init). V8Debugger uses this event to maintain task -> parent task map.
- kDebugEnqueueAsyncFunction(task)
This event occurs when first internal promise for async function is created. V8Debugger collects stack trace at this point.
- kDebugEnqueuePromiseResolve(task),
This event occurs when Promise fulfills with resolved status. V8Debugger collects stack trace at this point.
- kDebugEnqueuePromiseReject(task),
This event occurs when Promise fulfills with rejected status. V8Debugger collects stack trace at this point.
- kDebugPromiseCollected,
This event occurs when Promise is collected and no other chained callbacks can be added. V8Debugger removes information about async task for this promise.
- kDebugWillHandle,
This event occurs when chained promise function (either resolve or reject handler) is called. V8Debugger installs parent promise's stack (based on task -> parent_task map) as current if available or current promise's scheduled stack otherwise.
- kDebugDidHandle,
This event occurs after chained promise function has finished. V8Debugger restores asynchronous call chain to previous one.
With this change all instrumentation calls are related to current promise (before WillHandle and DidHandle were related to next async task).
Before V8Debugger supported only the following:
- asyncTaskScheduled(task1)
- asyncTaskStarted(task1)
- asyncTaskFinished(task1)
Now V8Debugger supports the following:
- asyncTaskScheduled(parent_task)
..
- asyncTaskCreated(task, parent_task),
- asyncTaskStarted(task), uses parent_task scheduled stack
- asyncTaskScheduled(task)
- asyncTaskFinished(task)
Additionally: WillHandle and DidHandle were migrated to PromiseHook API.
More details: https://docs.google.com/document/d/1u19N45f1gSF7M39mGsycJEK3IPyJgIXCBnWyiPeuJFE
BUG=v8:5738
R=dgozman@chromium.org,gsathya@chromium.org,yangguo@chromium.org
Review-Url: https://codereview.chromium.org/2650803003
Cr-Commit-Position: refs/heads/master@{#42644}
2017-01-25 07:05:43 +00:00
|
|
|
m.Return(m.SelectBooleanConstant(m.IsPromiseHookEnabledOrDebugIsActive()));
|
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();
|
|
|
|
CHECK_EQ(isolate->heap()->false_value(), *result);
|
|
|
|
|
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();
|
|
|
|
CHECK_EQ(isolate->heap()->true_value(), *result);
|
|
|
|
|
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();
|
|
|
|
CHECK_EQ(isolate->heap()->false_value(), *result);
|
|
|
|
}
|
|
|
|
|
2017-01-04 17:00:48 +00:00
|
|
|
TEST(AllocateAndInitJSPromise) {
|
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
|
|
|
|
|
|
|
Node* const context = m.Parameter(kNumParams + 2);
|
2017-01-04 17:00:48 +00:00
|
|
|
Node* const promise = m.AllocateAndInitJSPromise(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());
|
|
|
|
}
|
|
|
|
|
2017-01-04 17:00:48 +00:00
|
|
|
TEST(AllocateAndSetJSPromise) {
|
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
|
|
|
|
|
|
|
Node* const context = m.Parameter(kNumParams + 2);
|
2017-01-04 17:00:48 +00:00
|
|
|
Node* const promise = m.AllocateAndSetJSPromise(
|
2017-08-27 00:47:50 +00:00
|
|
|
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;
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2016-12-13 23:12:13 +00:00
|
|
|
|
|
|
|
Node* const symbol = m.Parameter(0);
|
|
|
|
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();
|
|
|
|
CHECK_EQ(isolate->heap()->true_value(), *result);
|
|
|
|
|
|
|
|
result = ft.Call(isolate->factory()->empty_string()).ToHandleChecked();
|
|
|
|
CHECK_EQ(isolate->heap()->false_value(), *result);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(IsPrivateSymbol) {
|
|
|
|
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-13 23:12:13 +00:00
|
|
|
|
|
|
|
Node* const symbol = m.Parameter(0);
|
|
|
|
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();
|
|
|
|
CHECK_EQ(isolate->heap()->false_value(), *result);
|
|
|
|
|
|
|
|
result = ft.Call(isolate->factory()->empty_string()).ToHandleChecked();
|
|
|
|
CHECK_EQ(isolate->heap()->false_value(), *result);
|
|
|
|
|
|
|
|
result = ft.Call(isolate->factory()->NewPrivateSymbol()).ToHandleChecked();
|
|
|
|
CHECK_EQ(isolate->heap()->true_value(), *result);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|
|
Node* const context = m.Parameter(kNumParams + 2);
|
2017-01-04 17:00:48 +00:00
|
|
|
Node* const promise =
|
|
|
|
m.AllocateAndInitJSPromise(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();
|
|
|
|
CHECK_EQ(isolate->heap()->false_value(), *result);
|
|
|
|
}
|
|
|
|
|
2016-12-19 22:21:35 +00:00
|
|
|
TEST(CreatePromiseResolvingFunctionsContext) {
|
|
|
|
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
|
|
|
|
|
|
|
Node* const context = m.Parameter(kNumParams + 2);
|
|
|
|
Node* const native_context = m.LoadNativeContext(context);
|
2017-01-04 17:00:48 +00:00
|
|
|
Node* const promise =
|
|
|
|
m.AllocateAndInitJSPromise(context, m.UndefinedConstant());
|
2016-12-19 22:21:35 +00:00
|
|
|
Node* const promise_context = m.CreatePromiseResolvingFunctionsContext(
|
|
|
|
promise, m.BooleanConstant(false), native_context);
|
|
|
|
m.Return(promise_context);
|
|
|
|
|
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 =
|
|
|
|
ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
|
|
|
CHECK(result->IsContext());
|
|
|
|
Handle<Context> context_js = Handle<Context>::cast(result);
|
|
|
|
CHECK_EQ(isolate->native_context()->closure(), context_js->closure());
|
|
|
|
CHECK_EQ(isolate->heap()->the_hole_value(), context_js->extension());
|
|
|
|
CHECK_EQ(*isolate->native_context(), context_js->native_context());
|
2017-01-17 17:09:51 +00:00
|
|
|
CHECK(context_js->get(PromiseBuiltinsAssembler::kPromiseSlot)->IsJSPromise());
|
2016-12-19 22:21:35 +00:00
|
|
|
CHECK_EQ(isolate->heap()->false_value(),
|
2017-01-17 17:09:51 +00:00
|
|
|
context_js->get(PromiseBuiltinsAssembler::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
|
|
|
|
|
|
|
Node* const context = m.Parameter(kNumParams + 2);
|
|
|
|
Node* const native_context = m.LoadNativeContext(context);
|
2017-01-04 17:00:48 +00:00
|
|
|
Node* const promise =
|
|
|
|
m.AllocateAndInitJSPromise(context, m.UndefinedConstant());
|
2016-12-19 22:21:35 +00:00
|
|
|
Node *resolve, *reject;
|
|
|
|
std::tie(resolve, reject) = m.CreatePromiseResolvingFunctions(
|
|
|
|
promise, m.BooleanConstant(false), native_context);
|
|
|
|
Node* const kSize = m.IntPtrConstant(2);
|
2017-06-30 11:26:14 +00:00
|
|
|
Node* const arr = 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());
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, 1);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-01-10 01:48:11 +00:00
|
|
|
m.Return(m.SmiTag(m.CalculateNewElementsCapacity(
|
|
|
|
m.SmiUntag(m.Parameter(0)), CodeStubAssembler::INTPTR_PARAMETERS)));
|
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())));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(NewElementsCapacitySmi) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
2017-07-18 13:45:08 +00:00
|
|
|
CodeAssemblerTester asm_tester(isolate, 1);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-01-10 01:48:11 +00:00
|
|
|
m.Return(m.CalculateNewElementsCapacity(m.Parameter(0),
|
|
|
|
CodeStubAssembler::SMI_PARAMETERS));
|
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
|
|
|
|
|
|
|
Node* const context = m.Parameter(kNumParams + 2);
|
|
|
|
Node* const native_context = m.LoadNativeContext(context);
|
2017-01-04 17:00:48 +00:00
|
|
|
Node* const promise =
|
|
|
|
m.AllocateAndInitJSPromise(context, m.UndefinedConstant());
|
2016-12-19 22:21:35 +00:00
|
|
|
Node* promise_context = m.CreatePromiseResolvingFunctionsContext(
|
|
|
|
promise, m.BooleanConstant(false), native_context);
|
[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
|
|
|
Node* resolve_info = m.LoadContextElement(
|
|
|
|
native_context,
|
|
|
|
Context::PROMISE_CAPABILITY_DEFAULT_RESOLVE_SHARED_FUN_INDEX);
|
2016-12-19 22:21:35 +00:00
|
|
|
Node* const map = m.LoadContextElement(
|
|
|
|
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
|
|
|
|
Node* const resolve =
|
|
|
|
m.AllocateFunctionWithMapAndContext(map, resolve_info, promise_context);
|
|
|
|
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);
|
2017-07-17 23:30:32 +00:00
|
|
|
CHECK_EQ(isolate->heap()->empty_property_array(), fun->property_array());
|
2016-12-19 22:21:35 +00:00
|
|
|
CHECK_EQ(isolate->heap()->empty_fixed_array(), fun->elements());
|
2017-02-06 10:18:05 +00:00
|
|
|
CHECK_EQ(isolate->heap()->undefined_cell(), fun->feedback_vector_cell());
|
2017-10-12 15:37:46 +00:00
|
|
|
CHECK(!fun->has_prototype_slot());
|
[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
|
|
|
CHECK_EQ(*isolate->promise_capability_default_resolve_shared_fun(),
|
|
|
|
fun->shared());
|
|
|
|
CHECK_EQ(isolate->promise_capability_default_resolve_shared_fun()->code(),
|
|
|
|
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
|
|
|
|
|
|
|
Node* const context = m.Parameter(kNumParams + 2);
|
|
|
|
Node* const native_context = m.LoadNativeContext(context);
|
|
|
|
|
2018-02-08 16:36:52 +00:00
|
|
|
Node* const map = m.LoadRoot(Heap::kPromiseCapabilityMapRootIndex);
|
2017-08-30 17:03:38 +00:00
|
|
|
Node* const capability = m.AllocateStruct(map);
|
2017-01-02 17:22:30 +00:00
|
|
|
m.StoreObjectFieldNoWriteBarrier(
|
2017-08-30 17:03:38 +00:00
|
|
|
capability, PromiseCapability::kPromiseOffset, m.UndefinedConstant());
|
2017-01-02 17:22:30 +00:00
|
|
|
m.StoreObjectFieldNoWriteBarrier(
|
2017-08-30 17:03:38 +00:00
|
|
|
capability, PromiseCapability::kResolveOffset, m.UndefinedConstant());
|
|
|
|
m.StoreObjectFieldNoWriteBarrier(capability, PromiseCapability::kRejectOffset,
|
|
|
|
m.UndefinedConstant());
|
2017-01-02 17:22:30 +00:00
|
|
|
Node* const executor_context =
|
|
|
|
m.CreatePromiseGetCapabilitiesExecutorContext(capability, native_context);
|
|
|
|
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);
|
2017-01-17 17:09:51 +00:00
|
|
|
CHECK_EQ(PromiseBuiltinsAssembler::kCapabilitiesContextLength,
|
|
|
|
context_js->length());
|
2017-01-02 17:22:30 +00:00
|
|
|
CHECK_EQ(isolate->native_context()->closure(), context_js->closure());
|
|
|
|
CHECK_EQ(isolate->heap()->the_hole_value(), context_js->extension());
|
|
|
|
CHECK_EQ(*isolate->native_context(), context_js->native_context());
|
2017-01-17 17:09:51 +00:00
|
|
|
CHECK(context_js->get(PromiseBuiltinsAssembler::kCapabilitySlot)
|
2017-08-30 17:03:38 +00:00
|
|
|
->IsPromiseCapability());
|
2017-01-02 17:22:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(NewPromiseCapability) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
{ // Builtin Promise
|
|
|
|
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
|
|
|
|
|
|
|
Node* const context = m.Parameter(kNumParams + 2);
|
|
|
|
Node* const native_context = m.LoadNativeContext(context);
|
|
|
|
Node* const promise_constructor =
|
|
|
|
m.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
|
|
|
|
|
2018-02-08 16:36:52 +00:00
|
|
|
Node* const debug_event = m.TrueConstant();
|
2017-01-02 17:22:30 +00:00
|
|
|
Node* const capability =
|
2018-02-08 16:36:52 +00:00
|
|
|
m.CallBuiltin(Builtins::kNewPromiseCapability, context,
|
|
|
|
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
|
|
|
|
|
|
|
Handle<Object> result_obj =
|
|
|
|
ft.Call(isolate->factory()->undefined_value()).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());
|
[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
|
|
|
CHECK_EQ(*isolate->promise_capability_default_reject_shared_fun(),
|
2017-01-02 17:22:30 +00:00
|
|
|
JSFunction::cast(result->reject())->shared());
|
[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
|
|
|
CHECK_EQ(*isolate->promise_capability_default_resolve_shared_fun(),
|
|
|
|
JSFunction::cast(result->resolve())->shared());
|
2017-01-02 17:22:30 +00:00
|
|
|
|
|
|
|
Handle<JSFunction> callbacks[] = {
|
|
|
|
handle(JSFunction::cast(result->resolve())),
|
|
|
|
handle(JSFunction::cast(result->reject()))};
|
|
|
|
|
|
|
|
for (auto&& callback : callbacks) {
|
|
|
|
Handle<Context> context(Context::cast(callback->context()));
|
|
|
|
CHECK_EQ(isolate->native_context()->closure(), context->closure());
|
|
|
|
CHECK_EQ(isolate->heap()->the_hole_value(), context->extension());
|
|
|
|
CHECK_EQ(*isolate->native_context(), context->native_context());
|
2017-01-17 17:09:51 +00:00
|
|
|
CHECK_EQ(PromiseBuiltinsAssembler::kPromiseContextLength,
|
|
|
|
context->length());
|
|
|
|
CHECK_EQ(context->get(PromiseBuiltinsAssembler::kPromiseSlot),
|
|
|
|
result->promise());
|
2017-01-02 17:22:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{ // Custom Promise
|
|
|
|
const int kNumParams = 2;
|
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
|
|
|
|
|
|
|
Node* const context = m.Parameter(kNumParams + 2);
|
|
|
|
|
|
|
|
Node* const constructor = m.Parameter(1);
|
2018-02-08 16:36:52 +00:00
|
|
|
Node* const debug_event = m.TrueConstant();
|
|
|
|
Node* const capability = m.CallBuiltin(Builtins::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);"
|
|
|
|
"})")));
|
|
|
|
|
|
|
|
Handle<Object> result_obj =
|
|
|
|
ft.Call(isolate->factory()->undefined_value(), 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());
|
|
|
|
Handle<JSObject> promise(JSObject::cast(result->promise()));
|
|
|
|
CHECK_EQ(constructor_fn->prototype_or_initial_map(), promise->map());
|
|
|
|
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);
|
|
|
|
|
|
|
|
Node* buffer_node = m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
|
|
|
|
for (size_t i = 0; i < element_count; ++i) {
|
|
|
|
for (size_t j = 0; j < element_count; ++j) {
|
|
|
|
Node* loaded = m.LoadBufferObject(buffer_node, static_cast<int>(i),
|
|
|
|
MachineType::Uint8());
|
|
|
|
Node* masked = m.Word32And(loaded, m.Int32Constant(buffer[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(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);
|
|
|
|
|
|
|
|
Node* buffer_node = m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
|
|
|
|
for (size_t i = 0; i < element_count; ++i) {
|
|
|
|
for (size_t j = 0; j < element_count; ++j) {
|
|
|
|
Node* loaded =
|
|
|
|
m.LoadBufferObject(buffer_node, static_cast<int>(i * sizeof(int16_t)),
|
|
|
|
MachineType::Uint16());
|
|
|
|
Node* masked = m.Word32And(loaded, m.Int32Constant(buffer[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(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);
|
|
|
|
Node* constants[element_count];
|
|
|
|
|
|
|
|
Node* buffer_node = m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
|
|
|
|
for (size_t i = 0; i < element_count; ++i) {
|
|
|
|
constants[i] = m.LoadBufferObject(buffer_node, static_cast<int>(i),
|
|
|
|
MachineType::Uint8());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < element_count; ++i) {
|
|
|
|
for (size_t j = 0; j < element_count; ++j) {
|
|
|
|
Node* loaded = m.LoadBufferObject(buffer_node, static_cast<int>(i),
|
|
|
|
MachineType::Uint8());
|
|
|
|
Node* 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
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
Node* constants[element_count];
|
|
|
|
|
|
|
|
Node* buffer_node1 = m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
|
|
|
|
for (size_t i = 0; i < element_count; ++i) {
|
|
|
|
constants[i] =
|
|
|
|
m.LoadBufferObject(buffer_node1, static_cast<int>(i * sizeof(int16_t)),
|
|
|
|
MachineType::Uint16());
|
|
|
|
}
|
|
|
|
Node* buffer_node2 = m.IntPtrConstant(reinterpret_cast<intptr_t>(buffer));
|
|
|
|
|
|
|
|
for (size_t i = 0; i < element_count; ++i) {
|
|
|
|
for (size_t j = 0; j < element_count; ++j) {
|
|
|
|
Node* loaded = m.LoadBufferObject(buffer_node1,
|
|
|
|
static_cast<int>(i * sizeof(int16_t)),
|
|
|
|
MachineType::Uint16());
|
|
|
|
Node* 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Force a memory access relative to a high-number register.
|
|
|
|
loaded = m.LoadBufferObject(buffer_node2,
|
|
|
|
static_cast<int>(i * sizeof(int16_t)),
|
|
|
|
MachineType::Uint16());
|
|
|
|
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;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
Node* context = m.Parameter(kNumParams + 2);
|
|
|
|
Node* native_context = m.LoadNativeContext(context);
|
|
|
|
Node* kind = m.SmiToWord32(m.Parameter(0));
|
|
|
|
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(
|
|
|
|
isolate->native_context()->GetInitialJSArrayMap(elements_kind));
|
|
|
|
CHECK_EQ(*csa_result, *result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-30 17:03:38 +00:00
|
|
|
TEST(AllocateStruct) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 3;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
{
|
|
|
|
Node* map = m.Parameter(0);
|
|
|
|
Node* result = m.AllocateStruct(map);
|
|
|
|
|
|
|
|
m.Return(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<Map> maps[] = {
|
2017-10-23 08:23:37 +00:00
|
|
|
handle(isolate->heap()->tuple3_map(), isolate),
|
2017-08-30 17:03:38 +00:00
|
|
|
handle(isolate->heap()->tuple2_map(), isolate),
|
|
|
|
};
|
|
|
|
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < 2; i++) {
|
|
|
|
Handle<Map> map = maps[i];
|
|
|
|
Handle<Struct> result =
|
|
|
|
Handle<Struct>::cast(ft.Call(map).ToHandleChecked());
|
|
|
|
CHECK_EQ(result->map(), *map);
|
|
|
|
#ifdef VERIFY_HEAP
|
|
|
|
isolate->heap()->Verify();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-05 02:19:29 +00:00
|
|
|
TEST(GotoIfNotWhiteSpaceOrLineTerminator) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
|
|
|
|
const int kNumParams = 1;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
StringTrimAssembler m(asm_tester.state());
|
|
|
|
|
|
|
|
{ // Returns true if whitespace, false otherwise.
|
|
|
|
Label if_not_whitespace(&m);
|
|
|
|
|
|
|
|
m.GotoIfNotWhiteSpaceOrLineTerminator(m.SmiToWord32(m.Parameter(0)),
|
|
|
|
&if_not_whitespace);
|
|
|
|
m.Return(m.TrueConstant());
|
|
|
|
|
|
|
|
m.BIND(&if_not_whitespace);
|
|
|
|
m.Return(m.FalseConstant());
|
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<Object> true_value = ft.true_value();
|
|
|
|
Handle<Object> false_value = ft.false_value();
|
|
|
|
|
|
|
|
for (uc16 c = 0; c < 0xFFFF; c++) {
|
|
|
|
Handle<Object> expected_value =
|
|
|
|
WhiteSpaceOrLineTerminator::Is(c) ? true_value : false_value;
|
|
|
|
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;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
Label return_true(&m), return_false(&m);
|
2017-12-13 00:12:10 +00:00
|
|
|
m.BranchIfNumberRelationalComparison(Operation::kGreaterThanOrEqual,
|
|
|
|
m.Parameter(0), m.Parameter(1),
|
|
|
|
&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;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
m.Return(m.SmiFromWord32(m.IsNumberArrayIndex(m.Parameter(0))));
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
CodeAssemblerTester asm_tester_min(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester_min.state());
|
|
|
|
m.Return(m.NumberMin(m.Parameter(0), m.Parameter(1)));
|
|
|
|
}
|
|
|
|
FunctionTester ft_min(asm_tester_min.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
CodeAssemblerTester asm_tester_max(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester_max.state());
|
|
|
|
m.Return(m.NumberMax(m.Parameter(0), m.Parameter(1)));
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
CodeAssemblerTester asm_tester_add(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester_add.state());
|
|
|
|
m.Return(m.NumberAdd(m.Parameter(0), m.Parameter(1)));
|
|
|
|
}
|
|
|
|
FunctionTester ft_add(asm_tester_add.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
CodeAssemblerTester asm_tester_sub(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester_sub.state());
|
|
|
|
m.Return(m.NumberSub(m.Parameter(0), m.Parameter(1)));
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
m.Return(m.CloneFixedArray(m.Parameter(0)));
|
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<FixedArray> source(isolate->factory()->empty_fixed_array());
|
|
|
|
Handle<Object> result_raw = ft.Call(source).ToHandleChecked();
|
|
|
|
FixedArray* result(FixedArray::cast(*result_raw));
|
|
|
|
CHECK_EQ(0, result->length());
|
|
|
|
CHECK_EQ(*(isolate->factory()->empty_fixed_array()), result);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(CloneFixedArray) {
|
|
|
|
Isolate* isolate(CcTest::InitIsolateOnce());
|
|
|
|
const int kNumParams = 1;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
m.Return(m.CloneFixedArray(m.Parameter(0)));
|
|
|
|
}
|
|
|
|
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();
|
|
|
|
FixedArray* result(FixedArray::cast(*result_raw));
|
|
|
|
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;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
m.Return(m.CloneFixedArray(m.Parameter(0)));
|
|
|
|
}
|
|
|
|
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
|
|
|
|
|
|
|
Handle<FixedArray> source(isolate->factory()->NewFixedArrayWithHoles(5));
|
|
|
|
source->set(1, Smi::FromInt(1234));
|
|
|
|
source->set_map(isolate->heap()->fixed_cow_array_map());
|
|
|
|
Handle<Object> result_raw = ft.Call(source).ToHandleChecked();
|
|
|
|
FixedArray* result(FixedArray::cast(*result_raw));
|
|
|
|
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;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
CodeStubAssembler::ExtractFixedArrayFlags flags;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kAllFixedArrays;
|
2017-10-19 14:17:56 +00:00
|
|
|
m.Return(m.ExtractFixedArray(m.Parameter(0), m.SmiConstant(0), nullptr,
|
|
|
|
nullptr, flags,
|
|
|
|
CodeStubAssembler::SMI_PARAMETERS));
|
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));
|
|
|
|
source->set_map(isolate->heap()->fixed_cow_array_map());
|
|
|
|
Handle<Object> result_raw = ft.Call(source).ToHandleChecked();
|
|
|
|
FixedArray* result(FixedArray::cast(*result_raw));
|
|
|
|
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;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-10-19 14:17:56 +00:00
|
|
|
CodeStubAssembler::ExtractFixedArrayFlags flags;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kAllFixedArrays;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kDontCopyCOW;
|
|
|
|
m.Return(m.ExtractFixedArray(m.Parameter(0), m.Parameter(1), m.Parameter(2),
|
|
|
|
nullptr, flags,
|
|
|
|
CodeStubAssembler::SMI_PARAMETERS));
|
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();
|
|
|
|
FixedArray* result(FixedArray::cast(*result_raw));
|
|
|
|
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;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-10-19 14:17:56 +00:00
|
|
|
CodeStubAssembler::ExtractFixedArrayFlags flags;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kAllFixedArrays;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kDontCopyCOW;
|
|
|
|
m.Return(m.ExtractFixedArray(m.Parameter(0), m.SmiConstant(1),
|
|
|
|
m.SmiConstant(2), nullptr, flags,
|
|
|
|
CodeStubAssembler::SMI_PARAMETERS));
|
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();
|
|
|
|
FixedArray* result(FixedArray::cast(*result_raw));
|
|
|
|
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;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
2017-10-19 14:17:56 +00:00
|
|
|
CodeStubAssembler::ExtractFixedArrayFlags flags;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kAllFixedArrays;
|
|
|
|
flags |= CodeStubAssembler::ExtractFixedArrayFlag::kDontCopyCOW;
|
|
|
|
m.Return(m.ExtractFixedArray(m.Parameter(0), m.IntPtrConstant(1),
|
|
|
|
m.IntPtrConstant(2), nullptr, flags,
|
|
|
|
CodeStubAssembler::INTPTR_PARAMETERS));
|
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();
|
|
|
|
FixedArray* result(FixedArray::cast(*result_raw));
|
|
|
|
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;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
m.Return(m.ExtractFixedArray(
|
|
|
|
m.Parameter(0), m.IntPtrConstant(1), m.IntPtrConstant(2), nullptr,
|
|
|
|
CodeStubAssembler::ExtractFixedArrayFlag::kFixedArrays,
|
|
|
|
CodeStubAssembler::INTPTR_PARAMETERS));
|
|
|
|
}
|
|
|
|
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();
|
|
|
|
FixedArray* result(FixedArray::cast(*result_raw));
|
|
|
|
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;
|
|
|
|
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
|
|
|
{
|
|
|
|
CodeStubAssembler m(asm_tester.state());
|
|
|
|
Node* p1_untagged = m.SmiUntag(m.Parameter(1));
|
|
|
|
Node* p2_untagged = m.SmiUntag(m.Parameter(2));
|
|
|
|
m.Return(m.ExtractFixedArray(m.Parameter(0), p1_untagged, p2_untagged));
|
|
|
|
}
|
|
|
|
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();
|
|
|
|
FixedArray* result(FixedArray::cast(*result_raw));
|
|
|
|
CHECK_EQ(2, result->length());
|
|
|
|
CHECK_EQ(Smi::cast(result->get(0))->value(), 1234);
|
|
|
|
CHECK(result->get(1)->IsTheHole(isolate));
|
|
|
|
|
|
|
|
Handle<FixedDoubleArray> source_double(Handle<FixedDoubleArray>::cast(
|
|
|
|
isolate->factory()->NewFixedDoubleArray(5)));
|
|
|
|
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();
|
|
|
|
FixedDoubleArray* double_result(FixedDoubleArray::cast(*double_result_raw));
|
|
|
|
CHECK_EQ(2, double_result->length());
|
|
|
|
CHECK_EQ(double_result->get_scalar(0), 11);
|
|
|
|
CHECK_EQ(double_result->get_scalar(1), 12);
|
|
|
|
}
|
|
|
|
|
2017-07-18 13:45:08 +00:00
|
|
|
} // namespace compiler
|
2016-06-01 21:08:22 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|