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 <stdlib.h> |
| 6 #include <sstream> |
| 7 #include <utility> |
| 8 |
| 9 #include "src/api.h" |
| 10 #include "src/objects.h" |
| 11 #include "src/v8.h" |
| 12 |
| 13 #include "test/cctest/cctest.h" |
| 14 |
| 15 using namespace v8::base; |
| 16 using namespace v8::internal; |
| 17 |
| 18 |
| 19 static const int kMaxInobjectProperties = |
| 20 (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2; |
| 21 |
| 22 |
| 23 template <typename T> |
| 24 static Handle<T> OpenHandle(v8::Local<v8::Value> value) { |
| 25 Handle<Object> obj = v8::Utils::OpenHandle(*value); |
| 26 return Handle<T>::cast(obj); |
| 27 } |
| 28 |
| 29 |
| 30 static inline v8::Local<v8::Value> Run(v8::Local<v8::Script> script) { |
| 31 v8::Local<v8::Value> result; |
| 32 if (script->Run(v8::Isolate::GetCurrent()->GetCurrentContext()) |
| 33 .ToLocal(&result)) { |
| 34 return result; |
| 35 } |
| 36 return v8::Local<v8::Value>(); |
| 37 } |
| 38 |
| 39 |
| 40 template <typename T = Object> |
| 41 Handle<T> GetGlobal(const char* name) { |
| 42 Isolate* isolate = CcTest::i_isolate(); |
| 43 Factory* factory = isolate->factory(); |
| 44 Handle<String> str_name = factory->InternalizeUtf8String(name); |
| 45 |
| 46 Handle<Object> value = |
| 47 Object::GetProperty(isolate->global_object(), str_name).ToHandleChecked(); |
| 48 return Handle<T>::cast(value); |
| 49 } |
| 50 |
| 51 |
| 52 template <typename T = Object> |
| 53 Handle<T> GetLexical(const char* name) { |
| 54 Isolate* isolate = CcTest::i_isolate(); |
| 55 Factory* factory = isolate->factory(); |
| 56 |
| 57 Handle<String> str_name = factory->InternalizeUtf8String(name); |
| 58 Handle<ScriptContextTable> script_contexts( |
| 59 isolate->native_context()->script_context_table()); |
| 60 |
| 61 ScriptContextTable::LookupResult lookup_result; |
| 62 if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) { |
| 63 Handle<Object> result = |
| 64 FixedArray::get(ScriptContextTable::GetContext( |
| 65 script_contexts, lookup_result.context_index), |
| 66 lookup_result.slot_index); |
| 67 return Handle<T>::cast(result); |
| 68 } |
| 69 return Handle<T>(); |
| 70 } |
| 71 |
| 72 |
| 73 template <typename T = Object> |
| 74 Handle<T> GetLexical(const std::string& name) { |
| 75 return GetLexical<T>(name.c_str()); |
| 76 } |
| 77 |
| 78 |
| 79 template <typename T> |
| 80 static inline Handle<T> Run(v8::Local<v8::Script> script) { |
| 81 return OpenHandle<T>(Run(script)); |
| 82 } |
| 83 |
| 84 |
| 85 template <typename T> |
| 86 static inline Handle<T> CompileRun(const char* script) { |
| 87 return OpenHandle<T>(CompileRun(script)); |
| 88 } |
| 89 |
| 90 |
| 91 static Object* GetFieldValue(JSObject* obj, int property_index) { |
| 92 FieldIndex index = FieldIndex::ForPropertyIndex(obj->map(), property_index); |
| 93 return obj->RawFastPropertyAt(index); |
| 94 } |
| 95 |
| 96 |
| 97 static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) { |
| 98 if (obj->IsUnboxedDoubleField(field_index)) { |
| 99 return obj->RawFastDoublePropertyAt(field_index); |
| 100 } else { |
| 101 Object* value = obj->RawFastPropertyAt(field_index); |
| 102 DCHECK(value->IsMutableHeapNumber()); |
| 103 return HeapNumber::cast(value)->value(); |
| 104 } |
| 105 } |
| 106 |
| 107 |
| 108 static double GetDoubleFieldValue(JSObject* obj, int property_index) { |
| 109 FieldIndex index = FieldIndex::ForPropertyIndex(obj->map(), property_index); |
| 110 return GetDoubleFieldValue(obj, index); |
| 111 } |
| 112 |
| 113 |
| 114 bool IsObjectShrinkable(JSObject* obj) { |
| 115 Handle<Map> filler_map = |
| 116 CcTest::i_isolate()->factory()->one_pointer_filler_map(); |
| 117 |
| 118 int inobject_properties = obj->map()->GetInObjectProperties(); |
| 119 int unused = obj->map()->unused_property_fields(); |
| 120 if (unused == 0) return false; |
| 121 |
| 122 for (int i = inobject_properties - unused; i < inobject_properties; i++) { |
| 123 if (*filler_map != GetFieldValue(obj, i)) { |
| 124 return false; |
| 125 } |
| 126 } |
| 127 return true; |
| 128 } |
| 129 |
| 130 |
| 131 TEST(JSObjectBasic) { |
| 132 // Avoid eventual completion of in-object slack tracking. |
| 133 FLAG_inline_construct = false; |
| 134 FLAG_always_opt = false; |
| 135 CcTest::InitializeVM(); |
| 136 v8::HandleScope scope(CcTest::isolate()); |
| 137 const char* source = |
| 138 "function A() {" |
| 139 " this.a = 42;" |
| 140 " this.d = 4.2;" |
| 141 " this.o = this;" |
| 142 "}"; |
| 143 CompileRun(source); |
| 144 |
| 145 Handle<JSFunction> func = GetGlobal<JSFunction>("A"); |
| 146 |
| 147 // Zero instances were created so far. |
| 148 CHECK(!func->has_initial_map()); |
| 149 |
| 150 v8::Local<v8::Script> new_A_script = v8_compile("new A();"); |
| 151 |
| 152 Handle<JSObject> obj = Run<JSObject>(new_A_script); |
| 153 |
| 154 CHECK(func->has_initial_map()); |
| 155 Handle<Map> initial_map(func->initial_map()); |
| 156 |
| 157 // One instance created. |
| 158 CHECK_EQ(Map::kSlackTrackingCounterStart - 1, initial_map->counter()); |
| 159 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 160 |
| 161 // There must be at least some slack. |
| 162 CHECK_LT(5, obj->map()->GetInObjectProperties()); |
| 163 CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj, 0)); |
| 164 CHECK_EQ(4.2, GetDoubleFieldValue(*obj, 1)); |
| 165 CHECK_EQ(*obj, GetFieldValue(*obj, 2)); |
| 166 CHECK(IsObjectShrinkable(*obj)); |
| 167 |
| 168 // Create several objects to complete the tracking. |
| 169 for (int i = 1; i < Map::kGenerousAllocationCount; i++) { |
| 170 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 171 Handle<JSObject> tmp = Run<JSObject>(new_A_script); |
| 172 CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(), |
| 173 IsObjectShrinkable(*tmp)); |
| 174 } |
| 175 CHECK(!initial_map->IsInobjectSlackTrackingInProgress()); |
| 176 CHECK(!IsObjectShrinkable(*obj)); |
| 177 |
| 178 // No slack left. |
| 179 CHECK_EQ(3, obj->map()->GetInObjectProperties()); |
| 180 } |
| 181 |
| 182 |
| 183 TEST(JSObjectBasicNoInlineNew) { |
| 184 FLAG_inline_new = false; |
| 185 TestJSObjectBasic(); |
| 186 } |
| 187 |
| 188 |
| 189 TEST(JSObjectComplex) { |
| 190 // Avoid eventual completion of in-object slack tracking. |
| 191 FLAG_inline_construct = false; |
| 192 FLAG_always_opt = false; |
| 193 CcTest::InitializeVM(); |
| 194 v8::HandleScope scope(CcTest::isolate()); |
| 195 const char* source = |
| 196 "function A(n) {" |
| 197 " if (n > 0) this.a = 42;" |
| 198 " if (n > 1) this.d = 4.2;" |
| 199 " if (n > 2) this.o1 = this;" |
| 200 " if (n > 3) this.o2 = this;" |
| 201 " if (n > 4) this.o3 = this;" |
| 202 " if (n > 5) this.o4 = this;" |
| 203 "}"; |
| 204 CompileRun(source); |
| 205 |
| 206 Handle<JSFunction> func = GetGlobal<JSFunction>("A"); |
| 207 |
| 208 // Zero instances were created so far. |
| 209 CHECK(!func->has_initial_map()); |
| 210 |
| 211 Handle<JSObject> obj1 = CompileRun<JSObject>("new A(1);"); |
| 212 Handle<JSObject> obj3 = CompileRun<JSObject>("new A(3);"); |
| 213 Handle<JSObject> obj5 = CompileRun<JSObject>("new A(5);"); |
| 214 |
| 215 CHECK(func->has_initial_map()); |
| 216 Handle<Map> initial_map(func->initial_map()); |
| 217 |
| 218 // Three instances created. |
| 219 CHECK_EQ(Map::kSlackTrackingCounterStart - 3, initial_map->counter()); |
| 220 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 221 |
| 222 // There must be at least some slack. |
| 223 CHECK_LT(5, obj3->map()->GetInObjectProperties()); |
| 224 CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj3, 0)); |
| 225 CHECK_EQ(4.2, GetDoubleFieldValue(*obj3, 1)); |
| 226 CHECK_EQ(*obj3, GetFieldValue(*obj3, 2)); |
| 227 CHECK(IsObjectShrinkable(*obj1)); |
| 228 CHECK(IsObjectShrinkable(*obj3)); |
| 229 CHECK(IsObjectShrinkable(*obj5)); |
| 230 |
| 231 // Create several objects to complete the tracking. |
| 232 for (int i = 3; i < Map::kGenerousAllocationCount; i++) { |
| 233 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 234 CompileRun("new A(3);"); |
| 235 } |
| 236 CHECK(!initial_map->IsInobjectSlackTrackingInProgress()); |
| 237 |
| 238 // obj1 and obj2 stays shrinkable because we don't clear unused fields. |
| 239 CHECK(IsObjectShrinkable(*obj1)); |
| 240 CHECK(IsObjectShrinkable(*obj3)); |
| 241 CHECK(!IsObjectShrinkable(*obj5)); |
| 242 |
| 243 CHECK_EQ(5, obj1->map()->GetInObjectProperties()); |
| 244 CHECK_EQ(4, obj1->map()->unused_property_fields()); |
| 245 |
| 246 CHECK_EQ(5, obj3->map()->GetInObjectProperties()); |
| 247 CHECK_EQ(2, obj3->map()->unused_property_fields()); |
| 248 |
| 249 CHECK_EQ(5, obj5->map()->GetInObjectProperties()); |
| 250 CHECK_EQ(0, obj5->map()->unused_property_fields()); |
| 251 |
| 252 // Since slack tracking is complete, the new objects should not be shrinkable. |
| 253 obj1 = CompileRun<JSObject>("new A(1);"); |
| 254 obj3 = CompileRun<JSObject>("new A(3);"); |
| 255 obj5 = CompileRun<JSObject>("new A(5);"); |
| 256 |
| 257 CHECK(!IsObjectShrinkable(*obj1)); |
| 258 CHECK(!IsObjectShrinkable(*obj3)); |
| 259 CHECK(!IsObjectShrinkable(*obj5)); |
| 260 } |
| 261 |
| 262 |
| 263 TEST(JSObjectComplexNoInlineNew) { |
| 264 FLAG_inline_new = false; |
| 265 TestJSObjectComplex(); |
| 266 } |
| 267 |
| 268 |
| 269 TEST(JSGeneratorObjectBasic) { |
| 270 // Avoid eventual completion of in-object slack tracking. |
| 271 FLAG_inline_construct = false; |
| 272 FLAG_always_opt = false; |
| 273 CcTest::InitializeVM(); |
| 274 v8::HandleScope scope(CcTest::isolate()); |
| 275 const char* source = |
| 276 "function* A() {" |
| 277 " var i = 0;" |
| 278 " while(true) {" |
| 279 " yield i++;" |
| 280 " }" |
| 281 "};" |
| 282 "function CreateGenerator() {" |
| 283 " var o = A();" |
| 284 " o.a = 42;" |
| 285 " o.d = 4.2;" |
| 286 " o.o = o;" |
| 287 " return o;" |
| 288 "}"; |
| 289 CompileRun(source); |
| 290 |
| 291 Handle<JSFunction> func = GetGlobal<JSFunction>("A"); |
| 292 |
| 293 // Zero instances were created so far. |
| 294 CHECK(!func->has_initial_map()); |
| 295 |
| 296 v8::Local<v8::Script> new_A_script = v8_compile("CreateGenerator();"); |
| 297 |
| 298 Handle<JSObject> obj = Run<JSObject>(new_A_script); |
| 299 |
| 300 CHECK(func->has_initial_map()); |
| 301 Handle<Map> initial_map(func->initial_map()); |
| 302 |
| 303 // One instance created. |
| 304 CHECK_EQ(Map::kSlackTrackingCounterStart - 1, initial_map->counter()); |
| 305 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 306 |
| 307 // There must be at least some slack. |
| 308 CHECK_LT(5, obj->map()->GetInObjectProperties()); |
| 309 CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj, 0)); |
| 310 CHECK_EQ(4.2, GetDoubleFieldValue(*obj, 1)); |
| 311 CHECK_EQ(*obj, GetFieldValue(*obj, 2)); |
| 312 CHECK(IsObjectShrinkable(*obj)); |
| 313 |
| 314 // Create several objects to complete the tracking. |
| 315 for (int i = 1; i < Map::kGenerousAllocationCount; i++) { |
| 316 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 317 Handle<JSObject> tmp = Run<JSObject>(new_A_script); |
| 318 CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(), |
| 319 IsObjectShrinkable(*tmp)); |
| 320 } |
| 321 CHECK(!initial_map->IsInobjectSlackTrackingInProgress()); |
| 322 CHECK(!IsObjectShrinkable(*obj)); |
| 323 |
| 324 // No slack left. |
| 325 CHECK_EQ(3, obj->map()->GetInObjectProperties()); |
| 326 } |
| 327 |
| 328 |
| 329 TEST(JSGeneratorObjectBasicNoInlineNew) { |
| 330 FLAG_inline_new = false; |
| 331 TestJSGeneratorObjectBasic(); |
| 332 } |
| 333 |
| 334 |
| 335 TEST(SubclassBasicNoBaseClassInstances) { |
| 336 // Avoid eventual completion of in-object slack tracking. |
| 337 FLAG_inline_construct = false; |
| 338 FLAG_always_opt = false; |
| 339 CcTest::InitializeVM(); |
| 340 v8::HandleScope scope(CcTest::isolate()); |
| 341 |
| 342 // Check that base class' and subclass' slack tracking do not interfere with |
| 343 // each other. |
| 344 // In this test we never create base class instances. |
| 345 |
| 346 const char* source = |
| 347 "'use strict';" |
| 348 "class A {" |
| 349 " constructor(...args) {" |
| 350 " this.aa = 42;" |
| 351 " this.ad = 4.2;" |
| 352 " this.ao = this;" |
| 353 " }" |
| 354 "};" |
| 355 "class B extends A {" |
| 356 " constructor(...args) {" |
| 357 " super(...args);" |
| 358 " this.ba = 142;" |
| 359 " this.bd = 14.2;" |
| 360 " this.bo = this;" |
| 361 " }" |
| 362 "};"; |
| 363 CompileRun(source); |
| 364 |
| 365 Handle<JSFunction> a_func = GetLexical<JSFunction>("A"); |
| 366 Handle<JSFunction> b_func = GetLexical<JSFunction>("B"); |
| 367 |
| 368 // Zero instances were created so far. |
| 369 CHECK(!a_func->has_initial_map()); |
| 370 CHECK(!b_func->has_initial_map()); |
| 371 |
| 372 v8::Local<v8::Script> new_B_script = v8_compile("new B();"); |
| 373 |
| 374 Handle<JSObject> obj = Run<JSObject>(new_B_script); |
| 375 |
| 376 CHECK(a_func->has_initial_map()); |
| 377 Handle<Map> a_initial_map(a_func->initial_map()); |
| 378 |
| 379 CHECK(b_func->has_initial_map()); |
| 380 Handle<Map> b_initial_map(b_func->initial_map()); |
| 381 |
| 382 // Zero instances of A created. |
| 383 CHECK_EQ(Map::kSlackTrackingCounterStart, a_initial_map->counter()); |
| 384 CHECK(a_initial_map->IsInobjectSlackTrackingInProgress()); |
| 385 |
| 386 // One instance of B created. |
| 387 CHECK_EQ(Map::kSlackTrackingCounterStart - 1, b_initial_map->counter()); |
| 388 CHECK(b_initial_map->IsInobjectSlackTrackingInProgress()); |
| 389 |
| 390 // There must be at least some slack. |
| 391 CHECK_LT(10, obj->map()->GetInObjectProperties()); |
| 392 CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj, 0)); |
| 393 CHECK_EQ(4.2, GetDoubleFieldValue(*obj, 1)); |
| 394 CHECK_EQ(*obj, GetFieldValue(*obj, 2)); |
| 395 CHECK_EQ(Smi::FromInt(142), GetFieldValue(*obj, 3)); |
| 396 CHECK_EQ(14.2, GetDoubleFieldValue(*obj, 4)); |
| 397 CHECK_EQ(*obj, GetFieldValue(*obj, 5)); |
| 398 CHECK(IsObjectShrinkable(*obj)); |
| 399 |
| 400 // Create several subclass instances to complete the tracking. |
| 401 for (int i = 1; i < Map::kGenerousAllocationCount; i++) { |
| 402 CHECK(b_initial_map->IsInobjectSlackTrackingInProgress()); |
| 403 Handle<JSObject> tmp = Run<JSObject>(new_B_script); |
| 404 CHECK_EQ(b_initial_map->IsInobjectSlackTrackingInProgress(), |
| 405 IsObjectShrinkable(*tmp)); |
| 406 } |
| 407 CHECK(!b_initial_map->IsInobjectSlackTrackingInProgress()); |
| 408 CHECK(!IsObjectShrinkable(*obj)); |
| 409 |
| 410 // Zero instances of A created. |
| 411 CHECK_EQ(Map::kSlackTrackingCounterStart, a_initial_map->counter()); |
| 412 CHECK(a_initial_map->IsInobjectSlackTrackingInProgress()); |
| 413 |
| 414 // No slack left. |
| 415 CHECK_EQ(6, obj->map()->GetInObjectProperties()); |
| 416 } |
| 417 |
| 418 |
| 419 TEST(SubclassBasicNoBaseClassInstancesNoInlineNew) { |
| 420 FLAG_inline_new = false; |
| 421 TestSubclassBasicNoBaseClassInstances(); |
| 422 } |
| 423 |
| 424 |
| 425 TEST(SubclassBasic) { |
| 426 // Avoid eventual completion of in-object slack tracking. |
| 427 FLAG_inline_construct = false; |
| 428 FLAG_always_opt = false; |
| 429 CcTest::InitializeVM(); |
| 430 v8::HandleScope scope(CcTest::isolate()); |
| 431 |
| 432 // Check that base class' and subclass' slack tracking do not interfere with |
| 433 // each other. |
| 434 // In this test we first create enough base class instances to complete |
| 435 // the slack tracking and then proceed creating subclass instances. |
| 436 |
| 437 const char* source = |
| 438 "'use strict';" |
| 439 "class A {" |
| 440 " constructor(...args) {" |
| 441 " this.aa = 42;" |
| 442 " this.ad = 4.2;" |
| 443 " this.ao = this;" |
| 444 " }" |
| 445 "};" |
| 446 "class B extends A {" |
| 447 " constructor(...args) {" |
| 448 " super(...args);" |
| 449 " this.ba = 142;" |
| 450 " this.bd = 14.2;" |
| 451 " this.bo = this;" |
| 452 " }" |
| 453 "};"; |
| 454 CompileRun(source); |
| 455 |
| 456 Handle<JSFunction> a_func = GetLexical<JSFunction>("A"); |
| 457 Handle<JSFunction> b_func = GetLexical<JSFunction>("B"); |
| 458 |
| 459 // Zero instances were created so far. |
| 460 CHECK(!a_func->has_initial_map()); |
| 461 CHECK(!b_func->has_initial_map()); |
| 462 |
| 463 v8::Local<v8::Script> new_A_script = v8_compile("new A();"); |
| 464 v8::Local<v8::Script> new_B_script = v8_compile("new B();"); |
| 465 |
| 466 Handle<JSObject> a_obj = Run<JSObject>(new_A_script); |
| 467 Handle<JSObject> b_obj = Run<JSObject>(new_B_script); |
| 468 |
| 469 CHECK(a_func->has_initial_map()); |
| 470 Handle<Map> a_initial_map(a_func->initial_map()); |
| 471 |
| 472 CHECK(b_func->has_initial_map()); |
| 473 Handle<Map> b_initial_map(b_func->initial_map()); |
| 474 |
| 475 // One instance of a base class created. |
| 476 CHECK_EQ(Map::kSlackTrackingCounterStart - 1, a_initial_map->counter()); |
| 477 CHECK(a_initial_map->IsInobjectSlackTrackingInProgress()); |
| 478 |
| 479 // One instance of a subclass created. |
| 480 CHECK_EQ(Map::kSlackTrackingCounterStart - 1, b_initial_map->counter()); |
| 481 CHECK(b_initial_map->IsInobjectSlackTrackingInProgress()); |
| 482 |
| 483 // Create several base class instances to complete the tracking. |
| 484 for (int i = 1; i < Map::kGenerousAllocationCount; i++) { |
| 485 CHECK(a_initial_map->IsInobjectSlackTrackingInProgress()); |
| 486 Handle<JSObject> tmp = Run<JSObject>(new_A_script); |
| 487 CHECK_EQ(a_initial_map->IsInobjectSlackTrackingInProgress(), |
| 488 IsObjectShrinkable(*tmp)); |
| 489 } |
| 490 CHECK(!a_initial_map->IsInobjectSlackTrackingInProgress()); |
| 491 CHECK(!IsObjectShrinkable(*a_obj)); |
| 492 |
| 493 // No slack left. |
| 494 CHECK_EQ(3, a_obj->map()->GetInObjectProperties()); |
| 495 |
| 496 // There must be at least some slack. |
| 497 CHECK_LT(10, b_obj->map()->GetInObjectProperties()); |
| 498 CHECK_EQ(Smi::FromInt(42), GetFieldValue(*b_obj, 0)); |
| 499 CHECK_EQ(4.2, GetDoubleFieldValue(*b_obj, 1)); |
| 500 CHECK_EQ(*b_obj, GetFieldValue(*b_obj, 2)); |
| 501 CHECK_EQ(Smi::FromInt(142), GetFieldValue(*b_obj, 3)); |
| 502 CHECK_EQ(14.2, GetDoubleFieldValue(*b_obj, 4)); |
| 503 CHECK_EQ(*b_obj, GetFieldValue(*b_obj, 5)); |
| 504 CHECK(IsObjectShrinkable(*b_obj)); |
| 505 |
| 506 // Create several subclass instances to complete the tracking. |
| 507 for (int i = 1; i < Map::kGenerousAllocationCount; i++) { |
| 508 CHECK(b_initial_map->IsInobjectSlackTrackingInProgress()); |
| 509 Handle<JSObject> tmp = Run<JSObject>(new_B_script); |
| 510 CHECK_EQ(b_initial_map->IsInobjectSlackTrackingInProgress(), |
| 511 IsObjectShrinkable(*tmp)); |
| 512 } |
| 513 CHECK(!b_initial_map->IsInobjectSlackTrackingInProgress()); |
| 514 CHECK(!IsObjectShrinkable(*b_obj)); |
| 515 |
| 516 // No slack left. |
| 517 CHECK_EQ(6, b_obj->map()->GetInObjectProperties()); |
| 518 } |
| 519 |
| 520 |
| 521 TEST(SubclassBasicNoInlineNew) { |
| 522 FLAG_inline_new = false; |
| 523 TestSubclassBasic(); |
| 524 } |
| 525 |
| 526 |
| 527 // Creates class hierachy of length matching the |hierarchy_desc| length and |
| 528 // with the number of fields at i'th level equal to |hierarchy_desc[i]|. |
| 529 static void CreateClassHierarchy(const std::vector<int>& hierarchy_desc) { |
| 530 std::ostringstream os; |
| 531 os << "'use strict';\n\n"; |
| 532 |
| 533 int n = static_cast<int>(hierarchy_desc.size()); |
| 534 for (int cur_class = 0; cur_class < n; cur_class++) { |
| 535 os << "class A" << cur_class; |
| 536 if (cur_class > 0) { |
| 537 os << " extends A" << (cur_class - 1); |
| 538 } |
| 539 os << " {\n" |
| 540 " constructor(...args) {\n"; |
| 541 if (cur_class > 0) { |
| 542 os << " super(...args);\n"; |
| 543 } |
| 544 int fields_count = hierarchy_desc[cur_class]; |
| 545 for (int k = 0; k < fields_count; k++) { |
| 546 os << " this.f" << cur_class << "_" << k << " = " << k << ";\n"; |
| 547 } |
| 548 os << " }\n" |
| 549 "};\n\n"; |
| 550 } |
| 551 CompileRun(os.str().c_str()); |
| 552 } |
| 553 |
| 554 |
| 555 static std::string GetClassName(int class_index) { |
| 556 std::ostringstream os; |
| 557 os << "A" << class_index; |
| 558 return os.str(); |
| 559 } |
| 560 |
| 561 |
| 562 static v8::Local<v8::Script> GetNewObjectScript(const std::string& class_name) { |
| 563 std::ostringstream os; |
| 564 os << "new " << class_name << "();"; |
| 565 return v8_compile(os.str().c_str()); |
| 566 } |
| 567 |
| 568 |
| 569 // Test that in-object slack tracking works as expected for first |n| classes |
| 570 // in the hierarchy. |
| 571 // This test works only for if the total property count is less than maximum |
| 572 // in-object properties count. |
| 573 static void TestClassHierarchy(const std::vector<int>& hierarchy_desc, int n) { |
| 574 int fields_count = 0; |
| 575 for (int cur_class = 0; cur_class < n; cur_class++) { |
| 576 std::string class_name = GetClassName(cur_class); |
| 577 int fields_count_at_current_level = hierarchy_desc[cur_class]; |
| 578 fields_count += fields_count_at_current_level; |
| 579 |
| 580 // This test is not suitable for in-object properties count overflow case. |
| 581 DCHECK_LT(fields_count, kMaxInobjectProperties); |
| 582 |
| 583 // Create |class_name| objects and check slack tracking. |
| 584 v8::Local<v8::Script> new_script = GetNewObjectScript(class_name); |
| 585 |
| 586 Handle<JSFunction> func = GetLexical<JSFunction>(class_name); |
| 587 |
| 588 Handle<JSObject> obj = Run<JSObject>(new_script); |
| 589 |
| 590 CHECK(func->has_initial_map()); |
| 591 Handle<Map> initial_map(func->initial_map()); |
| 592 |
| 593 // There must be at least some slack. |
| 594 CHECK_LT(fields_count, obj->map()->GetInObjectProperties()); |
| 595 |
| 596 // One instance was created. |
| 597 CHECK_EQ(Map::kSlackTrackingCounterStart - 1, initial_map->counter()); |
| 598 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 599 |
| 600 // Create several instances to complete the tracking. |
| 601 for (int i = 1; i < Map::kGenerousAllocationCount; i++) { |
| 602 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 603 Handle<JSObject> tmp = Run<JSObject>(new_script); |
| 604 CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(), |
| 605 IsObjectShrinkable(*tmp)); |
| 606 } |
| 607 CHECK(!initial_map->IsInobjectSlackTrackingInProgress()); |
| 608 CHECK(!IsObjectShrinkable(*obj)); |
| 609 |
| 610 // No slack left. |
| 611 CHECK_EQ(fields_count, obj->map()->GetInObjectProperties()); |
| 612 } |
| 613 } |
| 614 |
| 615 |
| 616 static void TestSubclassChain(const std::vector<int>& hierarchy_desc) { |
| 617 // Avoid eventual completion of in-object slack tracking. |
| 618 FLAG_inline_construct = false; |
| 619 FLAG_always_opt = false; |
| 620 CcTest::InitializeVM(); |
| 621 v8::HandleScope scope(CcTest::isolate()); |
| 622 |
| 623 CreateClassHierarchy(hierarchy_desc); |
| 624 TestClassHierarchy(hierarchy_desc, static_cast<int>(hierarchy_desc.size())); |
| 625 } |
| 626 |
| 627 |
| 628 TEST(LongSubclassChain1) { |
| 629 std::vector<int> hierarchy_desc; |
| 630 for (int i = 0; i < 7; i++) { |
| 631 hierarchy_desc.push_back(i * 10); |
| 632 } |
| 633 TestSubclassChain(hierarchy_desc); |
| 634 } |
| 635 |
| 636 |
| 637 TEST(LongSubclassChain2) { |
| 638 std::vector<int> hierarchy_desc; |
| 639 hierarchy_desc.push_back(10); |
| 640 for (int i = 0; i < 42; i++) { |
| 641 hierarchy_desc.push_back(0); |
| 642 } |
| 643 hierarchy_desc.push_back(230); |
| 644 TestSubclassChain(hierarchy_desc); |
| 645 } |
| 646 |
| 647 |
| 648 TEST(LongSubclassChain3) { |
| 649 std::vector<int> hierarchy_desc; |
| 650 for (int i = 0; i < 42; i++) { |
| 651 hierarchy_desc.push_back(5); |
| 652 } |
| 653 TestSubclassChain(hierarchy_desc); |
| 654 } |
| 655 |
| 656 |
| 657 TEST(InobjectPropetiesCountOverflowInSubclass) { |
| 658 // Avoid eventual completion of in-object slack tracking. |
| 659 FLAG_inline_construct = false; |
| 660 FLAG_always_opt = false; |
| 661 CcTest::InitializeVM(); |
| 662 v8::HandleScope scope(CcTest::isolate()); |
| 663 |
| 664 std::vector<int> hierarchy_desc; |
| 665 const int kNoOverflowCount = 5; |
| 666 for (int i = 0; i < kNoOverflowCount; i++) { |
| 667 hierarchy_desc.push_back(50); |
| 668 } |
| 669 // In this class we are going to have properties in the backing store. |
| 670 hierarchy_desc.push_back(100); |
| 671 |
| 672 CreateClassHierarchy(hierarchy_desc); |
| 673 |
| 674 // For the last class in the hierarchy we need different checks. |
| 675 { |
| 676 int cur_class = kNoOverflowCount; |
| 677 std::string class_name = GetClassName(cur_class); |
| 678 |
| 679 // Create |class_name| objects and check slack tracking. |
| 680 v8::Local<v8::Script> new_script = GetNewObjectScript(class_name); |
| 681 |
| 682 Handle<JSFunction> func = GetLexical<JSFunction>(class_name); |
| 683 |
| 684 Handle<JSObject> obj = Run<JSObject>(new_script); |
| 685 |
| 686 CHECK(func->has_initial_map()); |
| 687 Handle<Map> initial_map(func->initial_map()); |
| 688 |
| 689 // There must be no slack left. |
| 690 CHECK_EQ(JSObject::kMaxInstanceSize, obj->map()->instance_size()); |
| 691 CHECK_EQ(kMaxInobjectProperties, obj->map()->GetInObjectProperties()); |
| 692 |
| 693 // One instance was created. |
| 694 CHECK_EQ(Map::kSlackTrackingCounterStart - 1, initial_map->counter()); |
| 695 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 696 |
| 697 // Create several instances to complete the tracking. |
| 698 for (int i = 1; i < Map::kGenerousAllocationCount; i++) { |
| 699 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 700 Handle<JSObject> tmp = Run<JSObject>(new_script); |
| 701 CHECK(!IsObjectShrinkable(*tmp)); |
| 702 } |
| 703 CHECK(!initial_map->IsInobjectSlackTrackingInProgress()); |
| 704 CHECK(!IsObjectShrinkable(*obj)); |
| 705 |
| 706 // No slack left. |
| 707 CHECK_EQ(kMaxInobjectProperties, obj->map()->GetInObjectProperties()); |
| 708 } |
| 709 |
| 710 // The other classes in the hierarchy are not affected. |
| 711 TestClassHierarchy(hierarchy_desc, kNoOverflowCount); |
| 712 } |
| 713 |
| 714 |
| 715 TEST(SlowModeSubclass) { |
| 716 // Avoid eventual completion of in-object slack tracking. |
| 717 FLAG_inline_construct = false; |
| 718 FLAG_always_opt = false; |
| 719 CcTest::InitializeVM(); |
| 720 v8::HandleScope scope(CcTest::isolate()); |
| 721 |
| 722 std::vector<int> hierarchy_desc; |
| 723 const int kNoOverflowCount = 5; |
| 724 for (int i = 0; i < kNoOverflowCount; i++) { |
| 725 hierarchy_desc.push_back(50); |
| 726 } |
| 727 // This class should go dictionary mode. |
| 728 hierarchy_desc.push_back(1000); |
| 729 |
| 730 CreateClassHierarchy(hierarchy_desc); |
| 731 |
| 732 // For the last class in the hierarchy we need different checks. |
| 733 { |
| 734 int cur_class = kNoOverflowCount; |
| 735 std::string class_name = GetClassName(cur_class); |
| 736 |
| 737 // Create |class_name| objects and check slack tracking. |
| 738 v8::Local<v8::Script> new_script = GetNewObjectScript(class_name); |
| 739 |
| 740 Handle<JSFunction> func = GetLexical<JSFunction>(class_name); |
| 741 |
| 742 Handle<JSObject> obj = Run<JSObject>(new_script); |
| 743 |
| 744 CHECK(func->has_initial_map()); |
| 745 Handle<Map> initial_map(func->initial_map()); |
| 746 |
| 747 // Object should go dictionary mode. |
| 748 CHECK_EQ(JSObject::kHeaderSize, obj->map()->instance_size()); |
| 749 CHECK(obj->map()->is_dictionary_map()); |
| 750 |
| 751 // One instance was created. |
| 752 CHECK_EQ(Map::kSlackTrackingCounterStart - 1, initial_map->counter()); |
| 753 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 754 |
| 755 // Create several instances to complete the tracking. |
| 756 for (int i = 1; i < Map::kGenerousAllocationCount; i++) { |
| 757 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 758 Handle<JSObject> tmp = Run<JSObject>(new_script); |
| 759 CHECK(!IsObjectShrinkable(*tmp)); |
| 760 } |
| 761 CHECK(!initial_map->IsInobjectSlackTrackingInProgress()); |
| 762 CHECK(!IsObjectShrinkable(*obj)); |
| 763 |
| 764 // Object should stay in dictionary mode. |
| 765 CHECK_EQ(JSObject::kHeaderSize, obj->map()->instance_size()); |
| 766 CHECK(obj->map()->is_dictionary_map()); |
| 767 } |
| 768 |
| 769 // The other classes in the hierarchy are not affected. |
| 770 TestClassHierarchy(hierarchy_desc, kNoOverflowCount); |
| 771 } |
| 772 |
| 773 |
| 774 static void TestSubclassBuiltin(const char* subclass_name, |
| 775 InstanceType instance_type, |
| 776 const char* builtin_name, |
| 777 const char* ctor_arguments = "", |
| 778 int builtin_properties_count = 0) { |
| 779 { |
| 780 std::ostringstream os; |
| 781 os << "'use strict';\n" |
| 782 "class " |
| 783 << subclass_name << " extends " << builtin_name |
| 784 << " {\n" |
| 785 " constructor(...args) {\n" |
| 786 " super(...args);\n" |
| 787 " this.a = 42;\n" |
| 788 " this.d = 4.2;\n" |
| 789 " this.o = this;\n" |
| 790 " }\n" |
| 791 "};\n"; |
| 792 CompileRun(os.str().c_str()); |
| 793 } |
| 794 |
| 795 Handle<JSFunction> func = GetLexical<JSFunction>(subclass_name); |
| 796 |
| 797 // Zero instances were created so far. |
| 798 CHECK(!func->has_initial_map()); |
| 799 |
| 800 v8::Local<v8::Script> new_script; |
| 801 { |
| 802 std::ostringstream os; |
| 803 os << "new " << subclass_name << "(" << ctor_arguments << ");"; |
| 804 new_script = v8_compile(os.str().c_str()); |
| 805 } |
| 806 |
| 807 Run<JSObject>(new_script); |
| 808 |
| 809 CHECK(func->has_initial_map()); |
| 810 Handle<Map> initial_map(func->initial_map()); |
| 811 |
| 812 CHECK_EQ(instance_type, initial_map->instance_type()); |
| 813 |
| 814 // One instance of a subclass created. |
| 815 CHECK_EQ(Map::kSlackTrackingCounterStart - 1, initial_map->counter()); |
| 816 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 817 |
| 818 // Create two instances in order to ensure that |obj|.o is a data field |
| 819 // in case of Function subclassing. |
| 820 Handle<JSObject> obj = Run<JSObject>(new_script); |
| 821 |
| 822 // Two instances of a subclass created. |
| 823 CHECK_EQ(Map::kSlackTrackingCounterStart - 2, initial_map->counter()); |
| 824 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 825 |
| 826 // There must be at least some slack. |
| 827 CHECK_LT(builtin_properties_count + 5, obj->map()->GetInObjectProperties()); |
| 828 CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj, builtin_properties_count + 0)); |
| 829 CHECK_EQ(4.2, GetDoubleFieldValue(*obj, builtin_properties_count + 1)); |
| 830 CHECK_EQ(*obj, GetFieldValue(*obj, builtin_properties_count + 2)); |
| 831 CHECK(IsObjectShrinkable(*obj)); |
| 832 |
| 833 // Create several subclass instances to complete the tracking. |
| 834 for (int i = 2; i < Map::kGenerousAllocationCount; i++) { |
| 835 CHECK(initial_map->IsInobjectSlackTrackingInProgress()); |
| 836 Handle<JSObject> tmp = Run<JSObject>(new_script); |
| 837 CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(), |
| 838 IsObjectShrinkable(*tmp)); |
| 839 } |
| 840 CHECK(!initial_map->IsInobjectSlackTrackingInProgress()); |
| 841 CHECK(!IsObjectShrinkable(*obj)); |
| 842 |
| 843 // No slack left. |
| 844 CHECK_EQ(builtin_properties_count + 3, obj->map()->GetInObjectProperties()); |
| 845 |
| 846 CHECK_EQ(instance_type, obj->map()->instance_type()); |
| 847 } |
| 848 |
| 849 |
| 850 TEST(SubclassObjectBuiltin) { |
| 851 // Avoid eventual completion of in-object slack tracking. |
| 852 FLAG_inline_construct = false; |
| 853 FLAG_always_opt = false; |
| 854 CcTest::InitializeVM(); |
| 855 v8::HandleScope scope(CcTest::isolate()); |
| 856 |
| 857 TestSubclassBuiltin("A1", JS_OBJECT_TYPE, "Object", "true"); |
| 858 TestSubclassBuiltin("A2", JS_OBJECT_TYPE, "Object", "42"); |
| 859 TestSubclassBuiltin("A3", JS_OBJECT_TYPE, "Object", "'some string'"); |
| 860 } |
| 861 |
| 862 |
| 863 TEST(SubclassObjectBuiltinNoInlineNew) { |
| 864 FLAG_inline_new = false; |
| 865 TestSubclassObjectBuiltin(); |
| 866 } |
| 867 |
| 868 |
| 869 TEST(SubclassFunctionBuiltin) { |
| 870 // Avoid eventual completion of in-object slack tracking. |
| 871 FLAG_inline_construct = false; |
| 872 FLAG_always_opt = false; |
| 873 CcTest::InitializeVM(); |
| 874 v8::HandleScope scope(CcTest::isolate()); |
| 875 |
| 876 TestSubclassBuiltin("A1", JS_FUNCTION_TYPE, "Function", "'return 153;'"); |
| 877 TestSubclassBuiltin("A2", JS_FUNCTION_TYPE, "Function", "'this.a = 44;'"); |
| 878 } |
| 879 |
| 880 |
| 881 TEST(SubclassFunctionBuiltinNoInlineNew) { |
| 882 FLAG_inline_new = false; |
| 883 TestSubclassFunctionBuiltin(); |
| 884 } |
| 885 |
| 886 |
| 887 TEST(SubclassBooleanBuiltin) { |
| 888 // Avoid eventual completion of in-object slack tracking. |
| 889 FLAG_inline_construct = false; |
| 890 FLAG_always_opt = false; |
| 891 CcTest::InitializeVM(); |
| 892 v8::HandleScope scope(CcTest::isolate()); |
| 893 |
| 894 TestSubclassBuiltin("A1", JS_VALUE_TYPE, "Boolean", "true"); |
| 895 TestSubclassBuiltin("A2", JS_VALUE_TYPE, "Boolean", "false"); |
| 896 } |
| 897 |
| 898 |
| 899 TEST(SubclassBooleanBuiltinNoInlineNew) { |
| 900 FLAG_inline_new = false; |
| 901 TestSubclassBooleanBuiltin(); |
| 902 } |
| 903 |
| 904 |
| 905 TEST(SubclassErrorBuiltin) { |
| 906 // Avoid eventual completion of in-object slack tracking. |
| 907 FLAG_inline_construct = false; |
| 908 FLAG_always_opt = false; |
| 909 CcTest::InitializeVM(); |
| 910 v8::HandleScope scope(CcTest::isolate()); |
| 911 |
| 912 const int first_field = 2; |
| 913 TestSubclassBuiltin("A1", JS_OBJECT_TYPE, "Error", "'err'", first_field); |
| 914 TestSubclassBuiltin("A2", JS_OBJECT_TYPE, "EvalError", "'err'", first_field); |
| 915 TestSubclassBuiltin("A3", JS_OBJECT_TYPE, "RangeError", "'err'", first_field); |
| 916 TestSubclassBuiltin("A4", JS_OBJECT_TYPE, "ReferenceError", "'err'", |
| 917 first_field); |
| 918 TestSubclassBuiltin("A5", JS_OBJECT_TYPE, "SyntaxError", "'err'", |
| 919 first_field); |
| 920 TestSubclassBuiltin("A6", JS_OBJECT_TYPE, "TypeError", "'err'", first_field); |
| 921 TestSubclassBuiltin("A7", JS_OBJECT_TYPE, "URIError", "'err'", first_field); |
| 922 } |
| 923 |
| 924 |
| 925 TEST(SubclassErrorBuiltinNoInlineNew) { |
| 926 FLAG_inline_new = false; |
| 927 TestSubclassErrorBuiltin(); |
| 928 } |
| 929 |
| 930 |
| 931 TEST(SubclassNumberBuiltin) { |
| 932 // Avoid eventual completion of in-object slack tracking. |
| 933 FLAG_inline_construct = false; |
| 934 FLAG_always_opt = false; |
| 935 CcTest::InitializeVM(); |
| 936 v8::HandleScope scope(CcTest::isolate()); |
| 937 |
| 938 TestSubclassBuiltin("A1", JS_VALUE_TYPE, "Number", "42"); |
| 939 TestSubclassBuiltin("A2", JS_VALUE_TYPE, "Number", "4.2"); |
| 940 } |
| 941 |
| 942 |
| 943 TEST(SubclassNumberBuiltinNoInlineNew) { |
| 944 FLAG_inline_new = false; |
| 945 TestSubclassNumberBuiltin(); |
| 946 } |
| 947 |
| 948 |
| 949 TEST(SubclassDateBuiltin) { |
| 950 // Avoid eventual completion of in-object slack tracking. |
| 951 FLAG_inline_construct = false; |
| 952 FLAG_always_opt = false; |
| 953 CcTest::InitializeVM(); |
| 954 v8::HandleScope scope(CcTest::isolate()); |
| 955 |
| 956 TestSubclassBuiltin("A1", JS_DATE_TYPE, "Date", "123456789"); |
| 957 } |
| 958 |
| 959 |
| 960 TEST(SubclassDateBuiltinNoInlineNew) { |
| 961 FLAG_inline_new = false; |
| 962 TestSubclassDateBuiltin(); |
| 963 } |
| 964 |
| 965 |
| 966 TEST(SubclassStringBuiltin) { |
| 967 // Avoid eventual completion of in-object slack tracking. |
| 968 FLAG_inline_construct = false; |
| 969 FLAG_always_opt = false; |
| 970 CcTest::InitializeVM(); |
| 971 v8::HandleScope scope(CcTest::isolate()); |
| 972 |
| 973 TestSubclassBuiltin("A1", JS_VALUE_TYPE, "String", "'some string'"); |
| 974 TestSubclassBuiltin("A2", JS_VALUE_TYPE, "String", ""); |
| 975 } |
| 976 |
| 977 |
| 978 TEST(SubclassStringBuiltinNoInlineNew) { |
| 979 FLAG_inline_new = false; |
| 980 TestSubclassStringBuiltin(); |
| 981 } |
| 982 |
| 983 |
| 984 TEST(SubclassRegExpBuiltin) { |
| 985 // Avoid eventual completion of in-object slack tracking. |
| 986 FLAG_inline_construct = false; |
| 987 FLAG_always_opt = false; |
| 988 CcTest::InitializeVM(); |
| 989 v8::HandleScope scope(CcTest::isolate()); |
| 990 |
| 991 const int first_field = 1; |
| 992 TestSubclassBuiltin("A1", JS_REGEXP_TYPE, "RegExp", "'o(..)h', 'g'", |
| 993 first_field); |
| 994 } |
| 995 |
| 996 |
| 997 TEST(SubclassRegExpBuiltinNoInlineNew) { |
| 998 FLAG_inline_new = false; |
| 999 TestSubclassRegExpBuiltin(); |
| 1000 } |
| 1001 |
| 1002 |
| 1003 TEST(SubclassArrayBuiltin) { |
| 1004 // Avoid eventual completion of in-object slack tracking. |
| 1005 FLAG_inline_construct = false; |
| 1006 FLAG_always_opt = false; |
| 1007 CcTest::InitializeVM(); |
| 1008 v8::HandleScope scope(CcTest::isolate()); |
| 1009 |
| 1010 TestSubclassBuiltin("A1", JS_ARRAY_TYPE, "Array", "42"); |
| 1011 } |
| 1012 |
| 1013 |
| 1014 TEST(SubclassArrayBuiltinNoInlineNew) { |
| 1015 FLAG_inline_new = false; |
| 1016 TestSubclassArrayBuiltin(); |
| 1017 } |
| 1018 |
| 1019 |
| 1020 TEST(SubclassTypedArrayBuiltin) { |
| 1021 // Avoid eventual completion of in-object slack tracking. |
| 1022 FLAG_inline_construct = false; |
| 1023 FLAG_always_opt = false; |
| 1024 CcTest::InitializeVM(); |
| 1025 v8::HandleScope scope(CcTest::isolate()); |
| 1026 |
| 1027 #define TYPED_ARRAY_TEST(Type, type, TYPE, elementType, size) \ |
| 1028 TestSubclassBuiltin("A" #Type, JS_TYPED_ARRAY_TYPE, #Type "Array", "42"); |
| 1029 |
| 1030 TYPED_ARRAYS(TYPED_ARRAY_TEST) |
| 1031 |
| 1032 #undef TYPED_ARRAY_TEST |
| 1033 } |
| 1034 |
| 1035 |
| 1036 TEST(SubclassTypedArrayBuiltinNoInlineNew) { |
| 1037 FLAG_inline_new = false; |
| 1038 TestSubclassTypedArrayBuiltin(); |
| 1039 } |
| 1040 |
| 1041 |
| 1042 TEST(SubclassCollectionBuiltin) { |
| 1043 // Avoid eventual completion of in-object slack tracking. |
| 1044 FLAG_inline_construct = false; |
| 1045 FLAG_always_opt = false; |
| 1046 CcTest::InitializeVM(); |
| 1047 v8::HandleScope scope(CcTest::isolate()); |
| 1048 |
| 1049 TestSubclassBuiltin("A1", JS_SET_TYPE, "Set", ""); |
| 1050 TestSubclassBuiltin("A2", JS_MAP_TYPE, "Map", ""); |
| 1051 TestSubclassBuiltin("A3", JS_WEAK_SET_TYPE, "WeakSet", ""); |
| 1052 TestSubclassBuiltin("A4", JS_WEAK_MAP_TYPE, "WeakMap", ""); |
| 1053 } |
| 1054 |
| 1055 |
| 1056 TEST(SubclassCollectionBuiltinNoInlineNew) { |
| 1057 FLAG_inline_new = false; |
| 1058 TestSubclassCollectionBuiltin(); |
| 1059 } |
| 1060 |
| 1061 |
| 1062 TEST(SubclassArrayBufferBuiltin) { |
| 1063 // Avoid eventual completion of in-object slack tracking. |
| 1064 FLAG_inline_construct = false; |
| 1065 FLAG_always_opt = false; |
| 1066 CcTest::InitializeVM(); |
| 1067 v8::HandleScope scope(CcTest::isolate()); |
| 1068 |
| 1069 TestSubclassBuiltin("A1", JS_ARRAY_BUFFER_TYPE, "ArrayBuffer", "42"); |
| 1070 TestSubclassBuiltin("A2", JS_DATA_VIEW_TYPE, "DataView", |
| 1071 "new ArrayBuffer(42)"); |
| 1072 } |
| 1073 |
| 1074 |
| 1075 TEST(SubclassArrayBufferBuiltinNoInlineNew) { |
| 1076 FLAG_inline_new = false; |
| 1077 TestSubclassArrayBufferBuiltin(); |
| 1078 } |
| 1079 |
| 1080 |
| 1081 TEST(SubclassPromiseBuiltin) { |
| 1082 // Avoid eventual completion of in-object slack tracking. |
| 1083 FLAG_inline_construct = false; |
| 1084 FLAG_always_opt = false; |
| 1085 CcTest::InitializeVM(); |
| 1086 v8::HandleScope scope(CcTest::isolate()); |
| 1087 |
| 1088 const int first_field = 4; |
| 1089 TestSubclassBuiltin("A1", JS_PROMISE_TYPE, "Promise", |
| 1090 "function(resolve, reject) { resolve('ok'); }", |
| 1091 first_field); |
| 1092 } |
| 1093 |
| 1094 |
| 1095 TEST(SubclassPromiseBuiltinNoInlineNew) { |
| 1096 FLAG_inline_new = false; |
| 1097 TestSubclassPromiseBuiltin(); |
| 1098 } |
OLD | NEW |