Skip to content
Permalink
Browse files
[JSC] Not generating import.meta object if it is not referenced
https://bugs.webkit.org/show_bug.cgi?id=244176

Reviewed by Ross Kirsling.

`import.meta` is only available in modules. And eval, function constructor etc. cannot evaluate it.
This means that we can detect `import.meta` existence when parsing statically.
This patch collects this information and avoid to materialize it if it is not referenced.

* Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::usesImportMeta const):
* Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h:
* Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
* Source/JavaScriptCore/parser/ModuleAnalyzer.cpp:
(JSC::ModuleAnalyzer::ModuleAnalyzer):
(JSC::ModuleAnalyzer::analyze):
* Source/JavaScriptCore/parser/ModuleAnalyzer.h:
(JSC::ModuleAnalyzer::moduleRecord):
* Source/JavaScriptCore/parser/Parser.cpp:
(JSC::Parser<LexerType>::parseInner):
(JSC::Parser<LexerType>::parseMemberExpression):
* Source/JavaScriptCore/parser/Parser.h:
(JSC::Scope::Scope):
(JSC::Scope::isLexicalScope const):
(JSC::Scope::usesEval const):
(JSC::Scope::usesImportMeta const):
(JSC::Scope::setUsesImportMeta):
(JSC::Scope::setExpectedSuperBinding):
(JSC::Scope::expectedSuperBinding const):
(JSC::Scope::setConstructorKind):
(JSC::Scope::constructorKind const):
(JSC::Scope::collectFreeVariables):
(JSC::Scope::fillParametersForSourceProviderCache):
(JSC::Scope::restoreFromSourceProviderCache):
(JSC::Scope::isLexicalScope): Deleted.
(JSC::Scope::usesEval): Deleted.
* Source/JavaScriptCore/parser/ParserModes.h:
* Source/JavaScriptCore/parser/SourceProviderCacheItem.h:
(JSC::SourceProviderCacheItem::SourceProviderCacheItem):
* Source/JavaScriptCore/runtime/Completion.cpp:
(JSC::checkModuleSyntax):
* Source/JavaScriptCore/runtime/JSModuleLoader.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/runtime/JSModuleRecord.cpp:
(JSC::JSModuleRecord::create):
(JSC::JSModuleRecord::JSModuleRecord):
(JSC::JSModuleRecord::instantiateDeclarations):
* Source/JavaScriptCore/runtime/JSModuleRecord.h:
* Source/JavaScriptCore/runtime/SyntheticModuleRecord.cpp:
(JSC::SyntheticModuleRecord::tryCreateWithExportNamesAndValues):

Canonical link: https://commits.webkit.org/253636@main
  • Loading branch information
Constellation committed Aug 22, 2022
1 parent 609758e commit 1e07f486b4a0bf18fe258b8d1a5f6cb343f0d5b4
Show file tree
Hide file tree
Showing 15 changed files with 101 additions and 93 deletions.
@@ -0,0 +1,13 @@
import { shouldThrow } from "./resources/assert.js";

shouldThrow(() => {
eval('import.meta');
}, `SyntaxError: import.meta is only valid inside modules.`);

shouldThrow(() => {
new Function('import.meta')();
}, `SyntaxError: import.meta is only valid inside modules.`);

