use of com.github.anba.es6draft.compiler.CodeVisitor.LabelledHashKey in project es6draft by anba.
the class DefaultCodeGenerator method ClassDefinitionEvaluation.
/**
* 14.5.14 Runtime Semantics: ClassDefinitionEvaluation
*
* @param def
* the class definition node
* @param className
* the class name or {@code null} if not present
* @param mv
* the code visitor
*/
protected final void ClassDefinitionEvaluation(ClassDefinition def, Name className, CodeVisitor mv) {
mv.enterVariableScope();
List<Expression> classDecoratorsList = def.getDecorators();
Variable<Callable[]> classDecorators = null;
if (!classDecoratorsList.isEmpty()) {
classDecorators = mv.newVariable("classDecorators", Callable[].class);
mv.anewarray(classDecoratorsList.size(), Types.Callable);
mv.store(classDecorators);
int index = 0;
for (Expression decorator : classDecoratorsList) {
mv.astore(classDecorators, index++, __ -> {
expressionBoxed(decorator, mv);
CheckCallable(decorator, mv);
});
}
}
mv.enterClassDefinition();
// step 1 (not applicable)
// steps 2-4
BlockScope scope = def.getScope();
Variable<DeclarativeEnvironmentRecord> classScopeEnvRec = null;
if (scope != null) {
assert scope.isPresent() == (className != null);
if (scope.isPresent()) {
// stack: [] -> [classScope]
newDeclarativeEnvironment(scope, mv);
classScopeEnvRec = mv.newVariable("classScopeEnvRec", DeclarativeEnvironmentRecord.class);
getEnvRec(classScopeEnvRec, mv);
if (className != null) {
// stack: [classScope] -> [classScope]
Name innerName = scope.resolveName(className);
BindingOp<DeclarativeEnvironmentRecord> op = BindingOp.of(classScopeEnvRec, innerName);
op.createImmutableBinding(classScopeEnvRec, innerName, true, mv);
}
// stack: [classScope] -> []
pushLexicalEnvironment(mv);
}
mv.enterScope(def);
}
// steps 5-7
// stack: [] -> [<constructorParent,proto>]
Expression classHeritage = def.getHeritage();
if (classHeritage == null) {
mv.loadExecutionContext();
mv.invoke(Methods.ClassOperations_getDefaultClassProto);
} else if (classHeritage instanceof NullLiteral) {
mv.loadExecutionContext();
mv.invoke(Methods.ClassOperations_getClassProto_Null);
} else {
expressionBoxed(classHeritage, mv);
mv.loadExecutionContext();
mv.lineInfo(def);
mv.invoke(Methods.ClassOperations_getClassProto);
}
// stack: [<protoParent,constructorParent>] -> [<protoParent,constructorParent>]
Variable<OrdinaryObject> proto = mv.newVariable("proto", OrdinaryObject.class);
mv.dup();
mv.aload(0, Types.ScriptObject);
mv.loadExecutionContext();
mv.invoke(Methods.ClassOperations_createProto);
mv.store(proto);
// stack: [<protoParent,constructorParent>] -> [constructorParent, proto]
mv.aload(1, Types.ScriptObject);
mv.load(proto);
// Push the private-name environment to ensure private names are accessible in the constructor.
BlockScope bodyScope = def.getBodyScope();
if (bodyScope != null) {
List<Name> privateBoundNames = PrivateBoundNames(def);
assert bodyScope.isPresent() == !privateBoundNames.isEmpty();
if (bodyScope.isPresent()) {
// stack: [] -> [classPrivateEnv]
newDeclarativeEnvironment(bodyScope, mv);
Variable<DeclarativeEnvironmentRecord> classPrivateEnvRec = mv.newVariable("classPrivateEnvRec", DeclarativeEnvironmentRecord.class);
getEnvRec(classPrivateEnvRec, mv);
HashSet<Name> declaredPrivateNames = new HashSet<>();
for (Name name : privateBoundNames) {
// FIXME: spec bug - missing check for already declared private names for getter/setter pairs
if (declaredPrivateNames.add(name)) {
BindingOp<DeclarativeEnvironmentRecord> op = BindingOp.of(classPrivateEnvRec, name);
op.createImmutableBinding(classPrivateEnvRec, name, true, mv);
}
}
// stack: [classPrivateEnv] -> []
pushLexicalEnvironment(mv);
}
mv.enterScope(bodyScope);
}
// steps 8-9
// stack: [constructorParent, proto] -> [constructorParent, proto, <rti>]
MethodName method = mv.compile(def, codegen::classDefinition);
// Runtime Semantics: Evaluation -> MethodDefinition
mv.invoke(method);
// step 10 (not applicable)
// steps 11-18
// stack: [constructorParent, proto, <rti>] -> [F]
mv.iconst(classHeritage != null);
mv.loadExecutionContext();
mv.lineInfo(def);
mv.invoke(Methods.ClassOperations_EvaluateConstructorMethod);
// stack: [F] -> []
Variable<OrdinaryConstructorFunction> F = mv.newVariable("F", OrdinaryConstructorFunction.class);
mv.store(F);
// steps 19-21
ClassPropertyGenerator.Result result = ClassPropertyEvaluation(codegen, def, F, proto, mv);
Variable<Object[]> methodDecorators = result.methodDecorators;
if (!classDecoratorsList.isEmpty()) {
int index = 0;
for (Expression decorator : classDecoratorsList) {
mv.aload(classDecorators, index++, Types.Callable);
invokeDynamicCall(mv, decorator, mv.executionContext(), mv.undefinedValue(), F);
mv.pop();
}
}
if (methodDecorators != null) {
LabelledHashKey hashKey = new LabelledHashKey(def, "decorators");
MethodName decoratorsMethod = mv.compile(hashKey, () -> classMethodDecorators(def, mv));
// 0 = hint for stacktraces to omit this frame
mv.lineInfo(0);
mv.invoke(decoratorsMethod, mv.executionContext(), F, proto, methodDecorators);
}
if (scope != null) {
// steps 22-23 (moved)
if (className != null) {
// stack: [] -> []
Name innerName = scope.resolveName(className);
BindingOp<DeclarativeEnvironmentRecord> op = BindingOp.of(classScopeEnvRec, innerName);
op.initializeBinding(classScopeEnvRec, innerName, F, mv);
}
}
if (result.instanceClassField != null || result.instanceClassMethods != null) {
MethodName initializer = compileClassFieldInitializer(def, MethodDefinition.MethodAllocation.Prototype, mv);
// stack: [] -> [F]
mv.load(F);
// stack: [F] -> [F, initializer]
mv.load(proto);
mv.invoke(initializer);
if (result.instanceClassField != null) {
mv.load(result.instanceClassField);
} else {
mv.anull();
}
if (result.instanceClassMethods != null) {
mv.load(result.instanceClassMethods);
} else {
mv.anull();
}
mv.loadExecutionContext();
mv.invoke(Methods.ClassOperations_CreateClassFieldInitializer);
// stack: [F, initializer] -> []
mv.invoke(Methods.ClassOperations_setInstanceFieldsInitializer);
}
// Class fields: Call InitializeStaticFields.
if (result.staticClassField != null) {
MethodName initializer = compileClassFieldInitializer(def, MethodDefinition.MethodAllocation.Class, mv);
// stack: [] -> [staticInitializer]
mv.load(F);
mv.invoke(initializer);
mv.load(result.staticClassField);
mv.loadExecutionContext();
mv.invoke(Methods.ClassOperations_CreateStaticClassFieldInitializer);
// stack: [staticInitializer] -> []
invokeDynamicCall(mv, def, mv.executionContext(), F);
mv.pop(ValType.Any);
}
if (bodyScope != null) {
mv.exitScope();
if (bodyScope.isPresent()) {
popLexicalEnvironment(mv);
}
}
if (scope != null) {
mv.exitScope();
if (scope.isPresent()) {
popLexicalEnvironment(mv);
}
}
// stack: [] -> [F]
mv.load(F);
mv.exitVariableScope();
// step 24 (return F)
mv.exitClassDefinition();
}
Aggregations