Changeset 211195 in webkit
- Timestamp:
- Jan 25, 2017 6:38:41 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r211194 r211195 1 2017-01-25 Saam Barati <sbarati@apple.com> 2 3 WebAssembly JS API: coerce return values from imports 4 https://bugs.webkit.org/show_bug.cgi?id=165480 5 <rdar://problem/29760318> 6 7 Reviewed by Yusuke Suzuki. 8 9 * wasm/function-tests/function-import-return-value.js: Added. 10 (import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.const.tests.x.assert.eq): 11 (import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.const.tests.Math.fround): 12 (import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.let.type.of.Reflect.ownKeys): 13 (test.1): 14 (assert.truthy): 15 (assert.throws): 16 1 17 2017-01-25 Filip Pizlo <fpizlo@apple.com> 2 18 -
trunk/Source/JavaScriptCore/ChangeLog
r211194 r211195 1 2017-01-25 Saam Barati <sbarati@apple.com> 2 3 WebAssembly JS API: coerce return values from imports 4 https://bugs.webkit.org/show_bug.cgi?id=165480 5 <rdar://problem/29760318> 6 7 Reviewed by Yusuke Suzuki. 8 9 This patch does proper coercion for all possible 10 JSValue return types from an imported function. 11 12 It also adds the spec-compliant code to throw an exception 13 when calling an import that has an i64 parameter or return 14 value. 15 16 * jit/AssemblyHelpers.cpp: 17 (JSC::AssemblyHelpers::emitJumpIfException): 18 * jit/AssemblyHelpers.h: 19 * wasm/WasmB3IRGenerator.cpp: 20 * wasm/WasmBinding.cpp: 21 (JSC::Wasm::wasmToJs): 22 1 23 2017-01-25 Filip Pizlo <fpizlo@apple.com> 2 24 -
trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp
r210695 r211195 353 353 #endif 354 354 } 355 } 356 357 AssemblyHelpers::Jump AssemblyHelpers::emitJumpIfException() 358 { 359 return emitExceptionCheck(NormalExceptionCheck); 355 360 } 356 361 -
trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h
r210844 r211195 1186 1186 ExceptionCheckKind = NormalExceptionCheck, ExceptionJumpWidth = NormalJumpWidth); 1187 1187 JS_EXPORT_PRIVATE Jump emitNonPatchableExceptionCheck(); 1188 Jump emitJumpIfException(); 1188 1189 1189 1190 #if ENABLE(SAMPLING_COUNTERS) -
trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
r210259 r211195 977 977 978 978 patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) { 979 AllowMacroScratchRegisterUsage allowScratch(jit); 979 980 jit.call(params[returnType == Void ? 0 : 1].gpr()); 980 981 }); -
trunk/Source/JavaScriptCore/wasm/WasmBinding.cpp
r210244 r211195 29 29 #if ENABLE(WEBASSEMBLY) 30 30 31 #include "AssemblyHelpers.h" 32 #include "JSCJSValueInlines.h" 31 #include "CCallHelpers.h" 32 #include "FrameTracers.h" 33 #include "JITExceptions.h" 34 #include "JSCInlines.h" 33 35 #include "JSWebAssemblyInstance.h" 34 36 #include "LinkBuffer.h" 37 #include "NativeErrorConstructor.h" 35 38 #include "WasmCallingConvention.h" 39 #include "WasmExceptionType.h" 36 40 37 41 namespace JSC { namespace Wasm { 38 42 39 typedef AssemblyHelpers JIT;43 typedef CCallHelpers JIT; 40 44 41 45 static void materializeImportJSCell(VM* vm, JIT& jit, unsigned importIndex, GPRReg result) … … 62 66 jit.storePtr(JIT::TrustedImmPtr(vm->webAssemblyToJSCallee.get()), JIT::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register)))); 63 67 68 69 { 70 bool hasBadI64Use = false; 71 hasBadI64Use |= signature->returnType() == I64; 72 for (unsigned argNum = 0; argNum < argCount && !hasBadI64Use; ++argNum) { 73 Type argType = signature->argument(argNum); 74 switch (argType) { 75 case Void: 76 case Func: 77 case Anyfunc: 78 RELEASE_ASSERT_NOT_REACHED(); 79 80 case I64: { 81 hasBadI64Use = true; 82 break; 83 } 84 85 default: 86 break; 87 } 88 } 89 90 if (hasBadI64Use) { 91 jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(); 92 jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); 93 auto call = jit.call(); 94 jit.jumpToExceptionHandler(); 95 96 void (*throwBadI64)(ExecState*) = [] (ExecState* exec) -> void { 97 VM* vm = &exec->vm(); 98 NativeCallFrameTracer tracer(vm, exec); 99 100 { 101 auto throwScope = DECLARE_THROW_SCOPE(*vm); 102 JSGlobalObject* globalObject = vm->topJSWebAssemblyInstance->globalObject(); 103 auto* error = ErrorInstance::create(exec, *vm, globalObject->typeErrorConstructor()->errorStructure(), ASCIILiteral("i64 not allowed as return type or argument to an imported function")); 104 throwException(exec, throwScope, error); 105 } 106 107 genericUnwind(vm, exec); 108 ASSERT(!!vm->callFrameForCatch); 109 }; 110 111 LinkBuffer linkBuffer(*vm, jit, GLOBAL_THUNK_ID); 112 linkBuffer.link(call, throwBadI64); 113 return FINALIZE_CODE(linkBuffer, ("WebAssembly->JavaScript invalid i64 use in import[%i]", importIndex)); 114 } 115 } 116 64 117 // Here we assume that the JS calling convention saves at least all the wasm callee saved. We therefore don't need to save and restore more registers since the wasm callee already took care of this. 65 118 RegisterSet missingCalleeSaves = wasmCC.m_calleeSaveRegisters; … … 75 128 jit.subPtr(MacroAssembler::TrustedImm32(stackOffset), MacroAssembler::stackPointerRegister); 76 129 JIT::Address calleeFrame = CCallHelpers::Address(MacroAssembler::stackPointerRegister, -static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC))); 77 78 for (unsigned argNum = 0; argNum < argCount; ++argNum) {79 Type argType = signature->argument(argNum);80 switch (argType) {81 case Void:82 case Func:83 case Anyfunc:84 case I64: {85 // FIXME: Figure out the correct behavior here. I suspect we want such a stub to throw an exception immediately.86 // if called. https://bugs.webkit.org/show_bug.cgi?id=16599187 jit.breakpoint();88 LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);89 return FINALIZE_CODE(patchBuffer, ("WebAssembly import[%i] stub for signature %i", importIndex, signatureIndex));90 }91 case I32:92 case F32:93 case F64:94 continue;95 }96 }97 130 98 131 // FIXME make these loops which switch on Signature if there are many arguments on the stack. It'll otherwise be huge for huge signatures. https://bugs.webkit.org/show_bug.cgi?id=165547 … … 221 254 materializeImportJSCell(vm, jit, importIndex, importJSCellGPRReg); 222 255 223 uint64_t thisArgument = ValueUndefined; // FIXME what does the WebAssembly spec say this should be? https://bugs.webkit.org/show_bug.cgi?id=165471224 256 jit.store64(importJSCellGPRReg, calleeFrame.withOffset(CallFrameSlot::callee * static_cast<int>(sizeof(Register)))); 225 257 jit.store32(JIT::TrustedImm32(numberOfParameters), calleeFrame.withOffset(CallFrameSlot::argumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset)); 226 jit.store64(JIT::TrustedImm64( thisArgument), calleeFrame.withOffset(CallFrameSlot::thisArgument * static_cast<int>(sizeof(Register))));258 jit.store64(JIT::TrustedImm64(ValueUndefined), calleeFrame.withOffset(CallFrameSlot::thisArgument * static_cast<int>(sizeof(Register)))); 227 259 228 260 // FIXME Tail call if the wasm return type is void and no registers were spilled. https://bugs.webkit.org/show_bug.cgi?id=165488 … … 241 273 done.link(&jit); 242 274 275 CCallHelpers::JumpList exceptionChecks; 276 243 277 switch (signature->returnType()) { 244 278 case Void: … … 250 284 RELEASE_ASSERT_NOT_REACHED(); 251 285 break; 286 case I64: { 287 RELEASE_ASSERT_NOT_REACHED(); // Handled above. 288 } 252 289 case I32: { 290 CCallHelpers::JumpList done; 291 CCallHelpers::JumpList slowPath; 292 293 slowPath.append(jit.branchIfNotNumber(GPRInfo::returnValueGPR, DoNotHaveTagRegisters)); 294 slowPath.append(jit.branchIfNotInt32(JSValueRegs(GPRInfo::returnValueGPR), DoNotHaveTagRegisters)); 295 jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR); 296 done.append(jit.jump()); 297 298 slowPath.link(&jit); 299 jit.setupArgumentsWithExecState(GPRInfo::returnValueGPR); 300 auto call = jit.call(); 301 exceptionChecks.append(jit.emitJumpIfException()); 302 303 int32_t (*convertToI32)(ExecState*, JSValue) = [] (ExecState* exec, JSValue v) -> int32_t { 304 VM* vm = &exec->vm(); 305 NativeCallFrameTracer tracer(vm, exec); 306 return v.toInt32(exec); 307 }; 308 jit.addLinkTask([=] (LinkBuffer& linkBuffer) { 309 linkBuffer.link(call, convertToI32); 310 }); 311 312 done.link(&jit); 313 break; 314 } 315 case F32: { 316 CCallHelpers::JumpList done; 317 auto notANumber = jit.branchIfNotNumber(GPRInfo::returnValueGPR, DoNotHaveTagRegisters); 318 auto isDouble = jit.branchIfNotInt32(JSValueRegs(GPRInfo::returnValueGPR), DoNotHaveTagRegisters); 319 // We're an int32 320 jit.signExtend32ToPtr(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR); 321 jit.convertInt64ToFloat(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR); 322 done.append(jit.jump()); 323 324 isDouble.link(&jit); 253 325 jit.move(JIT::TrustedImm64(TagTypeNumber), GPRInfo::returnValueGPR2); 254 JIT::Jump checkJSInt32 = jit.branch64(JIT::AboveOrEqual, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2); 255 jit.move64ToDouble(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR); 256 jit.truncateDoubleToInt32(FPRInfo::returnValueFPR, GPRInfo::returnValueGPR); 257 JIT::Jump checkJSNumber = jit.branchTest64(JIT::NonZero, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2); 258 jit.abortWithReason(AHIsNotJSNumber); // FIXME Coerce when the values aren't what we expect, instead of aborting. https://bugs.webkit.org/show_bug.cgi?id=165480 259 checkJSInt32.link(&jit); 260 jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR); 261 checkJSNumber.link(&jit); 262 break; 263 } 264 case I64: { 265 jit.move(JIT::TrustedImm64(TagTypeNumber), GPRInfo::returnValueGPR2); 266 JIT::Jump checkJSInt32 = jit.branch64(JIT::AboveOrEqual, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2); 267 jit.move64ToDouble(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR); 268 jit.truncateDoubleToInt64(FPRInfo::returnValueFPR, GPRInfo::returnValueGPR); 269 JIT::Jump checkJSNumber = jit.branchTest64(JIT::NonZero, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2); 270 jit.abortWithReason(AHIsNotJSNumber); // FIXME Coerce when the values aren't what we expect, instead of aborting. https://bugs.webkit.org/show_bug.cgi?id=165480 271 checkJSInt32.link(&jit); 272 jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR); 273 checkJSNumber.link(&jit); 274 break; 275 } 276 case F32: { 277 jit.move(JIT::TrustedImm64(TagTypeNumber), GPRInfo::returnValueGPR2); 326 jit.add64(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR); 278 327 jit.move64ToDouble(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR); 279 328 jit.convertDoubleToFloat(FPRInfo::returnValueFPR, FPRInfo::returnValueFPR); 280 JIT::Jump checkJSInt32 = jit.branch64(JIT::AboveOrEqual, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2); 281 JIT::Jump checkJSNumber = jit.branchTest64(JIT::NonZero, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2); 282 jit.abortWithReason(AHIsNotJSNumber); // FIXME Coerce when the values aren't what we expect, instead of aborting. https://bugs.webkit.org/show_bug.cgi?id=165480 283 checkJSInt32.link(&jit); 284 jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR); 285 jit.convertInt64ToFloat(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR); 286 checkJSNumber.link(&jit); 329 done.append(jit.jump()); 330 331 notANumber.link(&jit); 332 jit.setupArgumentsWithExecState(GPRInfo::returnValueGPR); 333 auto call = jit.call(); 334 exceptionChecks.append(jit.emitJumpIfException()); 335 336 float (*convertToF32)(ExecState*, JSValue) = [] (ExecState* exec, JSValue v) -> float { 337 VM* vm = &exec->vm(); 338 NativeCallFrameTracer tracer(vm, exec); 339 return static_cast<float>(v.toNumber(exec)); 340 }; 341 jit.addLinkTask([=] (LinkBuffer& linkBuffer) { 342 linkBuffer.link(call, convertToF32); 343 }); 344 345 done.link(&jit); 287 346 break; 288 347 } 289 348 case F64: { 349 CCallHelpers::JumpList done; 350 auto notANumber = jit.branchIfNotNumber(GPRInfo::returnValueGPR, DoNotHaveTagRegisters); 351 auto isDouble = jit.branchIfNotInt32(JSValueRegs(GPRInfo::returnValueGPR), DoNotHaveTagRegisters); 352 // We're an int32 353 jit.signExtend32ToPtr(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR); 354 jit.convertInt64ToDouble(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR); 355 done.append(jit.jump()); 356 357 isDouble.link(&jit); 290 358 jit.move(JIT::TrustedImm64(TagTypeNumber), GPRInfo::returnValueGPR2); 359 jit.add64(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR); 291 360 jit.move64ToDouble(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR); 292 JIT::Jump checkJSInt32 = jit.branch64(JIT::AboveOrEqual, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2); 293 JIT::Jump checkJSNumber = jit.branchTest64(JIT::NonZero, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2); 294 jit.abortWithReason(AHIsNotJSNumber); // FIXME Coerce when the values aren't what we expect, instead of aborting. https://bugs.webkit.org/show_bug.cgi?id=165480 295 checkJSInt32.link(&jit); 296 jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR); 297 jit.convertInt64ToDouble(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR); 298 checkJSNumber.link(&jit); 361 done.append(jit.jump()); 362 363 notANumber.link(&jit); 364 jit.setupArgumentsWithExecState(GPRInfo::returnValueGPR); 365 auto call = jit.call(); 366 exceptionChecks.append(jit.emitJumpIfException()); 367 368 double (*convertToF64)(ExecState*, JSValue) = [] (ExecState* exec, JSValue v) -> double { 369 VM* vm = &exec->vm(); 370 NativeCallFrameTracer tracer(vm, exec); 371 return v.toNumber(exec); 372 }; 373 jit.addLinkTask([=] (LinkBuffer& linkBuffer) { 374 linkBuffer.link(call, convertToF64); 375 }); 376 377 done.link(&jit); 299 378 break; 300 379 } … … 303 382 jit.emitFunctionEpilogue(); 304 383 jit.ret(); 384 385 if (!exceptionChecks.empty()) { 386 exceptionChecks.link(&jit); 387 jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(); 388 jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); 389 auto call = jit.call(); 390 jit.jumpToExceptionHandler(); 391 392 void (*doUnwinding)(ExecState*) = [] (ExecState* exec) -> void { 393 VM* vm = &exec->vm(); 394 NativeCallFrameTracer tracer(vm, exec); 395 genericUnwind(vm, exec); 396 ASSERT(!!vm->callFrameForCatch); 397 }; 398 399 jit.addLinkTask([=] (LinkBuffer& linkBuffer) { 400 linkBuffer.link(call, doUnwinding); 401 }); 402 } 305 403 306 404 LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID); … … 310 408 CodeLocationNearCall hotPathOther = patchBuffer.locationOfNearCall(fastCall); 311 409 callLinkInfo->setCallLocations(callReturnLocation, hotPathBegin, hotPathOther); 410 #if !defined(NDEBUG) 312 411 String signatureDescription = SignatureInformation::get(vm, signatureIndex)->toString(); 412 #else 413 String signatureDescription; 414 #endif 313 415 return FINALIZE_CODE(patchBuffer, ("WebAssembly->JavaScript import[%i] %s", importIndex, signatureDescription.ascii().data())); 314 416 }
Note: See TracChangeset
for help on using the changeset viewer.