 Chromium Code Reviews
 Chromium Code Reviews Issue 10911062:
  Codegen support for the argument definition test.  (Closed) 
  Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
    
  
    Issue 10911062:
  Codegen support for the argument definition test.  (Closed) 
  Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/| Index: lib/compiler/implementation/ssa/builder.dart | 
| =================================================================== | 
| --- lib/compiler/implementation/ssa/builder.dart (revision 11792) | 
| +++ lib/compiler/implementation/ssa/builder.dart (working copy) | 
| @@ -806,13 +806,14 @@ | 
| LocalsHandler localsHandler; | 
| HInstruction rethrowableException; | 
| Map<Element, HParameterValue> parameters; | 
| + Map<Element, HInstruction> parametersWithSentinel; | 
| Map<TargetElement, JumpHandler> jumpTargets; | 
| /** | 
| * Variables stored in the current activation. These variables are | 
| * being updated in try/catch blocks, and should be | 
| - * accessed indirectly through HFieldGet and HFieldSet. | 
| + * accessed indirectly through [HLocalGet] and [HLocalSet]. | 
| */ | 
| Map<Element, HLocalValue> activationVariables; | 
| @@ -841,6 +842,7 @@ | 
| activationVariables = new Map<Element, HLocalValue>(), | 
| jumpTargets = new Map<TargetElement, JumpHandler>(), | 
| parameters = new Map<Element, HParameterValue>(), | 
| + parametersWithSentinel = new Map<Element, HInstruction>(), | 
| inliningStack = <InliningState>[], | 
| super(work.resolutionTree) { | 
| localsHandler = new LocalsHandler(this); | 
| @@ -1226,6 +1228,59 @@ | 
| return closeFunction(); | 
| } | 
| + void addParameterCheckInstruction(Element element) { | 
| + // This is the code we emit for a parameter that is being checked | 
| + // on whether it was given at value at the call site: | 
| + // | 
| + // foo([a = 42) { | 
| + // if (?a) print('parameter passed $a'); | 
| + // } | 
| + // | 
| + // foo([a = 42]) { | 
| + // var t1 = a === sentinel; | 
| + // if (t1) a = 42; | 
| + // if (!t1) print('parameter passed ' + a); | 
| + // } | 
| + | 
| + // Fetch the original default value of [element]; | 
| + ConstantHandler handler = compiler.constantHandler; | 
| + Constant constant = handler.compileVariable(element); | 
| + HConstant defaultValue = constant == null | 
| + ? graph.addConstantNull() | 
| + : graph.addConstant(constant); | 
| + | 
| + // Emit the equality check with the sentinel. | 
| + HConstant sentinel = graph.addConstant(SentinelConstant.SENTINEL); | 
| + Element equalsHelper = interceptors.getTripleEqualsInterceptor(); | 
| + HInstruction target = new HStatic(equalsHelper); | 
| + add(target); | 
| + HInstruction operand = parameters[element]; | 
| + HInstruction check = new HIdentity(target, sentinel, operand); | 
| + add(check); | 
| + | 
| + // If the check succeeds, we must update the parameter with the | 
| + // default value. | 
| + handleIf(element.parseNode(compiler), | 
| + () => stack.add(check), | 
| + () => localsHandler.updateLocal(element, defaultValue), | 
| + null); | 
| + | 
| + // Create the instruction that parameter checks will use. | 
| + check = new HNot(check); | 
| + add(check); | 
| + | 
| + // If the parameter check is also used by closures, | 
| + // we need to update the closure field holding that check. | 
| + ClosureClassMap closureData = localsHandler.closureData; | 
| + Element redirect = closureData.parametersWithSentinel[element]; | 
| + if (redirect != null) { | 
| + localsHandler.updateLocal(redirect, check); | 
| + } | 
| + // Cache the check so that uses in this method share the same | 
| + // check instruction. | 
| + parametersWithSentinel[element] = check; | 
| + } | 
| + | 
| void openFunction(FunctionElement functionElement, | 
| FunctionExpression node) { | 
| HBasicBlock block = graph.addNewBlock(); | 
| @@ -1236,11 +1291,17 @@ | 
| open(block); | 
| + FunctionSignature params = functionElement.computeSignature(compiler); | 
| + params.forEachParameter((Element element) { | 
| + if (elements.isParameterChecked(element)) { | 
| + addParameterCheckInstruction(element); | 
| + } | 
| + }); | 
| + | 
| // Put the type checks in the first successor of the entry, | 
| // because that is where the type guards will also be inserted. | 
| // This way we ensure that a type guard will dominate the type | 
| // check. | 
| - FunctionSignature params = functionElement.computeSignature(compiler); | 
| params.forEachParameter((Element element) { | 
| HInstruction newParameter = potentiallyCheckType( | 
| localsHandler.directLocals[element], element); | 
| @@ -1780,8 +1841,24 @@ | 
| void visitUnary(Send node, Operator op) { | 
| String value = op.source.stringValue; | 
| if (value === '?') { | 
| 
kasperl
2012/09/04 10:50:08
node.isParameterCheck?
 
ngeoffray
2012/09/04 10:53:44
Done.
 | 
| - // TODO(ahe): Implement argument definition test. | 
| - stack.add(graph.addConstantBool(true)); | 
| + Element element = elements[node.receiver]; | 
| + // If the parameter we're accessing is from the current | 
| + // function, we can just fetch the cached instruction. | 
| + HInstruction check = parametersWithSentinel[element]; | 
| + if (check !== null) { | 
| + stack.add(check); | 
| + } else { | 
| + // The parameter is from an outer function. Lookup the | 
| + // element in the closure data of the outer function and read | 
| + // it. | 
| + assert(element.enclosingElement != work.element); | 
| + Node node = element.enclosingElement.parseNode(compiler); | 
| + ClosureClassMap parameterClosureData = | 
| + compiler.closureToClassMapper.getMappingForNestedFunction(node); | 
| + Element fieldCheck = | 
| + parameterClosureData.parametersWithSentinel[element]; | 
| + stack.add(localsHandler.readLocal(fieldCheck)); | 
| + } | 
| return; | 
| } | 
| assert(node.argumentsNode is Prefix); | 
| @@ -2165,8 +2242,15 @@ | 
| return pop(); | 
| } | 
| - HInstruction compileConstant(Element constantElement) { | 
| - Constant constant = compiler.compileVariable(constantElement); | 
| + HInstruction compileConstant(Element parameter) { | 
| + Constant constant; | 
| + TreeElements calleeElements = | 
| + compiler.enqueuer.resolution.getCachedElements(element); | 
| + if (calleeElements.isParameterChecked(parameter)) { | 
| + constant = SentinelConstant.SENTINEL; | 
| + } else { | 
| + constant = compiler.compileVariable(parameter); | 
| + } | 
| return graph.addConstant(constant); | 
| } | 
| @@ -3669,7 +3753,11 @@ | 
| tooDifficult = true; | 
| } | 
| - void visitSend(Node node) { | 
| + void visitSend(Send node) { | 
| + if (node.isParameterCheck) { | 
| + tooDifficult = true; | 
| + return; | 
| + } | 
| node.visitChildren(this); | 
| } |