[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;
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
// Preserve argument count for later compare.
|
||||
__ Move(r4, r0);
|
||||
// Push the number of arguments to the callee.
|
||||
__ SmiTag(r0);
|
||||
__ push(r0);
|
||||
@ -1459,17 +1461,40 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
||||
// The function.
|
||||
__ push(r1);
|
||||
// Copy arguments from caller (stdlib, foreign, heap).
|
||||
for (int i = 2; i >= 0; --i) {
|
||||
__ ldr(r4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
||||
i * kPointerSize));
|
||||
__ push(r4);
|
||||
Label args_done;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
Label over;
|
||||
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.
|
||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||
// A smi 0 is returned on failure, an object on success.
|
||||
__ JumpIfSmi(r0, &failed);
|
||||
|
||||
__ Drop(2);
|
||||
__ pop(r4);
|
||||
__ SmiUntag(r4);
|
||||
scope.GenerateLeaveFrame();
|
||||
__ Drop(4);
|
||||
|
||||
__ add(r4, r4, Operand(1));
|
||||
__ Drop(r4);
|
||||
__ Ret();
|
||||
|
||||
__ bind(&failed);
|
||||
|
@ -1446,23 +1446,48 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
||||
Label failed;
|
||||
{
|
||||
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.
|
||||
__ SmiTag(x0);
|
||||
// Push another copy as a parameter to the runtime call.
|
||||
__ Push(x0, x1, x3, x1);
|
||||
|
||||
// Copy arguments from caller (stdlib, foreign, heap).
|
||||
for (int i = 2; i >= 0; --i) {
|
||||
__ ldr(x4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
||||
i * kPointerSize));
|
||||
__ push(x4);
|
||||
Label args_done;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
Label over;
|
||||
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.
|
||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||
// A smi 0 is returned on failure, an object on success.
|
||||
__ JumpIfSmi(x0, &failed);
|
||||
|
||||
__ Drop(2);
|
||||
__ pop(x4);
|
||||
__ SmiUntag(x4);
|
||||
scope.GenerateLeaveFrame();
|
||||
__ Drop(4);
|
||||
|
||||
__ add(x4, x4, Operand(1));
|
||||
__ Drop(x4);
|
||||
__ Ret();
|
||||
|
||||
__ bind(&failed);
|
||||
|
@ -1010,6 +1010,8 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
||||
Label failed;
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
// Preserve argument count for later compare.
|
||||
__ mov(ecx, eax);
|
||||
// Push the number of arguments to the callee.
|
||||
__ SmiTag(eax);
|
||||
__ push(eax);
|
||||
@ -1020,16 +1022,42 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
||||
// The function.
|
||||
__ push(edi);
|
||||
// Copy arguments from caller (stdlib, foreign, heap).
|
||||
for (int i = 2; i >= 0; --i) {
|
||||
__ push(Operand(
|
||||
ebp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize));
|
||||
Label args_done;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
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.
|
||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||
// A smi 0 is returned on failure, an object on success.
|
||||
__ JumpIfSmi(eax, &failed, Label::kNear);
|
||||
|
||||
__ Drop(2);
|
||||
__ Pop(ecx);
|
||||
__ SmiUntag(ecx);
|
||||
scope.GenerateLeaveFrame();
|
||||
__ ret(4 * kPointerSize);
|
||||
|
||||
__ PopReturnAddressTo(ebx);
|
||||
__ inc(ecx);
|
||||
__ lea(esp, Operand(esp, ecx, times_pointer_size, 0));
|
||||
__ PushReturnAddressFrom(ebx);
|
||||
__ ret(0);
|
||||
|
||||
__ bind(&failed);
|
||||
// Restore target function and new target.
|
||||
|
@ -1444,23 +1444,47 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
||||
Label failed;
|
||||
{
|
||||
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 function as parameter to the runtime call.
|
||||
__ SmiTag(a0);
|
||||
__ Push(a0, a1, a3, a1);
|
||||
|
||||
// Copy arguments from caller (stdlib, foreign, heap).
|
||||
for (int i = 2; i >= 0; --i) {
|
||||
__ lw(a3, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
||||
i * kPointerSize));
|
||||
__ push(a3);
|
||||
Label args_done;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
Label over;
|
||||
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.
|
||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||
// 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();
|
||||
__ Drop(4);
|
||||
|
||||
__ Addu(t4, t4, Operand(1));
|
||||
__ Lsa(sp, sp, t4, kPointerSizeLog2);
|
||||
__ Ret();
|
||||
|
||||
__ bind(&failed);
|
||||
|
@ -1438,21 +1438,44 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
// Push a copy of the target function and the new target.
|
||||
// Push function as parameter to the runtime call.
|
||||
__ Move(t2, a0);
|
||||
__ SmiTag(a0);
|
||||
__ Push(a0, a1, a3, a1);
|
||||
|
||||
// Copy arguments from caller (stdlib, foreign, heap).
|
||||
for (int i = 2; i >= 0; --i) {
|
||||
__ lw(a3, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
||||
i * kPointerSize));
|
||||
__ push(a3);
|
||||
Label args_done;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
Label over;
|
||||
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.
|
||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||
// 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();
|
||||
__ Drop(4);
|
||||
|
||||
__ Addu(t2, t2, Operand(1));
|
||||
__ Lsa(sp, sp, t2, kPointerSizeLog2);
|
||||
__ Ret();
|
||||
|
||||
__ bind(&failed);
|
||||
|
@ -1458,23 +1458,47 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
||||
Label failed;
|
||||
{
|
||||
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 function as parameter to the runtime call.
|
||||
__ SmiTag(r3);
|
||||
__ Push(r3, r4, r6, r4);
|
||||
|
||||
// Copy arguments from caller (stdlib, foreign, heap).
|
||||
for (int i = 2; i >= 0; --i) {
|
||||
__ LoadP(r4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
||||
i * kPointerSize));
|
||||
__ push(r4);
|
||||
Label args_done;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
Label over;
|
||||
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.
|
||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||
// A smi 0 is returned on failure, an object on success.
|
||||
__ JumpIfSmi(r3, &failed);
|
||||
|
||||
__ Drop(2);
|
||||
__ pop(r5);
|
||||
__ SmiUntag(r5);
|
||||
scope.GenerateLeaveFrame();
|
||||
__ Drop(4);
|
||||
|
||||
__ Drop(r5);
|
||||
__ Ret();
|
||||
|
||||
__ bind(&failed);
|
||||
|
@ -1465,23 +1465,48 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
||||
Label failed;
|
||||
{
|
||||
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.
|
||||
__ SmiTag(r2);
|
||||
// Push another copy as a parameter to the runtime call.
|
||||
__ Push(r2, r3, r5, r3);
|
||||
|
||||
// Copy arguments from caller (stdlib, foreign, heap).
|
||||
for (int i = 2; i >= 0; --i) {
|
||||
__ LoadP(r4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
|
||||
i * kPointerSize));
|
||||
__ push(r4);
|
||||
Label args_done;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
Label over;
|
||||
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.
|
||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||
// A smi 0 is returned on failure, an object on success.
|
||||
__ JumpIfSmi(r2, &failed);
|
||||
|
||||
__ Drop(2);
|
||||
__ pop(r4);
|
||||
__ SmiUntag(r4);
|
||||
scope.GenerateLeaveFrame();
|
||||
__ Drop(4);
|
||||
|
||||
__ AddP(r4, r4, Operand(1));
|
||||
__ Drop(r4, r7);
|
||||
__ Ret();
|
||||
|
||||
__ bind(&failed);
|
||||
|
@ -1062,6 +1062,8 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
||||
Label failed;
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
// Preserve argument count for later compare.
|
||||
__ movp(kScratchRegister, rax);
|
||||
// Push the number of arguments to the callee.
|
||||
__ Integer32ToSmi(rax, rax);
|
||||
__ Push(rax);
|
||||
@ -1072,16 +1074,42 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
||||
// The function.
|
||||
__ Push(rdi);
|
||||
// Copy arguments from caller (stdlib, foreign, heap).
|
||||
for (int i = 2; i >= 0; --i) {
|
||||
__ Push(Operand(
|
||||
rbp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize));
|
||||
Label args_done;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
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.
|
||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||
// A smi 0 is returned on failure, an object on success.
|
||||
__ JumpIfSmi(rax, &failed, Label::kNear);
|
||||
|
||||
__ Drop(2);
|
||||
__ Pop(kScratchRegister);
|
||||
__ SmiToInteger32(kScratchRegister, kScratchRegister);
|
||||
scope.GenerateLeaveFrame();
|
||||
__ ret(4 * kPointerSize);
|
||||
|
||||
__ PopReturnAddressTo(rbx);
|
||||
__ incp(kScratchRegister);
|
||||
__ leap(rsp, Operand(rsp, kScratchRegister, times_pointer_size, 0));
|
||||
__ PushReturnAddressFrom(rbx);
|
||||
__ ret(0);
|
||||
|
||||
__ bind(&failed);
|
||||
// Restore target function and new target.
|
||||
|
@ -1011,6 +1011,8 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
||||
Label failed;
|
||||
{
|
||||
FrameScope scope(masm, StackFrame::INTERNAL);
|
||||
// Preserve argument count for later compare.
|
||||
__ mov(ecx, eax);
|
||||
// Push the number of arguments to the callee.
|
||||
__ SmiTag(eax);
|
||||
__ push(eax);
|
||||
@ -1021,16 +1023,42 @@ void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) {
|
||||
// The function.
|
||||
__ push(edi);
|
||||
// Copy arguments from caller (stdlib, foreign, heap).
|
||||
for (int i = 2; i >= 0; --i) {
|
||||
__ push(Operand(
|
||||
ebp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize));
|
||||
Label args_done;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
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.
|
||||
__ CallRuntime(Runtime::kInstantiateAsmJs, 4);
|
||||
// A smi 0 is returned on failure, an object on success.
|
||||
__ JumpIfSmi(eax, &failed, Label::kNear);
|
||||
|
||||
__ Drop(2);
|
||||
__ Pop(ecx);
|
||||
__ SmiUntag(ecx);
|
||||
scope.GenerateLeaveFrame();
|
||||
__ ret(4 * kPointerSize);
|
||||
|
||||
__ PopReturnAddressTo(ebx);
|
||||
__ inc(ecx);
|
||||
__ lea(esp, Operand(esp, ecx, times_pointer_size, 0));
|
||||
__ PushReturnAddressFrom(ebx);
|
||||
__ ret(0);
|
||||
|
||||
__ bind(&failed);
|
||||
// Restore target function and new target.
|
||||
|
@ -476,7 +476,8 @@ int CodeAndMetadataSize(CompilationInfo* info) {
|
||||
bool GenerateUnoptimizedCode(CompilationInfo* info) {
|
||||
bool success;
|
||||
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;
|
||||
wasm_data = AsmJs::ConvertAsmToWasm(info->parse_info());
|
||||
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
|
||||
// switch to baseline code. We might consider keeping around the bytecode so
|
||||
// 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
|
||||
// function is inlined before being called for the first time.
|
||||
|
@ -6091,6 +6091,8 @@ BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_setter_function,
|
||||
kIsSetterFunction)
|
||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_default_constructor,
|
||||
kIsDefaultConstructor)
|
||||
BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_asm_wasm_broken,
|
||||
kIsAsmWasmBroken)
|
||||
|
||||
inline bool SharedFunctionInfo::is_resumable() const {
|
||||
return is_generator() || is_async();
|
||||
|
@ -7307,6 +7307,9 @@ class SharedFunctionInfo: public HeapObject {
|
||||
// Whether this function was created from a FunctionDeclaration.
|
||||
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 void set_kind(FunctionKind kind);
|
||||
|
||||
@ -7579,6 +7582,7 @@ class SharedFunctionInfo: public HeapObject {
|
||||
kIsAsyncFunction,
|
||||
kDeserialized,
|
||||
kIsDeclaration,
|
||||
kIsAsmWasmBroken,
|
||||
kCompilerHintsCount, // Pseudo entry
|
||||
};
|
||||
// Add hints for other modes when they're added.
|
||||
|
@ -101,8 +101,18 @@ RUNTIME_FUNCTION(Runtime_InstantiateAsmJs) {
|
||||
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()->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);
|
||||
}
|
||||
|
||||
|
@ -662,6 +662,22 @@ RUNTIME_FUNCTION(Runtime_InNewSpace) {
|
||||
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) \
|
||||
RUNTIME_FUNCTION(Runtime_Has##Name) { \
|
||||
|
@ -885,7 +885,8 @@ namespace internal {
|
||||
F(HasFixedUint8ClampedElements, 1, 1) \
|
||||
F(SpeciesProtector, 0, 1) \
|
||||
F(SerializeWasmModule, 1, 1) \
|
||||
F(DeserializeWasmModule, 1, 1)
|
||||
F(DeserializeWasmModule, 1, 1) \
|
||||
F(IsAsmWasmCode, 1, 1)
|
||||
|
||||
#define FOR_EACH_INTRINSIC_TYPEDARRAY(F) \
|
||||
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