OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "v8.h" | 5 #include "v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_ARM64 | 7 #if V8_TARGET_ARCH_ARM64 |
8 | 8 |
9 #include "codegen.h" | 9 #include "codegen.h" |
10 #include "debug.h" | 10 #include "debug.h" |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 CallRuntimePassFunction(masm, Runtime::kHiddenTryInstallOptimizedCode); | 297 CallRuntimePassFunction(masm, Runtime::kHiddenTryInstallOptimizedCode); |
298 GenerateTailCallToReturnedCode(masm); | 298 GenerateTailCallToReturnedCode(masm); |
299 | 299 |
300 __ Bind(&ok); | 300 __ Bind(&ok); |
301 GenerateTailCallToSharedCode(masm); | 301 GenerateTailCallToSharedCode(masm); |
302 } | 302 } |
303 | 303 |
304 | 304 |
305 static void Generate_JSConstructStubHelper(MacroAssembler* masm, | 305 static void Generate_JSConstructStubHelper(MacroAssembler* masm, |
306 bool is_api_function, | 306 bool is_api_function, |
| 307 bool count_constructions, |
307 bool create_memento) { | 308 bool create_memento) { |
308 // ----------- S t a t e ------------- | 309 // ----------- S t a t e ------------- |
309 // -- x0 : number of arguments | 310 // -- x0 : number of arguments |
310 // -- x1 : constructor function | 311 // -- x1 : constructor function |
311 // -- x2 : allocation site or undefined | 312 // -- x2 : allocation site or undefined |
312 // -- lr : return address | 313 // -- lr : return address |
313 // -- sp[...]: constructor arguments | 314 // -- sp[...]: constructor arguments |
314 // ----------------------------------- | 315 // ----------------------------------- |
315 | 316 |
316 ASM_LOCATION("Builtins::Generate_JSConstructStubHelper"); | 317 ASM_LOCATION("Builtins::Generate_JSConstructStubHelper"); |
| 318 // Should never count constructions for api objects. |
| 319 ASSERT(!is_api_function || !count_constructions); |
317 // Should never create mementos for api functions. | 320 // Should never create mementos for api functions. |
318 ASSERT(!is_api_function || !create_memento); | 321 ASSERT(!is_api_function || !create_memento); |
| 322 // Should never create mementos before slack tracking is finished. |
| 323 ASSERT(!count_constructions || !create_memento); |
319 | 324 |
320 Isolate* isolate = masm->isolate(); | 325 Isolate* isolate = masm->isolate(); |
321 | 326 |
322 // Enter a construct frame. | 327 // Enter a construct frame. |
323 { | 328 { |
324 FrameScope scope(masm, StackFrame::CONSTRUCT); | 329 FrameScope scope(masm, StackFrame::CONSTRUCT); |
325 | 330 |
326 // Preserve the three incoming parameters on the stack. | 331 // Preserve the three incoming parameters on the stack. |
327 if (create_memento) { | 332 if (create_memento) { |
328 __ AssertUndefinedOrAllocationSite(x2, x10); | 333 __ AssertUndefinedOrAllocationSite(x2, x10); |
(...skipping 25 matching lines...) Expand all Loading... |
354 JSFunction::kPrototypeOrInitialMapOffset)); | 359 JSFunction::kPrototypeOrInitialMapOffset)); |
355 __ JumpIfSmi(init_map, &rt_call); | 360 __ JumpIfSmi(init_map, &rt_call); |
356 __ JumpIfNotObjectType(init_map, x10, x11, MAP_TYPE, &rt_call); | 361 __ JumpIfNotObjectType(init_map, x10, x11, MAP_TYPE, &rt_call); |
357 | 362 |
358 // Check that the constructor is not constructing a JSFunction (see | 363 // Check that the constructor is not constructing a JSFunction (see |
359 // comments in Runtime_NewObject in runtime.cc). In which case the initial | 364 // comments in Runtime_NewObject in runtime.cc). In which case the initial |
360 // map's instance type would be JS_FUNCTION_TYPE. | 365 // map's instance type would be JS_FUNCTION_TYPE. |
361 __ CompareInstanceType(init_map, x10, JS_FUNCTION_TYPE); | 366 __ CompareInstanceType(init_map, x10, JS_FUNCTION_TYPE); |
362 __ B(eq, &rt_call); | 367 __ B(eq, &rt_call); |
363 | 368 |
364 Register constructon_count = x14; | 369 if (count_constructions) { |
365 if (!is_api_function) { | |
366 Label allocate; | 370 Label allocate; |
367 MemOperand bit_field3 = | |
368 FieldMemOperand(init_map, Map::kBitField3Offset); | |
369 // Check if slack tracking is enabled. | |
370 __ Ldr(x4, bit_field3); | |
371 __ DecodeField<Map::ConstructionCount>(constructon_count, x4); | |
372 __ Cmp(constructon_count, Operand(JSFunction::kNoSlackTracking)); | |
373 __ B(eq, &allocate); | |
374 // Decrease generous allocation count. | 371 // Decrease generous allocation count. |
375 __ Subs(x4, x4, Operand(1 << Map::ConstructionCount::kShift)); | 372 __ Ldr(x3, FieldMemOperand(constructor, |
376 __ Str(x4, bit_field3); | 373 JSFunction::kSharedFunctionInfoOffset)); |
377 __ Cmp(constructon_count, Operand(JSFunction::kFinishSlackTracking)); | 374 MemOperand constructor_count = |
| 375 FieldMemOperand(x3, SharedFunctionInfo::kConstructionCountOffset); |
| 376 __ Ldrb(x4, constructor_count); |
| 377 __ Subs(x4, x4, 1); |
| 378 __ Strb(x4, constructor_count); |
378 __ B(ne, &allocate); | 379 __ B(ne, &allocate); |
379 | 380 |
380 // Push the constructor and map to the stack, and the constructor again | 381 // Push the constructor and map to the stack, and the constructor again |
381 // as argument to the runtime call. | 382 // as argument to the runtime call. |
382 __ Push(constructor, init_map, constructor); | 383 __ Push(constructor, init_map, constructor); |
| 384 // The call will replace the stub, so the countdown is only done once. |
383 __ CallRuntime(Runtime::kHiddenFinalizeInstanceSize, 1); | 385 __ CallRuntime(Runtime::kHiddenFinalizeInstanceSize, 1); |
384 __ Pop(init_map, constructor); | 386 __ Pop(init_map, constructor); |
385 __ Mov(constructon_count, Operand(JSFunction::kNoSlackTracking)); | |
386 __ Bind(&allocate); | 387 __ Bind(&allocate); |
387 } | 388 } |
388 | 389 |
389 // Now allocate the JSObject on the heap. | 390 // Now allocate the JSObject on the heap. |
390 Register obj_size = x3; | 391 Register obj_size = x3; |
391 Register new_obj = x4; | 392 Register new_obj = x4; |
392 __ Ldrb(obj_size, FieldMemOperand(init_map, Map::kInstanceSizeOffset)); | 393 __ Ldrb(obj_size, FieldMemOperand(init_map, Map::kInstanceSizeOffset)); |
393 if (create_memento) { | 394 if (create_memento) { |
394 __ Add(x7, obj_size, | 395 __ Add(x7, obj_size, |
395 Operand(AllocationMemento::kSize / kPointerSize)); | 396 Operand(AllocationMemento::kSize / kPointerSize)); |
396 __ Allocate(x7, new_obj, x10, x11, &rt_call, SIZE_IN_WORDS); | 397 __ Allocate(x7, new_obj, x10, x11, &rt_call, SIZE_IN_WORDS); |
397 } else { | 398 } else { |
398 __ Allocate(obj_size, new_obj, x10, x11, &rt_call, SIZE_IN_WORDS); | 399 __ Allocate(obj_size, new_obj, x10, x11, &rt_call, SIZE_IN_WORDS); |
399 } | 400 } |
400 | 401 |
401 // Allocated the JSObject, now initialize the fields. Map is set to | 402 // Allocated the JSObject, now initialize the fields. Map is set to |
402 // initial map and properties and elements are set to empty fixed array. | 403 // initial map and properties and elements are set to empty fixed array. |
403 // NB. the object pointer is not tagged, so MemOperand is used. | 404 // NB. the object pointer is not tagged, so MemOperand is used. |
404 Register empty = x5; | 405 Register empty = x5; |
405 __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex); | 406 __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex); |
406 __ Str(init_map, MemOperand(new_obj, JSObject::kMapOffset)); | 407 __ Str(init_map, MemOperand(new_obj, JSObject::kMapOffset)); |
407 STATIC_ASSERT(JSObject::kElementsOffset == | 408 STATIC_ASSERT(JSObject::kElementsOffset == |
408 (JSObject::kPropertiesOffset + kPointerSize)); | 409 (JSObject::kPropertiesOffset + kPointerSize)); |
409 __ Stp(empty, empty, MemOperand(new_obj, JSObject::kPropertiesOffset)); | 410 __ Stp(empty, empty, MemOperand(new_obj, JSObject::kPropertiesOffset)); |
410 | 411 |
411 Register first_prop = x5; | 412 Register first_prop = x5; |
412 __ Add(first_prop, new_obj, JSObject::kHeaderSize); | 413 __ Add(first_prop, new_obj, JSObject::kHeaderSize); |
413 | 414 |
414 // Fill all of the in-object properties with the appropriate filler. | 415 // Fill all of the in-object properties with the appropriate filler. |
415 Register filler = x7; | 416 Register undef = x7; |
416 __ LoadRoot(filler, Heap::kUndefinedValueRootIndex); | 417 __ LoadRoot(undef, Heap::kUndefinedValueRootIndex); |
417 | 418 |
418 // Obtain number of pre-allocated property fields and in-object | 419 // Obtain number of pre-allocated property fields and in-object |
419 // properties. | 420 // properties. |
420 Register prealloc_fields = x10; | 421 Register prealloc_fields = x10; |
421 Register inobject_props = x11; | 422 Register inobject_props = x11; |
422 Register inst_sizes = x11; | 423 Register inst_sizes = x11; |
423 __ Ldr(inst_sizes, FieldMemOperand(init_map, Map::kInstanceSizesOffset)); | 424 __ Ldr(inst_sizes, FieldMemOperand(init_map, Map::kInstanceSizesOffset)); |
424 __ Ubfx(prealloc_fields, inst_sizes, | 425 __ Ubfx(prealloc_fields, inst_sizes, |
425 Map::kPreAllocatedPropertyFieldsByte * kBitsPerByte, | 426 Map::kPreAllocatedPropertyFieldsByte * kBitsPerByte, |
426 kBitsPerByte); | 427 kBitsPerByte); |
427 __ Ubfx(inobject_props, inst_sizes, | 428 __ Ubfx(inobject_props, inst_sizes, |
428 Map::kInObjectPropertiesByte * kBitsPerByte, kBitsPerByte); | 429 Map::kInObjectPropertiesByte * kBitsPerByte, kBitsPerByte); |
429 | 430 |
430 // Calculate number of property fields in the object. | 431 // Calculate number of property fields in the object. |
431 Register prop_fields = x6; | 432 Register prop_fields = x6; |
432 __ Sub(prop_fields, obj_size, JSObject::kHeaderSize / kPointerSize); | 433 __ Sub(prop_fields, obj_size, JSObject::kHeaderSize / kPointerSize); |
433 | 434 |
434 if (!is_api_function) { | 435 if (count_constructions) { |
435 Label no_inobject_slack_tracking; | 436 // Fill the pre-allocated fields with undef. |
| 437 __ FillFields(first_prop, prealloc_fields, undef); |
436 | 438 |
437 // Check if slack tracking is enabled. | 439 // Register first_non_prealloc is the offset of the first field after |
438 __ Cmp(constructon_count, Operand(JSFunction::kNoSlackTracking)); | |
439 __ B(eq, &no_inobject_slack_tracking); | |
440 constructon_count = NoReg; | |
441 | |
442 // Fill the pre-allocated fields with undef. | |
443 __ FillFields(first_prop, prealloc_fields, filler); | |
444 | |
445 // Update first_prop register to be the offset of the first field after | |
446 // pre-allocated fields. | 440 // pre-allocated fields. |
447 __ Add(first_prop, first_prop, | 441 Register first_non_prealloc = x12; |
| 442 __ Add(first_non_prealloc, first_prop, |
448 Operand(prealloc_fields, LSL, kPointerSizeLog2)); | 443 Operand(prealloc_fields, LSL, kPointerSizeLog2)); |
449 | 444 |
| 445 first_prop = NoReg; |
| 446 |
450 if (FLAG_debug_code) { | 447 if (FLAG_debug_code) { |
451 Register obj_end = x14; | 448 Register obj_end = x5; |
452 __ Add(obj_end, new_obj, Operand(obj_size, LSL, kPointerSizeLog2)); | 449 __ Add(obj_end, new_obj, Operand(obj_size, LSL, kPointerSizeLog2)); |
453 __ Cmp(first_prop, obj_end); | 450 __ Cmp(first_non_prealloc, obj_end); |
454 __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields); | 451 __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields); |
455 } | 452 } |
456 | 453 |
457 // Fill the remaining fields with one pointer filler map. | 454 // Fill the remaining fields with one pointer filler map. |
458 __ LoadRoot(filler, Heap::kOnePointerFillerMapRootIndex); | 455 Register one_pointer_filler = x5; |
459 __ Sub(prop_fields, prop_fields, prealloc_fields); | 456 Register non_prealloc_fields = x6; |
460 | 457 __ LoadRoot(one_pointer_filler, Heap::kOnePointerFillerMapRootIndex); |
461 __ bind(&no_inobject_slack_tracking); | 458 __ Sub(non_prealloc_fields, prop_fields, prealloc_fields); |
462 } | 459 __ FillFields(first_non_prealloc, non_prealloc_fields, |
463 if (create_memento) { | 460 one_pointer_filler); |
| 461 prop_fields = NoReg; |
| 462 } else if (create_memento) { |
464 // Fill the pre-allocated fields with undef. | 463 // Fill the pre-allocated fields with undef. |
465 __ FillFields(first_prop, prop_fields, filler); | 464 __ FillFields(first_prop, prop_fields, undef); |
466 __ Add(first_prop, new_obj, Operand(obj_size, LSL, kPointerSizeLog2)); | 465 __ Add(first_prop, new_obj, Operand(obj_size, LSL, kPointerSizeLog2)); |
467 __ LoadRoot(x14, Heap::kAllocationMementoMapRootIndex); | 466 __ LoadRoot(x14, Heap::kAllocationMementoMapRootIndex); |
468 ASSERT_EQ(0 * kPointerSize, AllocationMemento::kMapOffset); | 467 ASSERT_EQ(0 * kPointerSize, AllocationMemento::kMapOffset); |
469 __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex)); | 468 __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex)); |
470 // Load the AllocationSite | 469 // Load the AllocationSite |
471 __ Peek(x14, 2 * kXRegSize); | 470 __ Peek(x14, 2 * kXRegSize); |
472 ASSERT_EQ(1 * kPointerSize, AllocationMemento::kAllocationSiteOffset); | 471 ASSERT_EQ(1 * kPointerSize, AllocationMemento::kAllocationSiteOffset); |
473 __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex)); | 472 __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex)); |
474 first_prop = NoReg; | 473 first_prop = NoReg; |
475 } else { | 474 } else { |
476 // Fill all of the property fields with undef. | 475 // Fill all of the property fields with undef. |
477 __ FillFields(first_prop, prop_fields, filler); | 476 __ FillFields(first_prop, prop_fields, undef); |
478 first_prop = NoReg; | 477 first_prop = NoReg; |
479 prop_fields = NoReg; | 478 prop_fields = NoReg; |
480 } | 479 } |
481 | 480 |
482 // Add the object tag to make the JSObject real, so that we can continue | 481 // Add the object tag to make the JSObject real, so that we can continue |
483 // and jump into the continuation code at any time from now on. Any | 482 // and jump into the continuation code at any time from now on. Any |
484 // failures need to undo the allocation, so that the heap is in a | 483 // failures need to undo the allocation, so that the heap is in a |
485 // consistent state and verifiable. | 484 // consistent state and verifiable. |
486 __ Add(new_obj, new_obj, kHeapObjectTag); | 485 __ Add(new_obj, new_obj, kHeapObjectTag); |
487 | 486 |
(...skipping 22 matching lines...) Expand all Loading... |
510 | 509 |
511 Register array_map = x10; | 510 Register array_map = x10; |
512 __ LoadRoot(array_map, Heap::kFixedArrayMapRootIndex); | 511 __ LoadRoot(array_map, Heap::kFixedArrayMapRootIndex); |
513 __ Str(array_map, MemOperand(new_array, FixedArray::kMapOffset)); | 512 __ Str(array_map, MemOperand(new_array, FixedArray::kMapOffset)); |
514 __ SmiTag(x0, element_count); | 513 __ SmiTag(x0, element_count); |
515 __ Str(x0, MemOperand(new_array, FixedArray::kLengthOffset)); | 514 __ Str(x0, MemOperand(new_array, FixedArray::kLengthOffset)); |
516 | 515 |
517 // Initialize the fields to undefined. | 516 // Initialize the fields to undefined. |
518 Register elements = x10; | 517 Register elements = x10; |
519 __ Add(elements, new_array, FixedArray::kHeaderSize); | 518 __ Add(elements, new_array, FixedArray::kHeaderSize); |
520 __ FillFields(elements, element_count, filler); | 519 __ FillFields(elements, element_count, undef); |
521 | 520 |
522 // Store the initialized FixedArray into the properties field of the | 521 // Store the initialized FixedArray into the properties field of the |
523 // JSObject. | 522 // JSObject. |
524 __ Add(new_array, new_array, kHeapObjectTag); | 523 __ Add(new_array, new_array, kHeapObjectTag); |
525 __ Str(new_array, FieldMemOperand(new_obj, JSObject::kPropertiesOffset)); | 524 __ Str(new_array, FieldMemOperand(new_obj, JSObject::kPropertiesOffset)); |
526 | 525 |
527 // Continue with JSObject being successfully allocated. | 526 // Continue with JSObject being successfully allocated. |
528 __ B(&allocated); | 527 __ B(&allocated); |
529 | 528 |
530 // Undo the setting of the new top so that the heap is verifiable. For | 529 // Undo the setting of the new top so that the heap is verifiable. For |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 __ Ldr(cp, FieldMemOperand(constructor, JSFunction::kContextOffset)); | 617 __ Ldr(cp, FieldMemOperand(constructor, JSFunction::kContextOffset)); |
619 Handle<Code> code = | 618 Handle<Code> code = |
620 masm->isolate()->builtins()->HandleApiCallConstruct(); | 619 masm->isolate()->builtins()->HandleApiCallConstruct(); |
621 __ Call(code, RelocInfo::CODE_TARGET); | 620 __ Call(code, RelocInfo::CODE_TARGET); |
622 } else { | 621 } else { |
623 ParameterCount actual(argc); | 622 ParameterCount actual(argc); |
624 __ InvokeFunction(constructor, actual, CALL_FUNCTION, NullCallWrapper()); | 623 __ InvokeFunction(constructor, actual, CALL_FUNCTION, NullCallWrapper()); |
625 } | 624 } |
626 | 625 |
627 // Store offset of return address for deoptimizer. | 626 // Store offset of return address for deoptimizer. |
628 if (!is_api_function) { | 627 if (!is_api_function && !count_constructions) { |
629 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); | 628 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); |
630 } | 629 } |
631 | 630 |
632 // Restore the context from the frame. | 631 // Restore the context from the frame. |
633 // x0: result | 632 // x0: result |
634 // jssp[0]: receiver | 633 // jssp[0]: receiver |
635 // jssp[1]: constructor function | 634 // jssp[1]: constructor function |
636 // jssp[2]: number of arguments (smi-tagged) | 635 // jssp[2]: number of arguments (smi-tagged) |
637 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 636 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
638 | 637 |
(...skipping 30 matching lines...) Expand all Loading... |
669 // Leave construct frame. | 668 // Leave construct frame. |
670 } | 669 } |
671 | 670 |
672 __ DropBySMI(x1); | 671 __ DropBySMI(x1); |
673 __ Drop(1); | 672 __ Drop(1); |
674 __ IncrementCounter(isolate->counters()->constructed_objects(), 1, x1, x2); | 673 __ IncrementCounter(isolate->counters()->constructed_objects(), 1, x1, x2); |
675 __ Ret(); | 674 __ Ret(); |
676 } | 675 } |
677 | 676 |
678 | 677 |
| 678 void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) { |
| 679 Generate_JSConstructStubHelper(masm, false, true, false); |
| 680 } |
| 681 |
| 682 |
679 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { | 683 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { |
680 Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new); | 684 Generate_JSConstructStubHelper(masm, false, false, FLAG_pretenuring_call_new); |
681 } | 685 } |
682 | 686 |
683 | 687 |
684 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { | 688 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { |
685 Generate_JSConstructStubHelper(masm, true, false); | 689 Generate_JSConstructStubHelper(masm, true, false, false); |
686 } | 690 } |
687 | 691 |
688 | 692 |
689 // Input: | 693 // Input: |
690 // x0: code entry. | 694 // x0: code entry. |
691 // x1: function. | 695 // x1: function. |
692 // x2: receiver. | 696 // x2: receiver. |
693 // x3: argc. | 697 // x3: argc. |
694 // x4: argv. | 698 // x4: argv. |
695 // Output: | 699 // Output: |
(...skipping 860 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1556 __ Unreachable(); | 1560 __ Unreachable(); |
1557 } | 1561 } |
1558 } | 1562 } |
1559 | 1563 |
1560 | 1564 |
1561 #undef __ | 1565 #undef __ |
1562 | 1566 |
1563 } } // namespace v8::internal | 1567 } } // namespace v8::internal |
1564 | 1568 |
1565 #endif // V8_TARGET_ARCH_ARM | 1569 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |