|
1 |
|
2 # HG changeset patch |
|
3 # User Lars T Hansen <lhansen@mozilla.com> |
|
4 # Date 1519822672 -3600 |
|
5 # Node ID 800abe66894d6b07b24bccecbf6a65e2261076f6 |
|
6 # Parent 223c97459e96183eb616aed39147207bdb953ba8 |
|
7 Bug 1375074 - Save and restore non-volatile x28 on ARM64 for generated unboxed object constructor. r=sstangl |
|
8 |
|
9 diff --git a/js/src/jit-test/tests/bug1375074.js b/js/src/jit-test/tests/bug1375074.js |
|
10 new file mode 100644 |
|
11 --- /dev/null |
|
12 +++ b/js/src/jit-test/tests/bug1375074.js |
|
13 @@ -0,0 +1,18 @@ |
|
14 +// This forces the VM to start creating unboxed objects and thus stresses a |
|
15 +// particular path into generated code for a specialized unboxed object |
|
16 +// constructor. |
|
17 + |
|
18 +var K = 2000; // 2000 should be plenty |
|
19 +var s = "["; |
|
20 +var i; |
|
21 +for ( i=0; i < K-1; i++ ) |
|
22 + s = s + `{"i":${i}},`; |
|
23 +s += `{"i":${i}}]`; |
|
24 +var v = JSON.parse(s); |
|
25 + |
|
26 +assertEq(v.length == K, true); |
|
27 + |
|
28 +for ( i=0; i < K; i++) { |
|
29 + assertEq(v[i] instanceof Object, true); |
|
30 + assertEq(v[i].i, i); |
|
31 +} |
|
32 diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp |
|
33 --- a/js/src/vm/UnboxedObject.cpp |
|
34 +++ b/js/src/vm/UnboxedObject.cpp |
|
35 @@ -90,17 +90,25 @@ UnboxedLayout::makeConstructorCode(JSCon |
|
36 masm.loadPtr(Address(masm.getStackPointer(), sizeof(void*)), propertiesReg); |
|
37 masm.loadPtr(Address(masm.getStackPointer(), 2 * sizeof(void*)), newKindReg); |
|
38 #else |
|
39 propertiesReg = IntArgReg0; |
|
40 newKindReg = IntArgReg1; |
|
41 #endif |
|
42 |
|
43 #ifdef JS_CODEGEN_ARM64 |
|
44 - // ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing. |
|
45 + // ARM64 communicates stack address via sp, but uses a pseudo-sp (PSP) for |
|
46 + // addressing. The register we use for PSP may however also be used by |
|
47 + // calling code, and it is nonvolatile, so save it. Do this as a special |
|
48 + // case first because the generic save/restore code needs the PSP to be |
|
49 + // initialized already. |
|
50 + MOZ_ASSERT(PseudoStackPointer64.Is(masm.GetStackPointer64())); |
|
51 + masm.Str(PseudoStackPointer64, vixl::MemOperand(sp, -16, vixl::PreIndex)); |
|
52 + |
|
53 + // Initialize the PSP from the SP. |
|
54 masm.initStackPtr(); |
|
55 #endif |
|
56 |
|
57 MOZ_ASSERT(propertiesReg.volatile_()); |
|
58 MOZ_ASSERT(newKindReg.volatile_()); |
|
59 |
|
60 AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All()); |
|
61 regs.take(propertiesReg); |
|
62 @@ -228,17 +236,32 @@ UnboxedLayout::makeConstructorCode(JSCon |
|
63 if (object != ReturnReg) |
|
64 masm.movePtr(object, ReturnReg); |
|
65 |
|
66 // Restore non-volatile registers which were saved on entry. |
|
67 if (ScratchDoubleReg.volatile_()) |
|
68 masm.pop(ScratchDoubleReg); |
|
69 masm.PopRegsInMask(savedNonVolatileRegisters); |
|
70 |
|
71 +#ifdef JS_CODEGEN_ARM64 |
|
72 + // Now restore the value that was in the PSP register on entry, and return. |
|
73 + |
|
74 + // Obtain the correct SP from the PSP. |
|
75 + masm.Mov(sp, PseudoStackPointer64); |
|
76 + |
|
77 + // Restore the saved value of the PSP register, this value is whatever the |
|
78 + // caller had saved in it, not any actual SP value, and it must not be |
|
79 + // overwritten subsequently. |
|
80 + masm.Ldr(PseudoStackPointer64, vixl::MemOperand(sp, 16, vixl::PostIndex)); |
|
81 + |
|
82 + // Perform a plain Ret(), as abiret() will move SP <- PSP and that is wrong. |
|
83 + masm.Ret(vixl::lr); |
|
84 +#else |
|
85 masm.abiret(); |
|
86 +#endif |
|
87 |
|
88 masm.bind(&failureStoreOther); |
|
89 |
|
90 // There was a failure while storing a value which cannot be stored at all |
|
91 // in the unboxed object. Initialize the object so it is safe for GC and |
|
92 // return null. |
|
93 masm.initUnboxedObjectContents(object, templateObject); |
|
94 |
|
95 |