Skip to content

canonical binders or l2 cache sharing

Stéphane Lozier edited this page Jan 18, 2021 · 1 revision

18 Canonical Binders or L2 Cache Sharing

This section will briefly describe the DLR's caching for dynamic dispatch and explain the code that calls GetXBinder helpers rather than calling a SymplXBinder constructor. For a full discussion of caching, see sites-binders-dynobj-interop.doc on www.codeplex.com/dlr .

As described in section , when you use a DynamicExpression, the Expression Tree compiler creates a CallSite to cache rules for how to perform the CallSite's operation. The delegate that is stored in the CallSite's Target property is considered to be the L0 cache. When the rule in this delegate fails, the CallSite looks to the rules it has cached on the CallSite object (for now, up to ten such rules). These ten rules are considered to be the L1 cache.

When none of the rules seen previously by a CallSite match the current arguments, before the CallSite starts the binding search described in section , it looks at internal state of the binder attached to the CallSite. A binder instance caches up to 100 rules that it has produced. This is considered to be the L2 cache, and it can be shared across multiple CallSites. The idea is that, for example, any call site performing addition with the same metadata on the binder should share rules across an entire program. It is highly likely they are all just adding integers, strings, or a small number of combinations of argument types. Because producing a rule is expensive, you want to save that work once one call site has paid the price.

Sympl maps all binders with the same operation and metadata to a single such binder. It does this per Sympl runtime instance. Having canonical binders per Sympl runtime instance isn't really needed, but it is a good example of what real languages likely need to do. There might be global options per runtime instance, such as whether integers roll over to bignums, or whether division is truncating or float-producing, and so on.

The code for the GetXBinder methods is pretty straightforward. This section just makes a couple of points about how it creates canonical binders, but you can see the code in sympl.cs, which is well commented. You need to hash on the binder type's metadata, which is a little bit of work for InvokeMember binders. All the others just hash on the member name string or a CallInfo object (for which the DLR provides GetHashCode and Equals). For InvokeMember binders, you need to make a key class, InvokeMemberBinderKey, that holds a name and a CallInfo, and then implement GetHashCode and Equals.

Sympl hashes name strings with default .NET semantics and '==' equality, thus comparing case-senstively. The reason is that while Sympl is case-INsensitive, it is case-preserving in the binder metadata, as explained in section . This allows for more opportunity of language and library interoperability. Since a DynamicMetaObject might return a rule for looking up a member based on the case-sensitive spelling (that is, ignoring the ignoreCase metadata), Sympl needs to ensure no two CallSites with different spellings could share L2 rules.

SymPL Implementation on the Dynamic Language Runtime

Frontmatter
1 Introduction
  1.1 Sources
  1.2 Walkthrough Organization
2 Quick Language Overview
3 Walkthrough of Hello World
  3.1 Quick Code Overview
  3.2 Hosting, Globals, and .NET Namespaces Access
    3.2.1 DLR Dynamic Binding and Interoperability -- a Very Quick Description
    3.2.2 DynamicObjectHelpers
    3.2.3 TypeModels and TypeModelMetaObjects
    3.2.4 TypeModelMetaObject's BindInvokeMember -- Finding a Binding
    3.2.5 TypeModelMetaObject.BindInvokeMember -- Restrictions and Conversions
  3.3 Import Code Generation and File Module Scopes
  3.4 Function Call and Dotted Expression Code Generation
    3.4.1 Analyzing Function and Member Invocations
    3.4.2 Analyzing Dotted Expressions
    3.4.3 What Hello World Needs
  3.5 Identifier and File Globals Code Generation
  3.6 Sympl.ExecuteFile and Finally Running Code
4 Assignment to Globals and Locals
5 Function Definition and Dynamic Invocations
  5.1 Defining Functions
  5.2 SymplInvokeBinder and Binding Function Calls
6 CreateThrow Runtime Binding Helper
7 A Few Easy, Direct Translations to Expression Trees
  7.1 Let* Binding
  7.2 Lambda Expressions and Closures
  7.3 Conditional (IF) Expressions
  7.4 Eq Expressions
  7.5 Loop Expressions
8 Literal Expressions
  8.1 Integers and Strings
  8.2 Keyword Constants
  8.3 Quoted Lists and Symbols
    8.3.1 AnalyzeQuoteExpr -- Code Generation
    8.3.2 Cons and List Keyword Forms and Runtime Support
9 Importing Sympl Libraries and Accessing and Invoking Their Globals
10 Type instantiation
  10.1 New Keyword Form Code Generation
  10.2 Binding CreateInstance Operations in TypeModelMetaObject
  10.3 Binding CreateInstance Operations in FallbackCreateInstance
  10.4 Instantiating Arrays and GetRuntimeTypeMoFromModel
11 SymplGetMemberBinder and Binding .NET Instance Members
12 ErrorSuggestion Arguments to Binder FallbackX Methods
13 SymplSetMemberBinder and Binding .NET Instance Members
14 SymplInvokeMemberBinder and Binding .NET Member Invocations
  14.1 FallbackInvokeMember
  14.2 FallbackInvoke
15 Indexing Expressions: GetIndex and SetIndex
  15.1 SymplGetIndexBinder's FallbackGetIndex
  15.2 GetIndexingExpression
  15.3 SymplSetIndexBinder's FallbackSetIndex
16 Generic Type Instantiation
17 Arithmetic, Comparison, and Boolean Operators
  17.1 Analysis and Code Generation for Binary Operations
  17.2 Analysis and Code Generation for Unary Operations
  17.3 SymplBinaryOperationBinder
  17.4 SymplUnaryOperationBinder
18 Canonical Binders or L2 Cache Sharing
19 Binding COM Objects
20 Using Defer When MetaObjects Have No Value
21 SymPL Language Description
  21.1 High-level
  21.2 Lexical Aspects
  21.3 Built-in Types
  21.4 Control Flow
    21.4.1 Function Call
    21.4.2 Conditionals
    21.4.3 Loops
    21.4.4 Try/Catch/Finally and Throw
  21.5 Built-in Operations
  21.6 Globals, Scopes, and Import
    21.6.1 File Scopes and Import
    21.6.2 Lexical Scoping
    21.6.3 Closures
  21.7 Why No Classes
  21.8 Keywords
  21.9 Example Code (mostly from test.sympl)
22 Runtime and Hosting
  22.1 Class Summary
23 Appendixes
  23.1 Supporting the DLR Hosting APIs
    23.1.1 Main and Example Host Consumer
    23.1.2 Runtime.cs Changes
    23.1.3 Sympl.cs Changes
    23.1.4 Why Not Show Using ScriptRuntime.Globals Namespace Reflection
    23.1.5 The New DlrHosting.cs File
  23.2 Using the Codeplex.com DefaultBinder for rich .NET interop
  23.3 Using Codeplex.com Namespace/Type Trackers instead of ExpandoObjects
  23.4 Using Codeplex.com GeneratorFunctionExpression


Other documents:

Dynamic Language Runtime
DLR Hostirng Spec
Expression Trees v2 Spec
Getting Started with the DLR as a Library Author
Sites, Binders, and Dynamic Object Interop Spec

Clone this wiki locally