shouldThrow(() => {
(void 0, eval)('import.meta');
}, `SyntaxError: import.meta is only valid inside modules.`);
@@ -154,6 +154,7 @@ class UnlinkedCodeBlock : public JSCell {
bool hasTailCalls() const { return m_hasTailCalls; }
void setHasTailCalls() { m_hasTailCalls = true; }
bool allowDirectEvalCache() const { return !(m_features & NoEvalCacheFeature); }
bool usesImportMeta() const { return m_features & ImportMetaFeature; }

bool hasExpressionInfo() { return m_expressionInfo.size(); }
const FixedVector<ExpressionRangeInfo>& expressionInfo() { return m_expressionInfo; }
@@ -280,7 +280,7 @@ class UnlinkedFunctionExecutable final : public JSCell {
unsigned m_typeProfilingEndOffset;
unsigned m_parameterCount : 31;
unsigned m_privateBrandRequirement : 1;
unsigned m_features : 14;
unsigned m_features : bitWidthOfCodeFeatures;
unsigned m_constructorKind : 2;
SourceParseMode m_sourceParseMode;
unsigned m_implementationVisibility : bitWidthOfImplementationVisibility;
@@ -994,7 +994,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, ModuleProgramNode* moduleProgramNod
// Now declare all variables.

createVariable(m_vm.propertyNames->starNamespacePrivateName, VarKind::Scope, moduleEnvironmentSymbolTable, VerifyExisting);
createVariable(m_vm.propertyNames->builtinNames().metaPrivateName(), VarKind::Scope, moduleEnvironmentSymbolTable, VerifyExisting);
if (moduleProgramNode->features() & ImportMetaFeature)
createVariable(m_vm.propertyNames->builtinNames().metaPrivateName(), VarKind::Scope, moduleEnvironmentSymbolTable, VerifyExisting);

for (auto& entry : moduleProgramNode->varDeclarations()) {
ASSERT(!entry.value.isLet() && !entry.value.isConst());
@@ -34,9 +34,9 @@

namespace JSC {

ModuleAnalyzer::ModuleAnalyzer(JSGlobalObject* globalObject, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
ModuleAnalyzer::ModuleAnalyzer(JSGlobalObject* globalObject, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables, CodeFeatures features)
: m_vm(globalObject->vm())
, m_moduleRecord(m_vm, JSModuleRecord::create(globalObject, m_vm, globalObject->moduleRecordStructure(), moduleKey, sourceCode, declaredVariables, lexicalVariables))
, m_moduleRecord(JSModuleRecord::create(globalObject, m_vm, globalObject->moduleRecordStructure(), moduleKey, sourceCode, declaredVariables, lexicalVariables, features))
{
}

@@ -149,7 +149,7 @@ JSModuleRecord* ModuleAnalyzer::analyze(ModuleProgramNode& moduleProgramNode)
if (UNLIKELY(Options::dumpModuleRecord()))
m_moduleRecord->dump();

return m_moduleRecord.get();
return m_moduleRecord;
}

} // namespace JSC
@@ -35,22 +35,23 @@ class ScriptFetchParameters;

class ModuleAnalyzer {
WTF_MAKE_NONCOPYABLE(ModuleAnalyzer);
WTF_FORBID_HEAP_ALLOCATION;
public:
ModuleAnalyzer(JSGlobalObject*, const Identifier& moduleKey, const SourceCode&, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables);
ModuleAnalyzer(JSGlobalObject*, const Identifier& moduleKey, const SourceCode&, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables, CodeFeatures);

JSModuleRecord* analyze(ModuleProgramNode&);

VM& vm() { return m_vm; }

JSModuleRecord* moduleRecord() { return m_moduleRecord.get(); }
JSModuleRecord* moduleRecord() { return m_moduleRecord; }

void appendRequestedModule(const Identifier&, RefPtr<ScriptFetchParameters>&&);

private:
void exportVariable(ModuleProgramNode&, const RefPtr<UniquedStringImpl>&, const VariableEnvironmentEntry&);

VM& m_vm;
Strong<JSModuleRecord> m_moduleRecord;
JSModuleRecord* m_moduleRecord;
IdentifierSet m_requestedModules;
};

@@ -335,6 +335,8 @@ Expected<typename Parser<LexerType>::ParseInnerResult, String> Parser<LexerType>
features |= NoEvalCacheFeature;
if (scope->hasNonSimpleParameterList())
features |= NonSimpleParameterListFeature;
if (scope->usesImportMeta())
features |= ImportMetaFeature;

#if ASSERT_ENABLED
if (m_parsingBuiltin && isProgramParseMode(parseMode)) {
@@ -5211,6 +5213,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
if (matchContextualKeyword(m_vm.propertyNames->builtinNames().metaPublicName())) {
semanticFailIfFalse(m_scriptMode == JSParserScriptMode::Module, "import.meta is only valid inside modules");
base = context.createImportMetaExpr(location, createResolveAndUseVariable(context, &m_vm.propertyNames->metaPrivateName, false, expressionStart, location));
currentScope()->setUsesImportMeta();
next();
} else {
failIfTrue(match(IDENT), "\"import.\" can only be followed with meta");
@@ -151,37 +151,11 @@ struct Scope {
Scope(const VM& vm, ImplementationVisibility implementationVisibility, LexicalScopeFeatures lexicalScopeFeatures, bool isFunction, bool isGenerator, bool isArrowFunction, bool isAsyncFunction)
: m_vm(vm)
, m_implementationVisibility(implementationVisibility)
, m_shadowsArguments(false)
, m_usesEval(false)
, m_needsFullActivation(false)
, m_hasDirectSuper(false)
, m_needsSuperBinding(false)
, m_allowsVarDeclarations(true)
, m_allowsLexicalDeclarations(true)
, m_lexicalScopeFeatures(lexicalScopeFeatures)
, m_isFunction(isFunction)
, m_isGenerator(isGenerator)
, m_isGeneratorBoundary(false)
, m_isArrowFunction(isArrowFunction)
, m_isArrowFunctionBoundary(false)
, m_isAsyncFunction(isAsyncFunction)
, m_isAsyncFunctionBoundary(false)
, m_isLexicalScope(false)
, m_isGlobalCodeScope(false)
, m_isSimpleCatchParameterScope(false)
, m_isCatchBlockScope(false)
, m_isFunctionBoundary(false)
, m_isValidStrictMode(true)
, m_hasArguments(false)
, m_isEvalContext(false)
, m_hasNonSimpleParameterList(false)
, m_isClassScope(false)
, m_evalContextType(EvalContextType::None)
, m_constructorKind(static_cast<unsigned>(ConstructorKind::None))
, m_expectedSuperBinding(static_cast<unsigned>(SuperBinding::NotNeeded))
, m_loopDepth(0)
, m_switchDepth(0)
, m_innerArrowFunctionFeatures(0)
{
m_usedVariables.append(UniquedStringImplPtrSet());
}
@@ -321,8 +295,9 @@ struct Scope {
m_isClassScope = true;
}

bool isLexicalScope() { return m_isLexicalScope; }
bool usesEval() { return m_usesEval; }
bool isLexicalScope() const { return m_isLexicalScope; }
bool usesEval() const { return m_usesEval; }
bool usesImportMeta() const { return m_usesImportMeta; }

const HashSet<UniquedStringImpl*>& closedVariableCandidates() const { return m_closedVariableCandidates; }
VariableEnvironment& declaredVariables() { return m_declaredVariables; }
@@ -619,6 +594,8 @@ struct Scope {
useVariable(&ident, false);
}

void setUsesImportMeta() { m_usesImportMeta = true; }

void pushUsedVariableSet() { m_usedVariables.append(UniquedStringImplPtrSet()); }
size_t currentUsedVariablesSize() { return m_usedVariables.size(); }
void revertToPreviousUsedVariables(size_t size) { m_usedVariables.resize(size); }
@@ -639,10 +616,10 @@ struct Scope {

InnerArrowFunctionCodeFeatures innerArrowFunctionFeatures() { return m_innerArrowFunctionFeatures; }

void setExpectedSuperBinding(SuperBinding superBinding) { m_expectedSuperBinding = static_cast<unsigned>(superBinding); }
SuperBinding expectedSuperBinding() const { return static_cast<SuperBinding>(m_expectedSuperBinding); }
void setConstructorKind(ConstructorKind constructorKind) { m_constructorKind = static_cast<unsigned>(constructorKind); }
ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
void setExpectedSuperBinding(SuperBinding superBinding) { m_expectedSuperBinding = superBinding; }
SuperBinding expectedSuperBinding() const { return m_expectedSuperBinding; }
void setConstructorKind(ConstructorKind constructorKind) { m_constructorKind = constructorKind; }
ConstructorKind constructorKind() const { return m_constructorKind; }

void setInnerArrowFunctionUsesSuperCall() { m_innerArrowFunctionFeatures |= SuperCallInnerArrowFunctionFeature; }
void setInnerArrowFunctionUsesSuperProperty() { m_innerArrowFunctionFeatures |= SuperPropertyInnerArrowFunctionFeature; }
@@ -682,6 +659,8 @@ struct Scope {
{
if (nestedScope->m_usesEval)
m_usesEval = true;
if (nestedScope->m_usesImportMeta)
m_usesImportMeta = true;

{
UniquedStringImplPtrSet& destinationSet = m_usedVariables.last();
@@ -776,6 +755,7 @@ struct Scope {
{
ASSERT(m_isFunction);
parameters.usesEval = m_usesEval;
parameters.usesImportMeta = m_usesImportMeta;
parameters.lexicalScopeFeatures = m_lexicalScopeFeatures;
parameters.needsFullActivation = m_needsFullActivation;
parameters.innerArrowFunctionFeatures = m_innerArrowFunctionFeatures;
@@ -800,6 +780,7 @@ struct Scope {
{
ASSERT(m_isFunction);
m_usesEval = info->usesEval;
m_usesImportMeta = info->usesImportMeta;
m_lexicalScopeFeatures = info->lexicalScopeFeatures();
m_innerArrowFunctionFeatures = info->innerArrowFunctionFeatures;
m_needsFullActivation = info->needsFullActivation;
@@ -894,37 +875,38 @@ struct Scope {

const VM& m_vm;
ImplementationVisibility m_implementationVisibility;
bool m_shadowsArguments;
bool m_usesEval;
bool m_needsFullActivation;
bool m_hasDirectSuper;
bool m_needsSuperBinding;
bool m_allowsVarDeclarations;
bool m_allowsLexicalDeclarations;
LexicalScopeFeatures m_lexicalScopeFeatures;
bool m_isFunction;
bool m_isGenerator;
bool m_isGeneratorBoundary;
bool m_isArrowFunction;
bool m_isArrowFunctionBoundary;
bool m_isAsyncFunction;
bool m_isAsyncFunctionBoundary;
bool m_isLexicalScope;
bool m_isGlobalCodeScope;
bool m_isSimpleCatchParameterScope;
bool m_isCatchBlockScope;
bool m_isFunctionBoundary;
bool m_isValidStrictMode;
bool m_hasArguments;
bool m_isEvalContext;
bool m_hasNonSimpleParameterList;
bool m_isClassScope;
EvalContextType m_evalContextType;
unsigned m_constructorKind;
unsigned m_expectedSuperBinding;
int m_loopDepth;
int m_switchDepth;
InnerArrowFunctionCodeFeatures m_innerArrowFunctionFeatures;
bool m_shadowsArguments : 1 { false };
bool m_usesEval : 1 { false };
bool m_usesImportMeta : 1 { false };
bool m_needsFullActivation : 1 { false };
bool m_hasDirectSuper : 1 { false };
bool m_needsSuperBinding : 1 { false };
bool m_allowsVarDeclarations : 1 { true };
bool m_allowsLexicalDeclarations : 1 { true };
bool m_isFunction : 1;
bool m_isGenerator : 1;
bool m_isGeneratorBoundary : 1 { false };
bool m_isArrowFunction : 1;
bool m_isArrowFunctionBoundary : 1 { false };
bool m_isAsyncFunction : 1;
bool m_isAsyncFunctionBoundary : 1 { false };
bool m_isLexicalScope : 1 { false };
bool m_isGlobalCodeScope : 1 { false };
bool m_isSimpleCatchParameterScope : 1 { false };
bool m_isCatchBlockScope : 1 { false };
bool m_isFunctionBoundary : 1 { false };
bool m_isValidStrictMode : 1 { true };
bool m_hasArguments : 1 { false };
bool m_isEvalContext : 1 { false };
bool m_hasNonSimpleParameterList : 1 { false };
bool m_isClassScope : 1 { false };
EvalContextType m_evalContextType { EvalContextType::None };
ConstructorKind m_constructorKind { ConstructorKind::None };
SuperBinding m_expectedSuperBinding { SuperBinding::NotNeeded };
int m_loopDepth { 0 };
int m_switchDepth { 0 };
InnerArrowFunctionCodeFeatures m_innerArrowFunctionFeatures { 0 };

typedef Vector<ScopeLabelInfo, 2> LabelStack;
std::unique_ptr<LabelStack> m_labels;
@@ -330,9 +330,11 @@ const CodeFeatures SuperCallFeature = 1 << 8;
const CodeFeatures SuperPropertyFeature = 1 << 9;
const CodeFeatures NewTargetFeature = 1 << 10;
const CodeFeatures NoEvalCacheFeature = 1 << 11;
const CodeFeatures ImportMetaFeature = 1 << 12;

const CodeFeatures AllFeatures = EvalFeature | ArgumentsFeature | WithFeature | ThisFeature | NonSimpleParameterListFeature | ShadowsArgumentsFeature | ArrowFunctionFeature | AwaitFeature | SuperCallFeature | SuperPropertyFeature | NewTargetFeature | NoEvalCacheFeature;
static_assert(AllFeatures < (1 << 14), "CodeFeatures must be 14bits");
const CodeFeatures AllFeatures = EvalFeature | ArgumentsFeature | WithFeature | ThisFeature | NonSimpleParameterListFeature | ShadowsArgumentsFeature | ArrowFunctionFeature | AwaitFeature | SuperCallFeature | SuperPropertyFeature | NewTargetFeature | NoEvalCacheFeature | ImportMetaFeature;
static constexpr unsigned bitWidthOfCodeFeatures = 14;
static_assert(AllFeatures <= (1 << bitWidthOfCodeFeatures) - 1, "CodeFeatures must fit within 14 bits");

typedef uint8_t InnerArrowFunctionCodeFeatures;

@@ -34,22 +34,23 @@
namespace JSC {

struct SourceProviderCacheItemCreationParameters {
unsigned lastTokenLine;
unsigned lastTokenStartOffset;
unsigned lastTokenEndOffset;
unsigned lastTokenLineStartOffset;
unsigned endFunctionOffset;
unsigned parameterCount;
bool needsFullActivation;
bool usesEval;
LexicalScopeFeatures lexicalScopeFeatures;
bool needsSuperBinding;
InnerArrowFunctionCodeFeatures innerArrowFunctionFeatures;
unsigned lastTokenLine { 0 };
unsigned lastTokenStartOffset { 0 };
unsigned lastTokenEndOffset { 0 };
unsigned lastTokenLineStartOffset { 0 };
unsigned endFunctionOffset { 0 };
unsigned parameterCount { 0 };
LexicalScopeFeatures lexicalScopeFeatures { 0 };
InnerArrowFunctionCodeFeatures innerArrowFunctionFeatures { 0 };
Vector<UniquedStringImpl*, 8> usedVariables;
bool isBodyArrowExpression { false };
JSTokenType tokenType { CLOSEBRACE };
ConstructorKind constructorKind;
SuperBinding expectedSuperBinding;
bool needsFullActivation : 1 { false };
bool usesEval : 1 { false };
bool usesImportMeta : 1 { false };
bool needsSuperBinding : 1 { false };
bool isBodyArrowExpression : 1 { false };
};

#if COMPILER(MSVC)
@@ -102,6 +103,7 @@ class SourceProviderCacheItem {
unsigned tokenType : 24; // JSTokenType
unsigned innerArrowFunctionFeatures : 6; // InnerArrowFunctionCodeFeatures
unsigned constructorKind : 2; // ConstructorKind
bool usesImportMeta : 1 { false };

PackedPtr<UniquedStringImpl>* usedVariables() const { return const_cast<PackedPtr<UniquedStringImpl>*>(m_variables); }

@@ -142,6 +144,7 @@ inline SourceProviderCacheItem::SourceProviderCacheItem(const SourceProviderCach
, tokenType(static_cast<unsigned>(parameters.tokenType))
, innerArrowFunctionFeatures(static_cast<unsigned>(parameters.innerArrowFunctionFeatures))
, constructorKind(static_cast<unsigned>(parameters.constructorKind))
, usesImportMeta(parameters.usesImportMeta)
{
ASSERT(tokenType == static_cast<unsigned>(parameters.tokenType));
ASSERT(innerArrowFunctionFeatures == static_cast<unsigned>(parameters.innerArrowFunctionFeatures));
@@ -82,7 +82,7 @@ bool checkModuleSyntax(JSGlobalObject* globalObject, const SourceCode& source, P
return false;

PrivateName privateName(PrivateName::Description, "EntryPointModule"_s);
ModuleAnalyzer moduleAnalyzer(globalObject, Identifier::fromUid(privateName), source, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables());
ModuleAnalyzer moduleAnalyzer(globalObject, Identifier::fromUid(privateName), source, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables(), moduleProgramNode->features());
moduleAnalyzer.analyze(*moduleProgramNode);
return true;
}
@@ -364,7 +364,7 @@ JSC_DEFINE_HOST_FUNCTION(moduleLoaderParseModule, (JSGlobalObject* globalObject,
RELEASE_AND_RETURN(scope, JSValue::encode(rejectWithError(error.toErrorObject(globalObject, sourceCode))));
ASSERT(moduleProgramNode);

ModuleAnalyzer moduleAnalyzer(globalObject, moduleKey, sourceCode, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables());
ModuleAnalyzer moduleAnalyzer(globalObject, moduleKey, sourceCode, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables(), moduleProgramNode->features());
RETURN_IF_EXCEPTION(scope, JSValue::encode(promise->rejectWithCaughtException(globalObject, scope)));

scope.release();
@@ -44,17 +44,18 @@ Structure* JSModuleRecord::createStructure(VM& vm, JSGlobalObject* globalObject,
return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}

JSModuleRecord* JSModuleRecord::create(JSGlobalObject* globalObject, VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
JSModuleRecord* JSModuleRecord::create(JSGlobalObject* globalObject, VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables, CodeFeatures features)
{
JSModuleRecord* instance = new (NotNull, allocateCell<JSModuleRecord>(vm)) JSModuleRecord(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables);
JSModuleRecord* instance = new (NotNull, allocateCell<JSModuleRecord>(vm)) JSModuleRecord(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables, features);
instance->finishCreation(globalObject, vm);
return instance;
}
JSModuleRecord::JSModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
JSModuleRecord::JSModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables, CodeFeatures features)
: Base(vm, structure, moduleKey)
, m_sourceCode(sourceCode)
, m_declaredVariables(declaredVariables)
, m_lexicalVariables(lexicalVariables)
, m_features(features)
{
}

@@ -228,7 +229,7 @@ void JSModuleRecord::instantiateDeclarations(JSGlobalObject* globalObject, Modul
}
}

{
if (m_features & ImportMetaFeature) {
JSObject* metaProperties = globalObject->moduleLoader()->createImportMetaProperties(globalObject, identifierToJSValue(vm, moduleKey()), this, scriptFetcher);
RETURN_IF_EXCEPTION(scope, void());
bool putResult = false;

0 comments on commit 1e07f48

Please sign in to comment.