Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(566)

Side by Side Diff: pkg/compiler/lib/src/ssa/builder.dart

Issue 1318043005: Support user generated custom native JS classes. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: PTAL Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of ssa; 5 part of ssa;
6 6
7 class SsaFunctionCompiler implements FunctionCompiler { 7 class SsaFunctionCompiler implements FunctionCompiler {
8 final SsaCodeGeneratorTask generator; 8 final SsaCodeGeneratorTask generator;
9 final SsaBuilderTask builder; 9 final SsaBuilderTask builder;
10 final SsaOptimizerTask optimizer; 10 final SsaOptimizerTask optimizer;
(...skipping 1279 matching lines...) Expand 10 before | Expand all | Expand 10 after
1290 Selector selector, 1290 Selector selector,
1291 TypeMask mask, 1291 TypeMask mask,
1292 List<HInstruction> providedArguments, 1292 List<HInstruction> providedArguments,
1293 ast.Node currentNode, 1293 ast.Node currentNode,
1294 {InterfaceType instanceType}) { 1294 {InterfaceType instanceType}) {
1295 // TODO(johnniwinther): Register this on the [registry]. Currently the 1295 // TODO(johnniwinther): Register this on the [registry]. Currently the
1296 // [CodegenRegistry] calls the enqueuer, but [element] should _not_ be 1296 // [CodegenRegistry] calls the enqueuer, but [element] should _not_ be
1297 // enqueued. 1297 // enqueued.
1298 backend.registerStaticUse(element, compiler.enqueuer.codegen); 1298 backend.registerStaticUse(element, compiler.enqueuer.codegen);
1299 1299
1300 if (element.isJsInterop && !element.isFactoryConstructor) {
1301 // We only inline factory JavaScript interop constructors.
1302 return false;
1303 }
1304
1300 // Ensure that [element] is an implementation element. 1305 // Ensure that [element] is an implementation element.
1301 element = element.implementation; 1306 element = element.implementation;
1302 1307
1303 if (compiler.elementHasCompileTimeError(element)) return false; 1308 if (compiler.elementHasCompileTimeError(element)) return false;
1304 1309
1305 FunctionElement function = element; 1310 FunctionElement function = element;
1306 bool insideLoop = loopNesting > 0 || graph.calledInLoop; 1311 bool insideLoop = loopNesting > 0 || graph.calledInLoop;
1307 1312
1308 // Bail out early if the inlining decision is in the cache and we can't 1313 // Bail out early if the inlining decision is in the cache and we can't
1309 // inline (no need to check the hard constraints). 1314 // inline (no need to check the hard constraints).
(...skipping 10 matching lines...) Expand all
1320 Elements.isStaticOrTopLevel(element) || 1325 Elements.isStaticOrTopLevel(element) ||
1321 element.isGenerativeConstructorBody, 1326 element.isGenerativeConstructorBody,
1322 message: "Missing selector for inlining of $element.")); 1327 message: "Missing selector for inlining of $element."));
1323 if (selector != null) { 1328 if (selector != null) {
1324 if (!selector.applies(function, compiler.world)) return false; 1329 if (!selector.applies(function, compiler.world)) return false;
1325 if (mask != null && !mask.canHit(function, selector, compiler.world)) { 1330 if (mask != null && !mask.canHit(function, selector, compiler.world)) {
1326 return false; 1331 return false;
1327 } 1332 }
1328 } 1333 }
1329 1334
1335 if (element.isJsInterop) return false;
1336
1330 // Don't inline operator== methods if the parameter can be null. 1337 // Don't inline operator== methods if the parameter can be null.
1331 if (element.name == '==') { 1338 if (element.name == '==') {
1332 if (element.enclosingClass != compiler.objectClass 1339 if (element.enclosingClass != compiler.objectClass
1333 && providedArguments[1].canBeNull()) { 1340 && providedArguments[1].canBeNull()) {
1334 return false; 1341 return false;
1335 } 1342 }
1336 } 1343 }
1337 1344
1338 // Generative constructors of native classes should not be called directly 1345 // Generative constructors of native classes should not be called directly
1339 // and have an extra argument that causes problems with inlining. 1346 // and have an extra argument that causes problems with inlining.
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
1495 sourceInformationBuilder = 1502 sourceInformationBuilder =
1496 sourceInformationBuilder.forContext(element.implementation); 1503 sourceInformationBuilder.forContext(element.implementation);
1497 sourceElementStack.add(element.declaration); 1504 sourceElementStack.add(element.declaration);
1498 var result = f(); 1505 var result = f();
1499 sourceInformationBuilder = oldSourceInformationBuilder; 1506 sourceInformationBuilder = oldSourceInformationBuilder;
1500 sourceElementStack.removeLast(); 1507 sourceElementStack.removeLast();
1501 return result; 1508 return result;
1502 }); 1509 });
1503 } 1510 }
1504 1511
1512 /**
1513 * Return null so it is simple to remove the optional parameters completely
1514 * from interop methods to match JavaScript semantics for ommitted arguments.
1515 */
1516 HInstruction handleConstantForOptionalParameterJsInterop(Element parameter) =>
1517 null;
1518
1505 HInstruction handleConstantForOptionalParameter(Element parameter) { 1519 HInstruction handleConstantForOptionalParameter(Element parameter) {
1506 ConstantValue constantValue = 1520 ConstantValue constantValue =
1507 backend.constants.getConstantValueForVariable(parameter); 1521 backend.constants.getConstantValueForVariable(parameter);
1508 assert(invariant(parameter, constantValue != null, 1522 assert(invariant(parameter, constantValue != null,
1509 message: 'No constant computed for $parameter')); 1523 message: 'No constant computed for $parameter'));
1510 return graph.addConstant(constantValue, compiler); 1524 return graph.addConstant(constantValue, compiler);
1511 } 1525 }
1512 1526
1513 Element get currentNonClosureClass { 1527 Element get currentNonClosureClass {
1514 ClassElement cls = sourceElement.enclosingClass; 1528 ClassElement cls = sourceElement.enclosingClass;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
1589 /** 1603 /**
1590 * Documentation wanted -- johnniwinther 1604 * Documentation wanted -- johnniwinther
1591 * 1605 *
1592 * Invariant: [functionElement] must be an implementation element. 1606 * Invariant: [functionElement] must be an implementation element.
1593 */ 1607 */
1594 HGraph buildMethod(FunctionElement functionElement) { 1608 HGraph buildMethod(FunctionElement functionElement) {
1595 assert(invariant(functionElement, functionElement.isImplementation)); 1609 assert(invariant(functionElement, functionElement.isImplementation));
1596 graph.calledInLoop = compiler.world.isCalledInLoop(functionElement); 1610 graph.calledInLoop = compiler.world.isCalledInLoop(functionElement);
1597 ast.FunctionExpression function = functionElement.node; 1611 ast.FunctionExpression function = functionElement.node;
1598 assert(function != null); 1612 assert(function != null);
1599 assert(!function.modifiers.isExternal);
1600 assert(elements.getFunctionDefinition(function) != null); 1613 assert(elements.getFunctionDefinition(function) != null);
1601 openFunction(functionElement, function); 1614 openFunction(functionElement, function);
1602 String name = functionElement.name; 1615 String name = functionElement.name;
1616 if (functionElement.isJsInterop) {
1617 push(invokeJsInteropFunction(functionElement, parameters.values.toList(),
1618 sourceInformationBuilder.buildGeneric(function)));
1619 var value = pop();
1620 closeAndGotoExit(new HReturn(value,
1621 sourceInformationBuilder.buildReturn(functionElement.node)));
1622 return closeFunction();
1623 } else if (function.modifiers.isExternal) {
1624 compiler.reportError(
1625 function, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
1626 }
1627
1603 // If [functionElement] is `operator==` we explicitely add a null check at 1628 // If [functionElement] is `operator==` we explicitely add a null check at
1604 // the beginning of the method. This is to avoid having call sites do the 1629 // the beginning of the method. This is to avoid having call sites do the
1605 // null check. 1630 // null check.
1606 if (name == '==') { 1631 if (name == '==') {
1607 if (!backend.operatorEqHandlesNullArgument(functionElement)) { 1632 if (!backend.operatorEqHandlesNullArgument(functionElement)) {
1608 handleIf( 1633 handleIf(
1609 function, 1634 function,
1610 visitCondition: () { 1635 visitCondition: () {
1611 HParameterValue parameter = parameters.values.first; 1636 HParameterValue parameter = parameters.values.first;
1612 push(new HIdentity( 1637 push(new HIdentity(
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
1774 returnType = state.oldReturnType; 1799 returnType = state.oldReturnType;
1775 assert(stack.isEmpty); 1800 assert(stack.isEmpty);
1776 stack = state.oldStack; 1801 stack = state.oldStack;
1777 } 1802 }
1778 1803
1779 /** 1804 /**
1780 * Run this builder on the body of the [function] to be inlined. 1805 * Run this builder on the body of the [function] to be inlined.
1781 */ 1806 */
1782 void visitInlinedFunction(FunctionElement function) { 1807 void visitInlinedFunction(FunctionElement function) {
1783 potentiallyCheckInlinedParameterTypes(function); 1808 potentiallyCheckInlinedParameterTypes(function);
1809
1784 if (function.isGenerativeConstructor) { 1810 if (function.isGenerativeConstructor) {
1785 buildFactory(function); 1811 buildFactory(function);
1786 } else { 1812 } else {
1787 ast.FunctionExpression functionNode = function.node; 1813 ast.FunctionExpression functionNode = function.node;
1788 functionNode.body.accept(this); 1814 functionNode.body.accept(this);
1789 } 1815 }
1790 } 1816 }
1791 1817
1792 1818
1793 addInlinedInstantiation(DartType type) { 1819 addInlinedInstantiation(DartType type) {
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
2077 * current constructor and super constructors or constructors redirected 2103 * current constructor and super constructors or constructors redirected
2078 * to, starting from the current constructor. 2104 * to, starting from the current constructor.
2079 * - Call the constructor bodies, starting from the constructor(s) in the 2105 * - Call the constructor bodies, starting from the constructor(s) in the
2080 * super class(es). 2106 * super class(es).
2081 */ 2107 */
2082 HGraph buildFactory(ConstructorElement functionElement) { 2108 HGraph buildFactory(ConstructorElement functionElement) {
2083 functionElement = functionElement.implementation; 2109 functionElement = functionElement.implementation;
2084 ClassElement classElement = 2110 ClassElement classElement =
2085 functionElement.enclosingClass.implementation; 2111 functionElement.enclosingClass.implementation;
2086 bool isNativeUpgradeFactory = 2112 bool isNativeUpgradeFactory =
2087 Elements.isNativeOrExtendsNative(classElement); 2113 Elements.isNativeOrExtendsNative(classElement)
2114 && !classElement.isJsInterop;
2088 ast.FunctionExpression function = functionElement.node; 2115 ast.FunctionExpression function = functionElement.node;
2089 // Note that constructors (like any other static function) do not need 2116 // Note that constructors (like any other static function) do not need
2090 // to deal with optional arguments. It is the callers job to provide all 2117 // to deal with optional arguments. It is the callers job to provide all
2091 // arguments as if they were positional. 2118 // arguments as if they were positional.
2092 2119
2093 if (inliningStack.isEmpty) { 2120 if (inliningStack.isEmpty) {
2094 // The initializer list could contain closures. 2121 // The initializer list could contain closures.
2095 openFunction(functionElement, function); 2122 openFunction(functionElement, function);
2096 } 2123 }
2097 2124
(...skipping 1758 matching lines...) Expand 10 before | Expand all | Expand 10 after
3856 3883
3857 HInstruction compileArgument(ast.Node argument) { 3884 HInstruction compileArgument(ast.Node argument) {
3858 visit(argument); 3885 visit(argument);
3859 return pop(); 3886 return pop();
3860 } 3887 }
3861 3888
3862 return callStructure.makeArgumentsList( 3889 return callStructure.makeArgumentsList(
3863 arguments, 3890 arguments,
3864 element, 3891 element,
3865 compileArgument, 3892 compileArgument,
3866 handleConstantForOptionalParameter); 3893 element.isJsInterop ?
3894 handleConstantForOptionalParameterJsInterop :
3895 handleConstantForOptionalParameter
3896 );
3867 } 3897 }
3868 3898
3869 void addGenericSendArgumentsToList(Link<ast.Node> link, List<HInstruction> lis t) { 3899 void addGenericSendArgumentsToList(Link<ast.Node> link, List<HInstruction> lis t) {
3870 for (; !link.isEmpty; link = link.tail) { 3900 for (; !link.isEmpty; link = link.tail) {
3871 visit(link.head); 3901 visit(link.head);
3872 list.add(pop()); 3902 list.add(pop());
3873 } 3903 }
3874 } 3904 }
3875 3905
3876 /// Generate a dynamic method, getter or setter invocation. 3906 /// Generate a dynamic method, getter or setter invocation.
(...skipping 1114 matching lines...) Expand 10 before | Expand all | Expand 10 after
4991 5021
4992 if (compiler.elementHasCompileTimeError(constructor)) { 5022 if (compiler.elementHasCompileTimeError(constructor)) {
4993 // TODO(ahe): Do something like [generateWrongArgumentCountError]. 5023 // TODO(ahe): Do something like [generateWrongArgumentCountError].
4994 stack.add(graph.addConstantNull(compiler)); 5024 stack.add(graph.addConstantNull(compiler));
4995 return; 5025 return;
4996 } 5026 }
4997 if (checkTypeVariableBounds(node, type)) return; 5027 if (checkTypeVariableBounds(node, type)) return;
4998 5028
4999 var inputs = <HInstruction>[]; 5029 var inputs = <HInstruction>[];
5000 if (constructor.isGenerativeConstructor && 5030 if (constructor.isGenerativeConstructor &&
5001 Elements.isNativeOrExtendsNative(constructor.enclosingClass)) { 5031 Elements.isNativeOrExtendsNative(constructor.enclosingClass) &&
5032 !constructor.isJsInterop) {
5002 // Native class generative constructors take a pre-constructed object. 5033 // Native class generative constructors take a pre-constructed object.
5003 inputs.add(graph.addConstantNull(compiler)); 5034 inputs.add(graph.addConstantNull(compiler));
5004 } 5035 }
5005 // TODO(5347): Try to avoid the need for calling [implementation] before 5036 // TODO(5347): Try to avoid the need for calling [implementation] before
5006 // calling [makeStaticArgumentList]. 5037 // calling [makeStaticArgumentList].
5007 constructorImplementation = constructor.implementation; 5038 constructorImplementation = constructor.implementation;
5008 if (constructorImplementation.isErroneous || 5039 if (constructorImplementation.isErroneous ||
5009 !callStructure.signatureApplies( 5040 !callStructure.signatureApplies(
5010 constructorImplementation.functionSignature)) { 5041 constructorImplementation.functionSignature)) {
5011 generateWrongArgumentCountError(send, constructor, send.arguments); 5042 generateWrongArgumentCountError(send, constructor, send.arguments);
(...skipping 707 matching lines...) Expand 10 before | Expand all | Expand 10 after
5719 push( 5750 push(
5720 new HInvokeDynamicSetter(selector, mask, null, inputs, type) 5751 new HInvokeDynamicSetter(selector, mask, null, inputs, type)
5721 ..sourceInformation = sourceInformation); 5752 ..sourceInformation = sourceInformation);
5722 } else { 5753 } else {
5723 push( 5754 push(
5724 new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted) 5755 new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted)
5725 ..sourceInformation = sourceInformation); 5756 ..sourceInformation = sourceInformation);
5726 } 5757 }
5727 } 5758 }
5728 5759
5760 HForeignCode invokeJsInteropFunction(Element element,
5761 List<HInstruction> arguments,
5762 SourceInformation sourceInformation) {
5763 assert(element.isJsInterop);
5764 nativeEmitter.nativeMethods.add(element);
5765 String templateString;
5766
5767 if (element.isFactoryConstructor) {
5768 // Treat factory constructors as syntactic sugar for creating object
5769 // literals.
5770 ConstructorElement constructor = element;
5771 FunctionSignature params = constructor.functionSignature;
5772 int i = 0;
5773 int positions = 0;
5774 var filteredArguments = <HInstruction>[];
5775 var parameterNameMap = new Map<String, js.Expression>();
5776 params.orderedForEachParameter((ParameterElement parameter) {
5777 // TODO(jacobr): throw if parameter names do not match names of property
5778 // names in the class.
5779 assert (parameter.isNamed);
5780 if (!parameter.isNamed) {
5781 compiler.reportError(
5782 parameter, MessageKind.GENERIC,
5783 {'text': 'Error: all arguments to external constructors of'
5784 'JavaScript interop classes must be named as these'
5785 'constructors are syntactic sugar for object literals'});
5786 }
5787 HInstruction argument = arguments[i];
5788 if (argument != null) {
5789 filteredArguments.add(argument);
5790 parameterNameMap[parameter.name] =
5791 new js.InterpolatedExpression(positions++);
5792 }
5793 i++;
5794 });
5795 var codeTemplate = new js.Template(null,
5796 js.objectLiteral(parameterNameMap));
5797
5798 var nativeBehavior = new native.NativeBehavior()
5799 ..codeTemplate = codeTemplate;
5800 return new HForeignCode(
5801 codeTemplate,
5802 backend.dynamicType, filteredArguments,
5803 nativeBehavior: nativeBehavior)
5804 ..sourceInformation = sourceInformation;
5805 }
5806 var target = new HForeignCode(js.js.parseForeignJS(
5807 "${backend.namer.fixedBackendPath(element)}."
5808 "${element.fixedBackendName}"),
5809 backend.dynamicType,
5810 <HInstruction>[]);
5811 add(target);
5812 // Strip off trailing arguments that were not specified.
5813 // we could assert that the trailing arguments are all null.
5814 // TODO(jacobr): rewrite named arguments to an object literal matching
5815 // the factory constructor case.
5816 arguments = arguments.where((arg) => arg != null).toList();
5817 var inputs = <HInstruction>[target]..addAll(arguments);
5818
5819 js.Template codeTemplate;
5820 if (element.isGetter) {
5821 codeTemplate = js.js.parseForeignJS("#");
5822 } else if (element.isSetter) {
5823 codeTemplate = js.js.parseForeignJS("# = #");
5824 } else {
5825 var argsStub = <String>[];
5826 for (int i = 0; i < arguments.length; i++) {
5827 argsStub.add('#');
5828 }
5829 if (element.isConstructor) {
5830 codeTemplate = js.js.parseForeignJS("new #(${argsStub.join(",")})");
5831 } else {
5832 codeTemplate = js.js.parseForeignJS("#(${argsStub.join(",")})");
5833 }
5834 }
5835
5836 var nativeBehavior = new native.NativeBehavior()
5837 ..codeTemplate = codeTemplate
5838 ..typesReturned.add(
5839 backend.jsPlainJavaScriptObjectClass.computeType(compiler))
5840 ..typesInstantiated.add(
5841 backend.jsPlainJavaScriptObjectClass.computeType(compiler))
5842 ..sideEffects.setAllSideEffects();
5843 return new HForeignCode(
5844 codeTemplate,
5845 backend.dynamicType, inputs,
5846 nativeBehavior: nativeBehavior)
5847 ..sourceInformation = sourceInformation;
5848 }
5849
5729 void pushInvokeStatic(ast.Node location, 5850 void pushInvokeStatic(ast.Node location,
5730 Element element, 5851 Element element,
5731 List<HInstruction> arguments, 5852 List<HInstruction> arguments,
5732 {TypeMask typeMask, 5853 {TypeMask typeMask,
5733 InterfaceType instanceType, 5854 InterfaceType instanceType,
5734 SourceInformation sourceInformation}) { 5855 SourceInformation sourceInformation}) {
5735 // TODO(johnniwinther): Use [sourceInformation] instead of [location]. 5856 // TODO(johnniwinther): Use [sourceInformation] instead of [location].
5736 if (tryInlineMethod(element, null, null, arguments, location, 5857 if (tryInlineMethod(element, null, null, arguments, location,
5737 instanceType: instanceType)) { 5858 instanceType: instanceType)) {
5738 return; 5859 return;
5739 } 5860 }
5740 5861
5741 if (typeMask == null) { 5862 if (typeMask == null) {
5742 typeMask = 5863 typeMask =
5743 TypeMaskFactory.inferredReturnTypeForElement(element, compiler); 5864 TypeMaskFactory.inferredReturnTypeForElement(element, compiler);
5744 } 5865 }
5745 bool targetCanThrow = !compiler.world.getCannotThrow(element); 5866 bool targetCanThrow = !compiler.world.getCannotThrow(element);
5746 // TODO(5346): Try to avoid the need for calling [declaration] before 5867 // TODO(5346): Try to avoid the need for calling [declaration] before
5747 // creating an [HInvokeStatic]. 5868 var instruction;
5748 HInvokeStatic instruction = new HInvokeStatic( 5869 if (element.isJsInterop) {
5749 element.declaration, arguments, typeMask, 5870 instruction = invokeJsInteropFunction(element, arguments,
5750 targetCanThrow: targetCanThrow) 5871 sourceInformation);
5751 ..sourceInformation = sourceInformation; 5872 } else {
5752 if (!currentInlinedInstantiations.isEmpty) { 5873 // creating an [HInvokeStatic].
5753 instruction.instantiatedTypes = new List<DartType>.from( 5874 instruction = new HInvokeStatic(
5754 currentInlinedInstantiations); 5875 element.declaration, arguments, typeMask,
5876 targetCanThrow: targetCanThrow)
5877 ..sourceInformation = sourceInformation;
5878 if (!currentInlinedInstantiations.isEmpty) {
5879 instruction.instantiatedTypes = new List<DartType>.from(
5880 currentInlinedInstantiations);
5881 }
5882 instruction.sideEffects = compiler.world.getSideEffectsOfElement(element);
5755 } 5883 }
5756 instruction.sideEffects = compiler.world.getSideEffectsOfElement(element);
5757 if (location == null) { 5884 if (location == null) {
5758 push(instruction); 5885 push(instruction);
5759 } else { 5886 } else {
5760 pushWithPosition(instruction, location); 5887 pushWithPosition(instruction, location);
5761 } 5888 }
5762 } 5889 }
5763 5890
5764 HInstruction buildInvokeSuper(Selector selector, 5891 HInstruction buildInvokeSuper(Selector selector,
5765 Element element, 5892 Element element,
5766 List<HInstruction> arguments, 5893 List<HInstruction> arguments,
(...skipping 3159 matching lines...) Expand 10 before | Expand all | Expand 10 after
8926 if (unaliased is TypedefType) throw 'unable to unalias $type'; 9053 if (unaliased is TypedefType) throw 'unable to unalias $type';
8927 unaliased.accept(this, builder); 9054 unaliased.accept(this, builder);
8928 } 9055 }
8929 9056
8930 void visitDynamicType(DynamicType type, SsaBuilder builder) { 9057 void visitDynamicType(DynamicType type, SsaBuilder builder) {
8931 JavaScriptBackend backend = builder.compiler.backend; 9058 JavaScriptBackend backend = builder.compiler.backend;
8932 ClassElement cls = backend.findHelper('DynamicRuntimeType'); 9059 ClassElement cls = backend.findHelper('DynamicRuntimeType');
8933 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); 9060 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld)));
8934 } 9061 }
8935 } 9062 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698