static bool LinkModuleToHeap(JSContext *cx, AsmJSModule &module, Handle<ArrayBufferObject*> heap) { if (!IsValidAsmJSHeapLength(heap->byteLength())) { ScopedJSFreePtr<char> msg( JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next " "valid length is 0x%x", heap->byteLength(), RoundUpToNextValidAsmJSHeapLength(heap->byteLength()))); return LinkFail(cx, msg.get()); } // This check is sufficient without considering the size of the loaded datum because heap // loads and stores start on an aligned boundary and the heap byteLength has larger alignment. JS_ASSERT((module.minHeapLength() - 1) <= INT32_MAX); if (heap->byteLength() < module.minHeapLength()) { ScopedJSFreePtr<char> msg( JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (which is the" "largest constant heap access offset rounded up to the next valid " "heap size).", heap->byteLength(), module.minHeapLength())); return LinkFail(cx, msg.get()); } if (!ArrayBufferObject::prepareForAsmJS(cx, heap)) return LinkFail(cx, "Unable to prepare ArrayBuffer for asm.js use"); module.initHeap(heap, cx); return true; }
static bool LinkModuleToHeap(JSContext *cx, AsmJSModule &module, Handle<ArrayBufferObject*> heap) { uint32_t heapLength = heap->byteLength(); if (IsDeprecatedAsmJSHeapLength(heapLength)) { LinkFail(cx, "ArrayBuffer byteLengths smaller than 64KB are deprecated and " "will cause a link-time failure in the future"); // The goal of deprecation is to give apps some time before linking // fails. However, if warnings-as-errors is turned on (which happens as // part of asm.js testing) an exception may be raised. if (cx->isExceptionPending()) return false; } if (!IsValidAsmJSHeapLength(heapLength)) { ScopedJSFreePtr<char> msg( JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next " "valid length is 0x%x", heapLength, RoundUpToNextValidAsmJSHeapLength(heapLength))); return LinkFail(cx, msg.get()); } // This check is sufficient without considering the size of the loaded datum because heap // loads and stores start on an aligned boundary and the heap byteLength has larger alignment. JS_ASSERT((module.minHeapLength() - 1) <= INT32_MAX); if (heapLength < module.minHeapLength()) { ScopedJSFreePtr<char> msg( JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (which is the " "largest constant heap access offset rounded up to the next valid " "heap size).", heapLength, module.minHeapLength())); return LinkFail(cx, msg.get()); } // If we've generated the code with signal handlers in mind (for bounds // checks on x64 and for interrupt callback requesting on all platforms), // we need to be able to use signals at runtime. In particular, a module // can have been created using signals and cached, and executed without // signals activated. if (module.usesSignalHandlersForInterrupt() && !cx->canUseSignalHandlers()) return LinkFail(cx, "Code generated with signal handlers but signals are deactivated"); if (!ArrayBufferObject::prepareForAsmJS(cx, heap, module.usesSignalHandlersForOOB())) return LinkFail(cx, "Unable to prepare ArrayBuffer for asm.js use"); module.initHeap(heap, cx); return true; }
static bool LinkModuleToHeap(JSContext* cx, AsmJSModule& module, Handle<ArrayBufferObjectMaybeShared*> heap) { uint32_t heapLength = heap->byteLength(); if (!IsValidAsmJSHeapLength(heapLength)) { ScopedJSFreePtr<char> msg( JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next " "valid length is 0x%x", heapLength, RoundUpToNextValidAsmJSHeapLength(heapLength))); return LinkFail(cx, msg.get()); } // This check is sufficient without considering the size of the loaded datum because heap // loads and stores start on an aligned boundary and the heap byteLength has larger alignment. MOZ_ASSERT((module.minHeapLength() - 1) <= INT32_MAX); if (heapLength < module.minHeapLength()) { ScopedJSFreePtr<char> msg( JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (the size implied " "by const heap accesses and/or change-heap minimum-length requirements).", heapLength, module.minHeapLength())); return LinkFail(cx, msg.get()); } if (heapLength > module.maxHeapLength()) { ScopedJSFreePtr<char> msg( JS_smprintf("ArrayBuffer byteLength 0x%x is greater than maximum length of 0x%x", heapLength, module.maxHeapLength())); return LinkFail(cx, msg.get()); } // If we've generated the code with signal handlers in mind (for bounds // checks on x64 and for interrupt callback requesting on all platforms), // we need to be able to use signals at runtime. In particular, a module // can have been created using signals and cached, and executed without // signals activated. if (module.usesSignalHandlersForInterrupt() && !cx->canUseSignalHandlers()) return LinkFail(cx, "Code generated with signal handlers but signals are deactivated"); if (heap->is<ArrayBufferObject>()) { Rooted<ArrayBufferObject*> abheap(cx, &heap->as<ArrayBufferObject>()); if (!ArrayBufferObject::prepareForAsmJS(cx, abheap, module.usesSignalHandlersForOOB())) return LinkFail(cx, "Unable to prepare ArrayBuffer for asm.js use"); } module.initHeap(heap, cx); return true; }
static bool DynamicallyLinkModule(JSContext *cx, CallArgs args, AsmJSModule &module) { if (module.isLinked()) return LinkFail(cx, "As a temporary limitation, modules cannot be linked more than " "once. This limitation should be removed in a future release. To " "work around this, compile a second module (e.g., using the " "Function constructor)."); module.setIsLinked(); RootedValue globalVal(cx, UndefinedValue()); if (args.length() > 0) globalVal = args[0]; RootedValue importVal(cx, UndefinedValue()); if (args.length() > 1) importVal = args[1]; RootedValue bufferVal(cx, UndefinedValue()); if (args.length() > 2) bufferVal = args[2]; Rooted<ArrayBufferObject*> heap(cx); if (module.hasArrayView()) { if (!IsTypedArrayBuffer(bufferVal)) return LinkFail(cx, "bad ArrayBuffer argument"); heap = &bufferVal.toObject().as<ArrayBufferObject>(); if (!IsValidAsmJSHeapLength(heap->byteLength())) { return LinkFail(cx, JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next valid length is 0x%x", heap->byteLength(), RoundUpToNextValidAsmJSHeapLength(heap->byteLength()))); } // This check is sufficient without considering the size of the loaded datum because heap // loads and stores start on an aligned boundary and the heap byteLength has larger alignment. JS_ASSERT((module.minHeapLength() - 1) <= INT32_MAX); if (heap->byteLength() < module.minHeapLength()) { return LinkFail(cx, JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (which is the largest constant heap access offset rounded up to the next valid heap size).", heap->byteLength(), module.minHeapLength())); } if (!ArrayBufferObject::prepareForAsmJS(cx, heap)) return LinkFail(cx, "Unable to prepare ArrayBuffer for asm.js use"); module.initHeap(heap, cx); } AutoObjectVector ffis(cx); if (!ffis.resize(module.numFFIs())) return false; for (unsigned i = 0; i < module.numGlobals(); i++) { AsmJSModule::Global &global = module.global(i); switch (global.which()) { case AsmJSModule::Global::Variable: if (!ValidateGlobalVariable(cx, module, global, importVal)) return false; break; case AsmJSModule::Global::FFI: if (!ValidateFFI(cx, global, importVal, &ffis)) return false; break; case AsmJSModule::Global::ArrayView: if (!ValidateArrayView(cx, global, globalVal, bufferVal)) return false; break; case AsmJSModule::Global::MathBuiltin: if (!ValidateMathBuiltin(cx, global, globalVal)) return false; break; case AsmJSModule::Global::Constant: if (!ValidateGlobalConstant(cx, global, globalVal)) return false; break; } } for (unsigned i = 0; i < module.numExits(); i++) module.exitIndexToGlobalDatum(i).fun = &ffis[module.exit(i).ffiIndex()]->as<JSFunction>(); return true; }