void WASMModuleParser::parseModule(ExecState* exec) { uint32_t magicNumber; READ_UINT32_OR_FAIL(magicNumber, "Cannot read the magic number."); FAIL_IF_FALSE(magicNumber == wasmMagicNumber, "The magic number is incorrect."); uint32_t outputSizeInASMJS; READ_UINT32_OR_FAIL(outputSizeInASMJS, "Cannot read the output size in asm.js format."); parseConstantPoolSection(); PROPAGATE_ERROR(); parseSignatureSection(); PROPAGATE_ERROR(); parseFunctionImportSection(exec); PROPAGATE_ERROR(); parseGlobalSection(exec); PROPAGATE_ERROR(); parseFunctionDeclarationSection(); PROPAGATE_ERROR(); parseFunctionPointerTableSection(); PROPAGATE_ERROR(); parseFunctionDefinitionSection(); PROPAGATE_ERROR(); parseExportSection(); PROPAGATE_ERROR(); FAIL_IF_FALSE(!m_module->arrayBuffer() || m_module->arrayBuffer()->impl()->byteLength() < (1u << 31), "The ArrayBuffer's length must be less than 2^31."); }
void WASMModuleParser::parseExportSection() { WASMExportFormat exportFormat; READ_EXPORT_FORMAT_OR_FAIL(exportFormat, "Cannot read the export format."); switch (exportFormat) { case WASMExportFormat::Default: { uint32_t functionIndex; READ_COMPACT_UINT32_OR_FAIL(functionIndex, "Cannot read the function index."); FAIL_IF_FALSE(functionIndex < m_module->functionDeclarations().size(), "The function index is incorrect."); // FIXME: Export the function. break; } case WASMExportFormat::Record: { uint32_t numberOfExports; READ_COMPACT_UINT32_OR_FAIL(numberOfExports, "Cannot read the number of exports."); for (uint32_t exportIndex = 0; exportIndex < numberOfExports; ++exportIndex) { String exportName; READ_STRING_OR_FAIL(exportName, "Cannot read the function export name."); // FIXME: Check that exportName is legal. uint32_t functionIndex; READ_COMPACT_UINT32_OR_FAIL(functionIndex, "Cannot read the function index."); FAIL_IF_FALSE(functionIndex < m_module->functionDeclarations().size(), "The function index is incorrect."); // FIXME: Export the function. } break; } default: ASSERT_NOT_REACHED(); } }
void WASMModuleParser::parseFunctionImportSection() { uint32_t numberOfFunctionImports; uint32_t numberOfFunctionImportSignatures; READ_COMPACT_UINT32_OR_FAIL(numberOfFunctionImports, "Cannot read the number of function imports."); READ_COMPACT_UINT32_OR_FAIL(numberOfFunctionImportSignatures, "Cannot read the number of function import signatures."); m_module->functionImports().reserveInitialCapacity(numberOfFunctionImports); m_module->functionImportSignatures().reserveInitialCapacity(numberOfFunctionImportSignatures); for (uint32_t functionImportIndex = 0; functionImportIndex < numberOfFunctionImports; ++functionImportIndex) { WASMFunctionImport functionImport; READ_STRING_OR_FAIL(functionImport.functionName, "Cannot read the function import name."); m_module->functionImports().uncheckedAppend(functionImport); uint32_t numberOfSignatures; READ_COMPACT_UINT32_OR_FAIL(numberOfSignatures, "Cannot read the number of signatures."); FAIL_IF_FALSE(numberOfSignatures <= numberOfFunctionImportSignatures - m_module->functionImportSignatures().size(), "The number of signatures is incorrect."); for (uint32_t i = 0; i < numberOfSignatures; ++i) { WASMFunctionImportSignature functionImportSignature; READ_COMPACT_UINT32_OR_FAIL(functionImportSignature.signatureIndex, "Cannot read the signature index."); FAIL_IF_FALSE(functionImportSignature.signatureIndex < m_module->signatures().size(), "The signature index is incorrect."); functionImportSignature.functionImportIndex = functionImportIndex; m_module->functionImportSignatures().uncheckedAppend(functionImportSignature); } } FAIL_IF_FALSE(m_module->functionImportSignatures().size() == numberOfFunctionImportSignatures, "The number of function import signatures is incorrect."); }
void WASMModuleParser::getImportedValue(ExecState* exec, const String& importName, JSValue& value) { FAIL_IF_FALSE(m_imports, "Accessing property of non-object."); Identifier identifier = Identifier::fromString(&m_vm, importName); PropertySlot slot(m_imports.get(), PropertySlot::InternalMethodType::Get); if (!m_imports->getPropertySlot(exec, identifier, slot)) FAIL_WITH_MESSAGE("Can't find a property named \"" + importName + '"'); FAIL_IF_FALSE(slot.isValue(), "\"" + importName + "\" is not a data property."); // We only retrieve data properties. So, this does not cause any user-observable effect. value = slot.getValue(exec, identifier); }
void WASMModuleParser::parseModule() { uint32_t magicNumber; READ_UINT32_OR_FAIL(magicNumber, "Cannot read the magic number."); FAIL_IF_FALSE(magicNumber == wasmMagicNumber, "The magic number is incorrect."); uint32_t outputSizeInASMJS; READ_UINT32_OR_FAIL(outputSizeInASMJS, "Cannot read the output size in asm.js format."); parseConstantPoolSection(); PROPAGATE_ERROR(); parseSignatureSection(); PROPAGATE_ERROR(); parseFunctionImportSection(); PROPAGATE_ERROR(); parseGlobalSection(); PROPAGATE_ERROR(); parseFunctionDeclarationSection(); PROPAGATE_ERROR(); parseFunctionPointerTableSection(); PROPAGATE_ERROR(); parseFunctionDefinitionSection(); PROPAGATE_ERROR(); parseExportSection(); }
ContextStatement WASMFunctionParser::parseContinueLabelStatement(Context&) { uint32_t labelIndex; READ_COMPACT_UINT32_OR_FAIL(labelIndex, "Cannot read the label index."); FAIL_IF_FALSE(labelIndex < m_labelDepth, "The label index is incorrect."); // FIXME: Implement this instruction. return UNUSED; }
ContextStatement WASMFunctionParser::parseSetLocalStatement(Context& context, uint32_t localIndex) { FAIL_IF_FALSE(localIndex < m_localTypes.size(), "The local variable index is incorrect."); WASMType type = m_localTypes[localIndex]; parseExpression(context, WASMExpressionType(type)); // FIXME: Implement this instruction. return UNUSED; }
void WASMModuleParser::parseFunctionPointerTableSection() { uint32_t numberOfFunctionPointerTables; READ_COMPACT_UINT32_OR_FAIL(numberOfFunctionPointerTables, "Cannot read the number of function pointer tables."); m_module->functionPointerTables().reserveInitialCapacity(numberOfFunctionPointerTables); for (uint32_t i = 0; i < numberOfFunctionPointerTables; ++i) { WASMFunctionPointerTable functionPointerTable; READ_COMPACT_UINT32_OR_FAIL(functionPointerTable.signatureIndex, "Cannot read the signature index."); FAIL_IF_FALSE(functionPointerTable.signatureIndex < m_module->signatures().size(), "The signature index is incorrect."); uint32_t numberOfElements; READ_COMPACT_UINT32_OR_FAIL(numberOfElements, "Cannot read the number of elements of a function pointer table."); FAIL_IF_FALSE(hasOneBitSet(numberOfElements), "The number of elements must be a power of two."); functionPointerTable.elements.reserveInitialCapacity(numberOfElements); for (uint32_t j = 0; j < numberOfElements; ++j) { uint32_t element; READ_COMPACT_UINT32_OR_FAIL(element, "Cannot read an element of a function pointer table."); functionPointerTable.elements.uncheckedAppend(element); } m_module->functionPointerTables().uncheckedAppend(functionPointerTable); } }
void WASMModuleParser::parseFunctionDeclarationSection() { uint32_t numberOfFunctionDeclarations; READ_COMPACT_UINT32_OR_FAIL(numberOfFunctionDeclarations, "Cannot read the number of function declarations."); m_module->functionDeclarations().reserveInitialCapacity(numberOfFunctionDeclarations); for (uint32_t i = 0; i < numberOfFunctionDeclarations; ++i) { WASMFunctionDeclaration functionDeclaration; READ_COMPACT_UINT32_OR_FAIL(functionDeclaration.signatureIndex, "Cannot read the signature index."); FAIL_IF_FALSE(functionDeclaration.signatureIndex < m_module->signatures().size(), "The signature index is incorrect."); m_module->functionDeclarations().uncheckedAppend(functionDeclaration); } }
void WASMModuleParser::parseFunctionDefinition() { // FIXME: Support any functions. https://bugs.webkit.org/show_bug.cgi?id=147738 // Currently, we only support functions that have "return 0;" as their only statement. // These functions consist of exactly 4 bytes, i.e. // 1. The number of local variables (0) [0x80] // 2. The number of statements (1) [0x01] // 3. The return statement [0x0f] // 4. The immediate expression (0) [0xa0] uint32_t functionDefinitionBytes; READ_UINT32_OR_FAIL(functionDefinitionBytes, "Cannot read the function definition."); FAIL_IF_FALSE(functionDefinitionBytes == 0xa00f0180, "Only functions that have \"return 0;\" " "as their only statement are supported at the moment."); }
void WASMModuleParser::parseFunctionPointerTableSection() { uint32_t numberOfFunctionPointerTables; READ_COMPACT_UINT32_OR_FAIL(numberOfFunctionPointerTables, "Cannot read the number of function pointer tables."); m_module->functionPointerTables().reserveInitialCapacity(numberOfFunctionPointerTables); for (uint32_t i = 0; i < numberOfFunctionPointerTables; ++i) { WASMFunctionPointerTable functionPointerTable; READ_COMPACT_UINT32_OR_FAIL(functionPointerTable.signatureIndex, "Cannot read the signature index."); FAIL_IF_FALSE(functionPointerTable.signatureIndex < m_module->signatures().size(), "The signature index is incorrect."); uint32_t numberOfFunctions; READ_COMPACT_UINT32_OR_FAIL(numberOfFunctions, "Cannot read the number of functions of a function pointer table."); FAIL_IF_FALSE(hasOneBitSet(numberOfFunctions), "The number of functions must be a power of two."); functionPointerTable.functionIndices.reserveInitialCapacity(numberOfFunctions); functionPointerTable.functions.reserveInitialCapacity(numberOfFunctions); for (uint32_t j = 0; j < numberOfFunctions; ++j) { uint32_t functionIndex; READ_COMPACT_UINT32_OR_FAIL(functionIndex, "Cannot read a function index of a function pointer table."); FAIL_IF_FALSE(functionIndex < m_module->functionDeclarations().size(), "The function index is incorrect."); FAIL_IF_FALSE(m_module->functionDeclarations()[functionIndex].signatureIndex == functionPointerTable.signatureIndex, "The signature of the function doesn't match that of the function pointer table."); functionPointerTable.functionIndices.uncheckedAppend(functionIndex); } m_module->functionPointerTables().uncheckedAppend(functionPointerTable); } }
void WASMModuleParser::parseFunctionImportSection(ExecState* exec) { uint32_t numberOfFunctionImports; uint32_t numberOfFunctionImportSignatures; READ_COMPACT_UINT32_OR_FAIL(numberOfFunctionImports, "Cannot read the number of function imports."); READ_COMPACT_UINT32_OR_FAIL(numberOfFunctionImportSignatures, "Cannot read the number of function import signatures."); m_module->functionImports().reserveInitialCapacity(numberOfFunctionImports); m_module->functionImportSignatures().reserveInitialCapacity(numberOfFunctionImportSignatures); m_module->importedFunctions().reserveInitialCapacity(numberOfFunctionImports); for (uint32_t functionImportIndex = 0; functionImportIndex < numberOfFunctionImports; ++functionImportIndex) { WASMFunctionImport functionImport; READ_STRING_OR_FAIL(functionImport.functionName, "Cannot read the function import name."); m_module->functionImports().uncheckedAppend(functionImport); uint32_t numberOfSignatures; READ_COMPACT_UINT32_OR_FAIL(numberOfSignatures, "Cannot read the number of signatures."); FAIL_IF_FALSE(numberOfSignatures <= numberOfFunctionImportSignatures - m_module->functionImportSignatures().size(), "The number of signatures is incorrect."); for (uint32_t i = 0; i < numberOfSignatures; ++i) { WASMFunctionImportSignature functionImportSignature; READ_COMPACT_UINT32_OR_FAIL(functionImportSignature.signatureIndex, "Cannot read the signature index."); FAIL_IF_FALSE(functionImportSignature.signatureIndex < m_module->signatures().size(), "The signature index is incorrect."); functionImportSignature.functionImportIndex = functionImportIndex; m_module->functionImportSignatures().uncheckedAppend(functionImportSignature); } JSValue value; getImportedValue(exec, functionImport.functionName, value); PROPAGATE_ERROR(); FAIL_IF_FALSE(value.isFunction(), "\"" + functionImport.functionName + "\" is not a function."); JSFunction* function = jsCast<JSFunction*>(value.asCell()); m_module->importedFunctions().uncheckedAppend(WriteBarrier<JSFunction>(m_vm, m_module.get(), function)); } FAIL_IF_FALSE(m_module->functionImportSignatures().size() == numberOfFunctionImportSignatures, "The number of function import signatures is incorrect."); }
ContextStatement WASMFunctionParser::parseSwitchStatement(Context& context) { uint32_t numberOfCases; READ_COMPACT_UINT32_OR_FAIL(numberOfCases, "Cannot read the number of cases."); parseExpressionI32(context); PROPAGATE_ERROR(); m_breakScopeDepth++; for (uint32_t i = 0; i < numberOfCases; ++i) { WASMSwitchCase switchCase; READ_SWITCH_CASE_OR_FAIL(switchCase, "Cannot read the switch case."); switch (switchCase) { case WASMSwitchCase::CaseWithNoStatements: case WASMSwitchCase::CaseWithStatement: case WASMSwitchCase::CaseWithBlockStatement: { uint32_t value; READ_COMPACT_INT32_OR_FAIL(value, "Cannot read the value of the switch case."); if (switchCase == WASMSwitchCase::CaseWithStatement) { parseStatement(context); PROPAGATE_ERROR(); } else if (switchCase == WASMSwitchCase::CaseWithBlockStatement) { parseBlockStatement(context); PROPAGATE_ERROR(); } break; } case WASMSwitchCase::DefaultWithNoStatements: case WASMSwitchCase::DefaultWithStatement: case WASMSwitchCase::DefaultWithBlockStatement: { FAIL_IF_FALSE(i == numberOfCases - 1, "The default case must be the last case."); if (switchCase == WASMSwitchCase::DefaultWithStatement) { parseStatement(context); PROPAGATE_ERROR(); } else if (switchCase == WASMSwitchCase::DefaultWithBlockStatement) { parseBlockStatement(context); PROPAGATE_ERROR(); } break; } default: ASSERT_NOT_REACHED(); } } m_breakScopeDepth--; // FIXME: Implement this instruction. return UNUSED; }
void WASMModuleParser::parseGlobalSection(ExecState* exec) { uint32_t numberOfInternalI32GlobalVariables; uint32_t numberOfInternalF32GlobalVariables; uint32_t numberOfInternalF64GlobalVariables; uint32_t numberOfImportedI32GlobalVariables; uint32_t numberOfImportedF32GlobalVariables; uint32_t numberOfImportedF64GlobalVariables; READ_COMPACT_UINT32_OR_FAIL(numberOfInternalI32GlobalVariables, "Cannot read the number of internal int32 global variables."); READ_COMPACT_UINT32_OR_FAIL(numberOfInternalF32GlobalVariables, "Cannot read the number of internal float32 global variables."); READ_COMPACT_UINT32_OR_FAIL(numberOfInternalF64GlobalVariables, "Cannot read the number of internal float64 global variables."); READ_COMPACT_UINT32_OR_FAIL(numberOfImportedI32GlobalVariables, "Cannot read the number of imported int32 global variables."); READ_COMPACT_UINT32_OR_FAIL(numberOfImportedF32GlobalVariables, "Cannot read the number of imported float32 global variables."); READ_COMPACT_UINT32_OR_FAIL(numberOfImportedF64GlobalVariables, "Cannot read the number of imported float64 global variables."); uint32_t numberOfGlobalVariables = numberOfInternalI32GlobalVariables + numberOfInternalF32GlobalVariables + numberOfInternalF64GlobalVariables + numberOfImportedI32GlobalVariables + numberOfImportedF32GlobalVariables + numberOfImportedF64GlobalVariables; Vector<WASMType>& globalVariableTypes = m_module->globalVariableTypes(); globalVariableTypes.reserveInitialCapacity(numberOfGlobalVariables); Vector<JSWASMModule::GlobalVariable>& globalVariables = m_module->globalVariables(); globalVariables.reserveInitialCapacity(numberOfGlobalVariables); for (uint32_t i = 0; i < numberOfInternalI32GlobalVariables; ++i) { globalVariableTypes.uncheckedAppend(WASMType::I32); globalVariables.uncheckedAppend(JSWASMModule::GlobalVariable(0)); } for (uint32_t i = 0; i < numberOfInternalF32GlobalVariables; ++i) { globalVariableTypes.uncheckedAppend(WASMType::F32); globalVariables.uncheckedAppend(JSWASMModule::GlobalVariable(0.0f)); } for (uint32_t i = 0; i < numberOfInternalF64GlobalVariables; ++i) { globalVariableTypes.uncheckedAppend(WASMType::F64); globalVariables.uncheckedAppend(JSWASMModule::GlobalVariable(0.0)); } for (uint32_t i = 0; i < numberOfImportedI32GlobalVariables; ++i) { String importName; READ_STRING_OR_FAIL(importName, "Cannot read the import name of an int32 global variable."); globalVariableTypes.uncheckedAppend(WASMType::I32); JSValue value; getImportedValue(exec, importName, value); PROPAGATE_ERROR(); FAIL_IF_FALSE(value.isPrimitive() && !value.isSymbol(), "\"" + importName + "\" is not a primitive or is a Symbol."); globalVariables.uncheckedAppend(JSWASMModule::GlobalVariable(value.toInt32(exec))); } for (uint32_t i = 0; i < numberOfImportedF32GlobalVariables; ++i) { String importName; READ_STRING_OR_FAIL(importName, "Cannot read the import name of a float32 global variable."); globalVariableTypes.uncheckedAppend(WASMType::F32); JSValue value; getImportedValue(exec, importName, value); PROPAGATE_ERROR(); FAIL_IF_FALSE(value.isPrimitive() && !value.isSymbol(), "\"" + importName + "\" is not a primitive or is a Symbol."); globalVariables.uncheckedAppend(JSWASMModule::GlobalVariable(static_cast<float>(value.toNumber(exec)))); } for (uint32_t i = 0; i < numberOfImportedF64GlobalVariables; ++i) { String importName; READ_STRING_OR_FAIL(importName, "Cannot read the import name of a float64 global variable."); globalVariableTypes.uncheckedAppend(WASMType::F64); JSValue value; getImportedValue(exec, importName, value); PROPAGATE_ERROR(); FAIL_IF_FALSE(value.isPrimitive() && !value.isSymbol(), "\"" + importName + "\" is not a primitive or is a Symbol."); globalVariables.uncheckedAppend(JSWASMModule::GlobalVariable(value.toNumber(exec))); } }
ContextStatement WASMFunctionParser::parseContinueStatement(Context&) { FAIL_IF_FALSE(m_continueScopeDepth, "'continue' is only valid inside a loop statement."); // FIXME: Implement this instruction. return UNUSED; }
ContextStatement WASMFunctionParser::parseBreakStatement(Context&) { FAIL_IF_FALSE(m_breakScopeDepth, "'break' is only valid inside a switch or loop statement."); // FIXME: Implement this instruction. return UNUSED; }