JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope) { auto throwScope = DECLARE_THROW_SCOPE(vm); RELEASE_ASSERT(scope); JSGlobalObject* globalObject = scope->globalObject(); RELEASE_ASSERT(globalObject); ASSERT(&globalObject->vm() == &vm); ParserError error; JSParserStrictMode strictMode = isStrictMode() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict; DebuggerMode debuggerMode = globalObject->hasInteractiveDebugger() ? DebuggerOn : DebuggerOff; UnlinkedProgramCodeBlock* unlinkedCodeBlock = vm.codeCache()->getUnlinkedProgramCodeBlock( vm, this, source(), strictMode, debuggerMode, error); if (globalObject->hasDebugger()) globalObject->debugger()->sourceParsed(callFrame, source().provider(), error.line(), error.message()); if (error.isValid()) return error.toErrorObject(globalObject, source()); JSValue nextPrototype = globalObject->getPrototypeDirect(); while (nextPrototype && nextPrototype.isObject()) { if (UNLIKELY(asObject(nextPrototype)->type() == ProxyObjectType)) { ExecState* exec = globalObject->globalExec(); return createTypeError(exec, ASCIILiteral("Proxy is not allowed in the global prototype chain.")); } nextPrototype = asObject(nextPrototype)->getPrototypeDirect(); } JSGlobalLexicalEnvironment* globalLexicalEnvironment = globalObject->globalLexicalEnvironment(); const VariableEnvironment& variableDeclarations = unlinkedCodeBlock->variableDeclarations(); const VariableEnvironment& lexicalDeclarations = unlinkedCodeBlock->lexicalDeclarations(); // The ES6 spec says that no vars/global properties/let/const can be duplicated in the global scope. // This carried out section 15.1.8 of the ES6 spec: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-globaldeclarationinstantiation { ExecState* exec = globalObject->globalExec(); // Check for intersection of "var" and "let"/"const"/"class" for (auto& entry : lexicalDeclarations) { if (variableDeclarations.contains(entry.key)) return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'")); } // Check if any new "let"/"const"/"class" will shadow any pre-existing global property names, or "var"/"let"/"const" variables. // It's an error to introduce a shadow. for (auto& entry : lexicalDeclarations) { bool hasProperty = globalObject->hasProperty(exec, entry.key.get()); RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); if (hasProperty) { // The ES6 spec says that just RestrictedGlobalProperty can't be shadowed // This carried out section 8.1.1.4.14 of the ES6 spec: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasrestrictedglobalproperty PropertyDescriptor descriptor; globalObject->getOwnPropertyDescriptor(exec, entry.key.get(), descriptor); if (descriptor.value() != jsUndefined() && !descriptor.configurable()) return createSyntaxError(exec, makeString("Can't create duplicate variable that shadows a global property: '", String(entry.key.get()), "'")); } hasProperty = globalLexicalEnvironment->hasProperty(exec, entry.key.get()); RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); if (hasProperty) { if (UNLIKELY(entry.value.isConst() && !vm.globalConstRedeclarationShouldThrow() && !isStrictMode())) { // We only allow "const" duplicate declarations under this setting. // For example, we don't "let" variables to be overridden by "const" variables. if (globalLexicalEnvironment->isConstVariable(entry.key.get())) continue; } return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'")); } } // Check if any new "var"s will shadow any previous "let"/"const"/"class" names. // It's an error to introduce a shadow. if (!globalLexicalEnvironment->isEmpty()) { for (auto& entry : variableDeclarations) { bool hasProperty = globalLexicalEnvironment->hasProperty(exec, entry.key.get()); RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); if (hasProperty) return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'")); } } } m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock); BatchedTransitionOptimizer optimizer(vm, globalObject); for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) { UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i); ASSERT(!unlinkedFunctionExecutable->name().isEmpty()); globalObject->addFunction(callFrame, unlinkedFunctionExecutable->name()); if (vm.typeProfiler() || vm.controlFlowProfiler()) { vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(), unlinkedFunctionExecutable->typeProfilingStartOffset(), unlinkedFunctionExecutable->typeProfilingEndOffset()); } } for (auto& entry : variableDeclarations) { ASSERT(entry.value.isVar()); globalObject->addVar(callFrame, Identifier::fromUid(&vm, entry.key.get())); ASSERT(!throwScope.exception()); } { JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(globalObject->globalScope()); SymbolTable* symbolTable = globalLexicalEnvironment->symbolTable(); ConcurrentJSLocker locker(symbolTable->m_lock); for (auto& entry : lexicalDeclarations) { if (UNLIKELY(entry.value.isConst() && !vm.globalConstRedeclarationShouldThrow() && !isStrictMode())) { if (symbolTable->contains(locker, entry.key.get())) continue; } ScopeOffset offset = symbolTable->takeNextScopeOffset(locker); SymbolTableEntry newEntry(VarOffset(offset), entry.value.isConst() ? ReadOnly : 0); newEntry.prepareToWatch(); symbolTable->add(locker, entry.key.get(), newEntry); ScopeOffset offsetForAssert = globalLexicalEnvironment->addVariables(1, jsTDZValue()); RELEASE_ASSERT(offsetForAssert == offset); } } return nullptr; }
JSValue WebAssemblyModuleConstructor::createModule(ExecState* state, Structure* structure) { VM& vm = state->vm(); auto scope = DECLARE_THROW_SCOPE(vm); size_t byteOffset; size_t byteSize; uint8_t* base = getWasmBufferFromValue(state, state->argument(0), byteOffset, byteSize); RETURN_IF_EXCEPTION(scope, { }); Wasm::Plan plan(&vm, base + byteOffset, byteSize); // On failure, a new WebAssembly.CompileError is thrown. plan.run(); if (plan.failed()) return throwException(state, scope, createJSWebAssemblyCompileError(state, vm, plan.errorMessage())); // On success, a new WebAssembly.Module object is returned with [[Module]] set to the validated Ast.module. // The export symbol table is the same for all Instances of a Module. SymbolTable* exportSymbolTable = SymbolTable::create(vm); for (auto& exp : plan.exports()) { auto offset = exportSymbolTable->takeNextScopeOffset(NoLockingNecessary); exportSymbolTable->set(NoLockingNecessary, exp.field.impl(), SymbolTableEntry(VarOffset(offset))); } // Only wasm-internal functions have a callee, stubs to JS do not. unsigned calleeCount = plan.internalFunctionCount(); JSWebAssemblyModule* result = JSWebAssemblyModule::create(vm, structure, plan.takeModuleInformation(), plan.takeCallLinkInfos(), plan.takeWasmExitStubs(), exportSymbolTable, calleeCount); plan.initializeCallees(state->jsCallee()->globalObject(), [&] (unsigned calleeIndex, JSWebAssemblyCallee* jsEntrypointCallee, JSWebAssemblyCallee* wasmEntrypointCallee) { result->setJSEntrypointCallee(vm, calleeIndex, jsEntrypointCallee); result->setWasmEntrypointCallee(vm, calleeIndex, wasmEntrypointCallee); }); return result; }
JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope) { RELEASE_ASSERT(scope); JSGlobalObject* globalObject = scope->globalObject(); RELEASE_ASSERT(globalObject); ASSERT(&globalObject->vm() == &vm); JSObject* exception = 0; UnlinkedProgramCodeBlock* unlinkedCodeBlock = globalObject->createProgramCodeBlock(callFrame, this, &exception); if (exception) return exception; JSGlobalLexicalEnvironment* globalLexicalEnvironment = globalObject->globalLexicalEnvironment(); const VariableEnvironment& variableDeclarations = unlinkedCodeBlock->variableDeclarations(); const VariableEnvironment& lexicalDeclarations = unlinkedCodeBlock->lexicalDeclarations(); // The ES6 spec says that no vars/global properties/let/const can be duplicated in the global scope. // This carried out section 15.1.8 of the ES6 spec: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-globaldeclarationinstantiation { ExecState* exec = globalObject->globalExec(); // Check for intersection of "var" and "let"/"const"/"class" for (auto& entry : lexicalDeclarations) { if (variableDeclarations.contains(entry.key)) return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'")); } // Check if any new "let"/"const"/"class" will shadow any pre-existing global property names, or "var"/"let"/"const" variables. // It's an error to introduce a shadow. for (auto& entry : lexicalDeclarations) { if (globalObject->hasProperty(exec, entry.key.get())) return createSyntaxError(exec, makeString("Can't create duplicate variable that shadows a global property: '", String(entry.key.get()), "'")); if (globalLexicalEnvironment->hasProperty(exec, entry.key.get())) return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'")); } // Check if any new "var"s will shadow any previous "let"/"const"/"class" names. // It's an error to introduce a shadow. if (!globalLexicalEnvironment->isEmpty()) { for (auto& entry : variableDeclarations) { if (globalLexicalEnvironment->hasProperty(exec, entry.key.get())) return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'")); } } } m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock); BatchedTransitionOptimizer optimizer(vm, globalObject); for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) { UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i); ASSERT(!unlinkedFunctionExecutable->name().isEmpty()); globalObject->addFunction(callFrame, unlinkedFunctionExecutable->name()); if (vm.typeProfiler() || vm.controlFlowProfiler()) { vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(), unlinkedFunctionExecutable->typeProfilingStartOffset(), unlinkedFunctionExecutable->typeProfilingEndOffset()); } } for (auto& entry : variableDeclarations) { ASSERT(entry.value.isVar()); globalObject->addVar(callFrame, Identifier::fromUid(&vm, entry.key.get())); } { JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(globalObject->globalScope()); SymbolTable* symbolTable = globalLexicalEnvironment->symbolTable(); ConcurrentJITLocker locker(symbolTable->m_lock); for (auto& entry : lexicalDeclarations) { ScopeOffset offset = symbolTable->takeNextScopeOffset(locker); SymbolTableEntry newEntry(VarOffset(offset), entry.value.isConst() ? ReadOnly : 0); newEntry.prepareToWatch(); symbolTable->add(locker, entry.key.get(), newEntry); ScopeOffset offsetForAssert = globalLexicalEnvironment->addVariables(1, jsTDZValue()); RELEASE_ASSERT(offsetForAssert == offset); } } return 0; }
static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyModule(ExecState* state) { VM& vm = state->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue val = state->argument(0); // If the given bytes argument is not a BufferSource, a TypeError exception is thrown. JSArrayBuffer* arrayBuffer = val.getObject() ? jsDynamicCast<JSArrayBuffer*>(val.getObject()) : nullptr; JSArrayBufferView* arrayBufferView = val.getObject() ? jsDynamicCast<JSArrayBufferView*>(val.getObject()) : nullptr; if (!(arrayBuffer || arrayBufferView)) return JSValue::encode(throwException(state, scope, createTypeError(state, ASCIILiteral("first argument to WebAssembly.Module must be an ArrayBufferView or an ArrayBuffer"), defaultSourceAppender, runtimeTypeForValue(val)))); if (arrayBufferView ? arrayBufferView->isNeutered() : arrayBuffer->impl()->isNeutered()) return JSValue::encode(throwException(state, scope, createTypeError(state, ASCIILiteral("underlying TypedArray has been detatched from the ArrayBuffer"), defaultSourceAppender, runtimeTypeForValue(val)))); size_t byteOffset = arrayBufferView ? arrayBufferView->byteOffset() : 0; size_t byteSize = arrayBufferView ? arrayBufferView->length() : arrayBuffer->impl()->byteLength(); const auto* base = arrayBufferView ? static_cast<uint8_t*>(arrayBufferView->vector()) : static_cast<uint8_t*>(arrayBuffer->impl()->data()); Wasm::Plan plan(&vm, base + byteOffset, byteSize); // On failure, a new WebAssembly.CompileError is thrown. plan.run(); if (plan.failed()) return JSValue::encode(throwException(state, scope, createWebAssemblyCompileError(state, plan.errorMessage()))); // On success, a new WebAssembly.Module object is returned with [[Module]] set to the validated Ast.module. auto* structure = InternalFunction::createSubclassStructure(state, state->newTarget(), asInternalFunction(state->jsCallee())->globalObject()->WebAssemblyModuleStructure()); RETURN_IF_EXCEPTION(scope, { }); // The export symbol table is the same for all Instances of a Module. SymbolTable* exportSymbolTable = SymbolTable::create(vm); for (auto& exp : plan.exports()) { auto offset = exportSymbolTable->takeNextScopeOffset(NoLockingNecessary); exportSymbolTable->set(NoLockingNecessary, exp.field.impl(), SymbolTableEntry(VarOffset(offset))); } // Only wasm-internal functions have a callee, stubs to JS do not. unsigned calleeCount = plan.internalFunctionCount(); JSWebAssemblyModule* result = JSWebAssemblyModule::create(vm, structure, plan.takeModuleInformation(), plan.takeCallLinkInfos(), plan.takeWasmToJSStubs(), plan.takeFunctionIndexSpace(), exportSymbolTable, calleeCount); plan.initializeCallees(state->jsCallee()->globalObject(), [&] (unsigned calleeIndex, JSWebAssemblyCallee* jsEntrypointCallee, JSWebAssemblyCallee* wasmEntrypointCallee) { result->setJSEntrypointCallee(vm, calleeIndex, jsEntrypointCallee); result->setWasmEntrypointCallee(vm, calleeIndex, wasmEntrypointCallee); }); return JSValue::encode(result); }
Storage storageForGeneratorLocal(unsigned index) { // We assign a symbol to a register. There is one-on-one corresponding between a register and a symbol. // By doing so, we allocate the specific storage to save the given register. // This allow us not to save all the live registers even if the registers are not overwritten from the previous resuming time. // It means that, the register can be retrieved even if the immediate previous op_save does not save it. if (m_storages.size() <= index) m_storages.resize(index + 1); if (Optional<Storage> storage = m_storages[index]) return *storage; Identifier identifier = Identifier::fromUid(PrivateName()); unsigned identifierIndex = m_codeBlock->numberOfIdentifiers(); m_codeBlock->addIdentifier(identifier); ScopeOffset scopeOffset = m_generatorFrameSymbolTable->takeNextScopeOffset(NoLockingNecessary); m_generatorFrameSymbolTable->set(NoLockingNecessary, identifier.impl(), SymbolTableEntry(VarOffset(scopeOffset))); Storage storage = { identifier, identifierIndex, scopeOffset }; m_storages[index] = storage; return storage; }