Ignore:
Timestamp:
Jun 7, 2021, 8:22:27 PM (4 years ago)
Author:
[email protected]
Message:

[JSC] Use ResolvedClosureVar to get brand from scope
https://bugs.webkit.org/show_bug.cgi?id=226677
rdar://78802869

Reviewed by Saam Barati.

JSTests:

  • stress/private-access-nested-eval.js: Added.

(shouldThrow):
(shouldThrow.prototype.x):
(shouldThrow.prototype.m.C.prototype.z):
(shouldThrow.prototype.m.C.prototype.a):
(shouldThrow.prototype.m.C):
(shouldThrow.prototype.m):

  • stress/private-access-nested.js: Added.

(shouldThrow):
(shouldThrow.prototype.x):
(shouldThrow.prototype.m.C.prototype.z):
(shouldThrow.prototype.m.C.prototype.a):
(shouldThrow.prototype.m.C):
(shouldThrow.prototype.m):

Source/JavaScriptCore:

Private brand lookup is doing wrong way to get scope.

  1. op_resolve_scope with private name (e.g. #x)
  2. then, doing op_get_from_scope with (1)'s scope with different name (e.g. @privateBrand)

This is wrong in JSC. We resolve scope at link-time in CodeBlock. So we need to ensure that both op_resolve_scope and op_get_from_scope
starts with the current scope-register. As a result, private-brand lookup is broken right now. Let's see the buggy case.

class D {

#x() {}
m() {

class C {

#yy;
#z() { }
a() {

this.#x(); <===== This point.

}

}
let c = new C();
c.a();

}

}

In the above point, we first lookup the scope with #x, and we get the D's class-scope. But our get_from_scope is using privateBrand, and
privateBrand property exists too in C's class-scope too since C also has #yy and #z. As a result, CodeBlock linking configures the offset for
C's class-scope in get_from_scope. And this offset is different from D's class-scope's privateBrand.

Only allowed case for the above usage is ResolvedClosureVar. And generatorification uses it too. In this patch,

  1. We ensure that class-scope (with private name) must have @privateBrand and @privateClassBrand with offset 1 and 0.
  2. Use ResolvedClosureVar with the above pre-defined offset

Since CodeBlock's linking does not resolve the scope for get_from_scope if it is ResolvedClosureVar, we can just perform the desired ResolvedClosureVar lookup
with the given scope with the compiled offset.

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::instantiateLexicalVariables):
(JSC::BytecodeGenerator::pushLexicalScope):
(JSC::BytecodeGenerator::pushLexicalScopeInternal):
(JSC::BytecodeGenerator::emitCreatePrivateBrand):
(JSC::BytecodeGenerator::emitGetPrivateBrand):

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::BaseDotNode::emitGetPropertyValue):
(JSC::BaseDotNode::emitPutProperty):
(JSC::PostfixNode::emitDot):
(JSC::PrefixNode::emitDot):
(JSC::InNode::emitBytecode):
(JSC::BlockNode::emitBytecode):
(JSC::ForNode::emitBytecode):
(JSC::ForInNode::emitBytecode):
(JSC::ForOfNode::emitBytecode):
(JSC::SwitchNode::emitBytecode):
(JSC::ClassExprNode::emitBytecode):

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseClass):

  • parser/VariableEnvironment.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r278425 r278591  
    560560
    561561            const Identifier& ident = identifier(bytecode.m_var);
    562             RELEASE_ASSERT(bytecode.m_resolveType != LocalClosureVar);
     562            RELEASE_ASSERT(bytecode.m_resolveType != ResolvedClosureVar);
    563563
    564564            ResolveOp op = JSScope::abstractResolve(m_globalObject.get(), bytecode.m_localScopeDepth, scope, ident, Get, bytecode.m_resolveType, InitializationMode::NotInitialization);
     
    591591
    592592            ASSERT(!isInitialization(bytecode.m_getPutInfo.initializationMode()));
    593             if (bytecode.m_getPutInfo.resolveType() == LocalClosureVar) {
     593            if (bytecode.m_getPutInfo.resolveType() == ResolvedClosureVar) {
    594594                metadata.m_getPutInfo = GetPutInfo(bytecode.m_getPutInfo.resolveMode(), ClosureVar, bytecode.m_getPutInfo.initializationMode(), bytecode.m_getPutInfo.ecmaMode());
    595595                break;
     
    614614            INITIALIZE_METADATA(OpPutToScope)
    615615
    616             if (bytecode.m_getPutInfo.resolveType() == LocalClosureVar) {
     616            if (bytecode.m_getPutInfo.resolveType() == ResolvedClosureVar) {
    617617                // Only do watching if the property we're putting to is not anonymous.
    618618                if (bytecode.m_var != UINT_MAX) {
     
    14211421            GetPutInfo getPutInfo = metadata.m_getPutInfo;
    14221422            if (getPutInfo.resolveType() == GlobalVar || getPutInfo.resolveType() == GlobalVarWithVarInjectionChecks
    1423                 || getPutInfo.resolveType() == LocalClosureVar || getPutInfo.resolveType() == GlobalLexicalVar || getPutInfo.resolveType() == GlobalLexicalVarWithVarInjectionChecks)
     1423                || getPutInfo.resolveType() == ResolvedClosureVar || getPutInfo.resolveType() == GlobalLexicalVar || getPutInfo.resolveType() == GlobalLexicalVarWithVarInjectionChecks)
    14241424                return;
    14251425            WriteBarrierBase<Structure>& structure = metadata.m_structure;
Note: See TracChangeset for help on using the changeset viewer.