+ const Identifier& ident = identifier(pc[2].u.operand);
+
+ ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), needsActivation(), scope, ident, Put, modeAndType.type());
+
+ instructions[i + 4].u.operand = ResolveModeAndType(modeAndType.mode(), op.type).operand();
+ if (op.type == GlobalVar || op.type == GlobalVarWithVarInjectionChecks)
+ instructions[i + 5].u.watchpointSet = op.watchpointSet;
+ else if (op.type == ClosureVar || op.type == ClosureVarWithVarInjectionChecks) {
+ if (op.watchpointSet)
+ op.watchpointSet->invalidate(PutToScopeFireDetail(this, ident));
+ } else if (op.structure)
+ instructions[i + 5].u.structure.set(*vm(), ownerExecutable, op.structure);
+ instructions[i + 6].u.pointer = reinterpret_cast<void*>(op.operand);
+
+ break;
+ }
+
+ case op_profile_type: {
+ RELEASE_ASSERT(vm()->typeProfiler());
+ // The format of this instruction is: op_profile_type regToProfile, TypeLocation*, flag, identifier?, resolveType?
+ size_t instructionOffset = i + opLength - 1;
+ unsigned divotStart, divotEnd;
+ GlobalVariableID globalVariableID = 0;
+ RefPtr<TypeSet> globalTypeSet;
+ bool shouldAnalyze = m_unlinkedCode->typeProfilerExpressionInfoForBytecodeOffset(instructionOffset, divotStart, divotEnd);
+ VirtualRegister profileRegister(pc[1].u.operand);
+ ProfileTypeBytecodeFlag flag = static_cast<ProfileTypeBytecodeFlag>(pc[3].u.operand);
+ SymbolTable* symbolTable = nullptr;
+
+ switch (flag) {
+ case ProfileTypeBytecodePutToScope:
+ case ProfileTypeBytecodeGetFromScope: {
+ const Identifier& ident = identifier(pc[4].u.operand);
+ ResolveType type = static_cast<ResolveType>(pc[5].u.operand);
+ ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), needsActivation(), scope, ident, (flag == ProfileTypeBytecodeGetFromScope ? Get : Put), type);
+
+ // FIXME: handle other values for op.type here, and also consider what to do when we can't statically determine the globalID
+ // https://bugs.webkit.org/show_bug.cgi?id=135184
+ if (op.type == ClosureVar)
+ symbolTable = op.lexicalEnvironment->symbolTable();
+ else if (op.type == GlobalVar)
+ symbolTable = m_globalObject.get()->symbolTable();
+
+ if (symbolTable) {
+ ConcurrentJITLocker locker(symbolTable->m_lock);
+ // If our parent scope was created while profiling was disabled, it will not have prepared for profiling yet.
+ symbolTable->prepareForTypeProfiling(locker);
+ globalVariableID = symbolTable->uniqueIDForVariable(locker, ident.impl(), *vm());
+ globalTypeSet = symbolTable->globalTypeSetForVariable(locker, ident.impl(), *vm());
+ } else
+ globalVariableID = TypeProfilerNoGlobalIDExists;
+
+ break;
+ }
+ case ProfileTypeBytecodePutToLocalScope:
+ case ProfileTypeBytecodeGetFromLocalScope: {
+ const Identifier& ident = identifier(pc[4].u.operand);
+ symbolTable = m_symbolTable.get();
+ ConcurrentJITLocker locker(symbolTable->m_lock);
+ // If our parent scope was created while profiling was disabled, it will not have prepared for profiling yet.
+ symbolTable->prepareForTypeProfiling(locker);
+ globalVariableID = symbolTable->uniqueIDForVariable(locker, ident.impl(), *vm());
+ globalTypeSet = symbolTable->globalTypeSetForVariable(locker, ident.impl(), *vm());
+
+ break;
+ }
+
+ case ProfileTypeBytecodeHasGlobalID: {
+ symbolTable = m_symbolTable.get();
+ ConcurrentJITLocker locker(symbolTable->m_lock);
+ globalVariableID = symbolTable->uniqueIDForOffset(locker, VarOffset(profileRegister), *vm());
+ globalTypeSet = symbolTable->globalTypeSetForOffset(locker, VarOffset(profileRegister), *vm());
+ break;
+ }
+ case ProfileTypeBytecodeDoesNotHaveGlobalID:
+ case ProfileTypeBytecodeFunctionArgument: {
+ globalVariableID = TypeProfilerNoGlobalIDExists;
+ break;
+ }
+ case ProfileTypeBytecodeFunctionReturnStatement: {
+ RELEASE_ASSERT(ownerExecutable->isFunctionExecutable());
+ globalTypeSet = jsCast<FunctionExecutable*>(ownerExecutable)->returnStatementTypeSet();
+ globalVariableID = TypeProfilerReturnStatement;
+ if (!shouldAnalyze) {
+ // Because a return statement can be added implicitly to return undefined at the end of a function,
+ // and these nodes don't emit expression ranges because they aren't in the actual source text of
+ // the user's program, give the type profiler some range to identify these return statements.
+ // Currently, the text offset that is used as identification is on the open brace of the function
+ // and is stored on TypeLocation's m_divotForFunctionOffsetIfReturnStatement member variable.
+ divotStart = divotEnd = m_sourceOffset;
+ shouldAnalyze = true;
+ }
+ break;
+ }
+ }
+
+ std::pair<TypeLocation*, bool> locationPair = vm()->typeProfiler()->typeLocationCache()->getTypeLocation(globalVariableID,
+ m_ownerExecutable->sourceID(), divotStart, divotEnd, globalTypeSet, vm());
+ TypeLocation* location = locationPair.first;
+ bool isNewLocation = locationPair.second;
+
+ if (flag == ProfileTypeBytecodeFunctionReturnStatement)
+ location->m_divotForFunctionOffsetIfReturnStatement = m_sourceOffset;
+
+ if (shouldAnalyze && isNewLocation)
+ vm()->typeProfiler()->insertNewLocation(location);
+
+ instructions[i + 2].u.location = location;