| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "src/base/utils/random-number-generator.h" | |
| 6 #include "src/interface-descriptors.h" | |
| 7 #include "src/isolate.h" | |
| 8 #include "test/cctest/compiler/function-tester.h" | |
| 9 | |
| 10 namespace v8 { | |
| 11 namespace internal { | |
| 12 | |
| 13 using compiler::FunctionTester; | |
| 14 using compiler::Node; | |
| 15 | |
| 16 class CodeStubAssemblerTester : public CodeStubAssembler { | |
| 17 public: | |
| 18 // Test generating code for a stub. | |
| 19 CodeStubAssemblerTester(Isolate* isolate, | |
| 20 const CallInterfaceDescriptor& descriptor) | |
| 21 : CodeStubAssembler(isolate, isolate->runtime_zone(), descriptor, | |
| 22 Code::ComputeFlags(Code::STUB), "test"), | |
| 23 zone_scope_(isolate->runtime_zone()), | |
| 24 scope_(isolate) {} | |
| 25 | |
| 26 // Test generating code for a JS function (e.g. builtins). | |
| 27 CodeStubAssemblerTester(Isolate* isolate, int parameter_count) | |
| 28 : CodeStubAssembler(isolate, isolate->runtime_zone(), parameter_count, | |
| 29 Code::ComputeFlags(Code::FUNCTION), "test"), | |
| 30 zone_scope_(isolate->runtime_zone()), | |
| 31 scope_(isolate) {} | |
| 32 | |
| 33 private: | |
| 34 ZoneScope zone_scope_; | |
| 35 HandleScope scope_; | |
| 36 LocalContext context_; | |
| 37 }; | |
| 38 | |
| 39 TEST(SimpleSmiReturn) { | |
| 40 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 41 VoidDescriptor descriptor(isolate); | |
| 42 CodeStubAssemblerTester m(isolate, descriptor); | |
| 43 m.Return(m.SmiTag(m.Int32Constant(37))); | |
| 44 Handle<Code> code = m.GenerateCode(); | |
| 45 FunctionTester ft(descriptor, code); | |
| 46 MaybeHandle<Object> result = ft.Call(); | |
| 47 CHECK_EQ(37, Handle<Smi>::cast(result.ToHandleChecked())->value()); | |
| 48 } | |
| 49 | |
| 50 TEST(SimpleIntPtrReturn) { | |
| 51 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 52 VoidDescriptor descriptor(isolate); | |
| 53 CodeStubAssemblerTester m(isolate, descriptor); | |
| 54 int test; | |
| 55 m.Return(m.IntPtrConstant(reinterpret_cast<intptr_t>(&test))); | |
| 56 Handle<Code> code = m.GenerateCode(); | |
| 57 FunctionTester ft(descriptor, code); | |
| 58 MaybeHandle<Object> result = ft.Call(); | |
| 59 CHECK_EQ(reinterpret_cast<intptr_t>(&test), | |
| 60 reinterpret_cast<intptr_t>(*result.ToHandleChecked())); | |
| 61 } | |
| 62 | |
| 63 TEST(SimpleDoubleReturn) { | |
| 64 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 65 VoidDescriptor descriptor(isolate); | |
| 66 CodeStubAssemblerTester m(isolate, descriptor); | |
| 67 m.Return(m.NumberConstant(0.5)); | |
| 68 Handle<Code> code = m.GenerateCode(); | |
| 69 FunctionTester ft(descriptor, code); | |
| 70 MaybeHandle<Object> result = ft.Call(); | |
| 71 CHECK_EQ(0.5, Handle<HeapNumber>::cast(result.ToHandleChecked())->value()); | |
| 72 } | |
| 73 | |
| 74 TEST(SimpleCallRuntime1Arg) { | |
| 75 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 76 VoidDescriptor descriptor(isolate); | |
| 77 CodeStubAssemblerTester m(isolate, descriptor); | |
| 78 Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); | |
| 79 Node* b = m.SmiTag(m.Int32Constant(0)); | |
| 80 m.Return(m.CallRuntime(Runtime::kNumberToSmi, context, b)); | |
| 81 Handle<Code> code = m.GenerateCode(); | |
| 82 FunctionTester ft(descriptor, code); | |
| 83 MaybeHandle<Object> result = ft.Call(); | |
| 84 CHECK_EQ(0, Handle<Smi>::cast(result.ToHandleChecked())->value()); | |
| 85 } | |
| 86 | |
| 87 TEST(SimpleTailCallRuntime1Arg) { | |
| 88 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 89 VoidDescriptor descriptor(isolate); | |
| 90 CodeStubAssemblerTester m(isolate, descriptor); | |
| 91 Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); | |
| 92 Node* b = m.SmiTag(m.Int32Constant(0)); | |
| 93 m.TailCallRuntime(Runtime::kNumberToSmi, context, b); | |
| 94 Handle<Code> code = m.GenerateCode(); | |
| 95 FunctionTester ft(descriptor, code); | |
| 96 MaybeHandle<Object> result = ft.Call(); | |
| 97 CHECK_EQ(0, Handle<Smi>::cast(result.ToHandleChecked())->value()); | |
| 98 } | |
| 99 | |
| 100 TEST(SimpleCallRuntime2Arg) { | |
| 101 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 102 VoidDescriptor descriptor(isolate); | |
| 103 CodeStubAssemblerTester m(isolate, descriptor); | |
| 104 Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); | |
| 105 Node* a = m.SmiTag(m.Int32Constant(2)); | |
| 106 Node* b = m.SmiTag(m.Int32Constant(4)); | |
| 107 m.Return(m.CallRuntime(Runtime::kMathPow, context, a, b)); | |
| 108 Handle<Code> code = m.GenerateCode(); | |
| 109 FunctionTester ft(descriptor, code); | |
| 110 MaybeHandle<Object> result = ft.Call(); | |
| 111 CHECK_EQ(16, Handle<Smi>::cast(result.ToHandleChecked())->value()); | |
| 112 } | |
| 113 | |
| 114 TEST(SimpleTailCallRuntime2Arg) { | |
| 115 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 116 VoidDescriptor descriptor(isolate); | |
| 117 CodeStubAssemblerTester m(isolate, descriptor); | |
| 118 Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); | |
| 119 Node* a = m.SmiTag(m.Int32Constant(2)); | |
| 120 Node* b = m.SmiTag(m.Int32Constant(4)); | |
| 121 m.TailCallRuntime(Runtime::kMathPow, context, a, b); | |
| 122 Handle<Code> code = m.GenerateCode(); | |
| 123 FunctionTester ft(descriptor, code); | |
| 124 MaybeHandle<Object> result = ft.Call(); | |
| 125 CHECK_EQ(16, Handle<Smi>::cast(result.ToHandleChecked())->value()); | |
| 126 } | |
| 127 | |
| 128 TEST(VariableMerge1) { | |
| 129 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 130 VoidDescriptor descriptor(isolate); | |
| 131 CodeStubAssemblerTester m(isolate, descriptor); | |
| 132 CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); | |
| 133 CodeStubAssembler::Label l1(&m), l2(&m), merge(&m); | |
| 134 Node* temp = m.Int32Constant(0); | |
| 135 var1.Bind(temp); | |
| 136 m.Branch(m.Int32Constant(1), &l1, &l2); | |
| 137 m.Bind(&l1); | |
| 138 CHECK_EQ(var1.value(), temp); | |
| 139 m.Goto(&merge); | |
| 140 m.Bind(&l2); | |
| 141 CHECK_EQ(var1.value(), temp); | |
| 142 m.Goto(&merge); | |
| 143 m.Bind(&merge); | |
| 144 CHECK_EQ(var1.value(), temp); | |
| 145 } | |
| 146 | |
| 147 TEST(VariableMerge2) { | |
| 148 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 149 VoidDescriptor descriptor(isolate); | |
| 150 CodeStubAssemblerTester m(isolate, descriptor); | |
| 151 CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); | |
| 152 CodeStubAssembler::Label l1(&m), l2(&m), merge(&m); | |
| 153 Node* temp = m.Int32Constant(0); | |
| 154 var1.Bind(temp); | |
| 155 m.Branch(m.Int32Constant(1), &l1, &l2); | |
| 156 m.Bind(&l1); | |
| 157 CHECK_EQ(var1.value(), temp); | |
| 158 m.Goto(&merge); | |
| 159 m.Bind(&l2); | |
| 160 Node* temp2 = m.Int32Constant(2); | |
| 161 var1.Bind(temp2); | |
| 162 CHECK_EQ(var1.value(), temp2); | |
| 163 m.Goto(&merge); | |
| 164 m.Bind(&merge); | |
| 165 CHECK_NE(var1.value(), temp); | |
| 166 } | |
| 167 | |
| 168 TEST(VariableMerge3) { | |
| 169 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 170 VoidDescriptor descriptor(isolate); | |
| 171 CodeStubAssemblerTester m(isolate, descriptor); | |
| 172 CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); | |
| 173 CodeStubAssembler::Variable var2(&m, MachineRepresentation::kTagged); | |
| 174 CodeStubAssembler::Label l1(&m), l2(&m), merge(&m); | |
| 175 Node* temp = m.Int32Constant(0); | |
| 176 var1.Bind(temp); | |
| 177 var2.Bind(temp); | |
| 178 m.Branch(m.Int32Constant(1), &l1, &l2); | |
| 179 m.Bind(&l1); | |
| 180 CHECK_EQ(var1.value(), temp); | |
| 181 m.Goto(&merge); | |
| 182 m.Bind(&l2); | |
| 183 Node* temp2 = m.Int32Constant(2); | |
| 184 var1.Bind(temp2); | |
| 185 CHECK_EQ(var1.value(), temp2); | |
| 186 m.Goto(&merge); | |
| 187 m.Bind(&merge); | |
| 188 CHECK_NE(var1.value(), temp); | |
| 189 CHECK_NE(var1.value(), temp2); | |
| 190 CHECK_EQ(var2.value(), temp); | |
| 191 } | |
| 192 | |
| 193 TEST(VariableMergeBindFirst) { | |
| 194 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 195 VoidDescriptor descriptor(isolate); | |
| 196 CodeStubAssemblerTester m(isolate, descriptor); | |
| 197 CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); | |
| 198 CodeStubAssembler::Label l1(&m), l2(&m), merge(&m, &var1), end(&m); | |
| 199 Node* temp = m.Int32Constant(0); | |
| 200 var1.Bind(temp); | |
| 201 m.Branch(m.Int32Constant(1), &l1, &l2); | |
| 202 m.Bind(&l1); | |
| 203 CHECK_EQ(var1.value(), temp); | |
| 204 m.Goto(&merge); | |
| 205 m.Bind(&merge); | |
| 206 CHECK(var1.value() != temp); | |
| 207 CHECK(var1.value() != nullptr); | |
| 208 m.Goto(&end); | |
| 209 m.Bind(&l2); | |
| 210 Node* temp2 = m.Int32Constant(2); | |
| 211 var1.Bind(temp2); | |
| 212 CHECK_EQ(var1.value(), temp2); | |
| 213 m.Goto(&merge); | |
| 214 m.Bind(&end); | |
| 215 CHECK(var1.value() != temp); | |
| 216 CHECK(var1.value() != nullptr); | |
| 217 } | |
| 218 | |
| 219 TEST(VariableMergeSwitch) { | |
| 220 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 221 VoidDescriptor descriptor(isolate); | |
| 222 CodeStubAssemblerTester m(isolate, descriptor); | |
| 223 CodeStubAssembler::Variable var1(&m, MachineRepresentation::kTagged); | |
| 224 CodeStubAssembler::Label l1(&m), l2(&m), default_label(&m); | |
| 225 CodeStubAssembler::Label* labels[] = {&l1, &l2}; | |
| 226 int32_t values[] = {1, 2}; | |
| 227 Node* temp = m.Int32Constant(0); | |
| 228 var1.Bind(temp); | |
| 229 m.Switch(m.Int32Constant(2), &default_label, values, labels, 2); | |
| 230 m.Bind(&l1); | |
| 231 DCHECK_EQ(temp, var1.value()); | |
| 232 m.Return(temp); | |
| 233 m.Bind(&l2); | |
| 234 DCHECK_EQ(temp, var1.value()); | |
| 235 m.Return(temp); | |
| 236 m.Bind(&default_label); | |
| 237 DCHECK_EQ(temp, var1.value()); | |
| 238 m.Return(temp); | |
| 239 } | |
| 240 | |
| 241 TEST(FixedArrayAccessSmiIndex) { | |
| 242 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 243 VoidDescriptor descriptor(isolate); | |
| 244 CodeStubAssemblerTester m(isolate, descriptor); | |
| 245 Handle<FixedArray> array = isolate->factory()->NewFixedArray(5); | |
| 246 array->set(4, Smi::FromInt(733)); | |
| 247 m.Return(m.LoadFixedArrayElement(m.HeapConstant(array), | |
| 248 m.SmiTag(m.Int32Constant(4)), 0, | |
| 249 CodeStubAssembler::SMI_PARAMETERS)); | |
| 250 Handle<Code> code = m.GenerateCode(); | |
| 251 FunctionTester ft(descriptor, code); | |
| 252 MaybeHandle<Object> result = ft.Call(); | |
| 253 CHECK_EQ(733, Handle<Smi>::cast(result.ToHandleChecked())->value()); | |
| 254 } | |
| 255 | |
| 256 TEST(LoadHeapNumberValue) { | |
| 257 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 258 VoidDescriptor descriptor(isolate); | |
| 259 CodeStubAssemblerTester m(isolate, descriptor); | |
| 260 Handle<HeapNumber> number = isolate->factory()->NewHeapNumber(1234); | |
| 261 m.Return(m.SmiTag( | |
| 262 m.ChangeFloat64ToUint32(m.LoadHeapNumberValue(m.HeapConstant(number))))); | |
| 263 Handle<Code> code = m.GenerateCode(); | |
| 264 FunctionTester ft(descriptor, code); | |
| 265 MaybeHandle<Object> result = ft.Call(); | |
| 266 CHECK_EQ(1234, Handle<Smi>::cast(result.ToHandleChecked())->value()); | |
| 267 } | |
| 268 | |
| 269 TEST(LoadInstanceType) { | |
| 270 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 271 VoidDescriptor descriptor(isolate); | |
| 272 CodeStubAssemblerTester m(isolate, descriptor); | |
| 273 Handle<HeapObject> undefined = isolate->factory()->undefined_value(); | |
| 274 m.Return(m.SmiTag(m.LoadInstanceType(m.HeapConstant(undefined)))); | |
| 275 Handle<Code> code = m.GenerateCode(); | |
| 276 FunctionTester ft(descriptor, code); | |
| 277 MaybeHandle<Object> result = ft.Call(); | |
| 278 CHECK_EQ(InstanceType::ODDBALL_TYPE, | |
| 279 Handle<Smi>::cast(result.ToHandleChecked())->value()); | |
| 280 } | |
| 281 | |
| 282 namespace { | |
| 283 | |
| 284 class TestBitField : public BitField<unsigned, 3, 3> {}; | |
| 285 | |
| 286 } // namespace | |
| 287 | |
| 288 TEST(BitFieldDecode) { | |
| 289 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 290 VoidDescriptor descriptor(isolate); | |
| 291 CodeStubAssemblerTester m(isolate, descriptor); | |
| 292 m.Return(m.SmiTag(m.BitFieldDecode<TestBitField>(m.Int32Constant(0x2f)))); | |
| 293 Handle<Code> code = m.GenerateCode(); | |
| 294 FunctionTester ft(descriptor, code); | |
| 295 MaybeHandle<Object> result = ft.Call(); | |
| 296 // value = 00101111 | |
| 297 // mask = 00111000 | |
| 298 // result = 101 | |
| 299 CHECK_EQ(5, Handle<Smi>::cast(result.ToHandleChecked())->value()); | |
| 300 } | |
| 301 | |
| 302 namespace { | |
| 303 | |
| 304 Handle<JSFunction> CreateFunctionFromCode(int parameter_count_with_receiver, | |
| 305 Handle<Code> code) { | |
| 306 Isolate* isolate = code->GetIsolate(); | |
| 307 Handle<String> name = isolate->factory()->InternalizeUtf8String("test"); | |
| 308 Handle<JSFunction> function = | |
| 309 isolate->factory()->NewFunctionWithoutPrototype(name, code); | |
| 310 function->shared()->set_internal_formal_parameter_count( | |
| 311 parameter_count_with_receiver - 1); // Implicit undefined receiver. | |
| 312 return function; | |
| 313 } | |
| 314 | |
| 315 } // namespace | |
| 316 | |
| 317 TEST(JSFunction) { | |
| 318 const int kNumParams = 3; // Receiver, left, right. | |
| 319 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 320 CodeStubAssemblerTester m(isolate, kNumParams); | |
| 321 m.Return(m.SmiTag(m.Int32Add(m.SmiToWord32(m.Parameter(1)), | |
| 322 m.SmiToWord32(m.Parameter(2))))); | |
| 323 Handle<Code> code = m.GenerateCode(); | |
| 324 Handle<JSFunction> function = CreateFunctionFromCode(kNumParams, code); | |
| 325 Handle<Object> args[] = {Handle<Smi>(Smi::FromInt(23), isolate), | |
| 326 Handle<Smi>(Smi::FromInt(34), isolate)}; | |
| 327 MaybeHandle<Object> result = | |
| 328 Execution::Call(isolate, function, isolate->factory()->undefined_value(), | |
| 329 arraysize(args), args); | |
| 330 CHECK_EQ(57, Handle<Smi>::cast(result.ToHandleChecked())->value()); | |
| 331 } | |
| 332 | |
| 333 TEST(SplitEdgeBranchMerge) { | |
| 334 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 335 VoidDescriptor descriptor(isolate); | |
| 336 CodeStubAssemblerTester m(isolate, descriptor); | |
| 337 CodeStubAssembler::Label l1(&m), merge(&m); | |
| 338 m.Branch(m.Int32Constant(1), &l1, &merge); | |
| 339 m.Bind(&l1); | |
| 340 m.Goto(&merge); | |
| 341 m.Bind(&merge); | |
| 342 USE(m.GenerateCode()); | |
| 343 } | |
| 344 | |
| 345 TEST(SplitEdgeSwitchMerge) { | |
| 346 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 347 VoidDescriptor descriptor(isolate); | |
| 348 CodeStubAssemblerTester m(isolate, descriptor); | |
| 349 CodeStubAssembler::Label l1(&m), l2(&m), l3(&m), default_label(&m); | |
| 350 CodeStubAssembler::Label* labels[] = {&l1, &l2}; | |
| 351 int32_t values[] = {1, 2}; | |
| 352 m.Branch(m.Int32Constant(1), &l3, &l1); | |
| 353 m.Bind(&l3); | |
| 354 m.Switch(m.Int32Constant(2), &default_label, values, labels, 2); | |
| 355 m.Bind(&l1); | |
| 356 m.Goto(&l2); | |
| 357 m.Bind(&l2); | |
| 358 m.Goto(&default_label); | |
| 359 m.Bind(&default_label); | |
| 360 USE(m.GenerateCode()); | |
| 361 } | |
| 362 | |
| 363 TEST(TestToConstant) { | |
| 364 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 365 VoidDescriptor descriptor(isolate); | |
| 366 CodeStubAssemblerTester m(isolate, descriptor); | |
| 367 int32_t value32; | |
| 368 int64_t value64; | |
| 369 Node* a = m.Int32Constant(5); | |
| 370 CHECK(m.ToInt32Constant(a, value32)); | |
| 371 CHECK(m.ToInt64Constant(a, value64)); | |
| 372 | |
| 373 a = m.Int64Constant(static_cast<int64_t>(1) << 32); | |
| 374 CHECK(!m.ToInt32Constant(a, value32)); | |
| 375 CHECK(m.ToInt64Constant(a, value64)); | |
| 376 | |
| 377 a = m.Int64Constant(13); | |
| 378 CHECK(m.ToInt32Constant(a, value32)); | |
| 379 CHECK(m.ToInt64Constant(a, value64)); | |
| 380 | |
| 381 a = m.UndefinedConstant(); | |
| 382 CHECK(!m.ToInt32Constant(a, value32)); | |
| 383 CHECK(!m.ToInt64Constant(a, value64)); | |
| 384 | |
| 385 a = m.UndefinedConstant(); | |
| 386 CHECK(!m.ToInt32Constant(a, value32)); | |
| 387 CHECK(!m.ToInt64Constant(a, value64)); | |
| 388 } | |
| 389 | |
| 390 TEST(ComputeIntegerHash) { | |
| 391 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 392 const int param_count = 2; | |
| 393 CodeStubAssemblerTester m(isolate, param_count); | |
| 394 m.Return(m.SmiFromWord32(m.ComputeIntegerHash( | |
| 395 m.SmiToWord32(m.Parameter(0)), m.SmiToWord32(m.Parameter(1))))); | |
| 396 | |
| 397 Handle<Code> code = m.GenerateCode(); | |
| 398 FunctionTester ft(code, param_count); | |
| 399 | |
| 400 Handle<Smi> hash_seed = isolate->factory()->hash_seed(); | |
| 401 | |
| 402 base::RandomNumberGenerator rand_gen(FLAG_random_seed); | |
| 403 | |
| 404 for (int i = 0; i < 1024; i++) { | |
| 405 int k = rand_gen.NextInt(Smi::kMaxValue); | |
| 406 | |
| 407 Handle<Smi> key(Smi::FromInt(k), isolate); | |
| 408 Handle<Object> result = ft.Call(key, hash_seed).ToHandleChecked(); | |
| 409 | |
| 410 uint32_t hash = ComputeIntegerHash(k, hash_seed->value()); | |
| 411 Smi* expected = Smi::FromInt(hash & Smi::kMaxValue); | |
| 412 CHECK_EQ(expected, Smi::cast(*result)); | |
| 413 } | |
| 414 } | |
| 415 | |
| 416 TEST(TryToName) { | |
| 417 typedef CodeStubAssembler::Label Label; | |
| 418 typedef CodeStubAssembler::Variable Variable; | |
| 419 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 420 | |
| 421 const int param_count = 3; | |
| 422 CodeStubAssemblerTester m(isolate, param_count); | |
| 423 | |
| 424 enum Result { kKeyIsIndex, kKeyIsUnique, kBailout }; | |
| 425 { | |
| 426 Node* key = m.Parameter(0); | |
| 427 Node* expected_result = m.Parameter(1); | |
| 428 Node* expected_arg = m.Parameter(2); | |
| 429 | |
| 430 Label passed(&m), failed(&m); | |
| 431 Label if_keyisindex(&m), if_keyisunique(&m), if_bailout(&m); | |
| 432 Variable var_index(&m, MachineRepresentation::kWord32); | |
| 433 | |
| 434 m.TryToName(key, &if_keyisindex, &var_index, &if_keyisunique, &if_bailout); | |
| 435 | |
| 436 m.Bind(&if_keyisindex); | |
| 437 m.GotoUnless( | |
| 438 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kKeyIsIndex))), | |
| 439 &failed); | |
| 440 m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_index.value()), | |
| 441 &passed, &failed); | |
| 442 | |
| 443 m.Bind(&if_keyisunique); | |
| 444 m.GotoUnless( | |
| 445 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kKeyIsUnique))), | |
| 446 &failed); | |
| 447 m.Branch(m.WordEqual(expected_arg, key), &passed, &failed); | |
| 448 | |
| 449 m.Bind(&if_bailout); | |
| 450 m.Branch( | |
| 451 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))), | |
| 452 &passed, &failed); | |
| 453 | |
| 454 m.Bind(&passed); | |
| 455 m.Return(m.BooleanConstant(true)); | |
| 456 | |
| 457 m.Bind(&failed); | |
| 458 m.Return(m.BooleanConstant(false)); | |
| 459 } | |
| 460 | |
| 461 Handle<Code> code = m.GenerateCode(); | |
| 462 FunctionTester ft(code, param_count); | |
| 463 | |
| 464 Handle<Object> expect_index(Smi::FromInt(kKeyIsIndex), isolate); | |
| 465 Handle<Object> expect_unique(Smi::FromInt(kKeyIsUnique), isolate); | |
| 466 Handle<Object> expect_bailout(Smi::FromInt(kBailout), isolate); | |
| 467 | |
| 468 { | |
| 469 // TryToName(<zero smi>) => if_keyisindex: smi value. | |
| 470 Handle<Object> key(Smi::FromInt(0), isolate); | |
| 471 ft.CheckTrue(key, expect_index, key); | |
| 472 } | |
| 473 | |
| 474 { | |
| 475 // TryToName(<positive smi>) => if_keyisindex: smi value. | |
| 476 Handle<Object> key(Smi::FromInt(153), isolate); | |
| 477 ft.CheckTrue(key, expect_index, key); | |
| 478 } | |
| 479 | |
| 480 { | |
| 481 // TryToName(<negative smi>) => bailout. | |
| 482 Handle<Object> key(Smi::FromInt(-1), isolate); | |
| 483 ft.CheckTrue(key, expect_bailout); | |
| 484 } | |
| 485 | |
| 486 { | |
| 487 // TryToName(<symbol>) => if_keyisunique: <symbol>. | |
| 488 Handle<Object> key = isolate->factory()->NewSymbol(); | |
| 489 ft.CheckTrue(key, expect_unique, key); | |
| 490 } | |
| 491 | |
| 492 { | |
| 493 // TryToName(<internalized string>) => if_keyisunique: <internalized string> | |
| 494 Handle<Object> key = isolate->factory()->InternalizeUtf8String("test"); | |
| 495 ft.CheckTrue(key, expect_unique, key); | |
| 496 } | |
| 497 | |
| 498 { | |
| 499 // TryToName(<internalized number string>) => if_keyisindex: number. | |
| 500 Handle<Object> key = isolate->factory()->InternalizeUtf8String("153"); | |
| 501 Handle<Object> index(Smi::FromInt(153), isolate); | |
| 502 ft.CheckTrue(key, expect_index, index); | |
| 503 } | |
| 504 | |
| 505 { | |
| 506 // TryToName(<non-internalized string>) => bailout. | |
| 507 Handle<Object> key = isolate->factory()->NewStringFromAsciiChecked("test"); | |
| 508 ft.CheckTrue(key, expect_bailout); | |
| 509 } | |
| 510 } | |
| 511 | |
| 512 namespace { | |
| 513 | |
| 514 template <typename Dictionary> | |
| 515 void TestNameDictionaryLookup() { | |
| 516 typedef CodeStubAssembler::Label Label; | |
| 517 typedef CodeStubAssembler::Variable Variable; | |
| 518 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 519 | |
| 520 const int param_count = 4; | |
| 521 CodeStubAssemblerTester m(isolate, param_count); | |
| 522 | |
| 523 enum Result { kFound, kNotFound }; | |
| 524 { | |
| 525 Node* dictionary = m.Parameter(0); | |
| 526 Node* unique_name = m.Parameter(1); | |
| 527 Node* expected_result = m.Parameter(2); | |
| 528 Node* expected_arg = m.Parameter(3); | |
| 529 | |
| 530 Label passed(&m), failed(&m); | |
| 531 Label if_found(&m), if_not_found(&m); | |
| 532 Variable var_entry(&m, MachineRepresentation::kWord32); | |
| 533 | |
| 534 m.NameDictionaryLookup<Dictionary>(dictionary, unique_name, &if_found, | |
| 535 &var_entry, &if_not_found); | |
| 536 m.Bind(&if_found); | |
| 537 m.GotoUnless( | |
| 538 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))), | |
| 539 &failed); | |
| 540 m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_entry.value()), | |
| 541 &passed, &failed); | |
| 542 | |
| 543 m.Bind(&if_not_found); | |
| 544 m.Branch( | |
| 545 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))), | |
| 546 &passed, &failed); | |
| 547 | |
| 548 m.Bind(&passed); | |
| 549 m.Return(m.BooleanConstant(true)); | |
| 550 | |
| 551 m.Bind(&failed); | |
| 552 m.Return(m.BooleanConstant(false)); | |
| 553 } | |
| 554 | |
| 555 Handle<Code> code = m.GenerateCode(); | |
| 556 FunctionTester ft(code, param_count); | |
| 557 | |
| 558 Handle<Object> expect_found(Smi::FromInt(kFound), isolate); | |
| 559 Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate); | |
| 560 | |
| 561 Handle<Dictionary> dictionary = Dictionary::New(isolate, 40); | |
| 562 PropertyDetails fake_details = PropertyDetails::Empty(); | |
| 563 | |
| 564 Factory* factory = isolate->factory(); | |
| 565 Handle<Name> keys[] = { | |
| 566 factory->InternalizeUtf8String("0"), | |
| 567 factory->InternalizeUtf8String("42"), | |
| 568 factory->InternalizeUtf8String("-153"), | |
| 569 factory->InternalizeUtf8String("0.0"), | |
| 570 factory->InternalizeUtf8String("4.2"), | |
| 571 factory->InternalizeUtf8String(""), | |
| 572 factory->InternalizeUtf8String("name"), | |
| 573 factory->NewSymbol(), | |
| 574 factory->NewPrivateSymbol(), | |
| 575 }; | |
| 576 | |
| 577 for (size_t i = 0; i < arraysize(keys); i++) { | |
| 578 Handle<Object> value = factory->NewPropertyCell(); | |
| 579 dictionary = Dictionary::Add(dictionary, keys[i], value, fake_details); | |
| 580 } | |
| 581 | |
| 582 for (size_t i = 0; i < arraysize(keys); i++) { | |
| 583 int entry = dictionary->FindEntry(keys[i]); | |
| 584 CHECK_NE(Dictionary::kNotFound, entry); | |
| 585 | |
| 586 Handle<Object> expected_entry(Smi::FromInt(entry), isolate); | |
| 587 ft.CheckTrue(dictionary, keys[i], expect_found, expected_entry); | |
| 588 } | |
| 589 | |
| 590 Handle<Name> non_existing_keys[] = { | |
| 591 factory->InternalizeUtf8String("1"), | |
| 592 factory->InternalizeUtf8String("-42"), | |
| 593 factory->InternalizeUtf8String("153"), | |
| 594 factory->InternalizeUtf8String("-1.0"), | |
| 595 factory->InternalizeUtf8String("1.3"), | |
| 596 factory->InternalizeUtf8String("a"), | |
| 597 factory->InternalizeUtf8String("boom"), | |
| 598 factory->NewSymbol(), | |
| 599 factory->NewPrivateSymbol(), | |
| 600 }; | |
| 601 | |
| 602 for (size_t i = 0; i < arraysize(non_existing_keys); i++) { | |
| 603 int entry = dictionary->FindEntry(non_existing_keys[i]); | |
| 604 CHECK_EQ(Dictionary::kNotFound, entry); | |
| 605 | |
| 606 ft.CheckTrue(dictionary, non_existing_keys[i], expect_not_found); | |
| 607 } | |
| 608 } | |
| 609 | |
| 610 } // namespace | |
| 611 | |
| 612 TEST(NameDictionaryLookup) { TestNameDictionaryLookup<NameDictionary>(); } | |
| 613 | |
| 614 TEST(GlobalDictionaryLookup) { TestNameDictionaryLookup<GlobalDictionary>(); } | |
| 615 | |
| 616 namespace { | |
| 617 | |
| 618 template <typename Dictionary> | |
| 619 void TestNumberDictionaryLookup() { | |
| 620 typedef CodeStubAssembler::Label Label; | |
| 621 typedef CodeStubAssembler::Variable Variable; | |
| 622 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 623 | |
| 624 const int param_count = 4; | |
| 625 CodeStubAssemblerTester m(isolate, param_count); | |
| 626 | |
| 627 enum Result { kFound, kNotFound }; | |
| 628 { | |
| 629 Node* dictionary = m.Parameter(0); | |
| 630 Node* key = m.SmiToWord32(m.Parameter(1)); | |
| 631 Node* expected_result = m.Parameter(2); | |
| 632 Node* expected_arg = m.Parameter(3); | |
| 633 | |
| 634 Label passed(&m), failed(&m); | |
| 635 Label if_found(&m), if_not_found(&m); | |
| 636 Variable var_entry(&m, MachineRepresentation::kWord32); | |
| 637 | |
| 638 m.NumberDictionaryLookup<Dictionary>(dictionary, key, &if_found, &var_entry, | |
| 639 &if_not_found); | |
| 640 m.Bind(&if_found); | |
| 641 m.GotoUnless( | |
| 642 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))), | |
| 643 &failed); | |
| 644 m.Branch(m.Word32Equal(m.SmiToWord32(expected_arg), var_entry.value()), | |
| 645 &passed, &failed); | |
| 646 | |
| 647 m.Bind(&if_not_found); | |
| 648 m.Branch( | |
| 649 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))), | |
| 650 &passed, &failed); | |
| 651 | |
| 652 m.Bind(&passed); | |
| 653 m.Return(m.BooleanConstant(true)); | |
| 654 | |
| 655 m.Bind(&failed); | |
| 656 m.Return(m.BooleanConstant(false)); | |
| 657 } | |
| 658 | |
| 659 Handle<Code> code = m.GenerateCode(); | |
| 660 FunctionTester ft(code, param_count); | |
| 661 | |
| 662 Handle<Object> expect_found(Smi::FromInt(kFound), isolate); | |
| 663 Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate); | |
| 664 | |
| 665 const int kKeysCount = 1000; | |
| 666 Handle<Dictionary> dictionary = Dictionary::New(isolate, kKeysCount); | |
| 667 uint32_t keys[kKeysCount]; | |
| 668 | |
| 669 Handle<Object> fake_value(Smi::FromInt(42), isolate); | |
| 670 PropertyDetails fake_details = PropertyDetails::Empty(); | |
| 671 | |
| 672 base::RandomNumberGenerator rand_gen(FLAG_random_seed); | |
| 673 | |
| 674 for (int i = 0; i < kKeysCount; i++) { | |
| 675 int random_key = rand_gen.NextInt(Smi::kMaxValue); | |
| 676 keys[i] = static_cast<uint32_t>(random_key); | |
| 677 | |
| 678 dictionary = Dictionary::Add(dictionary, keys[i], fake_value, fake_details); | |
| 679 } | |
| 680 | |
| 681 // Now try querying existing keys. | |
| 682 for (int i = 0; i < kKeysCount; i++) { | |
| 683 int entry = dictionary->FindEntry(keys[i]); | |
| 684 CHECK_NE(Dictionary::kNotFound, entry); | |
| 685 | |
| 686 Handle<Object> key(Smi::FromInt(keys[i]), isolate); | |
| 687 Handle<Object> expected_entry(Smi::FromInt(entry), isolate); | |
| 688 ft.CheckTrue(dictionary, key, expect_found, expected_entry); | |
| 689 } | |
| 690 | |
| 691 // Now try querying random keys which do not exist in the dictionary. | |
| 692 for (int i = 0; i < kKeysCount;) { | |
| 693 int random_key = rand_gen.NextInt(Smi::kMaxValue); | |
| 694 int entry = dictionary->FindEntry(random_key); | |
| 695 if (entry != Dictionary::kNotFound) continue; | |
| 696 i++; | |
| 697 | |
| 698 Handle<Object> key(Smi::FromInt(random_key), isolate); | |
| 699 ft.CheckTrue(dictionary, key, expect_not_found); | |
| 700 } | |
| 701 } | |
| 702 | |
| 703 } // namespace | |
| 704 | |
| 705 TEST(SeededNumberDictionaryLookup) { | |
| 706 TestNumberDictionaryLookup<SeededNumberDictionary>(); | |
| 707 } | |
| 708 | |
| 709 TEST(UnseededNumberDictionaryLookup) { | |
| 710 TestNumberDictionaryLookup<UnseededNumberDictionary>(); | |
| 711 } | |
| 712 | |
| 713 namespace { | |
| 714 | |
| 715 void AddProperties(Handle<JSObject> object, Handle<Name> names[], | |
| 716 size_t count) { | |
| 717 Handle<Object> value(Smi::FromInt(42), object->GetIsolate()); | |
| 718 for (size_t i = 0; i < count; i++) { | |
| 719 JSObject::AddProperty(object, names[i], value, NONE); | |
| 720 } | |
| 721 } | |
| 722 | |
| 723 } // namespace | |
| 724 | |
| 725 TEST(TryLookupProperty) { | |
| 726 typedef CodeStubAssembler::Label Label; | |
| 727 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 728 | |
| 729 const int param_count = 4; | |
| 730 CodeStubAssemblerTester m(isolate, param_count); | |
| 731 | |
| 732 enum Result { kFound, kNotFound, kBailout }; | |
| 733 { | |
| 734 Node* object = m.Parameter(0); | |
| 735 Node* unique_name = m.Parameter(1); | |
| 736 Node* expected_result = m.Parameter(2); | |
| 737 | |
| 738 Label passed(&m), failed(&m); | |
| 739 Label if_found(&m), if_not_found(&m), if_bailout(&m); | |
| 740 | |
| 741 Node* map = m.LoadMap(object); | |
| 742 Node* instance_type = m.LoadMapInstanceType(map); | |
| 743 | |
| 744 m.TryLookupProperty(object, map, instance_type, unique_name, &if_found, | |
| 745 &if_not_found, &if_bailout); | |
| 746 | |
| 747 m.Bind(&if_found); | |
| 748 m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))), | |
| 749 &passed, &failed); | |
| 750 | |
| 751 m.Bind(&if_not_found); | |
| 752 m.Branch( | |
| 753 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))), | |
| 754 &passed, &failed); | |
| 755 | |
| 756 m.Bind(&if_bailout); | |
| 757 m.Branch( | |
| 758 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))), | |
| 759 &passed, &failed); | |
| 760 | |
| 761 m.Bind(&passed); | |
| 762 m.Return(m.BooleanConstant(true)); | |
| 763 | |
| 764 m.Bind(&failed); | |
| 765 m.Return(m.BooleanConstant(false)); | |
| 766 } | |
| 767 | |
| 768 Handle<Code> code = m.GenerateCode(); | |
| 769 FunctionTester ft(code, param_count); | |
| 770 | |
| 771 Handle<Object> expect_found(Smi::FromInt(kFound), isolate); | |
| 772 Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate); | |
| 773 Handle<Object> expect_bailout(Smi::FromInt(kBailout), isolate); | |
| 774 | |
| 775 Factory* factory = isolate->factory(); | |
| 776 Handle<Name> names[] = { | |
| 777 factory->InternalizeUtf8String("a"), | |
| 778 factory->InternalizeUtf8String("bb"), | |
| 779 factory->InternalizeUtf8String("ccc"), | |
| 780 factory->InternalizeUtf8String("dddd"), | |
| 781 factory->InternalizeUtf8String("eeeee"), | |
| 782 factory->InternalizeUtf8String(""), | |
| 783 factory->InternalizeUtf8String("name"), | |
| 784 factory->NewSymbol(), | |
| 785 factory->NewPrivateSymbol(), | |
| 786 }; | |
| 787 | |
| 788 std::vector<Handle<JSObject>> objects; | |
| 789 | |
| 790 { | |
| 791 Handle<JSFunction> function = factory->NewFunction(factory->empty_string()); | |
| 792 Handle<JSObject> object = factory->NewJSObject(function); | |
| 793 AddProperties(object, names, arraysize(names)); | |
| 794 CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); | |
| 795 CHECK(!object->map()->is_dictionary_map()); | |
| 796 objects.push_back(object); | |
| 797 } | |
| 798 | |
| 799 { | |
| 800 Handle<JSFunction> function = factory->NewFunction(factory->empty_string()); | |
| 801 Handle<JSObject> object = factory->NewJSObject(function); | |
| 802 AddProperties(object, names, arraysize(names)); | |
| 803 JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0, "test"); | |
| 804 CHECK_EQ(JS_OBJECT_TYPE, object->map()->instance_type()); | |
| 805 CHECK(object->map()->is_dictionary_map()); | |
| 806 objects.push_back(object); | |
| 807 } | |
| 808 | |
| 809 { | |
| 810 Handle<JSFunction> function = factory->NewFunction(factory->empty_string()); | |
| 811 JSFunction::EnsureHasInitialMap(function); | |
| 812 function->initial_map()->set_instance_type(JS_GLOBAL_OBJECT_TYPE); | |
| 813 function->initial_map()->set_is_prototype_map(true); | |
| 814 function->initial_map()->set_dictionary_map(true); | |
| 815 Handle<JSObject> object = factory->NewJSGlobalObject(function); | |
| 816 AddProperties(object, names, arraysize(names)); | |
| 817 CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map()->instance_type()); | |
| 818 CHECK(object->map()->is_dictionary_map()); | |
| 819 objects.push_back(object); | |
| 820 } | |
| 821 | |
| 822 { | |
| 823 for (Handle<JSObject> object : objects) { | |
| 824 for (size_t name_index = 0; name_index < arraysize(names); name_index++) { | |
| 825 Handle<Name> name = names[name_index]; | |
| 826 CHECK(JSReceiver::HasProperty(object, name).FromJust()); | |
| 827 ft.CheckTrue(object, name, expect_found); | |
| 828 } | |
| 829 } | |
| 830 } | |
| 831 | |
| 832 { | |
| 833 Handle<Name> non_existing_names[] = { | |
| 834 factory->InternalizeUtf8String("ne_a"), | |
| 835 factory->InternalizeUtf8String("ne_bb"), | |
| 836 factory->InternalizeUtf8String("ne_ccc"), | |
| 837 factory->InternalizeUtf8String("ne_dddd"), | |
| 838 }; | |
| 839 for (Handle<JSObject> object : objects) { | |
| 840 for (size_t key_index = 0; key_index < arraysize(non_existing_names); | |
| 841 key_index++) { | |
| 842 Handle<Name> key = non_existing_names[key_index]; | |
| 843 CHECK(!JSReceiver::HasProperty(object, key).FromJust()); | |
| 844 ft.CheckTrue(object, key, expect_not_found); | |
| 845 } | |
| 846 } | |
| 847 } | |
| 848 | |
| 849 { | |
| 850 Handle<JSFunction> function = factory->NewFunction(factory->empty_string()); | |
| 851 Handle<JSProxy> object = factory->NewJSProxy(function, objects[0]); | |
| 852 CHECK_EQ(JS_PROXY_TYPE, object->map()->instance_type()); | |
| 853 ft.CheckTrue(object, names[0], expect_bailout); | |
| 854 } | |
| 855 | |
| 856 { | |
| 857 Handle<JSObject> object = isolate->global_proxy(); | |
| 858 CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map()->instance_type()); | |
| 859 ft.CheckTrue(object, names[0], expect_bailout); | |
| 860 } | |
| 861 } | |
| 862 | |
| 863 namespace { | |
| 864 | |
| 865 void AddElement(Handle<JSObject> object, uint32_t index, Handle<Object> value, | |
| 866 PropertyAttributes attributes = NONE) { | |
| 867 JSObject::AddDataElement(object, index, value, attributes).ToHandleChecked(); | |
| 868 } | |
| 869 | |
| 870 } // namespace | |
| 871 | |
| 872 TEST(TryLookupElement) { | |
| 873 typedef CodeStubAssembler::Label Label; | |
| 874 Isolate* isolate(CcTest::InitIsolateOnce()); | |
| 875 | |
| 876 const int param_count = 4; | |
| 877 CodeStubAssemblerTester m(isolate, param_count); | |
| 878 | |
| 879 enum Result { kFound, kNotFound, kBailout }; | |
| 880 { | |
| 881 Node* object = m.Parameter(0); | |
| 882 Node* index = m.SmiToWord32(m.Parameter(1)); | |
| 883 Node* expected_result = m.Parameter(2); | |
| 884 | |
| 885 Label passed(&m), failed(&m); | |
| 886 Label if_found(&m), if_not_found(&m), if_bailout(&m); | |
| 887 | |
| 888 Node* map = m.LoadMap(object); | |
| 889 Node* instance_type = m.LoadMapInstanceType(map); | |
| 890 | |
| 891 m.TryLookupElement(object, map, instance_type, index, &if_found, | |
| 892 &if_not_found, &if_bailout); | |
| 893 | |
| 894 m.Bind(&if_found); | |
| 895 m.Branch(m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kFound))), | |
| 896 &passed, &failed); | |
| 897 | |
| 898 m.Bind(&if_not_found); | |
| 899 m.Branch( | |
| 900 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kNotFound))), | |
| 901 &passed, &failed); | |
| 902 | |
| 903 m.Bind(&if_bailout); | |
| 904 m.Branch( | |
| 905 m.WordEqual(expected_result, m.SmiConstant(Smi::FromInt(kBailout))), | |
| 906 &passed, &failed); | |
| 907 | |
| 908 m.Bind(&passed); | |
| 909 m.Return(m.BooleanConstant(true)); | |
| 910 | |
| 911 m.Bind(&failed); | |
| 912 m.Return(m.BooleanConstant(false)); | |
| 913 } | |
| 914 | |
| 915 Handle<Code> code = m.GenerateCode(); | |
| 916 FunctionTester ft(code, param_count); | |
| 917 | |
| 918 Factory* factory = isolate->factory(); | |
| 919 Handle<Object> smi0(Smi::FromInt(0), isolate); | |
| 920 Handle<Object> smi1(Smi::FromInt(1), isolate); | |
| 921 Handle<Object> smi7(Smi::FromInt(7), isolate); | |
| 922 Handle<Object> smi13(Smi::FromInt(13), isolate); | |
| 923 Handle<Object> smi42(Smi::FromInt(42), isolate); | |
| 924 | |
| 925 Handle<Object> expect_found(Smi::FromInt(kFound), isolate); | |
| 926 Handle<Object> expect_not_found(Smi::FromInt(kNotFound), isolate); | |
| 927 Handle<Object> expect_bailout(Smi::FromInt(kBailout), isolate); | |
| 928 | |
| 929 #define CHECK_FOUND(object, index) \ | |
| 930 CHECK(JSReceiver::HasElement(object, index).FromJust()); \ | |
| 931 ft.CheckTrue(object, smi##index, expect_found); | |
| 932 | |
| 933 #define CHECK_NOT_FOUND(object, index) \ | |
| 934 CHECK(!JSReceiver::HasElement(object, index).FromJust()); \ | |
| 935 ft.CheckTrue(object, smi##index, expect_not_found); | |
| 936 | |
| 937 { | |
| 938 Handle<JSArray> object = factory->NewJSArray(0, FAST_SMI_ELEMENTS); | |
| 939 AddElement(object, 0, smi0); | |
| 940 AddElement(object, 1, smi0); | |
| 941 CHECK_EQ(FAST_SMI_ELEMENTS, object->map()->elements_kind()); | |
| 942 | |
| 943 CHECK_FOUND(object, 0); | |
| 944 CHECK_FOUND(object, 1); | |
| 945 CHECK_NOT_FOUND(object, 7); | |
| 946 CHECK_NOT_FOUND(object, 13); | |
| 947 CHECK_NOT_FOUND(object, 42); | |
| 948 } | |
| 949 | |
| 950 { | |
| 951 Handle<JSArray> object = factory->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS); | |
| 952 AddElement(object, 0, smi0); | |
| 953 AddElement(object, 13, smi0); | |
| 954 CHECK_EQ(FAST_HOLEY_SMI_ELEMENTS, object->map()->elements_kind()); | |
| 955 | |
| 956 CHECK_FOUND(object, 0); | |
| 957 CHECK_NOT_FOUND(object, 1); | |
| 958 CHECK_NOT_FOUND(object, 7); | |
| 959 CHECK_FOUND(object, 13); | |
| 960 CHECK_NOT_FOUND(object, 42); | |
| 961 } | |
| 962 | |
| 963 { | |
| 964 Handle<JSArray> object = factory->NewJSArray(0, FAST_ELEMENTS); | |
| 965 AddElement(object, 0, smi0); | |
| 966 AddElement(object, 1, smi0); | |
| 967 CHECK_EQ(FAST_ELEMENTS, object->map()->elements_kind()); | |
| 968 | |
| 969 CHECK_FOUND(object, 0); | |
| 970 CHECK_FOUND(object, 1); | |
| 971 CHECK_NOT_FOUND(object, 7); | |
| 972 CHECK_NOT_FOUND(object, 13); | |
| 973 CHECK_NOT_FOUND(object, 42); | |
| 974 } | |
| 975 | |
| 976 { | |
| 977 Handle<JSArray> object = factory->NewJSArray(0, FAST_HOLEY_ELEMENTS); | |
| 978 AddElement(object, 0, smi0); | |
| 979 AddElement(object, 13, smi0); | |
| 980 CHECK_EQ(FAST_HOLEY_ELEMENTS, object->map()->elements_kind()); | |
| 981 | |
| 982 CHECK_FOUND(object, 0); | |
| 983 CHECK_NOT_FOUND(object, 1); | |
| 984 CHECK_NOT_FOUND(object, 7); | |
| 985 CHECK_FOUND(object, 13); | |
| 986 CHECK_NOT_FOUND(object, 42); | |
| 987 } | |
| 988 | |
| 989 { | |
| 990 Handle<JSFunction> constructor = isolate->string_function(); | |
| 991 Handle<JSObject> object = factory->NewJSObject(constructor); | |
| 992 Handle<String> str = factory->InternalizeUtf8String("ab"); | |
| 993 Handle<JSValue>::cast(object)->set_value(*str); | |
| 994 AddElement(object, 13, smi0); | |
| 995 CHECK_EQ(FAST_STRING_WRAPPER_ELEMENTS, object->map()->elements_kind()); | |
| 996 | |
| 997 CHECK_FOUND(object, 0); | |
| 998 CHECK_FOUND(object, 1); | |
| 999 CHECK_NOT_FOUND(object, 7); | |
| 1000 CHECK_FOUND(object, 13); | |
| 1001 CHECK_NOT_FOUND(object, 42); | |
| 1002 } | |
| 1003 | |
| 1004 { | |
| 1005 Handle<JSFunction> constructor = isolate->string_function(); | |
| 1006 Handle<JSObject> object = factory->NewJSObject(constructor); | |
| 1007 Handle<String> str = factory->InternalizeUtf8String("ab"); | |
| 1008 Handle<JSValue>::cast(object)->set_value(*str); | |
| 1009 AddElement(object, 13, smi0); | |
| 1010 JSObject::NormalizeElements(object); | |
| 1011 CHECK_EQ(SLOW_STRING_WRAPPER_ELEMENTS, object->map()->elements_kind()); | |
| 1012 | |
| 1013 CHECK_FOUND(object, 0); | |
| 1014 CHECK_FOUND(object, 1); | |
| 1015 CHECK_NOT_FOUND(object, 7); | |
| 1016 CHECK_FOUND(object, 13); | |
| 1017 CHECK_NOT_FOUND(object, 42); | |
| 1018 } | |
| 1019 | |
| 1020 // TODO(ishell): uncomment once NO_ELEMENTS kind is supported. | |
| 1021 // { | |
| 1022 // Handle<Map> map = Map::Create(isolate, 0); | |
| 1023 // map->set_elements_kind(NO_ELEMENTS); | |
| 1024 // Handle<JSObject> object = factory->NewJSObjectFromMap(map); | |
| 1025 // CHECK_EQ(NO_ELEMENTS, object->map()->elements_kind()); | |
| 1026 // | |
| 1027 // CHECK_NOT_FOUND(object, 0); | |
| 1028 // CHECK_NOT_FOUND(object, 1); | |
| 1029 // CHECK_NOT_FOUND(object, 7); | |
| 1030 // CHECK_NOT_FOUND(object, 13); | |
| 1031 // CHECK_NOT_FOUND(object, 42); | |
| 1032 // } | |
| 1033 | |
| 1034 #undef CHECK_FOUND | |
| 1035 #undef CHECK_NOT_FOUND | |
| 1036 | |
| 1037 { | |
| 1038 Handle<JSArray> handler = factory->NewJSArray(0); | |
| 1039 Handle<JSFunction> function = factory->NewFunction(factory->empty_string()); | |
| 1040 Handle<JSProxy> object = factory->NewJSProxy(function, handler); | |
| 1041 CHECK_EQ(JS_PROXY_TYPE, object->map()->instance_type()); | |
| 1042 ft.CheckTrue(object, smi0, expect_bailout); | |
| 1043 } | |
| 1044 | |
| 1045 { | |
| 1046 Handle<JSObject> object = isolate->global_object(); | |
| 1047 CHECK_EQ(JS_GLOBAL_OBJECT_TYPE, object->map()->instance_type()); | |
| 1048 ft.CheckTrue(object, smi0, expect_bailout); | |
| 1049 } | |
| 1050 | |
| 1051 { | |
| 1052 Handle<JSObject> object = isolate->global_proxy(); | |
| 1053 CHECK_EQ(JS_GLOBAL_PROXY_TYPE, object->map()->instance_type()); | |
| 1054 ft.CheckTrue(object, smi0, expect_bailout); | |
| 1055 } | |
| 1056 } | |
| 1057 | |
| 1058 } // namespace internal | |
| 1059 } // namespace v8 | |
| OLD | NEW |