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