[wasm] Support validation of asm.js modules with != 3 args.
Our previous per-arch instantiation thunks for asm.js didn't support modules that had or were called with anything other than 3 arguments. Adding support for this. Addding a runtime test method to check if asm validation succeeded. Adding a test of validation with different argument count combinations. R=mstarzinger@chromium.org TEST=mjsunit/asm/asm-validator.js BUG= https://bugs.chromium.org/p/v8/issues/detail?id=4203 Review-Url: https://codereview.chromium.org/2229723002 Cr-Commit-Position: refs/heads/master@{#38688}
This commit is contained in:
parent
b12669b0e2
commit
d0e52555f0
@ -1449,6 +1449,8 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
Label failed;
|
Label failed;
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
// Preserve argument count for later compare.
|
||||||
|
__ Move(r4, r0);
|
||||||
// Push the number of arguments to the callee.
|
// Push the number of arguments to the callee.
|
||||||
__ SmiTag(r0);
|
__ SmiTag(r0);
|
||||||
__ push(r0);
|
__ push(r0);
|
||||||
@ -1459,17 +1461,40 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
// The function.
|
// The function.
|
||||||
__ push(r1);
|
__ push(r1);
|
||||||
// Copy arguments from caller (stdlib, foreign, heap).
|
// Copy arguments from caller (stdlib, foreign, heap).
|
||||||
for (int i = 2; i >= 0; --i) {
|
Label args_done;
|
||||||
__ ldr(r4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
for (int j = 0; j < 4; ++j) {
|
||||||
i * kPointerSize));
|
Label over;
|
||||||
__ push(r4);
|
if (j < 3) {
|
||||||
|
__ cmp(r4, Operand(j));
|
||||||
|
__ b(ne, &over);
|
||||||
|
}
|
||||||
|
for (int i = j - 1; i >= 0; --i) {
|
||||||
|
__ ldr(r4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
||||||
|
i * kPointerSize));
|
||||||
|
__ push(r4);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3 - j; ++i) {
|
||||||
|
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||||
|
}
|
||||||
|
if (j < 3) {
|
||||||
|
__ jmp(&args_done);
|
||||||
|
__ bind(&over);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
__ bind(&args_done);
|
||||||
|
|
||||||
// Call runtime, on success unwind frame, and parent frame.
|
// Call runtime, on success unwind frame, and parent frame.
|
||||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||||
// A smi 0 is returned on failure, an object on success.
|
// A smi 0 is returned on failure, an object on success.
|
||||||
__ JumpIfSmi(r0, &failed);
|
__ JumpIfSmi(r0, &failed);
|
||||||
|
|
||||||
|
__ Drop(2);
|
||||||
|
__ pop(r4);
|
||||||
|
__ SmiUntag(r4);
|
||||||
scope.GenerateLeaveFrame();
|
scope.GenerateLeaveFrame();
|
||||||
__ Drop(4);
|
|
||||||
|
__ add(r4, r4, Operand(1));
|
||||||
|
__ Drop(r4);
|
||||||
__ Ret();
|
__ Ret();
|
||||||
|
|
||||||
__ bind(&failed);
|
__ bind(&failed);
|
||||||
|
@ -1446,23 +1446,48 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
Label failed;
|
Label failed;
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
// Preserve argument count for later compare.
|
||||||
|
__ Move(x4, x0);
|
||||||
// Push a copy of the target function and the new target.
|
// Push a copy of the target function and the new target.
|
||||||
__ SmiTag(x0);
|
__ SmiTag(x0);
|
||||||
// Push another copy as a parameter to the runtime call.
|
// Push another copy as a parameter to the runtime call.
|
||||||
__ Push(x0, x1, x3, x1);
|
__ Push(x0, x1, x3, x1);
|
||||||
|
|
||||||
// Copy arguments from caller (stdlib, foreign, heap).
|
// Copy arguments from caller (stdlib, foreign, heap).
|
||||||
for (int i = 2; i >= 0; --i) {
|
Label args_done;
|
||||||
__ ldr(x4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
for (int j = 0; j < 4; ++j) {
|
||||||
i * kPointerSize));
|
Label over;
|
||||||
__ push(x4);
|
if (j < 3) {
|
||||||
|
__ cmp(x4, Operand(j));
|
||||||
|
__ B(ne, &over);
|
||||||
|
}
|
||||||
|
for (int i = j - 1; i >= 0; --i) {
|
||||||
|
__ ldr(x4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
||||||
|
i * kPointerSize));
|
||||||
|
__ push(x4);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3 - j; ++i) {
|
||||||
|
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||||
|
}
|
||||||
|
if (j < 3) {
|
||||||
|
__ jmp(&args_done);
|
||||||
|
__ bind(&over);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
__ bind(&args_done);
|
||||||
|
|
||||||
// Call runtime, on success unwind frame, and parent frame.
|
// Call runtime, on success unwind frame, and parent frame.
|
||||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||||
// A smi 0 is returned on failure, an object on success.
|
// A smi 0 is returned on failure, an object on success.
|
||||||
__ JumpIfSmi(x0, &failed);
|
__ JumpIfSmi(x0, &failed);
|
||||||
|
|
||||||
|
__ Drop(2);
|
||||||
|
__ pop(x4);
|
||||||
|
__ SmiUntag(x4);
|
||||||
scope.GenerateLeaveFrame();
|
scope.GenerateLeaveFrame();
|
||||||
__ Drop(4);
|
|
||||||
|
__ add(x4, x4, Operand(1));
|
||||||
|
__ Drop(x4);
|
||||||
__ Ret();
|
__ Ret();
|
||||||
|
|
||||||
__ bind(&failed);
|
__ bind(&failed);
|
||||||
|
@ -1010,6 +1010,8 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
Label failed;
|
Label failed;
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
// Preserve argument count for later compare.
|
||||||
|
__ mov(ecx, eax);
|
||||||
// Push the number of arguments to the callee.
|
// Push the number of arguments to the callee.
|
||||||
__ SmiTag(eax);
|
__ SmiTag(eax);
|
||||||
__ push(eax);
|
__ push(eax);
|
||||||
@ -1020,16 +1022,42 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
// The function.
|
// The function.
|
||||||
__ push(edi);
|
__ push(edi);
|
||||||
// Copy arguments from caller (stdlib, foreign, heap).
|
// Copy arguments from caller (stdlib, foreign, heap).
|
||||||
for (int i = 2; i >= 0; --i) {
|
Label args_done;
|
||||||
__ push(Operand(
|
for (int j = 0; j < 4; ++j) {
|
||||||
ebp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize));
|
Label over;
|
||||||
|
if (j < 3) {
|
||||||
|
__ cmp(ecx, Immediate(j));
|
||||||
|
__ j(not_equal, &over, Label::kNear);
|
||||||
|
}
|
||||||
|
for (int i = j - 1; i >= 0; --i) {
|
||||||
|
__ Push(Operand(
|
||||||
|
ebp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3 - j; ++i) {
|
||||||
|
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||||
|
}
|
||||||
|
if (j < 3) {
|
||||||
|
__ jmp(&args_done, Label::kNear);
|
||||||
|
__ bind(&over);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
__ bind(&args_done);
|
||||||
|
|
||||||
// Call runtime, on success unwind frame, and parent frame.
|
// Call runtime, on success unwind frame, and parent frame.
|
||||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||||
// A smi 0 is returned on failure, an object on success.
|
// A smi 0 is returned on failure, an object on success.
|
||||||
__ JumpIfSmi(eax, &failed, Label::kNear);
|
__ JumpIfSmi(eax, &failed, Label::kNear);
|
||||||
|
|
||||||
|
__ Drop(2);
|
||||||
|
__ Pop(ecx);
|
||||||
|
__ SmiUntag(ecx);
|
||||||
scope.GenerateLeaveFrame();
|
scope.GenerateLeaveFrame();
|
||||||
__ ret(4 * kPointerSize);
|
|
||||||
|
__ PopReturnAddressTo(ebx);
|
||||||
|
__ inc(ecx);
|
||||||
|
__ lea(esp, Operand(esp, ecx, times_pointer_size, 0));
|
||||||
|
__ PushReturnAddressFrom(ebx);
|
||||||
|
__ ret(0);
|
||||||
|
|
||||||
__ bind(&failed);
|
__ bind(&failed);
|
||||||
// Restore target function and new target.
|
// Restore target function and new target.
|
||||||
|
@ -1444,23 +1444,47 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
Label failed;
|
Label failed;
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
// Preserve argument count for later compare.
|
||||||
|
__ Move(t4, a0);
|
||||||
// Push a copy of the target function and the new target.
|
// Push a copy of the target function and the new target.
|
||||||
// Push function as parameter to the runtime call.
|
// Push function as parameter to the runtime call.
|
||||||
__ SmiTag(a0);
|
__ SmiTag(a0);
|
||||||
__ Push(a0, a1, a3, a1);
|
__ Push(a0, a1, a3, a1);
|
||||||
|
|
||||||
// Copy arguments from caller (stdlib, foreign, heap).
|
// Copy arguments from caller (stdlib, foreign, heap).
|
||||||
for (int i = 2; i >= 0; --i) {
|
Label args_done;
|
||||||
__ lw(a3, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
for (int j = 0; j < 4; ++j) {
|
||||||
i * kPointerSize));
|
Label over;
|
||||||
__ push(a3);
|
if (j < 3) {
|
||||||
|
__ Branch(&over, ne, t4, Operand(j));
|
||||||
|
}
|
||||||
|
for (int i = j - 1; i >= 0; --i) {
|
||||||
|
__ lw(t4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
||||||
|
i * kPointerSize));
|
||||||
|
__ push(t4);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3 - j; ++i) {
|
||||||
|
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||||
|
}
|
||||||
|
if (j < 3) {
|
||||||
|
__ jmp(&args_done);
|
||||||
|
__ bind(&over);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
__ bind(&args_done);
|
||||||
|
|
||||||
// Call runtime, on success unwind frame, and parent frame.
|
// Call runtime, on success unwind frame, and parent frame.
|
||||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||||
// A smi 0 is returned on failure, an object on success.
|
// A smi 0 is returned on failure, an object on success.
|
||||||
__ JumpIfSmi(a0, &failed);
|
__ JumpIfSmi(v0, &failed);
|
||||||
|
|
||||||
|
__ Drop(2);
|
||||||
|
__ pop(t4);
|
||||||
|
__ SmiUntag(t4);
|
||||||
scope.GenerateLeaveFrame();
|
scope.GenerateLeaveFrame();
|
||||||
__ Drop(4);
|
|
||||||
|
__ Addu(t4, t4, Operand(1));
|
||||||
|
__ Lsa(sp, sp, t4, kPointerSizeLog2);
|
||||||
__ Ret();
|
__ Ret();
|
||||||
|
|
||||||
__ bind(&failed);
|
__ bind(&failed);
|
||||||
|
@ -1438,21 +1438,44 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
// Push a copy of the target function and the new target.
|
// Push a copy of the target function and the new target.
|
||||||
// Push function as parameter to the runtime call.
|
// Push function as parameter to the runtime call.
|
||||||
|
__ Move(t2, a0);
|
||||||
__ SmiTag(a0);
|
__ SmiTag(a0);
|
||||||
__ Push(a0, a1, a3, a1);
|
__ Push(a0, a1, a3, a1);
|
||||||
|
|
||||||
// Copy arguments from caller (stdlib, foreign, heap).
|
// Copy arguments from caller (stdlib, foreign, heap).
|
||||||
for (int i = 2; i >= 0; --i) {
|
Label args_done;
|
||||||
__ lw(a3, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
for (int j = 0; j < 4; ++j) {
|
||||||
i * kPointerSize));
|
Label over;
|
||||||
__ push(a3);
|
if (j < 3) {
|
||||||
|
__ Branch(&over, ne, t2, Operand(j));
|
||||||
|
}
|
||||||
|
for (int i = j - 1; i >= 0; --i) {
|
||||||
|
__ lw(t2, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
||||||
|
i * kPointerSize));
|
||||||
|
__ push(t2);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3 - j; ++i) {
|
||||||
|
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||||
|
}
|
||||||
|
if (j < 3) {
|
||||||
|
__ jmp(&args_done);
|
||||||
|
__ bind(&over);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
__ bind(&args_done);
|
||||||
|
|
||||||
// Call runtime, on success unwind frame, and parent frame.
|
// Call runtime, on success unwind frame, and parent frame.
|
||||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||||
// A smi 0 is returned on failure, an object on success.
|
// A smi 0 is returned on failure, an object on success.
|
||||||
__ JumpIfSmi(a0, &failed);
|
__ JumpIfSmi(v0, &failed);
|
||||||
|
|
||||||
|
__ Drop(2);
|
||||||
|
__ pop(t2);
|
||||||
|
__ SmiUntag(t2);
|
||||||
scope.GenerateLeaveFrame();
|
scope.GenerateLeaveFrame();
|
||||||
__ Drop(4);
|
|
||||||
|
__ Addu(t2, t2, Operand(1));
|
||||||
|
__ Lsa(sp, sp, t2, kPointerSizeLog2);
|
||||||
__ Ret();
|
__ Ret();
|
||||||
|
|
||||||
__ bind(&failed);
|
__ bind(&failed);
|
||||||
|
@ -1458,23 +1458,47 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
Label failed;
|
Label failed;
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
// Preserve argument count for later compare.
|
||||||
|
__ Move(r5, r3);
|
||||||
// Push a copy of the target function and the new target.
|
// Push a copy of the target function and the new target.
|
||||||
// Push function as parameter to the runtime call.
|
// Push function as parameter to the runtime call.
|
||||||
__ SmiTag(r3);
|
__ SmiTag(r3);
|
||||||
__ Push(r3, r4, r6, r4);
|
__ Push(r3, r4, r6, r4);
|
||||||
|
|
||||||
// Copy arguments from caller (stdlib, foreign, heap).
|
// Copy arguments from caller (stdlib, foreign, heap).
|
||||||
for (int i = 2; i >= 0; --i) {
|
Label args_done;
|
||||||
__ LoadP(r4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
for (int j = 0; j < 4; ++j) {
|
||||||
i * kPointerSize));
|
Label over;
|
||||||
__ push(r4);
|
if (j < 3) {
|
||||||
|
__ cmpi(r5, Operand(j));
|
||||||
|
__ bne(&over);
|
||||||
|
}
|
||||||
|
for (int i = j - 1; i >= 0; --i) {
|
||||||
|
__ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
||||||
|
i * kPointerSize));
|
||||||
|
__ push(r5);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3 - j; ++i) {
|
||||||
|
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||||
|
}
|
||||||
|
if (j < 3) {
|
||||||
|
__ jmp(&args_done);
|
||||||
|
__ bind(&over);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
__ bind(&args_done);
|
||||||
|
|
||||||
// Call runtime, on success unwind frame, and parent frame.
|
// Call runtime, on success unwind frame, and parent frame.
|
||||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||||
// A smi 0 is returned on failure, an object on success.
|
// A smi 0 is returned on failure, an object on success.
|
||||||
__ JumpIfSmi(r3, &failed);
|
__ JumpIfSmi(r3, &failed);
|
||||||
|
|
||||||
|
__ Drop(2);
|
||||||
|
__ pop(r5);
|
||||||
|
__ SmiUntag(r5);
|
||||||
scope.GenerateLeaveFrame();
|
scope.GenerateLeaveFrame();
|
||||||
__ Drop(4);
|
|
||||||
|
__ Drop(r5);
|
||||||
__ Ret();
|
__ Ret();
|
||||||
|
|
||||||
__ bind(&failed);
|
__ bind(&failed);
|
||||||
|
@ -1465,23 +1465,48 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
Label failed;
|
Label failed;
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
// Preserve argument count for later compare.
|
||||||
|
__ Move(r4, r2);
|
||||||
// Push a copy of the target function and the new target.
|
// Push a copy of the target function and the new target.
|
||||||
__ SmiTag(r2);
|
__ SmiTag(r2);
|
||||||
// Push another copy as a parameter to the runtime call.
|
// Push another copy as a parameter to the runtime call.
|
||||||
__ Push(r2, r3, r5, r3);
|
__ Push(r2, r3, r5, r3);
|
||||||
|
|
||||||
// Copy arguments from caller (stdlib, foreign, heap).
|
// Copy arguments from caller (stdlib, foreign, heap).
|
||||||
for (int i = 2; i >= 0; --i) {
|
Label args_done;
|
||||||
__ LoadP(r4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
for (int j = 0; j < 4; ++j) {
|
||||||
i * kPointerSize));
|
Label over;
|
||||||
__ push(r4);
|
if (j < 3) {
|
||||||
|
__ CmpP(r4, Operand(j));
|
||||||
|
__ b(ne, &over);
|
||||||
|
}
|
||||||
|
for (int i = j - 1; i >= 0; --i) {
|
||||||
|
__ LoadP(r9, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
||||||
|
i * kPointerSize));
|
||||||
|
__ push(r9);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3 - j; ++i) {
|
||||||
|
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||||
|
}
|
||||||
|
if (j < 3) {
|
||||||
|
__ jmp(&args_done);
|
||||||
|
__ bind(&over);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
__ bind(&args_done);
|
||||||
|
|
||||||
// Call runtime, on success unwind frame, and parent frame.
|
// Call runtime, on success unwind frame, and parent frame.
|
||||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||||
// A smi 0 is returned on failure, an object on success.
|
// A smi 0 is returned on failure, an object on success.
|
||||||
__ JumpIfSmi(r2, &failed);
|
__ JumpIfSmi(r2, &failed);
|
||||||
|
|
||||||
|
__ Drop(2);
|
||||||
|
__ pop(r4);
|
||||||
|
__ SmiUntag(r4);
|
||||||
scope.GenerateLeaveFrame();
|
scope.GenerateLeaveFrame();
|
||||||
__ Drop(4);
|
|
||||||
|
__ AddP(r4, r4, Operand(1));
|
||||||
|
__ Drop(r4, r7);
|
||||||
__ Ret();
|
__ Ret();
|
||||||
|
|
||||||
__ bind(&failed);
|
__ bind(&failed);
|
||||||
|
@ -1062,6 +1062,8 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
Label failed;
|
Label failed;
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
// Preserve argument count for later compare.
|
||||||
|
__ movp(kScratchRegister, rax);
|
||||||
// Push the number of arguments to the callee.
|
// Push the number of arguments to the callee.
|
||||||
__ Integer32ToSmi(rax, rax);
|
__ Integer32ToSmi(rax, rax);
|
||||||
__ Push(rax);
|
__ Push(rax);
|
||||||
@ -1072,16 +1074,42 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
// The function.
|
// The function.
|
||||||
__ Push(rdi);
|
__ Push(rdi);
|
||||||
// Copy arguments from caller (stdlib, foreign, heap).
|
// Copy arguments from caller (stdlib, foreign, heap).
|
||||||
for (int i = 2; i >= 0; --i) {
|
Label args_done;
|
||||||
__ Push(Operand(
|
for (int j = 0; j < 4; ++j) {
|
||||||
rbp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize));
|
Label over;
|
||||||
|
if (j < 3) {
|
||||||
|
__ cmpp(kScratchRegister, Immediate(j));
|
||||||
|
__ j(not_equal, &over, Label::kNear);
|
||||||
|
}
|
||||||
|
for (int i = j - 1; i >= 0; --i) {
|
||||||
|
__ Push(Operand(
|
||||||
|
rbp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3 - j; ++i) {
|
||||||
|
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||||
|
}
|
||||||
|
if (j < 3) {
|
||||||
|
__ jmp(&args_done, Label::kNear);
|
||||||
|
__ bind(&over);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
__ bind(&args_done);
|
||||||
|
|
||||||
// Call runtime, on success unwind frame, and parent frame.
|
// Call runtime, on success unwind frame, and parent frame.
|
||||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||||
// A smi 0 is returned on failure, an object on success.
|
// A smi 0 is returned on failure, an object on success.
|
||||||
__ JumpIfSmi(rax, &failed, Label::kNear);
|
__ JumpIfSmi(rax, &failed, Label::kNear);
|
||||||
|
|
||||||
|
__ Drop(2);
|
||||||
|
__ Pop(kScratchRegister);
|
||||||
|
__ SmiToInteger32(kScratchRegister, kScratchRegister);
|
||||||
scope.GenerateLeaveFrame();
|
scope.GenerateLeaveFrame();
|
||||||
__ ret(4 * kPointerSize);
|
|
||||||
|
__ PopReturnAddressTo(rbx);
|
||||||
|
__ incp(kScratchRegister);
|
||||||
|
__ leap(rsp, Operand(rsp, kScratchRegister, times_pointer_size, 0));
|
||||||
|
__ PushReturnAddressFrom(rbx);
|
||||||
|
__ ret(0);
|
||||||
|
|
||||||
__ bind(&failed);
|
__ bind(&failed);
|
||||||
// Restore target function and new target.
|
// Restore target function and new target.
|
||||||
|
@ -1011,6 +1011,8 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
Label failed;
|
Label failed;
|
||||||
{
|
{
|
||||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
// Preserve argument count for later compare.
|
||||||
|
__ mov(ecx, eax);
|
||||||
// Push the number of arguments to the callee.
|
// Push the number of arguments to the callee.
|
||||||
__ SmiTag(eax);
|
__ SmiTag(eax);
|
||||||
__ push(eax);
|
__ push(eax);
|
||||||
@ -1021,16 +1023,42 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
|||||||
// The function.
|
// The function.
|
||||||
__ push(edi);
|
__ push(edi);
|
||||||
// Copy arguments from caller (stdlib, foreign, heap).
|
// Copy arguments from caller (stdlib, foreign, heap).
|
||||||
for (int i = 2; i >= 0; --i) {
|
Label args_done;
|
||||||
__ push(Operand(
|
for (int j = 0; j < 4; ++j) {
|
||||||
ebp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize));
|
Label over;
|
||||||
|
if (j < 3) {
|
||||||
|
__ cmp(ecx, Immediate(j));
|
||||||
|
__ j(not_equal, &over, Label::kNear);
|
||||||
|
}
|
||||||
|
for (int i = j - 1; i >= 0; --i) {
|
||||||
|
__ Push(Operand(
|
||||||
|
ebp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3 - j; ++i) {
|
||||||
|
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||||
|
}
|
||||||
|
if (j < 3) {
|
||||||
|
__ jmp(&args_done, Label::kNear);
|
||||||
|
__ bind(&over);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
__ bind(&args_done);
|
||||||
|
|
||||||
// Call runtime, on success unwind frame, and parent frame.
|
// Call runtime, on success unwind frame, and parent frame.
|
||||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||||
// A smi 0 is returned on failure, an object on success.
|
// A smi 0 is returned on failure, an object on success.
|
||||||
__ JumpIfSmi(eax, &failed, Label::kNear);
|
__ JumpIfSmi(eax, &failed, Label::kNear);
|
||||||
|
|
||||||
|
__ Drop(2);
|
||||||
|
__ Pop(ecx);
|
||||||
|
__ SmiUntag(ecx);
|
||||||
scope.GenerateLeaveFrame();
|
scope.GenerateLeaveFrame();
|
||||||
__ ret(4 * kPointerSize);
|
|
||||||
|
__ PopReturnAddressTo(ebx);
|
||||||
|
__ inc(ecx);
|
||||||
|
__ lea(esp, Operand(esp, ecx, times_pointer_size, 0));
|
||||||
|
__ PushReturnAddressFrom(ebx);
|
||||||
|
__ ret(0);
|
||||||
|
|
||||||
__ bind(&failed);
|
__ bind(&failed);
|
||||||
// Restore target function and new target.
|
// Restore target function and new target.
|
||||||
|
@ -476,7 +476,8 @@ int CodeAndMetadataSize(CompilationInfo* info) {
|
|||||||
bool GenerateUnoptimizedCode(CompilationInfo* info) {
|
bool GenerateUnoptimizedCode(CompilationInfo* info) {
|
||||||
bool success;
|
bool success;
|
||||||
EnsureFeedbackMetadata(info);
|
EnsureFeedbackMetadata(info);
|
||||||
if (FLAG_validate_asm && info->scope()->asm_module()) {
|
if (FLAG_validate_asm && info->scope()->asm_module() &&
|
||||||
|
!info->shared_info()->is_asm_wasm_broken()) {
|
||||||
MaybeHandle<FixedArray> wasm_data;
|
MaybeHandle<FixedArray> wasm_data;
|
||||||
wasm_data = AsmJs::ConvertAsmToWasm(info->parse_info());
|
wasm_data = AsmJs::ConvertAsmToWasm(info->parse_info());
|
||||||
if (!wasm_data.is_null()) {
|
if (!wasm_data.is_null()) {
|
||||||
@ -1436,7 +1437,9 @@ bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) {
|
|||||||
// TODO(4280): For now we play it safe and remove the bytecode array when we
|
// TODO(4280): For now we play it safe and remove the bytecode array when we
|
||||||
// switch to baseline code. We might consider keeping around the bytecode so
|
// switch to baseline code. We might consider keeping around the bytecode so
|
||||||
// that it can be used as the "source of truth" eventually.
|
// that it can be used as the "source of truth" eventually.
|
||||||
if (!FLAG_ignition_preserve_bytecode) shared->ClearBytecodeArray();
|
if (shared->HasBytecodeArray()) {
|
||||||
|
if (!FLAG_ignition_preserve_bytecode) shared->ClearBytecodeArray();
|
||||||
|
}
|
||||||
|
|
||||||
// The scope info might not have been set if a lazily compiled
|
// The scope info might not have been set if a lazily compiled
|
||||||
// function is inlined before being called for the first time.
|
// function is inlined before being called for the first time.
|
||||||
|
@ -6091,6 +6091,8 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_setter_function,
|
|||||||
kIsSetterFunction)
|
kIsSetterFunction)
|
||||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_default_constructor,
|
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_default_constructor,
|
||||||
kIsDefaultConstructor)
|
kIsDefaultConstructor)
|
||||||
|
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_asm_wasm_broken,
|
||||||
|
kIsAsmWasmBroken)
|
||||||
|
|
||||||
inline bool SharedFunctionInfo::is_resumable() const {
|
inline bool SharedFunctionInfo::is_resumable() const {
|
||||||
return is_generator() || is_async();
|
return is_generator() || is_async();
|
||||||
|
@ -7307,6 +7307,9 @@ class SharedFunctionInfo: public HeapObject {
|
|||||||
// Whether this function was created from a FunctionDeclaration.
|
// Whether this function was created from a FunctionDeclaration.
|
||||||
DECL_BOOLEAN_ACCESSORS(is_declaration)
|
DECL_BOOLEAN_ACCESSORS(is_declaration)
|
||||||
|
|
||||||
|
// Indicates that asm->wasm conversion failed and should not be re-attempted.
|
||||||
|
DECL_BOOLEAN_ACCESSORS(is_asm_wasm_broken)
|
||||||
|
|
||||||
inline FunctionKind kind();
|
inline FunctionKind kind();
|
||||||
inline void set_kind(FunctionKind kind);
|
inline void set_kind(FunctionKind kind);
|
||||||
|
|
||||||
@ -7579,6 +7582,7 @@ class SharedFunctionInfo: public HeapObject {
|
|||||||
kIsAsyncFunction,
|
kIsAsyncFunction,
|
||||||
kDeserialized,
|
kDeserialized,
|
||||||
kIsDeclaration,
|
kIsDeclaration,
|
||||||
|
kIsAsmWasmBroken,
|
||||||
kCompilerHintsCount, // Pseudo entry
|
kCompilerHintsCount, // Pseudo entry
|
||||||
};
|
};
|
||||||
// Add hints for other modes when they're added.
|
// Add hints for other modes when they're added.
|
||||||
|
@ -101,8 +101,18 @@ RUNTIME_FUNCTION(Runtime_InstantiateAsmJs) {
|
|||||||
return *result.ToHandleChecked();
|
return *result.ToHandleChecked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove wasm data and return a smi 0 to indicate failure.
|
// Remove wasm data, mark as broken for asm->wasm,
|
||||||
|
// replace code with CompileLazy, and return a smi 0 to indicate failure.
|
||||||
function->shared()->ClearAsmWasmData();
|
function->shared()->ClearAsmWasmData();
|
||||||
|
function->shared()->set_is_asm_wasm_broken(true);
|
||||||
|
DCHECK(function->code() ==
|
||||||
|
isolate->builtins()->builtin(Builtins::kInstantiateAsmJs));
|
||||||
|
function->ReplaceCode(isolate->builtins()->builtin(Builtins::kCompileLazy));
|
||||||
|
if (function->shared()->code() ==
|
||||||
|
isolate->builtins()->builtin(Builtins::kInstantiateAsmJs)) {
|
||||||
|
function->shared()->ReplaceCode(
|
||||||
|
isolate->builtins()->builtin(Builtins::kCompileLazy));
|
||||||
|
}
|
||||||
return Smi::FromInt(0);
|
return Smi::FromInt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,6 +662,22 @@ RUNTIME_FUNCTION(Runtime_InNewSpace) {
|
|||||||
return isolate->heap()->ToBoolean(isolate->heap()->InNewSpace(obj));
|
return isolate->heap()->ToBoolean(isolate->heap()->InNewSpace(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_IsAsmWasmCode) {
|
||||||
|
SealHandleScope shs(isolate);
|
||||||
|
DCHECK(args.length() == 1);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
||||||
|
|
||||||
|
if (!function->shared()->HasAsmWasmData()) {
|
||||||
|
// Doesn't have wasm data.
|
||||||
|
return isolate->heap()->ToBoolean(false);
|
||||||
|
}
|
||||||
|
if (function->shared()->code() !=
|
||||||
|
isolate->builtins()->builtin(Builtins::kInstantiateAsmJs)) {
|
||||||
|
// Hasn't been compiled yet.
|
||||||
|
return isolate->heap()->ToBoolean(false);
|
||||||
|
}
|
||||||
|
return isolate->heap()->ToBoolean(true);
|
||||||
|
}
|
||||||
|
|
||||||
#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
|
#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
|
||||||
RUNTIME_FUNCTION(Runtime_Has##Name) { \
|
RUNTIME_FUNCTION(Runtime_Has##Name) { \
|
||||||
|
@ -885,7 +885,8 @@ namespace internal {
|
|||||||
F(HasFixedUint8ClampedElements, 1, 1) \
|
F(HasFixedUint8ClampedElements, 1, 1) \
|
||||||
F(SpeciesProtector, 0, 1) \
|
F(SpeciesProtector, 0, 1) \
|
||||||
F(SerializeWasmModule, 1, 1) \
|
F(SerializeWasmModule, 1, 1) \
|
||||||
F(DeserializeWasmModule, 1, 1)
|
F(DeserializeWasmModule, 1, 1) \
|
||||||
|
F(IsAsmWasmCode, 1, 1)
|
||||||
|
|
||||||
#define FOR_EACH_INTRINSIC_TYPEDARRAY(F) \
|
#define FOR_EACH_INTRINSIC_TYPEDARRAY(F) \
|
||||||
F(ArrayBufferGetByteLength, 1, 1) \
|
F(ArrayBufferGetByteLength, 1, 1) \
|
||||||
|
188
test/mjsunit/asm/asm-validation.js
Normal file
188
test/mjsunit/asm/asm-validation.js
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// Flags: --validate-asm --allow-natives-syntax
|
||||||
|
|
||||||
|
function IsAlwaysOpt(module) {
|
||||||
|
return %GetOptimizationStatus(module) === 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
(function TestModuleArgs() {
|
||||||
|
function Module1(stdlib) {
|
||||||
|
"use asm";
|
||||||
|
function foo() { }
|
||||||
|
return { foo: foo };
|
||||||
|
}
|
||||||
|
function Module2(stdlib, ffi) {
|
||||||
|
"use asm";
|
||||||
|
function foo() { }
|
||||||
|
return { foo: foo };
|
||||||
|
}
|
||||||
|
function Module3(stdlib, ffi, heap) {
|
||||||
|
"use asm";
|
||||||
|
function foo() { }
|
||||||
|
return { foo: foo };
|
||||||
|
}
|
||||||
|
var modules = [Module1, Module2, Module3];
|
||||||
|
var heap = new ArrayBuffer(1024 * 1024);
|
||||||
|
for (var i = 0; i < modules.length; ++i) {
|
||||||
|
print('Module' + (i + 1));
|
||||||
|
var module = modules[i];
|
||||||
|
// TODO(bradnelson): Support modules without the stdlib.
|
||||||
|
var m = module({});
|
||||||
|
assertTrue(%IsAsmWasmCode(module) || IsAlwaysOpt(module));
|
||||||
|
var m = module({}, {});
|
||||||
|
assertTrue(%IsAsmWasmCode(module) || IsAlwaysOpt(module));
|
||||||
|
var m = module({}, {}, heap);
|
||||||
|
assertTrue(%IsAsmWasmCode(module) || IsAlwaysOpt(module));
|
||||||
|
var m = module({}, {}, heap, {});
|
||||||
|
assertTrue(%IsAsmWasmCode(module) || IsAlwaysOpt(module));
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function TestBadModule() {
|
||||||
|
function Module(stdlib, ffi, heap) {
|
||||||
|
"use asm";
|
||||||
|
function foo() { var y = 3; var x = 1 + y; return 123; }
|
||||||
|
return { foo: foo };
|
||||||
|
}
|
||||||
|
var m = Module({});
|
||||||
|
assertFalse(%IsAsmWasmCode(Module));
|
||||||
|
assertEquals(123, m.foo());
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function TestBadArgTypes() {
|
||||||
|
function Module(a, b, c) {
|
||||||
|
"use asm";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
var m = Module(1, 2, 3);
|
||||||
|
assertFalse(%IsAsmWasmCode(Module));
|
||||||
|
assertEquals({}, m);
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function TestBadArgTypesMismatch() {
|
||||||
|
function Module(a, b, c) {
|
||||||
|
"use asm";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
var m = Module(1, 2);
|
||||||
|
assertFalse(%IsAsmWasmCode(Module));
|
||||||
|
assertEquals({}, m);
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function TestModuleNoStdlib() {
|
||||||
|
// TODO(bradnelson):
|
||||||
|
// Support modules like this if they don't use the whole stdlib.
|
||||||
|
function Module() {
|
||||||
|
"use asm";
|
||||||
|
function foo() { return 123; }
|
||||||
|
return { foo: foo };
|
||||||
|
}
|
||||||
|
var m = Module({});
|
||||||
|
assertFalse(%IsAsmWasmCode(Module));
|
||||||
|
assertEquals(123, m.foo());
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function TestModuleWith5() {
|
||||||
|
function Module(a, b, c, d, e) {
|
||||||
|
"use asm";
|
||||||
|
function foo() { return 123; }
|
||||||
|
return { foo: foo };
|
||||||
|
}
|
||||||
|
var heap = new ArrayBuffer(1024 * 1024);
|
||||||
|
var m = Module({}, {}, heap);
|
||||||
|
assertFalse(%IsAsmWasmCode(Module));
|
||||||
|
assertEquals(123, m.foo());
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function TestModuleNoStdlibCall() {
|
||||||
|
function Module(stdlib, ffi, heap) {
|
||||||
|
"use asm";
|
||||||
|
function foo() { return 123; }
|
||||||
|
return { foo: foo };
|
||||||
|
}
|
||||||
|
// TODO(bradnelson): Support instantiation like this if stdlib is unused.
|
||||||
|
var m = Module();
|
||||||
|
assertFalse(%IsAsmWasmCode(Module));
|
||||||
|
assertEquals(123, m.foo());
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function TestModuleNew() {
|
||||||
|
function Module(stdlib, ffi, heap) {
|
||||||
|
"use asm";
|
||||||
|
function foo() { return 123; }
|
||||||
|
return { foo: foo };
|
||||||
|
}
|
||||||
|
var m = new Module({}, {});
|
||||||
|
assertTrue(%IsAsmWasmCode(Module) || IsAlwaysOpt(Module));
|
||||||
|
assertEquals(123, m.foo());
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function TestMultipleFailures() {
|
||||||
|
function Module(stdlib) {
|
||||||
|
"use asm";
|
||||||
|
function foo() { return 123; }
|
||||||
|
return { foo: foo };
|
||||||
|
}
|
||||||
|
var m1 = Module(1, 2, 3);
|
||||||
|
assertFalse(%IsAsmWasmCode(Module));
|
||||||
|
var m2 = Module(1, 2, 3);
|
||||||
|
assertFalse(%IsAsmWasmCode(Module));
|
||||||
|
assertEquals(123, m1.foo());
|
||||||
|
assertEquals(123, m2.foo());
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function TestFailureThenSuccess() {
|
||||||
|
function MkModule() {
|
||||||
|
function Module(stdlib, ffi, heap) {
|
||||||
|
"use asm";
|
||||||
|
function foo() { return 123; }
|
||||||
|
return { foo: foo };
|
||||||
|
}
|
||||||
|
return Module;
|
||||||
|
}
|
||||||
|
var Module1 = MkModule();
|
||||||
|
var Module2 = MkModule();
|
||||||
|
var heap = new ArrayBuffer(1024 * 1024);
|
||||||
|
var m1 = Module1(1, 2, 3);
|
||||||
|
assertFalse(%IsAsmWasmCode(Module1));
|
||||||
|
var m2 = Module2({}, {}, heap);
|
||||||
|
assertFalse(%IsAsmWasmCode(Module2));
|
||||||
|
assertEquals(123, m1.foo());
|
||||||
|
assertEquals(123, m2.foo());
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function TestSuccessThenFailure() {
|
||||||
|
function MkModule() {
|
||||||
|
function Module(stdlib, ffi, heap) {
|
||||||
|
"use asm";
|
||||||
|
function foo() { return 123; }
|
||||||
|
return { foo: foo };
|
||||||
|
}
|
||||||
|
return Module;
|
||||||
|
}
|
||||||
|
var Module1 = MkModule();
|
||||||
|
var Module2 = MkModule();
|
||||||
|
var heap = new ArrayBuffer(1024 * 1024);
|
||||||
|
var m1 = Module1({}, {}, heap);
|
||||||
|
assertTrue(%IsAsmWasmCode(Module1) || IsAlwaysOpt(Module1));
|
||||||
|
var m2 = Module2(1, 2, 3);
|
||||||
|
assertFalse(%IsAsmWasmCode(Module2));
|
||||||
|
assertEquals(123, m1.foo());
|
||||||
|
assertEquals(123, m2.foo());
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function TestBoundFunction() {
|
||||||
|
function Module(stdlib, ffi, heap) {
|
||||||
|
"use asm";
|
||||||
|
function foo() { return 123; }
|
||||||
|
return { foo: foo };
|
||||||
|
}
|
||||||
|
var heap = new ArrayBuffer(1024 * 1024);
|
||||||
|
var ModuleBound = Module.bind(this, {}, {}, heap);
|
||||||
|
var m = ModuleBound();
|
||||||
|
assertTrue(%IsAsmWasmCode(Module) || IsAlwaysOpt(Module));
|
||||||
|
assertEquals(123, m.foo());
|
||||||
|
})();
|
Loading…
Reference in New Issue
Block a user