Version 1.10.0-dev.1.0
svn merge -r 44706:45051 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@45054 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..c4321b3
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,214 @@
+## 1.9.1 (2015-03-25)
+
+### Language changes
+
+* Support for `async`, `await`, `sync*`, `async*`, `yield`, `yield*`, and `await
+ for`. See the [the language tour][async] for more details.
+
+* Enum support is fully enabled. See [the language tour][enum] for more details.
+
+[async]: https://www.dartlang.org/docs/dart-up-and-running/ch02.html#asynchrony
+[enum]: https://www.dartlang.org/docs/dart-up-and-running/ch02.html#enums
+
+### Tool changes
+
+* The formatter is much more comprehensive and generates much more readable
+ code. See [its tool page][dartfmt] for more details.
+
+* The analysis server is integrated into the IntelliJ plugin and the Dart
+ editor. This allows analysis to run out-of-process, so that interaction
+ remains smooth even for large projects.
+
+* Analysis supports more and better hints, including unused variables and unused
+ private members.
+
+[dartfmt]: https://www.dartlang.org/tools/dartfmt/
+
+### Core library changes
+
+#### Highlights
+
+* There's a new model for shared server sockets with no need for a `Socket`
+ reference.
+
+* A new, much faster [regular expression engine][regexp].
+
+* The Isolate API now works across the VM and `dart2js`.
+
+[regexp]: http://news.dartlang.org/2015/02/irregexp-dart-vms-new-regexp.html
+
+#### Details
+
+For more information on any of these changes, see the corresponding
+documentation on the [Dart API site](http://api.dartlang.org).
+
+* `dart:async`:
+
+ * `Future.wait` added a new named argument, `cleanUp`, which is a callback
+ that releases resources allocated by a successful `Future`.
+
+ * The `SynchronousStreamController` class was added as an explicit name for
+ the type returned when the `sync` argument is passed to `new
+ StreamController`.
+
+* `dart:collection`: The `new SplayTreeSet.from(Iterable)` constructor was
+ added.
+
+* `dart:convert`: `Utf8Encoder.convert` and `Utf8Decoder.convert` added optional
+ `start` and `end` arguments.
+
+* `dart:core`:
+
+ * `RangeError` added new static helper functions: `checkNotNegative`,
+ `checkValidIndex`, `checkValidRange`, and `checkValueInInterval`.
+
+ * `int` added the `modPow` function.
+
+ * `String` added the `replaceFirstMapped` and `replaceRange` functions.
+
+* `dart:io`:
+
+ * Support for locking files to prevent concurrent modification was added. This
+ includes the `File.lock`, `File.lockSync`, `File.unlock`, and
+ `File.unlockSync` functions as well as the `FileLock` class.
+
+ * Support for starting detached processes by passing the named `mode` argument
+ (a `ProcessStartMode`) to `Process.start`. A process can be fully attached,
+ fully detached, or detached except for its standard IO streams.
+
+ * `HttpServer.bind` and `HttpServer.bindSecure` added the `v6Only` named
+ argument. If this is true, only IPv6 connections will be accepted.
+
+ * `HttpServer.bind`, `HttpServer.bindSecure`, `ServerSocket.bind`,
+ `RawServerSocket.bind`, `SecureServerSocket.bind` and
+ `RawSecureServerSocket.bind` added the `shared` named argument. If this is
+ true, multiple servers or sockets in the same Dart process may bind to the
+ same address, and incoming requests will automatically be distributed
+ between them.
+
+ * **Deprecation:** the experimental `ServerSocketReference` and
+ `RawServerSocketReference` classes, as well as getters that returned them,
+ are marked as deprecated. The `shared` named argument should be used
+ instead. These will be removed in Dart 1.10.
+
+ * `Socket.connect` and `RawSocket.connect` added the `sourceAddress` named
+ argument, which specifies the local address to bind when making a
+ connection.
+
+ * The static `Process.killPid` method was added to kill a process with a given
+ PID.
+
+ * `Stdout` added the `nonBlocking` instance property, which returns a
+ non-blocking `IOSink` that writes to standard output.
+
+* `dart:isolate`:
+
+ * The static getter `Isolate.current` was added.
+
+ * The `Isolate` methods `addOnExitListener`, `removeOnExitListener`,
+ `setErrorsFatal`, `addOnErrorListener`, and `removeOnErrorListener` now work
+ on the VM.
+
+ * Isolates spawned via `Isolate.spawn` now allow most objects, including
+ top-level and static functions, to be sent between them.
+
+## 1.8.5 (2015-01-21)
+
+* Code generation for SIMD on ARM and ARM64 is fixed.
+
+* A possible crash on MIPS with newer GCC toolchains has been prevented.
+
+* A segfault when using `rethrow` was fixed ([issue 21795][]).
+
+[issue 21795]: https://code.google.com/p/dart/issues/detail?id=21795
+
+## 1.8.3 (2014-12-10)
+
+* Breakpoints can be set in the Editor using file suffixes ([issue 21280][]).
+
+* IPv6 addresses are properly handled by `HttpClient` in `dart:io`, fixing a
+ crash in pub ([issue 21698][]).
+
+* Issues with the experimental `async`/`await` syntax have been fixed.
+
+* Issues with a set of number operations in the VM have been fixed.
+
+* `ListBase` in `dart:collection` always returns an `Iterable` with the correct
+ type argument.
+
+[issue 21280]: https://code.google.com/p/dart/issues/detail?id=21280
+[issue 21698]: https://code.google.com/p/dart/issues/detail?id=21698
+
+## 1.8.0 (2014-11-28)
+
+* `dart:collection`: `SplayTree` added the `toSet` function.
+
+* `dart:convert`: The `JsonUtf8Encoder` class was added.
+
+* `dart:core`:
+
+ * The `IndexError` class was added for errors caused by an index being outside
+ its expected range.
+
+ * The `new RangeError.index` constructor was added. It forwards to `new
+ IndexError`.
+
+ * `RangeError` added three new properties. `invalidProperty` is the value that
+ caused the error, and `start` and `end` are the minimum and maximum values
+ that the value is allowed to assume.
+
+ * `new RangeError.value` and `new RangeError.range` added an optional
+ `message` argument.
+
+ * The `new String.fromCharCodes` constructor added optional `start` and `end`
+ arguments.
+
+* `dart:io`:
+
+ * Support was added for the [Application-Layer Protocol Negotiation][alpn]
+ extension to the TLS protocol for both the client and server.
+
+ * `SecureSocket.connect`, `SecureServerSocket.bind`,
+ `RawSecureSocket.connect`, `RawSecureSocket.secure`,
+ `RawSecureSocket.secureServer`, and `RawSecureServerSocket.bind` added a
+ `supportedProtocols` named argument for protocol negotiation.
+
+ * `RawSecureServerSocket` added a `supportedProtocols` field.
+
+ * `RawSecureSocket` and `SecureSocket` added a `selectedProtocol` field which
+ contains the protocol selected during protocol negotiation.
+
+[alpn]: https://tools.ietf.org/html/rfc7301
+
+## 1.7.0 (2014-10-15)
+
+### Tool changes
+
+* `pub` now generates binstubs for packages that are globally activated so that
+ they can be put on the user's `PATH` and used as normal executables. See the
+ [`pub global activate` documentation][pub global activate].
+
+* When using `dart2js`, deferred loading now works with multiple Dart apps on
+ the same page.
+
+[pub global activate]: https://www.dartlang.org/tools/pub/cmd/pub-global.html#running-a-script-from-your-path
+
+### Core library changes
+
+* `dart:async`: `Zone`, `ZoneDelegate`, and `ZoneSpecification` added the
+ `errorCallback` function, which allows errors that have been programmatically
+ added to a `Future` or `Stream` to be intercepted.
+
+* `dart:io`:
+
+ * **Breaking change:** `HttpClient.close` must be called for all clients or
+ they will keep the Dart process alive until they time out. This fixes the
+ handling of persistent connections. Previously, the client would shut down
+ immediately after a request.
+
+ * **Breaking change:** `HttpServer` no longer compresses all traffic by
+ default. The new `autoCompress` property can be set to `true` to re-enable
+ compression.
+
+* `dart:isolate`: `Isolate.spawnUri` added the optional `packageRoot` argument,
+ which controls how it resolves `package:` URIs.
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index 502038c..9c1f568 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -37,7 +37,7 @@
A conforming implementation of the Dart programming language must provide and support all the APIs (libraries, types, functions, getters, setters, whether top-level, static, instance or local) mandated in this specification.
\LMHash{}
-A conforming implementation is permitted to provide additional APIs, but not additional syntax.
+A conforming implementation is permitted to provide additional APIs, but not additional syntax, except for experimental features in support of null-aware cascades and tear-offs that are likely to be introduced in the next revision of this specification.
\section{Normative References}
\LMLabel{ecmaNormativeReferences}
@@ -2349,6 +2349,7 @@
literal;
identifier;
newExpression;
+ \NEW{} type `\#' (`{\escapegrammar .}' identifier)?;
constObjectExpression;
`(' expression `)'
.
@@ -3525,11 +3526,14 @@
}
\LMHash{}
-If $f$ is asynchronous then, when $f$ terminates, any open stream subscriptions associated with any asynchronous for loops (\ref{asynchronousFor-in}) or yield-each statements (\ref{yieldEach}) executing within $f$ are canceled.
+If $f$ is asynchronous then, when $f$ terminates, any open stream subscriptions associated with any asynchronous for loops (\ref{asynchronousFor-in}) or yield-each statements (\ref{yieldEach}) executing within $f$ are canceled, in the order of their nesting, innermost first.
\rationale{Such streams may be left open by for loops that were escaped when an exception was thrown within them for example.
}
+%\LMHash{}
+%When a stream is canceled, the implementation must wait for the cancelation future returned by \cd{cancell()} to complete before proceeding.
+
\LMHash{}
If $f$ is marked \SYNC* (\ref{functions}), then a fresh instance $i$ implementing the built-in class \code{Iterable} is associated with the invocation and immediately returned.
@@ -3775,12 +3779,30 @@
\LMLabel{ordinaryInvocation}
\LMHash{}
-An ordinary method invocation $i$ has the form
+An ordinary method invocation can be {\em conditional} or {\em unconditional}.
+
+\LMHash{}
+Evaluation of a {\em conditional ordinary method invocation} $e$ of the form
+
+\LMHash{}
+$o?.m(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$
+
+\LMHash{}
+is equivalent to the evaluation of the expression
+
+\LMHash{}
+$((x) => x == \NULL ? \NULL : x.m(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k}))(o)$.
+
+\LMHash{}
+The static type of $e$ is the same as the static type of $o.m(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$. Exactly the same static warnings that would be caused by $o.m(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$ are also generated in the case of $o?.m(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$.
+
+\LMHash{}
+An {\em unconditional ordinary method invocation} $i$ has the form
$o.m(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$.
\LMHash{}
-Evaluation of an ordinary method invocation $i$ of the form
+Evaluation of an unconditional ordinary method invocation $i$ of the form
$o.m(a_1, \ldots , a_n, x_{n+1}: a_{n+1}, \ldots , x_{n+k}: a_{n+k})$
@@ -3812,7 +3834,7 @@
If getter lookup has also failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that :
\begin{itemize}
\item \code{im.isMethod} evaluates to \code{\TRUE{}}.
-\item \code{im.memberName} evaluates to \code{'m'}.
+\item \code{im.memberName} evaluates to the symbol \code{m}.
\item \code{im.positionalArguments} evaluates to an immutable list with the same values as \code{[$o_1, \ldots, o_n$]}.
\item \code{im.namedArguments} evaluates to an immutable map with the same keys and values as \code{\{$x_{n+1}: o_{n+1}, \ldots, x_{n+k} : o_{n+k}$\}}.
\end{itemize}
@@ -3820,10 +3842,10 @@
\LMHash{}
Then the method \code{noSuchMethod()} is looked up in $v_o$ and invoked with argument $im$, and the result of this invocation is the result of evaluating $i$. However, if the implementation found cannot be invoked with a single positional argument, the implementation of \code{noSuchMethod()} in class \code{Object} is invoked on $v_o$ with argument $im'$, where $im'$ is an instance of \code{Invocation} such that :
\begin{itemize}
-\item \code{im.isMethod} evaluates to \code{\TRUE{}}.
-\item \code{im.memberName} evaluates to \code{noSuchMethod'}.
-\item \code{im.positionalArguments} evaluates to an immutable list whose sole element is $im$.
-\item \code{im.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
+\item \code{im'.isMethod} evaluates to \code{\TRUE{}}.
+\item \code{im'.memberName} evaluates to \code{\#noSuchMethod}.
+\item \code{im'.positionalArguments} evaluates to an immutable list whose sole element is $im$.
+\item \code{im'.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
\end{itemize}
and the result of the latter invocation is the result of evaluating $i$.
@@ -3876,6 +3898,12 @@
\LMHash{}
A cascaded method invocation expression of the form {\em e..suffix} is equivalent to the expression \code{(t)\{t.{\em suffix}; \RETURN{} t;\}($e$)}.
+\rationale{
+With the introduction of null-aware conditional assignable expressions (\ref{assignableExpressions}), it would make sense to extend cascades with a null-aware conditional form as well. One might define {\em e?..suffix} to be equivalent to the expression \code{(t)\{t?.{\em suffix}; \RETURN{} t;\}($e$)}.
+
+The present specification has not added such a construct, in the interests of simplicity and rapid language evolution. However, Dart implementations may experiment with such constructs, as noted in section \ref{ecmaConformance}.
+}
+
\subsubsection{Super Invocation}
\LMLabel{superInvocation}
@@ -3905,16 +3933,16 @@
If getter lookup has also failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that :
\begin{itemize}
\item \code{im.isMethod} evaluates to \code{\TRUE{}}.
-\item \code{im.memberName} evaluates to \code{'m'}.
+\item \code{im.memberName} evaluates to the symbol \code{m}.
\item \code{im.positionalArguments} evaluates to an immutable list with the same values as \code{[$o_1, \ldots, o_n$]}.
\item \code{im.namedArguments} evaluates to an immutable map with the same keys and values as \code{\{$x_{n+1}: o_{n+1}, \ldots, x_{n+k} : o_{n+k}$\}}.
\end{itemize}
Then the method \code{noSuchMethod()} is looked up in $S$ and invoked on \THIS{} with argument $im$, and the result of this invocation is the result of evaluating $i$. However, if the implementation found cannot be invoked with a single positional argument, the implementation of \code{noSuchMethod()} in class \code{Object} is invoked on \THIS{} with argument $im'$, where $im'$ is an instance of \code{Invocation} such that :
\begin{itemize}
-\item \code{im.isMethod} evaluates to \code{\TRUE{}}.
-\item \code{im.memberName} evaluates to \code{noSuchMethod}.
-\item \code{im.positionalArguments} evaluates to an immutable list whose sole element is $im$.
-\item \code{im.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
+\item \code{im'.isMethod} evaluates to \code{\TRUE{}}.
+\item \code{im'.memberName} evaluates to \code{\#noSuchMethod}.
+\item \code{im'.positionalArguments} evaluates to an immutable list whose sole element is $im$.
+\item \code{im'.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
\end{itemize}
and the result of this latter invocation is the result of evaluating $i$.
@@ -3946,36 +3974,62 @@
\LMLabel{propertyExtraction}
\LMHash{}
-{\em Property extraction} allows for a member of an object to be concisely extracted from the object.
+{\em Property extraction} allows for a member or constructor to be accessed as a property rather than a function.
A property extraction can be either:
\begin{enumerate}
-\item A {\em closurization} (\ref{closurization}) which allows a method to be treated as if it were a getter for a function valued object. Or
+\item A {\em closurization} which converts a method or constructor into a closure. Or
\item A {\em getter invocation} which returns the result of invoking of a getter method.
\end{enumerate}
+
+\commentary{Closures derived from members via closurization are colloquially known as tear-offs}
+
+Property extraction can be either {\em conditional} or {\em unconditional}.
+
+\rationale {
+Tear-offs using the \cd{ x\#id} syntax cannot be conditional at this time; this is inconsistent, and is likely to be addressed in the near future, perhaps via notation such as \cd{ x?\#id} . As indicated in section \ref{ecmaConformance}, experimentation in this area is allowed.
+}
+
+Evaluation of a {\em conditional property extraction expression} $e$ of the form $e_1?.id$ is equivalent to the evaluation of the expression $((x) => x == \NULL ? \NULL : x.id)(e_1)$. The static type of $e$ is the same as the static type of $e_1.id$. Let $T$ be the static type of $e_1$ and let $y$ be a fresh variable o type $T$. Exactly the same static warnings that would be caused by $y.id$ are also generated in the case of $e_1?.id$.
+
+\commentary{
+One might be tempted to conclude that for $e \ne \NULL{}$, $e?.v$ is always equivalent to $e.v$. However this is not the case. If $e$ is a type literal representing a type with static member $v$, then $e.v$ refers to that member, but $e?.v$ does not.
+}
+
+\LMHash{}
+Unconditional property extraction takes several syntactic forms: $e.m$ (\ref{getterAccessAndMethodExtraction}), $\SUPER.m$ (\ref{superGetterAccessAndMethodClosurization}), $e\#m$ (\ref{generalClosurization}), $\NEW{}$ $T\#m$ (\ref{namedConstructorExtraction}), $\NEW{}$ $T\#$ (\ref{anonymousConstructorExtraction}) and $\SUPER\#m$ (\ref{generalSuperPropertyExtraction}), where $e$ is an expression, $m$ is an identifier optionally followed by an equal sign and $T$ is a type.
+
+\subsubsection{Getter Access and Method Extraction}
+\LMLabel{getterAccessAndMethodExtraction}
+
\LMHash{}
Evaluation of a property extraction $i$ of the form $e.m$ proceeds as follows:
\LMHash{}
-First, the expression $e$ is evaluated to an object $o$. Let $f$ be the result of looking up (\ref{methodLookup}) method (\ref{instanceMethods}) $m$ in $o$ with respect to the current library $L$. If $o$ is an instance of \code{Type} but $e$ is not a constant type literal, then if $m$ is a method that forwards (\ref{functionDeclarations}) to a static method, method lookup fails. If method lookup succeeds and $f$ is a concrete method then $i$ evaluates to the closurization of $o.m$.
+First, the expression $e$ is evaluated to an object $o$. Let $f$ be the result of looking up (\ref{methodLookup}) method (\ref{instanceMethods}) $m$ in $o$ with respect to the current library $L$. If $o$ is an instance of \code{Type} but $e$ is not a constant type literal, then if $f$ is a method that forwards (\ref{functionDeclarations}) to a static method, method lookup fails. If method lookup succeeds then $i$ evaluates to the closurization of method $f$ on object $o$ (\ref{ordinaryMemberClosurization}).
+
+\commentary {
+Note that $f$ is never an abstract method, because method lookup skips abstract methods. Hence, if $m$ refers to an abstract method, we will continue to the next step. However, since methods and getters never override each other, getter lookup will necessarily fail as well, and \cd{noSuchMethod()} will ultimately be invoked. The regrettable implication is that the error will refer to a missing getter rather than an attempt to closurize an abstract method.
+}
\LMHash{}
-Otherwise, $i$ is a getter invocation, and the getter function (\ref{getters}) $m$ is looked up (\ref{getterAndSetterLookup}) in $o$ with respect to $L$. If $o$ is an instance of \code{Type} but $e$ is not a constant type literal, then if $m$ is a getter that forwards to a static getter, getter lookup fails. Otherwise, the body of $m$ is executed with \THIS{} bound to $o$. The value of $i$ is the result returned by the call to the getter function.
+Otherwise, $i$ is a getter invocation. Let $f$ be the result of looking up
+(\ref{getterAndSetterLookup}) getter (\ref{getters}) $m$ in $o$ with respect to $L$. If $o$ is an instance of \code{Type} but $e$ is not a constant type literal, then if $f$ is a getter that forwards to a static getter, getter lookup fails. Otherwise, the body of $f$ is executed with \THIS{} bound to $o$. The value of $i$ is the result returned by the call to the getter function.
\LMHash{}
If the getter lookup has failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that :
\begin{itemize}
\item \code{im.isGetter} evaluates to \code{\TRUE{}}.
-\item \code{im.memberName} evaluates to \code{'m'}.
+\item \code{im.memberName} evaluates to the symbol \code{m}.
\item \code{im.positionalArguments} evaluates to the value of \code{\CONST{} []}.
\item \code{im.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
\end{itemize}
Then the method \code{noSuchMethod()} is looked up in $o$ and invoked with argument $im$, and the result of this invocation is the result of evaluating $i$. However, if the implementation found cannot be invoked with a single positional argument, the implementation of \code{noSuchMethod()} in class \code{Object} is invoked on $o$ with argument $im'$, where $im'$ is an instance of \code{Invocation} such that :
\begin{itemize}
-\item \code{im.isMethod} evaluates to \code{\TRUE{}}.
-\item \code{im.memberName} evaluates to \code{noSuchMethod}.
-\item \code{im.positionalArguments} evaluates to an immutable list whose sole element is $im$.
-\item \code{im.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
+\item \code{im'.isMethod} evaluates to \code{\TRUE{}}.
+\item \code{im'.memberName} evaluates to \code{\#noSuchMethod}.
+\item \code{im'.positionalArguments} evaluates to an immutable list whose sole element is $im$.
+\item \code{im'.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
\end{itemize}
and the result of this latter invocation is the result of evaluating $i$.
@@ -3996,63 +4050,195 @@
\end{itemize}
\LMHash{}
-If $i$ is a getter invocation, the static type of $i$ is:
+The static type of $i$ is:
\begin{itemize}
-\item The declared return type of $T.m$, if $T.m$ exists.
-\item The declared return type of $m$, if $T$ is \code{Type}, $e$ is a constant type literal and the class corresponding to $e$ has a static method or getter named $m$.
+\item The declared return type of $T.m$, if $T$ has an accessible instance getter named $m$.
+\item The declared return type of $m$, if $T$ is \code{Type}, $e$ is a constant type literal and the class corresponding to $e$ declares an accessible static getter named $m$.
+\item The static type of function $T.m$ if $T$ has an accessible instance method named $m$.
+\item The static type of function $m$, if $T$ is \code{Type}, $e$ is a constant type literal and the class corresponding to $e$ declares an accessible static method named $m$.
\item The type \DYNAMIC{} otherwise.
\end{itemize}
-\LMHash{}
-If $i$ is a closurization, its static type is as described in section \ref{closurization}.
+
+\subsubsection{Super Getter Access and Method Closurization}
+\LMLabel{superGetterAccessAndMethodClosurization}
\LMHash{}
Evaluation of a property extraction $i$ of the form $\SUPER.m$ proceeds as follows:
\LMHash{}
- Let $S$ be the superclass of the immediately enclosing class. Let $f$ be the result of looking up method $m$ in $S$ with respect to the current library $L$. If $f$ is a concrete method then $i$ evaluates to the closurization of $\SUPER.m$ with respect to superclass $S$(\ref{closurization}).
+ Let $S$ be the superclass of the immediately enclosing class. Let $f$ be the result of looking up method $m$ in $S$ with respect to the current library $L$. If method lookup succeeds then $i$ evaluates to the closurization of method $f$ with respect to superclass $S$ (\ref{superClosurization}).
\LMHash{}
- Otherwise, $i$ is a getter invocation and the getter function $m$ is looked up in $S$ with respect to $L$, and its body is executed with \THIS{} bound to the current value of \THIS{}. The value of $i$ is the result returned by the call to the getter function.
+ Otherwise, $i$ is a getter invocation. Let $f$ be the result of looking up getter $m$ in $S$ with respect to $L$. The body of $f$ is executed with \THIS{} bound to the current value of \THIS{}. The value of $i$ is the result returned by the call to the getter function.
\LMHash{}
If the getter lookup has failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that :
\begin{itemize}
\item \code{im.isGetter} evaluates to \code{\TRUE{}}.
-\item \code{im.memberName} evaluates to \code{'m'}.
+\item \code{im.memberName} evaluates to the symbol \code{m}.
\item \code{im.positionalArguments} evaluates to the value of \code{\CONST{} []}.
\item \code{im.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
\end{itemize}
Then the method \code{noSuchMethod()} is looked up in $S$ and invoked with argument $im$, and the result of this invocation is the result of evaluating $i$. However, if the implementation found cannot be invoked with a single positional argument, the implementation of \code{noSuchMethod()} in class \code{Object} is invoked on \THIS{} with argument $im'$, where $im'$ is an instance of \code{Invocation} such that :
\begin{itemize}
-\item \code{im.isMethod} evaluates to \code{\TRUE{}}.
-\item \code{im.memberName} evaluates to \code{noSuchMethod}.
-\item \code{im.positionalArguments} evaluates to an immutable list whose sole element is $im$.
-\item \code{im.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
+\item \code{im'.isMethod} evaluates to \code{\TRUE{}}.
+\item \code{im'.memberName} evaluates to \code{\#noSuchMethod}.
+\item \code{im'.positionalArguments} evaluates to an immutable list whose sole element is $im$.
+\item \code{im'.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
\end{itemize}
-
and the result of this latter invocation is the result of evaluating $i$.
\LMHash{}
-It is a static type warning if $S$ does not have a method or getter named $m$. If $i$ is a getter invocation, the static type of $i$ is the declared return type of $S.m$, if $S.m$ exists and \DYNAMIC{} otherwise. If $i$ is a closurization, its static type is as described in section \ref{closurization}.
+It is a static type warning if $S$ does not have an accessible instance method or getter named $m$.
+
+The static type of $i$ is:
+\begin{itemize}
+\item The declared return type of $S.m$, if $S$ has an accessible instance getter named $m$.
+\item The static type of function $S.m$ if $S$ has an accessible instance method named $m$.
+\item The type \DYNAMIC{} otherwise.
+\end{itemize}
-\subsubsection{Closurization}
-\LMLabel{closurization}
+\subsubsection{General Closurization}
+\LMLabel{generalClosurization}
\LMHash{}
-The {\em closurization of $o.m$} is defined to be equivalent to:
+Evaluation of a property extraction $i$ of the form $e\#m$ proceeds as follows:
+\LMHash{}
+First, the expression $e$ is evaluated to an object $o$. Then:
+
+\LMHash{}
+ if $m$ is a setter name, let $f$ be the result of looking up setter $m$ in $o$ with respect to the current library $L$. If $o$ is an instance of \cd{Type} but $e$ is not a constant type literal, then if $f$ is a method that forwards to a static setter, setter lookup fails. If setter lookup succeeds then $i$ evaluates to the closurization of setter $f$ on object $o$ (\ref{ordinaryMemberClosurization}).
+ If setter lookup failed, a \cd{NoSuchMethodError} is thrown.
+
+ \rationale {
+It would be more in keeping with the rules of Dart to invoke \cd{noSuchMethod} in this and similar cases below. However, current implementations of \cd{noSuchMethod} cannot distinguish between an invocation of a closurization and an actual call. It is likely that future versions of Dart will provide a mechanism to detect whether \cd{noSuchMethod} is invoked in response to a closurization, say by means of a getter like \cd{isTearOff}. By being conservative at this stage and insisting on failure, we can ensure that no functioning code will break when/if this functionality is introduced.
+ }
+
+
+ \LMHash{}
+If $m$ is not a setter name, let $f$ be the result of looking up method $m$ in $o$ with respect to the current library $L$. If $o$ is an instance of \cd{Type} but $e$ is not a constant type literal, then if $f$ is a method that forwards to a static method, method lookup fails. If method lookup succeeds then $i$ evaluates to the closurization of method $f$ on object $o$ (\ref{ordinaryMemberClosurization}).
+
+\LMHash{}
+If method lookup failed, let $f$ be the result of looking up getter $m$ in $o$ with respect to the current library $L$. If $o$ is an instance of \cd{Type} but $e$ is not a constant type literal, then if $f$ is a method that forwards to a static getter, getter lookup fails. If getter lookup succeeds then $i$ evaluates to the closurization of getter $f$ on object $o$ (\ref{ordinaryMemberClosurization}).
+ If getter lookup failed, a \cd{NoSuchMethodError} is thrown.
+
+
+
+
+%\LMHash{}
+%Otherwise, a new instance $im$ of the predefined class \code{Invocation} is created, such that :
+%\begin{itemize}
+%\item If $m$ is a setter name, \code{im.isSetter} evaluates to \code{\TRUE{}}; otherwise \code{im.isMethod} evaluates to \code{\TRUE{}}
+%\item \code{im.memberName} evaluates to the symbol \code{m}.
+%\item \code{im.positionalArguments} evaluates to the value of \code{\CONST{} []}.
+%\item \code{im.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
+%\end{itemize}
+%Then the method \code{noSuchMethod()} is looked up in $o$ and invoked with argument $im$, and the result of this invocation is the result of evaluating $i$. However, if the implementation found cannot be invoked with a single positional argument, the implementation of \code{noSuchMethod()} in class \code{Object} is invoked on $o$ with argument $im'$, where $im'$ is an instance of \code{Invocation} such that :
+%\begin{itemize}
+%\item \code{im'.isMethod} evaluates to \code{\TRUE{}}.
+%\item \code{im'.memberName} evaluates to \code{\#noSuchMethod}.
+%\item \code{im'.positionalArguments} evaluates to an immutable list whose sole element is $im$.
+%\item \code{im'.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
+%\end{itemize}
+%and the result of this latter invocation is the result of evaluating $i$.
+
+\LMHash{}
+It is a compile-time error if $e$ is a prefix object (\ref{imports}) and $m$ refers to a type or a member of class \cd{Object}.
+
+\commentary{
+This restriction is in line with other limitations on the use of prefixes as objects. The only permitted uses of $p\#m$ are closurizing top level methods and getters imported via the prefix $p$. Top level methods are directly available by their qualified names: $p.m$. However, getters and setters are not, and allowing their closurization is the whole point of the $e\#m$ syntax.
+}
+
+\LMHash{}
+Let $T$ be the static type of $e$. It is a static type warning if $T$ does not have an accessible instance method or getter named $m$ unless either:
\begin{itemize}
+\item $T$ or a superinterface of $T$ is annotated with an annotation denoting a constant identical to the constant proxy defined in \cd{dart:core}. Or
+\item $T$ is \cd{Type}, $e$ is a constant type literal and the class corresponding to $e$ declares an accessible static method or getter named $m$.
+\end{itemize}
+The static type of $i$ is:
+\begin{itemize}
+\item The static type of function $T.m$, if $T$ has an accessible instance member named $m$.
+\item The static type of function $T.m$, if $T$ is \cd{Type}, $e$ is a constant type literal and the class corresponding to $e$ declares an accessible static member or constructor named $m$.
+\item The type \DYNAMIC{} otherwise.
+\end{itemize}
+
+\subsubsection{Named Constructor Extraction}
+\LMLabel{namedConstructorExtraction}
+
+\LMHash{}
+Evaluation of a property extraction $i$ of the form \NEW{} $T\#m$ proceeds as follows:
+
+\LMHash{}
+If $T$ is a malformed type (\ref{staticTypes}), a dynamic error occurs. If $T$ is a deferred type with prefix $p$, then if $p$ has not been successfully loaded, a dynamic error occurs. If $T$ does not denote a class, a dynamic error occurs. In checked mode, if $T$ or any of its superclasses is malbounded a dynamic error occurs. Otherwise, if the type $T$ does not declare an accessible named constructor $f$ with name $m$, a \cd{NoSuchMethodError} is thrown. Otherwise, $i$ evaluates to the closurization of constructor $f$ of type $T$ (\ref{namedConstructorClosurization}).
+
+\commentary{Note that if $T$ is malformed or malbounded, a static warning occurs, as always.}
+
+\LMHash{}
+The static type of $i$ is the type of the constructor function, if $T$ denotes a class in the surrounding scope with an accessible constructor $f$ named $m$. Otherwise the static type of $i$ is \DYNAMIC{}.
+
+\subsubsection{Anonymous Constructor Extraction}
+\LMLabel{anonymousConstructorExtraction}
+
+\LMHash{}
+Evaluation of a property extraction $i$ of the form \NEW{} $T\#$ proceeds as follows:
+
+\LMHash{}
+If $T$ is a malformed type (\ref{staticTypes}), a dynamic error occurs. If $T$ is a deferred type with prefix $p$, then if $p$ has not been successfully loaded, a dynamic error occurs. If $T$ does not denote a class, a dynamic error occurs. In checked mode, if $T$ or any of its superclasses is malbounded a dynamic error occurs. Otherwise, if the type $T$ does not declare an accessible anonymous constructor, a \cd{NoSuchMethodError} is thrown. Otherwise, $i$ evaluates to the closurization of the anonymous constructor of type $T$ (\ref{anonymousConstructorClosurization}).
+
+\commentary{Again, note that if $T$ is malformed or malbounded, existing rules ensure that a static warning occurs. This also means that $x\#$ where $x$ is not a type will always give a static warning.}
+
+\LMHash{}
+The static type of $i$ is the type of the constructor function $T()$, if $T$ denotes a class in the surrounding scope with an anonymous constructor $T()$. Otherwise the static type of $i$ is \DYNAMIC{}.
+
+\subsubsection{General Super Property Extraction}
+\LMLabel{generalSuperPropertyExtraction}
+
+
+\LMHash{}
+Evaluation of a property extraction $i$ of the form \SUPER$\#m$ proceeds as follows:
+
+ \LMHash{}
+Let $S$ be the superclass of the immediately enclosing class.
+
+ \LMHash{}
+If $m$ is a setter name, let $f$ be the result of looking up setter $m$ in $S$ with respect to the current library $L$. If setter lookup succeeds then $i$ evaluates to the closurization of setter $f$ with respect to superclass $S$ (\ref{superClosurization}). If setter lookup failed, a \cd{NoSuchMethodError} is thrown.
+
+If $m$ is not a setter name, let $f$ be the result of looking up method $m$ in $S$ with respect to the current library $L$. If method lookup succeeds then $i$ evaluates to the closurization of method $m$ with respect to superclass $S$ (\ref{superClosurization}).
+
+\LMHash{}
+ Otherwise, let $f$ be the result of looking up getter $m$ in $S$ with respect to the current library $L$. If getter lookup succeeds then $i$ evaluates to the closurization of getter $f$ with respect to superclass $S$ (\ref{superClosurization}). If getter lookup failed, a \cd{NoSuchMethodError} is thrown.
+
+\LMHash{}
+It is a static type warning if $S$ does not have an accessible instance member named $m$.
+
+\LMHash{}
+The static type of $i$ is the static type of the function $S.m$, if $S$ has an accessible instance member named $m$. Otherwise the static type of $i$ is \DYNAMIC{}.
+
+
+
+\subsubsection{Ordinary Member Closurization}
+\LMLabel{ordinaryMemberClosurization}
+
+
+\LMHash{}
+Let $o$ be an object, and let $u$ be a fresh final variable bound to $o$.
+The {\em closurization of method $f$ on object $o$} is defined to be equivalent to:
+\begin{itemize}
+\item $(a) \{\RETURN{}$ $u$ $op$ $a;$\} if $f$ is named $op$ and $op$ is one of \code{$<$, $>$, $<$=, $>$=, ==, -, +, /, \~{}/, *, \%, $|$, \^{}, \&, $<<$, $>>$} (this precludes closurization of unary -).
+\item $() \{\RETURN{}$ \~{} $u;$\} if $f$ is named \~{}.
+\item $(a) \{\RETURN{}$ $u[a];$\} if $f$ is named $[]$.
+\item $(a, b) \{\RETURN{}$ $u[a] = b;$\} if $f$ is named $[]=$.
\item
\begin{dartCode}
$(r_1, \ldots, r_n, \{p_1 : d_1, \ldots , p_k : d_k\})$ \{
\RETURN{} $ u.m(r_1, \ldots, r_n, p_1: p_1, \ldots, p_k: p_k);$
\}
\end{dartCode}
-
-if $m$ has required parameters $r_1, \ldots, r_n$, and named parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
+if $f$ is named $m$ and has required parameters $r_1, \ldots, r_n$, and named parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
\item
\begin{dartCode}
$(r_1, \ldots, r_n, [p_1 = d_1, \ldots , p_k = d_k])$\{
@@ -4060,14 +4246,18 @@
\}
\end{dartCode}
-if $m$ has required parameters $r_1, \ldots, r_n$, and optional positional parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
+if $f$ is named $m$ and has required parameters $r_1, \ldots, r_n$, and optional positional parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
\end{itemize}
-where $u$ is a fresh final variable bound to $o$, except that:
-\begin{enumerate}
-\item Iff \code{identical($o_1, o_2$)} then \cd{$o_1.m$ == $o_2.m$}.
-\item The static type of the property extraction is the static type of function $T.m$, where $T$ is the static type of $e$, if $T.m$ is defined. Otherwise the static type of $e.m$ is \DYNAMIC{}.
-\end{enumerate}
+\LMHash{}
+Except that iff \code{identical($o_1, o_2$)} then \cd{$o_1\#m$ == $o_2\#m$}, \cd{$o_1.m$ == $o_2.m$}, \cd{$o_1\#m$ == $o_2.m$} and \cd{$o_1.m$ == $o_2\#m$}.
+%\item The static type of the property extraction is the static type of function $T.m$, where $T$ is the static type of $e$, if $T.m$ is defined. Otherwise the static type of $e.m$ is \DYNAMIC{}.
+
+\LMHash{}
+The {\em closurization of getter $f$ on object $o$} is defined to be equivalent to \cd{()\{\RETURN{} u.m;\}} if $f$ is named $m$, except that iff \code{identical($o_1, o_2$)} then \cd{$o_1\#m$ == $o_2\#m$}.
+
+\LMHash{}
+The {\em closurization of setter $f$ on object $o$} is defined to be equivalent to \cd{(a)\{\RETURN{} u.m = a;\}} if $f$ is named $m=$, except that iff \code{identical($o_1, o_2$)} then \cd{$o_1\#m=$ == $o_2\#m=$}.
\commentary{
There is no guarantee that \cd{identical($o_1.m, o_2.m$)}. Dart implementations are not required to canonicalize these or any other closures.
@@ -4078,50 +4268,112 @@
The special treatment of equality in this case facilitates the use of extracted property functions in APIs where callbacks such as event listeners must often be registered and later unregistered. A common example is the DOM API in web browsers.
}
+\commentary {
+Observations:
+
+One cannot closurize a constructor, getter or a setter via the dot based syntax. One must use the \# based form. One can tell whether one implemented a property via a method or via a field/getter, which means that one has to plan ahead as to what construct to use, and that choice is reflected in the interface of the class.
+}
-\commentary{Observations:
-\begin{enumerate}
-\item One cannot closurize a getter or a setter.
-\item One can tell whether one implemented a property via a method or via a field/getter, which means that one has to plan ahead as to what construct to use, and that choice is reflected in the interface of the class.
-\end{enumerate}
-}
+\subsubsection{Named Constructor Closurization}
+\LMLabel{namedConstructorClosurization}
-
-
\LMHash{}
-The closurization of $\SUPER{}.m$ with respect to superclass $S$ is defined to be equivalent to:
-
+The {\em closurization of constructor $f$ of type $T$} is defined to be equivalent to:
\begin{itemize}
- %\item $(r_1, \ldots, r_n)\{\RETURN{}$ $o.m(r_1, \ldots, r_n);\}$ if $m$ has only required parameters $r_1, \ldots r_n$.
-%\item $(r_1, \ldots, r_n, rest)\{return$ $o.m(r_1, \ldots, r_n, rest);\}$ if $m$ has required parameters $r_1, \ldots r_n$, and a rest parameter $rest$.
-%\item
\item
\begin{dartCode}
-$(r_1, \ldots, r_n, \{p_1 : d_1, \ldots , p_k : d_k\})$\{
- \RETURN{} \SUPER{}$.m(r_1, \ldots, r_n, p_1: p_1, \ldots, p_k: p_k)$;
-\}
-\end{dartCode}
-
-if $m$ has required parameters $r_1, \ldots, r_n$, and named parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
-\item
-\begin{dartCode}
-$(r_1, \ldots, r_n, [p_1 = d_1, \ldots , p_k = d_k])$\{
- \RETURN{} \SUPER{}$.m(r_1, \ldots, r_n, p_1, \ldots, p_k)$;
+$(r_1, \ldots, r_n, \{p_1 : d_1, \ldots , p_k : d_k\})$ \{
+ \RETURN{} \NEW{} $T.m(r_1, \ldots, r_n, p_1: p_1, \ldots, p_k: p_k);$
\}
\end{dartCode}
-if $m$ has required parameters $r_1, \ldots, r_n$, and optional positional parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
+if $f$ is a named constructor with name $m$ that has required parameters $r_1, \ldots, r_n$, and named parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
+\item
+\begin{dartCode}
+$(r_1, \ldots, r_n, [p_1 = d_1, \ldots , p_k = d_k])$\{
+ \RETURN{} \NEW{} $T.m(r_1, \ldots, r_n, p_1, \ldots, p_k)$;
+\}
+\end{dartCode}
+
+if $f$ is a named constructor with name $m$ that has required parameters $r_1, \ldots, r_n$, and optional positional parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
\end{itemize}
\LMHash{}
-Except that:
-\begin{enumerate}
-\item iff \code{identical($o_1, o_2$)} then \cd{$o_1.m$ == $o_2.m$}.
+Except that iff \code{identical($T_1, T_2$)} then \cd{\NEW{} $T_1\#m$ == \NEW{} $T_2\#m$}.
+
+\commentary{
+The above implies that for non-parameterized types, one can rely on the equality of closures resulting from closurization on the ``same'' type. For parameterized types, one cannot, since there is no requirement to canonicalize them.
+}
+
+\subsubsection{Anonymous Constructor Closurization}
+\LMLabel{anonymousConstructorClosurization}
+
+\LMHash{}
+The {\em closurization of anonymous constructor $f$ of type $T$} is defined to be equivalent to:
+\begin{itemize}
+\item
+\begin{dartCode}
+$(r_1, \ldots, r_n, \{p_1 : d_1, \ldots , p_k : d_k\})$ \{
+ \RETURN{} \NEW{} $T(r_1, \ldots, r_n, p_1: p_1, \ldots, p_k: p_k);$
+\}
+\end{dartCode}
+
+if $f$ is an anonymous constructor that has required parameters $r_1, \ldots, r_n$, and named parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
\item
-The static type of the property extraction is the static type of the method $S.m$, if $S.m$ is defined. Otherwise the static type of $\SUPER{}.m$ is \DYNAMIC{}.
-\end{enumerate}
+\begin{dartCode}
+$(r_1, \ldots, r_n, [p_1 = d_1, \ldots , p_k = d_k])$\{
+ \RETURN{} \NEW{} $T(r_1, \ldots, r_n, p_1, \ldots, p_k)$;
+\}
+\end{dartCode}
+
+if $f$ is an anonymous constructor that has required parameters $r_1, \ldots, r_n$, and optional positional parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
+\end{itemize}
+
+\LMHash{}
+Except that iff \code{identical($T_1, T_2$)} then \cd{\NEW{} $T_1\#$ == \NEW{} $T_2\#$}.
+
+
+\subsubsection{Super Closurization}
+\LMLabel{superClosurization}
+
+\LMHash{}
+The {\em closurization of method $f$ with respect to superclass $S$} is defined to be equivalent to:
+
+\LMHash{}
+\begin{itemize}
+\item $(a) \{\RETURN{}$ \SUPER{} $op$ $a;$\} if $f$ is named $op$ and $op$ is one of \code{$<$, $>$, $<$=, $>$=, ==, -, +, /, \~{}/, *, \%, $|$, \^{}, \&, $<<$, $>>$}.
+\item $() \{\RETURN{}$ \~{}\SUPER;\} if $f$ is named \~{}.
+\item $(a) \{\RETURN{}$ $\SUPER[a];$\} if $f$ is named $[]$.
+\item $(a, b) \{\RETURN{}$ $\SUPER[a] = b;$\} if $f$ is named $[]=$.
+\item
+\begin{dartCode}
+$(r_1, \ldots, r_n, \{p_1 : d_1, \ldots , p_k : d_k\})$ \{
+ \RETURN{} \SUPER$.m(r_1, \ldots, r_n, p_1: p_1, \ldots, p_k: p_k);$
+\}
+\end{dartCode}
+if $f$ is named $m$ and has required parameters $r_1, \ldots, r_n$, and named parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
+\item
+\begin{dartCode}
+$(r_1, \ldots, r_n, [p_1 = d_1, \ldots , p_k = d_k])$\{
+ \RETURN{} \SUPER$.m(r_1, \ldots, r_n, p_1, \ldots, p_k)$;
+\}
+\end{dartCode}
+
+if $f$ is named $m$ and has required parameters $r_1, \ldots, r_n$, and optional positional parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
+\end{itemize}
+
+\LMHash{}
+Except that iff two closurizations were created by code declared in the same class with identical bindings of \THIS{} then \cd{\SUPER$_1\#m$ == \SUPER$_2\#m$}, \cd{\SUPER$_1.m$ == \SUPER$_2.m$}, \cd{\SUPER$_1\#m$ == \SUPER$_2.m$} and \cd{\SUPER$_1.m$ == \SUPER$_2\#m$}.
+
+
+\LMHash{}
+The {\em closurization of getter $f$ with respect to superclass $S$} is defined to be equivalent to \cd{()\{\RETURN{} \SUPER.m;\}} if $f$ is named $m$, except that iff two closurizations were created by code declared in the same class with identical bindings of \THIS{} then \cd{\SUPER$_1\#m$ == \SUPER$_2\#m$}.
+
+\LMHash{}
+The {\em closurization of setter $f$ with respect to superclass $S$} is defined to be equivalent to \cd{(a)\{\RETURN{} \SUPER.m = a;\}} if $f$ is named $m=$, except that iff two closurizations were created by code declared in the same class with identical bindings of \THIS{} then \cd{\SUPER$_1\#m=$ == \SUPER$_2\#m=$}.
+
\subsection{ Assignment}
@@ -4174,6 +4426,9 @@
It is a static type warning if the static type of $e$ may not be assigned to the static type of $v$. The static type of the expression $v$ \code{=} $e$ is the static type of $e$.
\LMHash{}
+Evaluation of an assignment $a$ of the form $e_1?.v$ \code{=} $e_2$ is equivalent to the evaluation of the expression $((x) => x == \NULL? \NULL: x.v = e_2)(e_1)$. The static type of $a$ is the static type of $e_2$. Let $T$ be the static type of $e_1$ and let $y$ be a fresh variable of type $T$. Exactly the same static warnings that would be caused by $y.v = e_2$ are also generated in the case of $e_1?.v$ \code{=} $e_2$.
+
+\LMHash{}
Evaluation of an assignment of the form $e_1.v$ \code{=} $e_2$ proceeds as follows:
\LMHash{}
@@ -4183,7 +4438,7 @@
If the setter lookup has failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that :
\begin{itemize}
\item \code{im.isSetter} evaluates to \code{\TRUE{}}.
-\item \code{im.memberName} evaluates to \code{'v='}.
+\item \code{im.memberName} evaluates to the symbol \code{v=}.
\item \code{im.positionalArguments} evaluates to an immutable list with the same values as \code{[$o_2$]}.
\item \code{im.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
\end{itemize}
@@ -4192,10 +4447,10 @@
Then the method \code{noSuchMethod()} is looked up in $o_1$ and invoked with argument $im$.
However, if the implementation found cannot be invoked with a single positional argument, the implementation of \code{noSuchMethod()} in class \code{Object} is invoked on $o_1$ with argument $im'$, where $im'$ is an instance of \code{Invocation} such that :
\begin{itemize}
-\item \code{im.isMethod} evaluates to \code{\TRUE{}}.
-\item \code{im.memberName} evaluates to \code{noSuchMethod}.
-\item \code{im.positionalArguments} evaluates to an immutable list whose sole element is $im$.
-\item \code{im.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
+\item \code{im'.isMethod} evaluates to \code{\TRUE{}}.
+\item \code{im'.memberName} evaluates to \code{\#noSuchMethod}.
+\item \code{im'.positionalArguments} evaluates to an immutable list whose sole element is $im$.
+\item \code{im'.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
\end{itemize}
\LMHash{}
@@ -4217,8 +4472,55 @@
It is a static type warning if the static type of $e_2$ may not be assigned to the static type of the formal parameter of the setter $v=$. The static type of the expression $e_1.v$ \code{=} $e_2$ is the static type of $e_2$.
\LMHash{}
+Evaluation of an assignment of the form $\SUPER.v$ \code{=} $e$ proceeds as follows:
+
+\LMHash{}
+Let $S$ be the superclass of the immediately enclosing class.
+The expression $e$ is evaluated to an object $o$. Then, the setter $v=$ is looked up (\ref{getterAndSetterLookup}) in $S$ with respect to the current library. The body of $v=$ is executed with its formal parameter bound to $o$ and \THIS{} bound to \THIS{}.
+
+\LMHash{}
+If the setter lookup has failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that :
+\begin{itemize}
+\item \code{im.isSetter} evaluates to \code{\TRUE{}}.
+\item \code{im.memberName} evaluates to the symbol \code{v=}.
+\item \code{im.positionalArguments} evaluates to an immutable list with the same values as \code{[$o$]}.
+\item \code{im.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
+\end{itemize}
+
+\LMHash{}
+Then the method \code{noSuchMethod()} is looked up in $S$ and invoked with argument $im$.
+However, if the implementation found cannot be invoked with a single positional argument, the implementation of \code{noSuchMethod()} in class \code{Object} is invoked on \THIS{} with argument $im'$, where $im'$ is an instance of \code{Invocation} such that :
+\begin{itemize}
+\item \code{im'.isMethod} evaluates to \code{\TRUE{}}.
+\item \code{im'.memberName} evaluates to \code{\#noSuchMethod}.
+\item \code{im'.positionalArguments} evaluates to an immutable list whose sole element is $im$.
+\item \code{im'.namedArguments} evaluates to the value of \code{\CONST{} \{\}}.
+\end{itemize}
+
+\LMHash{}
+The value of the assignment expression is $o$ irrespective of whether setter lookup has failed or succeeded.
+
+\LMHash{}
+In checked mode, it is a dynamic type error if $o$ is not \NULL{} and the interface of the class of $o$ is not a subtype of the actual type of $S.v$.
+
+\LMHash{}
+It is a static type warning if $S$ does not have an accessible instance setter named $v=$ unless $S$ or a superinterface of $S$ is annotated with an annotation denoting a constant identical to the constant \code{@proxy} defined in \code{dart:core}.
+
+\LMHash{}
+It is a static type warning if the static type of $e$ may not be assigned to the static type of the formal parameter of the setter $v=$. The static type of the expression $\SUPER.v$ \code{=} $e$ is the static type of $e$.
+
+
+
+
+
+
+\LMHash{}
Evaluation of an assignment of the form $e_1[e_2]$ \code{=} $e_3$ is equivalent to the evaluation of the expression \code{(a, i, e)\{a.[]=(i, e); \RETURN{} e; \} ($e_1, e_2, e_3$)}. The static type of the expression $e_1[e_2]$ \code{=} $e_3$ is the static type of $e_3$.
+\LMHash{}
+An assignment of the form $\SUPER[e_1]$ \code{=} $e_2$ is equivalent to the expression $\SUPER.[e_1]$ \code{=} $e_2$. The static type of the expression $\SUPER[e_1]$ \code{=} $e_2$ is the static type of $e_2$.
+
+
% Should we add: It is a dynamic error if $e_1$ evaluates to an constant list or map.
\LMHash{}
@@ -4233,9 +4535,35 @@
\LMLabel{compoundAssignment}
\LMHash{}
-A compound assignment of the form $v$ $op\code{=} e$ is equivalent to $v \code{=} v$ $op$ $e$. A compound assignment of the form $C.v$ $op \code{=} e$ is equivalent to $C.v \code{=} C.v$ $op$ $e$. A compound assignment of the form $e_1.v$ $op = e_2$ is equivalent to \code{((x) $=>$ x.v = x.v $op$ $e_2$)($e_1$)} where $x$ is a variable that is not used in $e_2$. A compound assignment of the form $e_1[e_2]$ $op\code{=} e_3$ is equivalent to
+Evaluation of a compound assignment of the form $v$ {\em ??=} $e$ is equivalent to the evaluation of the expression $((x) => x == \NULL{}$ ? $v=e : x)(v)$ where $x$ is a fresh variable that is not used in $e$. Evaluation of a compound assignment of the form $C.v$ {\em ??=} $e$, where $C$ is a type literal, is equivalent to the evaluation of the expression $((x) => x == \NULL{}$? $C.v=e: x)(C.v)$ where $x$ is a fresh variable that is not used in $e$. Evaluation of a compound assignment of the form $e_1.v$ {\em ??=} $e_2$ is equivalent to the evaluation of the expression $((x) =>((y) => y == \NULL{}$ ? $ x.v = e_2: y)(x.v))(e_1)$ where $x$ and $y$ are distinct fresh variables that are not used in $e_2$. Evaluation of a compound assignment of the form $e_1[e_2]$ {\em ??=} $e_3$ is equivalent to the evaluation of the expression
+$((a, i) => ((x) => x == \NULL{}$ ? $a[i] = e_3: x)(a[i]))(e_1, e_2)$ where $x$, $a$ and $i$ are distinct fresh variables that are not used in $e_3$. Evaluation of a compound assignment of the form $\SUPER.v$ {\em ??=} $e$ is equivalent to the evaluation of the expression $((x) => x == \NULL{}$ ? $\SUPER.v = e: x)(\SUPER.v)$ where $x$ is a fresh variable that is not used in $e$.
+
+\LMHash{}
+Evaluation of a compound assignment of the form $e_1?.v$ {\em ??=} $e_2$ is equivalent to the evaluation of the expression \code{((x) $=>$ x == \NULL{} ? \NULL: $x.v ??= e_2$)($e_1$)} where $x$ is a variable that is not used in $e_2$.
+
+
+\LMHash{}
+The static type of a compound assignment of the form $v$ {\em ??=} $e$ is the least upper bound of the static type of $v$ and the static type of $e$. Exactly the same static warnings that would be caused by $v = e$ are also generated in the case of $v$ {\em ??=} $e$.
+
+
+\LMHash{}
+The static type of a compound assignment of the form $C.v$ {\em ??=} $e$ is the least upper bound of the static type of $C.v$ and the static type of $e$. Exactly the same static warnings that would be caused by $C.v = e$ are also generated in the case of $C.v$ {\em ??=} $e$.
+
+\LMHash{}
+The static type of a compound assignment of the form $e_1.v$ {\em ??=} $e_2$ is the least upper bound of the static type of $e_1.v$ and the static type of $e_2$. Let $T$ be the static type of $e_1$ and let $z$ be a fresh variable of type $T$. Exactly the same static warnings that would be caused by $z.v = e$ are also generated in the case of $e_1.v$ {\em ??=} $e_2$.
+
+\LMHash{}
+The static type of a compound assignment of the form $e_1[e_2]$ {\em ??=} $e_3$ is the least upper bound of the static type of $e_1[e_2]$ and the static type of $e_3$. Exactly the same static warnings that would be caused by $e_1[e_2] = e_3$ are also generated in the case of $e_1[e_2]$ {\em ??=} $e_3$.
+
+\LMHash{}
+The static type of a compound assignment of the form $\SUPER.v$ {\em ??=} $e$ is the least upper bound of the static type of $\SUPER.v$ and the static type of $e$. Exactly the same static warnings that would be caused by $\SUPER.v = e$ are also generated in the case of $\SUPER.v$ {\em ??=} $e$.
+
+\LMHash{}
+For any other valid operator $op$, a compound assignment of the form $v$ $op\code{=} e$ is equivalent to $v \code{=} v$ $op$ $e$. A compound assignment of the form $C.v$ $op \code{=} e$ is equivalent to $C.v \code{=} C.v$ $op$ $e$. A compound assignment of the form $e_1.v$ $op = e_2$ is equivalent to \code{((x) $=>$ x.v = x.v $op$ $e_2$)($e_1$)} where $x$ is a variable that is not used in $e_2$. A compound assignment of the form $e_1[e_2]$ $op\code{=} e_3$ is equivalent to
\code{((a, i) $=>$ a[i] = a[i] $op$ $e_3$)($e_1, e_2$)} where $a$ and $i$ are a variables that are not used in $e_3$.
+\LMHash{}
+Evaluation of a compound assignment of the form $e_1?.v$ $op = e_2$ is equivalent to \code{((x) $=>$ x?.v = x.v $op$ $e_2$)($e_1$)} where $x$ is a variable that is not used in $e_2$. The static type of $e_1?.v$ $op = e_2$ is the static type of $e_1.v$ $op$ $e_2$. Exactly the same static warnings that would be caused by $e_1.v$ $op = e_2$ are also generated in the case of $e_1?.v$ $op = e_2$.
\begin{grammar}
{\bf compoundAssignmentOperator:}`*=';
@@ -4248,7 +4576,8 @@
`{\escapegrammar \gt \gt}=';
`\&=';
`\^{}=';
- `$|$='
+ `$|$=';
+ `??=';
.
\end{grammar}
@@ -4261,7 +4590,7 @@
\begin{grammar}
{\bf conditionalExpression:}
- logicalOrExpression (`?' expressionWithoutCascade `{\escapegrammar :}' expressionWithoutCascade)?
+ ifNullExpression (`?' expressionWithoutCascade `{\escapegrammar :}' expressionWithoutCascade)?
. % the first branches could top level expressions, it seems, but certainly NOT the second
\end{grammar}
@@ -4284,6 +4613,21 @@
\LMHash{}
It is a static type warning if the static type of $e_1$ may not be assigned to \code{bool}. The static type of $c$ is the least upper bound (\ref{leastUpperBounds}) of the static type of $e_2$ and the static type of $e_3$.
+
+
+ \subsection{If-null Expressions}
+ \label{ifNull}
+
+ \LMHash{}
+ An {\em if-null expression}evaluates an expression and if the result is \NULL, evaluates another.
+
+\begin{grammar}
+{\bf ifNullExpression:}
+ logicalOrExpression (`??' logicalOrExpression)*
+\end{grammar}
+
+\LMHash{}
+Evaluation of an if-null expression $e$ of the form $e_1??e_2 $ is equivalent to the evaluation of the expression $((x) => x == \NULL? e_2: x)(e_1)$. The static type of $e$ is least upper bound (\ref{leastUpperBounds}) of the static type of $e_1$ and the static type of $e_2$.
\subsection{ Logical Boolean Expressions}
@@ -4633,7 +4977,7 @@
\begin{grammar}
{\bf postfixExpression:}assignableExpression postfixOperator;
- primary selector*
+ primary (selector* $|$ ( `\#' ( (identifier `='?) $|$ operator)))
.
{\bf postfixOperator:}
@@ -4711,21 +5055,27 @@
\begin{grammar}
{\bf assignableExpression:}primary (arguments* assignableSelector)+;
- \SUPER{} assignableSelector;
+ \SUPER{} unconditionalAssignableSelector;
identifier
.
-{\bf assignableSelector:}`[' expression `]'; % again, could be top level
- `{\escapegrammar .}' identifier
+{\bf unconditionalAssignableSelector:}`[' expression `]'; % again, could be top level
+ `{\escapegrammar .}' identifier
+ .
+
+{\bf assignableSelector:}
+ unconditionalAssignableSelector;
+ `{\escapegrammar ?.}' identifier
.
\end{grammar}
+
\LMHash{}
An {\em assignable expression} is either:
\begin{itemize}
\item An identifier.
-\item An invocation of a getter (\ref{getters}) or list access operator on an expression $e$.
+\item An invocation (possibly conditional) of a getter (\ref{getters}) or list access operator on an expression $e$.
\item An invocation of a getter or list access operator on \SUPER{}.
\end{itemize}
@@ -4736,7 +5086,7 @@
%An assignable expression of the form $e.id(a_1, \ldots, a_n)$ is evaluated as a method invocation (\ref{methodInvocation}).
\LMHash{}
-An assignable expression of the form $e.id$ is evaluated as a property extraction (\ref{propertyExtraction}).
+An assignable expression of the form $e.id$ or $e?.id$ is evaluated as a property extraction (\ref{propertyExtraction}).
\LMHash{}
An assignable expression of the form \code{$e_1$[$e_2$]} is evaluated as a method invocation of the operator method \code{[]} on $e_1$ with argument $e_2$.
@@ -5667,7 +6017,7 @@
A finally clause \FINALLY{} $s$ defines an exception handler $h$ that executes as follows:
\LMHash{}
-Let $r$ be the current return value (\ref{return}). Then the current return value becomes undefined. Any open streams associated with any asynchronous for loops (\ref{asynchronousFor-in}) and yield-each (\ref{yieldEach}) statements executing within the dynamic scope of $h$ are canceled.
+Let $r$ be the current return value (\ref{return}). Then the current return value becomes undefined. Any open streams associated with any asynchronous for loops (\ref{asynchronousFor-in}) and yield-each (\ref{yieldEach}) statements executing within the dynamic scope of $h$ are canceled, in the order of their nesting, innermost first.
\rationale{
Streams left open by for loops that were escaped for whatever reason would be canceled at function termination, but it is best to cancel them as soon as possible.
@@ -5873,7 +6223,7 @@
Let $s_b$ be a \BREAK{} statement. If $s_b$ is of the form \code{\BREAK{} $L$;}, then let $s_E$ be the the innermost labeled statement with label $L$ enclosing $s_b$. If $s_b$ is of the form \code{\BREAK{};}, then let $s_E$ be the the innermost \DO{} (\ref{do}), \FOR{} (\ref{for}), \SWITCH{} (\ref{switch}) or \WHILE{} (\ref{while}) statement enclosing $s_b$. It is a compile-time error if no such statement $s_E$ exists within the innermost function in which $s_b$ occurs. Furthermore, let $s_1, \ldots, s_n$ be those \TRY{} statements that are both enclosed in $s_E$ and that enclose $s_b$, and that have a \FINALLY{} clause. Lastly, let $f_j$ be the \FINALLY{} clause of $s_j, 1 \le j \le n$. Executing $s_b$ first executes $f_1, \ldots, f_n$ in innermost-clause-first order and then terminates $s_E$.
\LMHash{}
-If $s_E$ is an asynchronous for loop (\ref{asynchronousFor-in}), its associated stream subscription is canceled. Furthermore, let $a_k$ be the set of asynchronous for loops and yield-each statements (\ref{yieldEach}) enclosing $s_b$ that are enclosed in $s_E , 1 \le k \le m$. The stream subscriptions associated with $a_j$ are canceled, $1 \le j \le m$.
+If $s_E$ is an asynchronous for loop (\ref{asynchronousFor-in}), its associated stream subscription is canceled. Furthermore, let $a_k$ be the set of asynchronous for loops and yield-each statements (\ref{yieldEach}) enclosing $s_b$ that are enclosed in $s_E , 1 \le k \le m$, where $a_k$ is enclosed in $a_{k+1}$. The stream subscriptions associated with $a_j$ are canceled, $1 \le j \le m$, innermost first, so that $a_j$ is canceled before $a_{j+1}$.
@@ -5897,7 +6247,7 @@
}
\LMHash{}
- If $s_E$ is an asynchronous for loop (\ref{asynchronousFor-in}), let $a_k$ be the set of asynchronous for loops and yield-each statements (\ref{yieldEach}) enclosing $s_c$ that are enclosed in $s_E , 1 \le k \le m$. The stream subscriptions associated with $a_j$ are canceled, $1 \le j \le m$.
+ If $s_E$ is an asynchronous for loop (\ref{asynchronousFor-in}), let $a_k$ be the set of asynchronous for loops and yield-each statements (\ref{yieldEach}) enclosing $s_c$ that are enclosed in $s_E , 1 \le k \le m$, where $a_k$ is enclosed in $a_{k+1}$. The stream subscriptions associated with $a_j$ are canceled, $1 \le j \le m$, innermost first, so that $a_j$ is canceled before $a_{j+1}$.
\subsection{ Yield and Yield-Each}
\LMLabel{yieldAndYieldEach}
@@ -7222,29 +7572,31 @@
\hline
Description & Operator & Associativity & Precedence \\
\hline
-Unary postfix & ., e++, e--, e1[e2], e1() , () & None & 15 \\
+Unary postfix & ., ?., e++, e--, e1[e2], e1() , () & None & 16 \\
\hline
-Unary prefix & -e, !e, \~{}e, ++e, --e & None & 14\\
+Unary prefix & -e, !e, \~{}e, ++e, --e & None & 15\\
\hline
-Multiplicative & *, /, \~/, \% & Left & 13\\
+Multiplicative & *, /, \~/, \% & Left & 14\\
\hline
-Additive & +, - & Left & 12\\
+Additive & +, - & Left & 13\\
\hline
-Shift & $<<$, $>>$& Left & 11\\
+Shift & $<<$, $>>$& Left & 12\\
\hline
-Bitwise AND & \& & Left & 10\\
+Bitwise AND & \& & Left & 11\\
\hline
-Bitwise XOR & \^{} & Left & 9\\
+Bitwise XOR & \^{} & Left & 10\\
\hline
-Bitwise Or & $|$ & Left & 8\\
+Bitwise Or & $|$ & Left & 9\\
\hline
-Relational & $<$, $>$, $<=$, $>=$, \AS{}, \IS{}, \IS{}! & None & 7\\
+Relational & $<$, $>$, $<=$, $>=$, \AS{}, \IS{}, \IS{}! & None & 8\\
\hline
-Equality & ==, != & None & 6\\
+Equality & ==, != & None & 7\\
\hline
-Logical AND & \&\& & Left & 5\\
+Logical AND & \&\& & Left & 6\\
\hline
-Logical Or & $||$ & Left & 4\\
+Logical Or & $||$ & Left & 5\\
+\hline
+If-null & ?? & Left & 4\\
\hline
Conditional & e1? e2: e3 & Right & 3\\
\hline
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index f0dac74..59a5359 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -43,7 +43,7 @@
</style></head>
<body>
<h1>Analysis Server API Specification</h1>
- <h1 style="color:#999999">Version 1.5.0</h1>
+ <h1 style="color:#999999">Version 1.6.0</h1>
<p>
This document contains a specification of the API provided by the
analysis server. The API in this document is currently under
@@ -2224,25 +2224,31 @@
<dl><dt class="field"><b><i>enableAsync ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
- <p><b><i>Deprecated</i></b>/</p><p>
- </p><p>
+ <p><b><i>Deprecated</i></b></p>
+ <p>
True if the client wants to enable support for the
proposed async feature.
</p>
</dd><dt class="field"><b><i>enableDeferredLoading ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
- <p><b><i>Deprecated</i></b>/</p><p>
- </p><p>
+ <p><b><i>Deprecated</i></b></p>
+ <p>
True if the client wants to enable support for the
proposed deferred loading feature.
</p>
</dd><dt class="field"><b><i>enableEnums ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
- <p><b><i>Deprecated</i></b>/</p><p>
- </p><p>
+ <p><b><i>Deprecated</i></b></p>
+ <p>
True if the client wants to enable support for the
proposed enum feature.
</p>
+ </dd><dt class="field"><b><i>enableNullAwareOperators ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
+
+ <p>
+ True if the client wants to enable support for the
+ proposed "null aware operators" feature.
+ </p>
</dd><dt class="field"><b><i>generateDart2jsHints ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
<p>
@@ -3129,6 +3135,12 @@
which does not match a file currently subject to
analysis.
</p>
+ </dd><dt class="value">INVALID_ANALYSIS_ROOT</dt><dd>
+
+ <p>
+ A path passed as an argument to a request (such as
+ analysis.reanalyze) is required to be an analysis root, but isn't.
+ </p>
</dd><dt class="value">INVALID_EXECUTION_CONTEXT</dt><dd>
<p>
@@ -3212,6 +3224,12 @@
not recognize, or cannot handle in its current
configuation.
</p>
+ </dd><dt class="value">UNKNOWN_SOURCE</dt><dd>
+
+ <p>
+ The analysis server was requested to perform an action
+ on a source that does not exist.
+ </p>
</dd><dt class="value">UNSUPPORTED_FEATURE</dt><dd>
<p>
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index bad954c..706b382 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -66,7 +66,7 @@
* The version of the analysis server. The value should be replaced
* automatically during the build.
*/
- static final String VERSION = '1.5.0';
+ static final String VERSION = '1.6.0';
/**
* The number of milliseconds to perform operations before inserting
@@ -463,6 +463,14 @@
return new ContextSourcePair(context, source);
}
}
+ // try to find a context for which the file is a priority source
+ for (InternalAnalysisContext context in folderMap.values) {
+ List<Source> sources = context.getSourcesWithFullName(path);
+ if (sources.isNotEmpty) {
+ Source source = sources.first;
+ return new ContextSourcePair(context, source);
+ }
+ }
// file-based source
Source fileSource = file != null ? file.createSource() : null;
return new ContextSourcePair(null, fileSource);
@@ -733,14 +741,21 @@
}
/**
- * Trigger reanalysis of all files from disk.
+ * Trigger reanalysis of all files in the given list of analysis [roots], or
+ * everything if the analysis roots is `null`.
*/
- void reanalyze() {
+ void reanalyze(List<Resource> roots) {
// Clear any operations that are pending.
- operationQueue.clear();
+ if (roots == null) {
+ operationQueue.clear();
+ } else {
+ for (AnalysisContext context in _getContexts(roots)) {
+ operationQueue.contextRemoved(context);
+ }
+ }
// Instruct the contextDirectoryManager to rebuild all contexts from
// scratch.
- contextDirectoryManager.refresh();
+ contextDirectoryManager.refresh(roots);
}
/**
@@ -916,10 +931,27 @@
new HashMap<AnalysisContext, List<Source>>();
List<String> unanalyzed = new List<String>();
Source firstSource = null;
- files.forEach((file) {
+ files.forEach((String file) {
ContextSourcePair contextSource = getContextSourcePair(file);
AnalysisContext preferredContext = contextSource.context;
Source source = contextSource.source;
+ // Try to make the file analyzable.
+ // If it is not in any context yet, add it to the first one which
+ // could use it, e.g. imports its package, even if not the library.
+ if (preferredContext == null) {
+ Resource resource = resourceProvider.getResource(file);
+ if (resource is File && resource.exists) {
+ for (AnalysisContext context in folderMap.values) {
+ Uri uri = context.sourceFactory.restoreUri(source);
+ if (uri.scheme != 'file') {
+ preferredContext = context;
+ source = ContextManager.createSourceInContext(context, resource);
+ break;
+ }
+ }
+ }
+ }
+ // Fill the source map.
bool contextFound = false;
for (AnalysisContext context in folderMap.values) {
if (context == preferredContext ||
@@ -1038,10 +1070,24 @@
throw new AnalysisException('Illegal change type');
}
overlayState.setContents(source, newContents);
+ // If the source does not exist, then it was an overlay-only one.
+ // Remove it from contexts.
+ if (newContents == null && !source.exists()) {
+ for (InternalAnalysisContext context in folderMap.values) {
+ List<Source> sources = context.getSourcesWithFullName(file);
+ ChangeSet changeSet = new ChangeSet();
+ sources.forEach(changeSet.removedSource);
+ context.applyChanges(changeSet);
+ schedulePerformAnalysisOperation(context);
+ }
+ return;
+ }
// Update all contexts.
+ bool anyContextUpdated = false;
for (InternalAnalysisContext context in folderMap.values) {
List<Source> sources = context.getSourcesWithFullName(file);
sources.forEach((Source source) {
+ anyContextUpdated = true;
if (context.handleContentsChanged(
source, oldContents, newContents, true)) {
schedulePerformAnalysisOperation(context);
@@ -1067,6 +1113,16 @@
}
});
}
+ // The source is not analyzed by any context, add to the containing one.
+ if (!anyContextUpdated) {
+ AnalysisContext context = contextSource.context;
+ if (context != null && source != null) {
+ ChangeSet changeSet = new ChangeSet();
+ changeSet.addedSource(source);
+ context.applyChanges(changeSet);
+ schedulePerformAnalysisOperation(context);
+ }
+ }
});
}
@@ -1096,6 +1152,20 @@
}
/**
+ * Return a set of contexts containing all of the resources in the given list
+ * of [resources].
+ */
+ Set<AnalysisContext> _getContexts(List<Resource> resources) {
+ Set<AnalysisContext> contexts = new HashSet<AnalysisContext>();
+ resources.forEach((Resource resource) {
+ if (resource is Folder) {
+ contexts.addAll(contextDirectoryManager.contextsInAnalysisRoot(resource));
+ }
+ });
+ return contexts;
+ }
+
+ /**
* Returns the [CompilationUnit] of the Dart file with the given [source] that
* should be used to resend notifications for already resolved unit.
* Returns `null` if the file is not a part of any context, library has not
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index aad7ca3..ceafb22e 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -95,17 +95,20 @@
// description
hover.elementDescription = element.toString();
hover.elementKind = element.kind.displayName;
- // containing class
- ClassElement containingClass =
- element.getAncestor((e) => e is ClassElement);
- if (containingClass != null) {
- hover.containingClassDescription = containingClass.toString();
- }
- // containing library
- LibraryElement library = element.library;
- if (library != null) {
- hover.containingLibraryName = library.name;
- hover.containingLibraryPath = library.source.fullName;
+ // not local element
+ if (element.enclosingElement is! ExecutableElement) {
+ // containing class
+ ClassElement containingClass =
+ element.getAncestor((e) => e is ClassElement);
+ if (containingClass != null) {
+ hover.containingClassDescription = containingClass.toString();
+ }
+ // containing library
+ LibraryElement library = element.library;
+ if (library != null) {
+ hover.containingLibraryName = library.name;
+ hover.containingLibraryPath = library.source.fullName;
+ }
}
// documentation
String dartDoc = element.computeDocumentationComment();
diff --git a/pkg/analysis_server/lib/src/computer/computer_overrides.dart b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
index c47e127..ba7cb76 100644
--- a/pkg/analysis_server/lib/src/computer/computer_overrides.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
@@ -45,6 +45,30 @@
return _overrides;
}
+ void _addInterfaceOverrides(List<engine.Element> elements, String name,
+ engine.InterfaceType type, bool checkType,
+ Set<engine.InterfaceType> visited) {
+ if (type == null) {
+ return;
+ }
+ if (!visited.add(type)) {
+ return;
+ }
+ // check type
+ if (checkType) {
+ engine.Element element = _lookupMember(type.element, name);
+ if (element != null) {
+ elements.add(element);
+ }
+ }
+ // check interfaces
+ for (engine.InterfaceType interfaceType in type.interfaces) {
+ _addInterfaceOverrides(elements, name, interfaceType, true, visited);
+ }
+ // check super
+ _addInterfaceOverrides(elements, name, type.superclass, checkType, visited);
+ }
+
void _addOverride(int offset, int length, String name) {
// super
engine.Element superEngineElement;
@@ -56,21 +80,15 @@
}
// interfaces
List<engine.Element> interfaceEngineElements = <engine.Element>[];
- for (engine.InterfaceType interfaceType in _currentClass.interfaces) {
- engine.ClassElement interfaceElement = interfaceType.element;
- engine.Element interfaceMember = _lookupMember(interfaceElement, name);
- if (interfaceMember != null) {
- interfaceEngineElements.add(interfaceMember);
- }
- }
+ _addInterfaceOverrides(interfaceEngineElements, name, _currentClass.type,
+ false, new Set<engine.InterfaceType>());
// is there any override?
if (superEngineElement != null || interfaceEngineElements.isNotEmpty) {
OverriddenMember superMember = superEngineElement != null
? newOverriddenMember_fromEngine(superEngineElement)
: null;
List<OverriddenMember> interfaceMembers = interfaceEngineElements
- .map(
- (engine.Element member) => newOverriddenMember_fromEngine(member))
+ .map((member) => newOverriddenMember_fromEngine(member))
.toList();
_overrides.add(new Override(offset, length,
superclassMember: superMember,
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 058662c..b52f6ad 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -163,13 +163,39 @@
}
/**
- * Rebuild the set of contexts from scratch based on the data last sent to
- * setRoots().
+ * Return a list containing all of the contexts contained in the given
+ * [analysisRoot].
*/
- void refresh() {
+ List<AnalysisContext> contextsInAnalysisRoot(Folder analysisRoot) {
+ List<AnalysisContext> contexts = <AnalysisContext>[];
+ _contexts.forEach((Folder contextFolder, _ContextInfo info) {
+ if (analysisRoot.isOrContains(contextFolder.path)) {
+ contexts.add(info.context);
+ }
+ });
+ return contexts;
+ }
+
+ /**
+ * Rebuild the set of contexts from scratch based on the data last sent to
+ * setRoots(). Only contexts contained in the given list of analysis [roots]
+ * will be rebuilt, unless the list is `null`, in which case every context
+ * will be rebuilt.
+ */
+ void refresh(List<Resource> roots) {
// Destroy old contexts
List<Folder> contextFolders = _contexts.keys.toList();
- contextFolders.forEach(_destroyContext);
+ if (roots == null) {
+ contextFolders.forEach(_destroyContext);
+ } else {
+ roots.forEach((Resource resource) {
+ contextFolders.forEach((Folder contextFolder) {
+ if (resource is Folder && resource.isOrContains(contextFolder.path)) {
+ _destroyContext(contextFolder);
+ }
+ });
+ });
+ }
// Rebuild contexts based on the data last sent to setRoots().
setRoots(includedPaths, excludedPaths, packageRoots);
@@ -335,7 +361,7 @@
for (Resource child in children) {
String path = child.path;
// ignore excluded files or folders
- if (_isExcluded(path)) {
+ if (_isExcluded(path) || info.excludes(path)) {
continue;
}
// add files, recurse into folders
@@ -400,47 +426,45 @@
}
/**
- * Creates a new context associated with [folder].
+ * Potentially create a new context associated with the given [folder].
*
- * If there are subfolders with 'pubspec.yaml' files, separate contexts
- * are created for them, and excluded from the context associated with
+ * If there are subfolders with 'pubspec.yaml' files, separate contexts are
+ * created for them and excluded from the context associated with the
* [folder].
*
- * If [folder] itself contains a 'pubspec.yaml' file, subfolders are ignored.
- *
* If [withPubspecOnly] is `true`, a context will be created only if there
- * is a 'pubspec.yaml' file in [folder].
+ * is a 'pubspec.yaml' file in the [folder].
*
* Returns create pubspec-based contexts.
*/
List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) {
- // check whether there is a pubspec in the folder
- File pubspecFile = folder.getChild(PUBSPEC_NAME);
- if (pubspecFile.exists) {
- _ContextInfo info =
- _createContextWithSources(folder, pubspecFile, <_ContextInfo>[]);
- return [info];
- }
// try to find subfolders with pubspec files
List<_ContextInfo> children = <_ContextInfo>[];
try {
for (Resource child in folder.getChildren()) {
if (child is Folder) {
- List<_ContextInfo> childContexts = _createContexts(child, true);
- children.addAll(childContexts);
+ children.addAll(_createContexts(child, true));
}
}
} on FileSystemException {
// The directory either doesn't exist or cannot be read. Either way, there
// are no subfolders that need to be added.
}
+ // check whether there is a pubspec in the folder
+ File pubspecFile = folder.getChild(PUBSPEC_NAME);
+ if (pubspecFile.exists) {
+ return <_ContextInfo>[
+ _createContextWithSources(folder, pubspecFile, children)
+ ];
+ }
// no pubspec, done
if (withPubspecOnly) {
return children;
}
// OK, create a context without a pubspec
- _createContextWithSources(folder, pubspecFile, children);
- return children;
+ return <_ContextInfo>[
+ _createContextWithSources(folder, pubspecFile, children)
+ ];
}
/**
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 5b46107..d6e2ec5 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -11,6 +11,7 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/dependencies/library_dependencies.dart';
+import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart' as engine;
@@ -136,7 +137,23 @@
* Implement the 'analysis.reanalyze' request.
*/
Response reanalyze(Request request) {
- server.reanalyze();
+ AnalysisReanalyzeParams params =
+ new AnalysisReanalyzeParams.fromRequest(request);
+ List<String> roots = params.roots;
+ if (roots == null || roots.isNotEmpty) {
+ List<String> includedPaths = server.contextDirectoryManager.includedPaths;
+ List<Resource> rootResources = null;
+ if (roots != null) {
+ rootResources = <Resource>[];
+ for (String rootPath in roots) {
+ if (!includedPaths.contains(rootPath)) {
+ return new Response.invalidAnalysisRoot(request, rootPath);
+ }
+ rootResources.add(server.resourceProvider.getResource(rootPath));
+ }
+ }
+ server.reanalyze(rootResources);
+ }
return new AnalysisReanalyzeResult().toResponse(request.id);
}
@@ -189,6 +206,11 @@
var params = new AnalysisUpdateOptionsParams.fromRequest(request);
AnalysisOptions newOptions = params.options;
List<OptionUpdater> updaters = new List<OptionUpdater>();
+ if (newOptions.enableNullAwareOperators != null) {
+ updaters.add((engine.AnalysisOptionsImpl options) {
+ options.enableNullAwareOperators = newOptions.enableNullAwareOperators;
+ });
+ }
if (newOptions.generateDart2jsHints != null) {
updaters.add((engine.AnalysisOptionsImpl options) {
options.dart2jsHint = newOptions.generateDart2jsHints;
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index affe17c..70808d5 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -177,6 +177,9 @@
ContextSourcePair contextSource = server.getContextSourcePair(params.file);
AnalysisContext context = contextSource.context;
Source source = contextSource.source;
+ if (context == null || !context.exists(source)) {
+ return new Response.unknownSource(request);
+ }
recordRequest(performance, context, source, params.offset);
if (manager == null) {
manager = completionManagerFor(context, source);
diff --git a/pkg/analysis_server/lib/src/generated_protocol.dart b/pkg/analysis_server/lib/src/generated_protocol.dart
index bbd7572..27ad110 100644
--- a/pkg/analysis_server/lib/src/generated_protocol.dart
+++ b/pkg/analysis_server/lib/src/generated_protocol.dart
@@ -5644,6 +5644,7 @@
* "enableAsync": optional bool
* "enableDeferredLoading": optional bool
* "enableEnums": optional bool
+ * "enableNullAwareOperators": optional bool
* "generateDart2jsHints": optional bool
* "generateHints": optional bool
* "generateLints": optional bool
@@ -5651,14 +5652,14 @@
*/
class AnalysisOptions implements HasToJson {
/**
- * Deprecated/
+ * Deprecated
*
* True if the client wants to enable support for the proposed async feature.
*/
bool enableAsync;
/**
- * Deprecated/
+ * Deprecated
*
* True if the client wants to enable support for the proposed deferred
* loading feature.
@@ -5666,13 +5667,19 @@
bool enableDeferredLoading;
/**
- * Deprecated/
+ * Deprecated
*
* True if the client wants to enable support for the proposed enum feature.
*/
bool enableEnums;
/**
+ * True if the client wants to enable support for the proposed "null aware
+ * operators" feature.
+ */
+ bool enableNullAwareOperators;
+
+ /**
* True if hints that are specific to dart2js should be generated. This
* option is ignored if generateHints is false.
*/
@@ -5690,7 +5697,7 @@
*/
bool generateLints;
- AnalysisOptions({this.enableAsync, this.enableDeferredLoading, this.enableEnums, this.generateDart2jsHints, this.generateHints, this.generateLints});
+ AnalysisOptions({this.enableAsync, this.enableDeferredLoading, this.enableEnums, this.enableNullAwareOperators, this.generateDart2jsHints, this.generateHints, this.generateLints});
factory AnalysisOptions.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
if (json == null) {
@@ -5709,6 +5716,10 @@
if (json.containsKey("enableEnums")) {
enableEnums = jsonDecoder._decodeBool(jsonPath + ".enableEnums", json["enableEnums"]);
}
+ bool enableNullAwareOperators;
+ if (json.containsKey("enableNullAwareOperators")) {
+ enableNullAwareOperators = jsonDecoder._decodeBool(jsonPath + ".enableNullAwareOperators", json["enableNullAwareOperators"]);
+ }
bool generateDart2jsHints;
if (json.containsKey("generateDart2jsHints")) {
generateDart2jsHints = jsonDecoder._decodeBool(jsonPath + ".generateDart2jsHints", json["generateDart2jsHints"]);
@@ -5721,7 +5732,7 @@
if (json.containsKey("generateLints")) {
generateLints = jsonDecoder._decodeBool(jsonPath + ".generateLints", json["generateLints"]);
}
- return new AnalysisOptions(enableAsync: enableAsync, enableDeferredLoading: enableDeferredLoading, enableEnums: enableEnums, generateDart2jsHints: generateDart2jsHints, generateHints: generateHints, generateLints: generateLints);
+ return new AnalysisOptions(enableAsync: enableAsync, enableDeferredLoading: enableDeferredLoading, enableEnums: enableEnums, enableNullAwareOperators: enableNullAwareOperators, generateDart2jsHints: generateDart2jsHints, generateHints: generateHints, generateLints: generateLints);
} else {
throw jsonDecoder.mismatch(jsonPath, "AnalysisOptions");
}
@@ -5738,6 +5749,9 @@
if (enableEnums != null) {
result["enableEnums"] = enableEnums;
}
+ if (enableNullAwareOperators != null) {
+ result["enableNullAwareOperators"] = enableNullAwareOperators;
+ }
if (generateDart2jsHints != null) {
result["generateDart2jsHints"] = generateDart2jsHints;
}
@@ -5759,6 +5773,7 @@
return enableAsync == other.enableAsync &&
enableDeferredLoading == other.enableDeferredLoading &&
enableEnums == other.enableEnums &&
+ enableNullAwareOperators == other.enableNullAwareOperators &&
generateDart2jsHints == other.generateDart2jsHints &&
generateHints == other.generateHints &&
generateLints == other.generateLints;
@@ -5772,6 +5787,7 @@
hash = _JenkinsSmiHash.combine(hash, enableAsync.hashCode);
hash = _JenkinsSmiHash.combine(hash, enableDeferredLoading.hashCode);
hash = _JenkinsSmiHash.combine(hash, enableEnums.hashCode);
+ hash = _JenkinsSmiHash.combine(hash, enableNullAwareOperators.hashCode);
hash = _JenkinsSmiHash.combine(hash, generateDart2jsHints.hashCode);
hash = _JenkinsSmiHash.combine(hash, generateHints.hashCode);
hash = _JenkinsSmiHash.combine(hash, generateLints.hashCode);
@@ -9338,6 +9354,7 @@
* CONTENT_MODIFIED
* FORMAT_INVALID_FILE
* GET_ERRORS_INVALID_FILE
+ * INVALID_ANALYSIS_ROOT
* INVALID_EXECUTION_CONTEXT
* INVALID_OVERLAY_CHANGE
* INVALID_PARAMETER
@@ -9350,6 +9367,7 @@
* SORT_MEMBERS_PARSE_ERRORS
* UNANALYZED_PRIORITY_FILES
* UNKNOWN_REQUEST
+ * UNKNOWN_SOURCE
* UNSUPPORTED_FEATURE
* }
*/
@@ -9374,6 +9392,12 @@
static const GET_ERRORS_INVALID_FILE = const RequestErrorCode._("GET_ERRORS_INVALID_FILE");
/**
+ * A path passed as an argument to a request (such as analysis.reanalyze) is
+ * required to be an analysis root, but isn't.
+ */
+ static const INVALID_ANALYSIS_ROOT = const RequestErrorCode._("INVALID_ANALYSIS_ROOT");
+
+ /**
* The context root used to create an execution context does not exist.
*/
static const INVALID_EXECUTION_CONTEXT = const RequestErrorCode._("INVALID_EXECUTION_CONTEXT");
@@ -9450,6 +9474,12 @@
static const UNKNOWN_REQUEST = const RequestErrorCode._("UNKNOWN_REQUEST");
/**
+ * The analysis server was requested to perform an action on a source that
+ * does not exist.
+ */
+ static const UNKNOWN_SOURCE = const RequestErrorCode._("UNKNOWN_SOURCE");
+
+ /**
* The analysis server was requested to perform an action which is not
* supported.
*
@@ -9461,7 +9491,7 @@
/**
* A list containing all of the enum values that are defined.
*/
- static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FORMAT_INVALID_FILE, GET_ERRORS_INVALID_FILE, INVALID_EXECUTION_CONTEXT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, NO_INDEX_GENERATED, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNSUPPORTED_FEATURE];
+ static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FORMAT_INVALID_FILE, GET_ERRORS_INVALID_FILE, INVALID_ANALYSIS_ROOT, INVALID_EXECUTION_CONTEXT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, NO_INDEX_GENERATED, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNKNOWN_SOURCE, UNSUPPORTED_FEATURE];
final String name;
@@ -9475,6 +9505,8 @@
return FORMAT_INVALID_FILE;
case "GET_ERRORS_INVALID_FILE":
return GET_ERRORS_INVALID_FILE;
+ case "INVALID_ANALYSIS_ROOT":
+ return INVALID_ANALYSIS_ROOT;
case "INVALID_EXECUTION_CONTEXT":
return INVALID_EXECUTION_CONTEXT;
case "INVALID_OVERLAY_CHANGE":
@@ -9499,6 +9531,8 @@
return UNANALYZED_PRIORITY_FILES;
case "UNKNOWN_REQUEST":
return UNKNOWN_REQUEST;
+ case "UNKNOWN_SOURCE":
+ return UNKNOWN_SOURCE;
case "UNSUPPORTED_FEATURE":
return UNSUPPORTED_FEATURE;
}
diff --git a/pkg/analysis_server/lib/src/get_handler.dart b/pkg/analysis_server/lib/src/get_handler.dart
index fffe9ad..14d18cd 100644
--- a/pkg/analysis_server/lib/src/get_handler.dart
+++ b/pkg/analysis_server/lib/src/get_handler.dart
@@ -1007,6 +1007,8 @@
_writeOption(
buffer, 'Analyze functon bodies', options.analyzeFunctionBodies);
_writeOption(buffer, 'Cache size', options.cacheSize);
+ _writeOption(buffer, 'Enable null-aware operators',
+ options.enableNullAwareOperators);
_writeOption(
buffer, 'Enable strict call checks', options.enableStrictCallChecks);
_writeOption(buffer, 'Generate hints', options.hint);
diff --git a/pkg/analysis_server/lib/src/protocol.dart b/pkg/analysis_server/lib/src/protocol.dart
index 31e52c9..bdc8608 100644
--- a/pkg/analysis_server/lib/src/protocol.dart
+++ b/pkg/analysis_server/lib/src/protocol.dart
@@ -733,6 +733,16 @@
/**
* Initialize a newly created instance to represent an error condition caused
+ * by an analysis.reanalyze [request] that specifies an analysis root that is
+ * not in the current list of analysis roots.
+ */
+ Response.invalidAnalysisRoot(Request request, String rootPath) : this(
+ request.id,
+ error: new RequestError(RequestErrorCode.INVALID_ANALYSIS_ROOT,
+ "Invalid analysis root: $rootPath"));
+
+ /**
+ * Initialize a newly created instance to represent an error condition caused
* by a [request] that specifies an execution context whose context root does
* not exist.
*/
@@ -826,6 +836,14 @@
error: new RequestError(
RequestErrorCode.UNKNOWN_REQUEST, 'Unknown request'));
+ /**
+ * Initialize a newly created instance to represent an error condition caused
+ * by a [request] referencing a source that does not exist.
+ */
+ Response.unknownSource(Request request) : this(request.id,
+ error: new RequestError(
+ RequestErrorCode.UNKNOWN_SOURCE, 'Unknown source'));
+
Response.unsupportedFeature(String requestId, String message) : this(
requestId,
error: new RequestError(
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index f5c5806..913e1f2 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -213,18 +213,6 @@
engine.Element element, int fileToIndex(String file)) {
ElementKind kind = newElementKind_fromEngine(element.kind);
Location location = newLocation_fromElement(element);
- // TODO(scheglov) debug null Location
- if (location == null) {
- String desc = 'location == null';
- try {
- desc += ' for: $element';
- desc += ' of type: ${element.runtimeType}';
- desc += ' element.location: ${element.location}';
- desc += ' element.context: ${element.context}';
- desc += ' element.source: ${element.source}';
- } catch (e) {}
- throw new ArgumentError(desc);
- }
String file = location.file;
int fileIndex = fileToIndex(file);
return new NavigationTarget(kind, fileIndex, location.offset, location.length,
diff --git a/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart b/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart
deleted file mode 100644
index 55b342a..0000000
--- a/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library services.completion.computer.dart.arglist;
-
-import 'dart:async';
-
-import 'package:analysis_server/src/protocol_server.dart'
- hide Element, ElementKind;
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/local_declaration_visitor.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
-
-/**
- * A computer for calculating `completion.getSuggestions` request results
- * when the cursor position is inside the arguments to a method call.
- */
-class ArgListComputer extends DartCompletionComputer {
- _ArgListSuggestionBuilder builder;
-
- @override
- bool computeFast(DartCompletionRequest request) {
- builder = request.node.accept(new _ArgListAstVisitor(request));
- return builder == null;
- }
-
- @override
- Future<bool> computeFull(DartCompletionRequest request) {
- if (builder != null) {
- return builder.compute(request.node);
- }
- return new Future.value(false);
- }
-}
-
-/**
- * A visitor for determining whether an argument list suggestion is needed
- * and instantiating the builder to create the suggestion.
- */
-class _ArgListAstVisitor
- extends GeneralizingAstVisitor<_ArgListSuggestionBuilder> {
- final DartCompletionRequest request;
-
- _ArgListAstVisitor(this.request);
-
- @override
- _ArgListSuggestionBuilder visitArgumentList(ArgumentList node) {
- Token leftParen = node.leftParenthesis;
- if (leftParen != null && request.offset > leftParen.offset) {
- AstNode parent = node.parent;
- if (parent is MethodInvocation) {
- SimpleIdentifier selector = parent.methodName;
- if (selector != null) {
- String name = selector.name;
- if (name != null && name.length > 0) {
- if (parent.period == null) {
- /*
- * If a local declaration is found, then return null
- * indicating that suggestions were added
- * and no further action is necessary
- */
- if (new _LocalDeclarationFinder(request, request.offset, name)
- .visit(node)) {
- return null;
- }
- } else {
- // determine target
- }
- }
- }
- }
- return new _ArgListSuggestionBuilder(request);
- }
- return null;
- }
-
- @override
- _ArgListSuggestionBuilder visitNode(AstNode node) {
- return null;
- }
-}
-
-/**
- * A `_ArgListSuggestionBuilder` determines which method or function is being
- * invoked, then builds the argument list suggestion.
- * This operation is instantiated during `computeFast`
- * and calculates the suggestions during `computeFull`.
- */
-class _ArgListSuggestionBuilder {
- final DartCompletionRequest request;
-
- _ArgListSuggestionBuilder(this.request);
-
- Future<bool> compute(ArgumentList node) {
- return new Future.value(false);
- }
-}
-
-/**
- * `_LocalDeclarationFinder` visits an [AstNode] and its parent recursively
- * looking for a matching declaration. If found, it adds the appropriate
- * suggestions and sets finished to `true`.
- */
-class _LocalDeclarationFinder extends LocalDeclarationVisitor {
- final DartCompletionRequest request;
- final String name;
-
- _LocalDeclarationFinder(this.request, int offset, this.name) : super(offset);
-
- @override
- void declaredClass(ClassDeclaration declaration) {}
-
- @override
- void declaredClassTypeAlias(ClassTypeAlias declaration) {}
-
- @override
- void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) {}
-
- @override
- void declaredFunction(FunctionDeclaration declaration) {
- SimpleIdentifier selector = declaration.name;
- if (selector != null && name == selector.name) {
- _addArgListSuggestion(declaration.functionExpression.parameters);
- finished();
- }
- }
-
- @override
- void declaredFunctionTypeAlias(FunctionTypeAlias declaration) {}
-
- @override
- void declaredLabel(Label label, bool isCaseLabel) {}
-
- @override
- void declaredLocalVar(SimpleIdentifier name, TypeName type) {}
-
- @override
- void declaredMethod(MethodDeclaration declaration) {
- SimpleIdentifier selector = declaration.name;
- if (selector != null && name == selector.name) {
- _addArgListSuggestion(declaration.parameters);
- finished();
- }
- }
-
- @override
- void declaredParam(SimpleIdentifier name, TypeName type) {}
-
- @override
- void declaredTopLevelVar(
- VariableDeclarationList varList, VariableDeclaration varDecl) {}
-
- void _addArgListSuggestion(FormalParameterList parameters) {
- if (parameters.parameters.length == 0) {
- return;
- }
- StringBuffer completion = new StringBuffer('(');
- List<String> paramNames = new List<String>();
- List<String> paramTypes = new List<String>();
- for (FormalParameter param in parameters.parameters) {
- SimpleIdentifier paramId = param.identifier;
- if (paramId != null) {
- String name = paramId.name;
- if (name != null && name.length > 0) {
- if (completion.length > 1) {
- completion.write(', ');
- }
- completion.write(name);
- paramNames.add(name);
- paramTypes.add(_getParamType(param));
- }
- }
- }
- completion.write(')');
- CompletionSuggestion suggestion = new CompletionSuggestion(
- CompletionSuggestionKind.ARGUMENT_LIST, DART_RELEVANCE_HIGH,
- completion.toString(), completion.length, 0, false, false);
- suggestion.parameterNames = paramNames;
- suggestion.parameterTypes = paramTypes;
- request.addSuggestion(suggestion);
- }
-
- String _getParamType(FormalParameter param) {
- TypeName type;
- if (param is SimpleFormalParameter) {
- type = param.type;
- }
- if (type != null) {
- Identifier id = type.name;
- if (id != null) {
- String name = id.name;
- if (name != null && name.length > 0) {
- return name;
- }
- }
- }
- return 'dynamic';
- }
-}
diff --git a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
new file mode 100644
index 0000000..0dac520
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
@@ -0,0 +1,359 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.completion.contributor.dart.arglist;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol_server.dart'
+ hide Element, ElementKind;
+import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
+import 'package:analysis_server/src/services/completion/local_declaration_visitor.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+void _addNamedParameterSuggestion(
+ DartCompletionRequest request, List<String> namedArgs, String name) {
+ if (name != null && name.length > 0 && !namedArgs.contains(name)) {
+ request.addSuggestion(new CompletionSuggestion(
+ CompletionSuggestionKind.NAMED_ARGUMENT, DART_RELEVANCE_PARAMETER,
+ '$name: ', name.length + 2, 0, false, false));
+ }
+}
+
+/**
+ * Determine the number of arguments.
+ */
+int _argCount(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ if (node is ArgumentList) {
+ return node.arguments.length;
+ }
+ return 0;
+}
+
+/**
+ * Determine if the completion target is at the end of the list of arguments.
+ */
+bool _isAppendingToArgList(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ if (node is ArgumentList) {
+ var entity = request.target.entity;
+ if (entity == node.rightParenthesis) {
+ return true;
+ }
+ if (node.arguments.length > 0 && node.arguments.last == entity) {
+ return entity is SimpleIdentifier;
+ }
+ }
+ return false;
+}
+
+/**
+ * Determine if the completion target is an emtpy argument list.
+ */
+bool _isEmptyArgList(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ return node is ArgumentList &&
+ node.leftParenthesis.next == node.rightParenthesis;
+}
+
+/**
+ * Return a collection of currently specified named arguments
+ */
+Iterable<String> _namedArgs(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ List<String> namedArgs = new List<String>();
+ if (node is ArgumentList) {
+ for (Expression arg in node.arguments) {
+ if (arg is NamedExpression) {
+ namedArgs.add(arg.name.label.name);
+ }
+ }
+ }
+ return namedArgs;
+}
+
+/**
+ * A contributor for calculating `completion.getSuggestions` request results
+ * when the cursor position is inside the arguments to a method call.
+ */
+class ArgListContributor extends DartCompletionContributor {
+ _ArgSuggestionBuilder builder;
+
+ @override
+ bool computeFast(DartCompletionRequest request) {
+ builder =
+ request.target.containingNode.accept(new _ArgListAstVisitor(request));
+ return builder == null;
+ }
+
+ @override
+ Future<bool> computeFull(DartCompletionRequest request) {
+ if (builder != null) {
+ return builder.compute(request.target.containingNode);
+ }
+ return new Future.value(false);
+ }
+}
+
+/**
+ * A visitor for determining whether an argument list suggestion is needed
+ * and instantiating the builder to create the suggestion.
+ */
+class _ArgListAstVisitor extends GeneralizingAstVisitor<_ArgSuggestionBuilder> {
+ final DartCompletionRequest request;
+
+ _ArgListAstVisitor(this.request);
+
+ @override
+ _ArgSuggestionBuilder visitArgumentList(ArgumentList node) {
+ Token leftParen = node.leftParenthesis;
+ if (leftParen != null && request.offset > leftParen.offset) {
+ AstNode parent = node.parent;
+ if (parent is MethodInvocation) {
+ SimpleIdentifier selector = parent.methodName;
+ if (selector != null) {
+ String name = selector.name;
+ if (name != null && name.length > 0) {
+ if (parent.operator == null) {
+ /*
+ * If a local declaration is found, then return null
+ * indicating that suggestions were added
+ * and no further action is necessary
+ */
+ if (new _LocalArgSuggestionBuilder(request, request.offset, name)
+ .visit(node)) {
+ return null;
+ }
+ } else {
+ // determine target
+ }
+ return new _ArgSuggestionBuilder(request, name);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @override
+ _ArgSuggestionBuilder visitNode(AstNode node) {
+ return null;
+ }
+}
+
+/**
+ * A [_ArgSuggestionBuilder] determines which method or function is being
+ * invoked, then builds the argument list suggestion.
+ * This operation is instantiated during `computeFast`
+ * and calculates the suggestions during `computeFull`.
+ */
+class _ArgSuggestionBuilder {
+ final DartCompletionRequest request;
+ final String methodName;
+
+ _ArgSuggestionBuilder(this.request, this.methodName);
+
+ Future<bool> compute(ArgumentList node) {
+ AstNode parent = node.parent;
+ if (parent is MethodInvocation) {
+ SimpleIdentifier methodName = parent.methodName;
+ if (methodName != null) {
+ Element methodElem = methodName.bestElement;
+ if (methodElem is ExecutableElement) {
+ _addSuggestions(methodElem.parameters);
+ }
+ }
+ }
+ return new Future.value(false);
+ }
+
+ void _addArgListSuggestion(Iterable<ParameterElement> requiredParam) {
+ StringBuffer completion = new StringBuffer('(');
+ List<String> paramNames = new List<String>();
+ List<String> paramTypes = new List<String>();
+ for (ParameterElement param in requiredParam) {
+ String name = param.name;
+ if (name != null && name.length > 0) {
+ if (completion.length > 1) {
+ completion.write(', ');
+ }
+ completion.write(name);
+ paramNames.add(name);
+ paramTypes.add(_getParamType(param));
+ }
+ }
+ completion.write(')');
+ CompletionSuggestion suggestion = new CompletionSuggestion(
+ CompletionSuggestionKind.ARGUMENT_LIST, DART_RELEVANCE_HIGH,
+ completion.toString(), completion.length, 0, false, false);
+ suggestion.parameterNames = paramNames;
+ suggestion.parameterTypes = paramTypes;
+ request.addSuggestion(suggestion);
+ }
+
+ void _addDefaultParamSuggestions(Iterable<ParameterElement> parameters) {
+ Iterable<String> namedArgs = _namedArgs(request);
+ for (ParameterElement param in parameters) {
+ if (param.parameterKind == ParameterKind.NAMED) {
+ _addNamedParameterSuggestion(request, namedArgs, param.name);
+ }
+ }
+ }
+
+ void _addSuggestions(Iterable<ParameterElement> parameters) {
+ if (parameters == null || parameters.length == 0) {
+ return;
+ }
+ Iterable<ParameterElement> requiredParam = parameters.where(
+ (ParameterElement p) => p.parameterKind == ParameterKind.REQUIRED);
+ if (requiredParam.length > 0 && _isEmptyArgList(request)) {
+ _addArgListSuggestion(requiredParam);
+ return;
+ }
+ if (_isAppendingToArgList(request) &&
+ _argCount(request) > requiredParam.length) {
+ _addDefaultParamSuggestions(parameters);
+ }
+ }
+
+ String _getParamType(ParameterElement param) {
+ DartType type = param.type;
+ if (type != null) {
+ return type.displayName;
+ }
+ return 'dynamic';
+ }
+}
+
+/**
+ * [_LocalArgSuggestionBuilder] visits an [AstNode] and its parent recursively
+ * looking for a matching declaration. If found, it adds the appropriate
+ * suggestions and sets finished to `true`.
+ */
+class _LocalArgSuggestionBuilder extends LocalDeclarationVisitor {
+ final DartCompletionRequest request;
+ final String name;
+
+ _LocalArgSuggestionBuilder(this.request, int offset, this.name)
+ : super(offset);
+
+ @override
+ void declaredClass(ClassDeclaration declaration) {}
+
+ @override
+ void declaredClassTypeAlias(ClassTypeAlias declaration) {}
+
+ @override
+ void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) {}
+
+ @override
+ void declaredFunction(FunctionDeclaration declaration) {
+ SimpleIdentifier selector = declaration.name;
+ if (selector != null && name == selector.name) {
+ _addSuggestions(declaration.functionExpression.parameters);
+ finished();
+ }
+ }
+
+ @override
+ void declaredFunctionTypeAlias(FunctionTypeAlias declaration) {}
+
+ @override
+ void declaredLabel(Label label, bool isCaseLabel) {}
+
+ @override
+ void declaredLocalVar(SimpleIdentifier name, TypeName type) {}
+
+ @override
+ void declaredMethod(MethodDeclaration declaration) {
+ SimpleIdentifier selector = declaration.name;
+ if (selector != null && name == selector.name) {
+ _addSuggestions(declaration.parameters);
+ finished();
+ }
+ }
+
+ @override
+ void declaredParam(SimpleIdentifier name, TypeName type) {}
+
+ @override
+ void declaredTopLevelVar(
+ VariableDeclarationList varList, VariableDeclaration varDecl) {}
+
+ void _addArgListSuggestion(Iterable<FormalParameter> requiredParam) {
+ StringBuffer completion = new StringBuffer('(');
+ List<String> paramNames = new List<String>();
+ List<String> paramTypes = new List<String>();
+ for (FormalParameter param in requiredParam) {
+ SimpleIdentifier paramId = param.identifier;
+ if (paramId != null) {
+ String name = paramId.name;
+ if (name != null && name.length > 0) {
+ if (completion.length > 1) {
+ completion.write(', ');
+ }
+ completion.write(name);
+ paramNames.add(name);
+ paramTypes.add(_getParamType(param));
+ }
+ }
+ }
+ completion.write(')');
+ CompletionSuggestion suggestion = new CompletionSuggestion(
+ CompletionSuggestionKind.ARGUMENT_LIST, DART_RELEVANCE_HIGH,
+ completion.toString(), completion.length, 0, false, false);
+ suggestion.parameterNames = paramNames;
+ suggestion.parameterTypes = paramTypes;
+ request.addSuggestion(suggestion);
+ }
+
+ void _addDefaultParamSuggestions(FormalParameterList parameters) {
+ Iterable<String> namedArgs = _namedArgs(request);
+ for (FormalParameter param in parameters.parameters) {
+ if (param.kind == ParameterKind.NAMED) {
+ SimpleIdentifier paramId = param.identifier;
+ if (paramId != null) {
+ _addNamedParameterSuggestion(request, namedArgs, paramId.name);
+ }
+ }
+ }
+ }
+
+ void _addSuggestions(FormalParameterList parameters) {
+ if (parameters == null || parameters.parameters.length == 0) {
+ return;
+ }
+ Iterable<FormalParameter> requiredParam = parameters.parameters
+ .where((FormalParameter p) => p.kind == ParameterKind.REQUIRED);
+ if (requiredParam.length > 0 && _isEmptyArgList(request)) {
+ _addArgListSuggestion(requiredParam);
+ return;
+ }
+ if (_isAppendingToArgList(request) &&
+ _argCount(request) > requiredParam.length) {
+ _addDefaultParamSuggestions(parameters);
+ }
+ }
+
+ String _getParamType(FormalParameter param) {
+ TypeName type;
+ if (param is SimpleFormalParameter) {
+ type = param.type;
+ }
+ if (type != null) {
+ Identifier id = type.name;
+ if (id != null) {
+ String name = id.name;
+ if (name != null && name.length > 0) {
+ return name;
+ }
+ }
+ }
+ return 'dynamic';
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/combinator_computer.dart b/pkg/analysis_server/lib/src/services/completion/combinator_contributor.dart
similarity index 83%
rename from pkg/analysis_server/lib/src/services/completion/combinator_computer.dart
rename to pkg/analysis_server/lib/src/services/completion/combinator_contributor.dart
index 3da2f69..402d4a2 100644
--- a/pkg/analysis_server/lib/src/services/completion/combinator_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/combinator_contributor.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library services.completion.computer.dart.combinator;
+library services.completion.contributor.dart.combinator;
import 'dart:async';
@@ -14,22 +14,23 @@
import 'package:analyzer/src/generated/element.dart';
/**
- * A computer for calculating `completion.getSuggestions` request results
+ * A contributor for calculating `completion.getSuggestions` request results
* for the import combinators show and hide.
*/
-class CombinatorComputer extends DartCompletionComputer {
+class CombinatorContributor extends DartCompletionContributor {
_CombinatorSuggestionBuilder builder;
@override
bool computeFast(DartCompletionRequest request) {
- builder = request.node.accept(new _CombinatorAstVisitor(request));
+ builder = request.target.containingNode
+ .accept(new _CombinatorAstVisitor(request));
return builder == null;
}
@override
Future<bool> computeFull(DartCompletionRequest request) {
if (builder != null) {
- return builder.execute(request.node);
+ return builder.execute(request.target.containingNode);
}
return new Future.value(false);
}
@@ -55,11 +56,6 @@
_CombinatorSuggestionBuilder visitNode(AstNode node) {
return null;
}
-
- @override
- _CombinatorSuggestionBuilder visitSimpleIdentifier(SimpleIdentifier node) {
- return node.parent.accept(this);
- }
}
/**
@@ -71,7 +67,7 @@
class _CombinatorSuggestionBuilder extends LibraryElementSuggestionBuilder {
_CombinatorSuggestionBuilder(
DartCompletionRequest request, CompletionSuggestionKind kind)
- : super(request, kind);
+ : super(request, kind, false);
Future<bool> execute(AstNode node) {
var directive = node.getAncestor((parent) => parent is NamespaceDirective);
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
index a46adae..5ed7b1a 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library services.completion.computer;
+library services.completion.manager;
import 'dart:async';
@@ -32,7 +32,7 @@
}
/**
- * Manages `CompletionComputer`s for a given completion request.
+ * Manages completion contributors for a given completion request.
*/
abstract class CompletionManager {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
index 17127f7..d8afca4 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
@@ -127,7 +127,7 @@
assert(unit.element.source == source);
// Exclude elements from local library
- // because they are provided by LocalComputer
+ // because they are provided by LocalReferenceContributor
Set<LibraryElement> excludedLibs = new Set<LibraryElement>();
excludedLibs.add(unit.element.enclosingElement);
@@ -237,7 +237,7 @@
});
} else {
// Exclude elements from prefixed imports
- // because they are provided by InvocationComputer
+ // because they are provided by PrefixedElementContributor
_addLibraryPrefixSuggestion(importElem);
excludedLibs.add(importElem.importedLibrary);
}
@@ -277,6 +277,20 @@
*/
void _addNonImportedElementSuggestions(
List<SearchMatch> matches, Set<LibraryElement> excludedLibs) {
+
+ // Exclude internal Dart SDK libraries
+ for (var lib in context.sourceFactory.dartSdk.sdkLibraries) {
+ if (lib.isInternal) {
+ Source libUri = context.sourceFactory.forUri(lib.shortName);
+ if (libUri != null) {
+ LibraryElement libElem = context.getLibraryElement(libUri);
+ if (libElem != null) {
+ excludedLibs.add(libElem);
+ }
+ }
+ }
+ }
+
AnalysisContext sdkContext = context.sourceFactory.dartSdk.context;
matches.forEach((SearchMatch match) {
if (match.kind == MatchKind.DECLARATION) {
@@ -296,9 +310,15 @@
*/
void _addSuggestion(Element element, int relevance) {
if (element is ExecutableElement) {
+ // Do not suggest operators or local functions
if (element.isOperator) {
return;
}
+ if (element is FunctionElement) {
+ if (element.enclosingElement is! CompilationUnitElement) {
+ return;
+ }
+ }
}
CompletionSuggestion suggestion =
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
index 0f77b19..c1b0339 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
@@ -7,16 +7,16 @@
import 'dart:async';
import 'package:analysis_server/src/protocol.dart';
-import 'package:analysis_server/src/services/completion/arglist_computer.dart';
-import 'package:analysis_server/src/services/completion/combinator_computer.dart';
+import 'package:analysis_server/src/services/completion/arglist_contributor.dart';
+import 'package:analysis_server/src/services/completion/combinator_contributor.dart';
import 'package:analysis_server/src/services/completion/common_usage_computer.dart';
import 'package:analysis_server/src/services/completion/completion_manager.dart';
import 'package:analysis_server/src/services/completion/completion_target.dart';
import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
-import 'package:analysis_server/src/services/completion/imported_computer.dart';
-import 'package:analysis_server/src/services/completion/invocation_computer.dart';
-import 'package:analysis_server/src/services/completion/keyword_computer.dart';
-import 'package:analysis_server/src/services/completion/local_computer.dart';
+import 'package:analysis_server/src/services/completion/imported_reference_contributor.dart';
+import 'package:analysis_server/src/services/completion/prefixed_element_contributor.dart';
+import 'package:analysis_server/src/services/completion/keyword_contributor.dart';
+import 'package:analysis_server/src/services/completion/local_reference_contributor.dart';
import 'package:analysis_server/src/services/completion/optype.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/src/generated/ast.dart';
@@ -41,15 +41,15 @@
const int DART_RELEVANCE_PARAMETER = 1059;
/**
- * The base class for computing code completion suggestions.
+ * The base class for contributing code completion suggestions.
*/
-abstract class DartCompletionComputer {
+abstract class DartCompletionContributor {
/**
* Computes the initial set of [CompletionSuggestion]s based on
* the given completion context. The compilation unit and completion node
* in the given completion context may not be resolved.
* This method should execute quickly and not block waiting for any analysis.
- * Returns `true` if the computer's work is complete
+ * Returns `true` if the contributor's work is complete
* or `false` if [computeFull] should be called to complete the work.
*/
bool computeFast(DartCompletionRequest request);
@@ -69,23 +69,24 @@
class DartCompletionManager extends CompletionManager {
final SearchEngine searchEngine;
final DartCompletionCache cache;
- List<DartCompletionComputer> computers;
+ List<DartCompletionContributor> contributors;
CommonUsageComputer commonUsageComputer;
DartCompletionManager(
AnalysisContext context, this.searchEngine, Source source, this.cache,
- [this.computers, this.commonUsageComputer])
+ [this.contributors, this.commonUsageComputer])
: super(context, source) {
- if (computers == null) {
- computers = [
- // LocalComputer before ImportedComputer
+ if (contributors == null) {
+ contributors = [
+ // LocalReferenceContributor before ImportedReferenceContributor
// because local suggestions take precedence
- new LocalComputer(),
- new ImportedComputer(),
- new KeywordComputer(),
- new ArgListComputer(),
- new CombinatorComputer(),
- new InvocationComputer()
+ // and can hide other suggestions with the same name
+ new LocalReferenceContributor(),
+ new ImportedReferenceContributor(),
+ new KeywordContributor(),
+ new ArgListContributor(),
+ new CombinatorContributor(),
+ new PrefixedElementContributor()
];
}
if (commonUsageComputer == null) {
@@ -116,20 +117,20 @@
/**
* Compute suggestions based upon cached information only
* then send an initial response to the client.
- * Return a list of computers for which [computeFull] should be called
+ * Return a list of contributors for which [computeFull] should be called
*/
- List<DartCompletionComputer> computeFast(DartCompletionRequest request) {
+ List<DartCompletionContributor> computeFast(DartCompletionRequest request) {
return request.performance.logElapseTime('computeFast', () {
CompilationUnit unit = context.parseCompilationUnit(source);
request.unit = unit;
- request.node = new NodeLocator.con1(request.offset).searchWithin(unit);
request.target = new CompletionTarget.forOffset(unit, request.offset);
- if (request.node == null) {
+ request.replacementOffset = request.offset;
+ request.replacementLength = 0;
+ if (request.offset < 0 || request.offset > unit.end) {
+ sendResults(request, true);
return [];
}
- request.replacementOffset = request.offset;
- request.replacementLength = 0;
var entity = request.target.entity;
Token token = entity is AstNode ? entity.beginToken : entity;
if (token != null &&
@@ -140,8 +141,8 @@
request.replacementLength = token.length;
}
- List<DartCompletionComputer> todo = new List.from(computers);
- todo.removeWhere((DartCompletionComputer c) {
+ List<DartCompletionContributor> todo = new List.from(contributors);
+ todo.removeWhere((DartCompletionContributor c) {
return request.performance.logElapseTime('computeFast ${c.runtimeType}',
() {
return c.computeFast(request);
@@ -155,11 +156,11 @@
/**
* If there is remaining work to be done, then wait for the unit to be
- * resolved and request that each remaining computer finish their work.
+ * resolved and request that each remaining contributor finish their work.
* Return a [Future] that completes when the last notification has been sent.
*/
Future computeFull(
- DartCompletionRequest request, List<DartCompletionComputer> todo) {
+ DartCompletionRequest request, List<DartCompletionContributor> todo) {
request.performance.logStartTime('waitForAnalysis');
return waitForAnalysis().then((CompilationUnit unit) {
if (controller.isClosed) {
@@ -172,12 +173,11 @@
}
request.performance.logElapseTime('computeFull', () {
request.unit = unit;
- request.node = new NodeLocator.con1(request.offset).searchWithin(unit);
// TODO(paulberry): Do we need to invoke _ReplacementOffsetBuilder
// again?
request.target = new CompletionTarget.forOffset(unit, request.offset);
int count = todo.length;
- todo.forEach((DartCompletionComputer c) {
+ todo.forEach((DartCompletionContributor c) {
String name = c.runtimeType.toString();
String completeTag = 'computeFull $name complete';
request.performance.logStartTime(completeTag);
@@ -202,7 +202,7 @@
searchEngine, source, completionRequest.offset, cache,
completionRequest.performance);
request.performance.logElapseTime('compute', () {
- List<DartCompletionComputer> todo = computeFast(request);
+ List<DartCompletionContributor> todo = computeFast(request);
if (!todo.isEmpty) {
computeFull(request, todo);
}
@@ -272,24 +272,14 @@
/**
* The compilation unit in which the completion was requested. This unit
- * may or may not be resolved when [DartCompletionComputer.computeFast]
- * is called but is resolved when [DartCompletionComputer.computeFull].
+ * may or may not be resolved when [DartCompletionContributor.computeFast]
+ * is called but is resolved when [DartCompletionContributor.computeFull].
*/
CompilationUnit unit;
/**
- * The node in which the completion occurred. This node
- * may or may not be resolved when [DartCompletionComputer.computeFast]
- * is called but is resolved when [DartCompletionComputer.computeFull].
- */
- AstNode node;
-
- /**
* The completion target. This determines what part of the parse tree
* will receive the newly inserted text.
- *
- * TODO(paulberry) gradually transition code over to using this rather than
- * [node].
*/
CompletionTarget target;
diff --git a/pkg/analysis_server/lib/src/services/completion/imported_computer.dart b/pkg/analysis_server/lib/src/services/completion/imported_reference_contributor.dart
similarity index 85%
rename from pkg/analysis_server/lib/src/services/completion/imported_computer.dart
rename to pkg/analysis_server/lib/src/services/completion/imported_reference_contributor.dart
index 2031557..5608f8f 100644
--- a/pkg/analysis_server/lib/src/services/completion/imported_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/imported_reference_contributor.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library services.completion.computer.dart.toplevel;
+library services.completion.contributor.dart.toplevel;
import 'dart:async';
import 'dart:collection';
@@ -17,47 +17,48 @@
import 'package:analyzer/src/generated/element.dart';
/**
- * A computer for calculating imported class and top level variable
+ * A contributor for calculating imported class and top level variable
* `completion.getSuggestions` request results.
*/
-class ImportedComputer extends DartCompletionComputer {
+class ImportedReferenceContributor extends DartCompletionContributor {
bool shouldWaitForLowPrioritySuggestions;
bool suggestionsComputed;
_ImportedSuggestionBuilder builder;
- ImportedComputer({this.shouldWaitForLowPrioritySuggestions: false});
+ ImportedReferenceContributor({this.shouldWaitForLowPrioritySuggestions: false});
@override
bool computeFast(DartCompletionRequest request) {
OpType optype = request.optype;
- if (optype.includeReturnValueSuggestions ||
- optype.includeTypeNameSuggestions ||
- optype.includeVoidReturnSuggestions ||
- optype.includeConstructorSuggestions) {
- builder = new _ImportedSuggestionBuilder(request, optype);
- builder.shouldWaitForLowPrioritySuggestions =
- shouldWaitForLowPrioritySuggestions;
- // If target is an argument in an argument list
- // then suggestions may need to be adjusted
- suggestionsComputed = builder.computeFast(request.node);
- return suggestionsComputed && request.target.argIndex == null;
+ if (!optype.isPrefixed) {
+ if (optype.includeReturnValueSuggestions ||
+ optype.includeTypeNameSuggestions ||
+ optype.includeVoidReturnSuggestions ||
+ optype.includeConstructorSuggestions) {
+ builder = new _ImportedSuggestionBuilder(request, optype);
+ builder.shouldWaitForLowPrioritySuggestions =
+ shouldWaitForLowPrioritySuggestions;
+ // If target is an argument in an argument list
+ // then suggestions may need to be adjusted
+ suggestionsComputed = builder.computeFast(request.target.containingNode);
+ return suggestionsComputed && request.target.argIndex == null;
+ }
}
return true;
}
@override
- Future<bool> computeFull(DartCompletionRequest request) {
+ Future<bool> computeFull(DartCompletionRequest request) async {
if (builder != null) {
if (!suggestionsComputed) {
- return builder.computeFull(request.node).then((bool result) {
- _updateSuggestions(request);
- return result;
- });
+ bool result = await builder.computeFull(request.target.containingNode);
+ _updateSuggestions(request);
+ return result;
}
_updateSuggestions(request);
- return new Future.value(true);
+ return true;
}
- return new Future.value(false);
+ return false;
}
/**
@@ -143,7 +144,7 @@
*/
void _addElementSuggestions(List<Element> elements,
{int relevance: DART_RELEVANCE_DEFAULT}) {
- elements.forEach((Element elem) {
+ for (Element elem in elements) {
if (elem is! ClassElement) {
if (optype.includeOnlyTypeNameSuggestions) {
return;
@@ -158,7 +159,8 @@
}
}
addSuggestion(elem, relevance: relevance);
- });
+ }
+ ;
}
/**
@@ -190,7 +192,7 @@
// and include any inherited imported members
List<String> inheritedTypes = new List<String>();
visitInheritedTypes(classDecl, (_) {
- // local declarations are handled by the local computer
+ // local declarations are handled by the local reference contributor
}, (String typeName) {
inheritedTypes.add(typeName);
});
diff --git a/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart b/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
deleted file mode 100644
index 36d403b..0000000
--- a/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library services.completion.computer.dart.keyword;
-
-import 'dart:async';
-
-import 'package:analysis_server/src/protocol.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
-
-/**
- * A computer for calculating `completion.getSuggestions` request results
- * for the local library in which the completion is requested.
- */
-class KeywordComputer extends DartCompletionComputer {
- @override
- bool computeFast(DartCompletionRequest request) {
- request.node.accept(new _KeywordVisitor(request));
- return true;
- }
-
- @override
- Future<bool> computeFull(DartCompletionRequest request) {
- return new Future.value(false);
- }
-}
-
-/**
- * A vistor for generating keyword suggestions.
- */
-class _KeywordVisitor extends GeneralizingAstVisitor {
- final DartCompletionRequest request;
-
- /**
- * The identifier visited or `null` if not visited.
- */
- SimpleIdentifier identifier;
-
- _KeywordVisitor(this.request);
-
- @override
- visitBlock(Block node) {
- if (_isInClassMemberBody(node)) {
- _addSuggestions([
- Keyword.ASSERT,
- Keyword.CASE,
- Keyword.CONTINUE,
- Keyword.DO,
- Keyword.FINAL,
- Keyword.FOR,
- Keyword.IF,
- Keyword.NEW,
- Keyword.RETHROW,
- Keyword.RETURN,
- Keyword.SUPER,
- Keyword.SWITCH,
- Keyword.THIS,
- Keyword.THROW,
- Keyword.TRY,
- Keyword.VAR,
- Keyword.VOID,
- Keyword.WHILE
- ]);
- } else {
- _addSuggestions([
- Keyword.ASSERT,
- Keyword.CASE,
- Keyword.CONTINUE,
- Keyword.DO,
- Keyword.FINAL,
- Keyword.FOR,
- Keyword.IF,
- Keyword.NEW,
- Keyword.RETHROW,
- Keyword.RETURN,
- Keyword.SWITCH,
- Keyword.THROW,
- Keyword.TRY,
- Keyword.VAR,
- Keyword.VOID,
- Keyword.WHILE
- ]);
- }
- }
-
- @override
- visitClassDeclaration(ClassDeclaration node) {
- // Don't suggest class name
- if (node.name == identifier) {
- return;
- }
- // Inside the class declaration { }
- if (request.offset > node.leftBracket.offset) {
- _addSuggestions([
- Keyword.CONST,
- Keyword.DYNAMIC,
- Keyword.FACTORY,
- Keyword.FINAL,
- Keyword.GET,
- Keyword.OPERATOR,
- Keyword.SET,
- Keyword.STATIC,
- Keyword.VAR,
- Keyword.VOID
- ]);
- return;
- }
- _addClassDeclarationKeywords(node);
- }
-
- @override
- visitCompilationUnit(CompilationUnit node) {
- Directive firstDirective;
- int endOfDirectives = 0;
- if (node.directives.length > 0) {
- firstDirective = node.directives[0];
- endOfDirectives = node.directives.last.end - 1;
- }
- int startOfDeclarations = node.end;
- if (node.declarations.length > 0) {
- startOfDeclarations = node.declarations[0].offset;
- // If the first token is a simple identifier
- // and cursor position in within that first token
- // then consider cursor to be before the first declaration
- Token token = node.declarations[0].firstTokenAfterCommentAndMetadata;
- if (token.offset <= request.offset && request.offset <= token.end) {
- startOfDeclarations = token.end;
- }
- }
-
- // Simplistic check for library as first directive
- if (firstDirective is! LibraryDirective) {
- if (firstDirective != null) {
- if (request.offset <= firstDirective.offset) {
- _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
- }
- } else {
- if (request.offset <= startOfDeclarations) {
- _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
- }
- }
- }
- if (request.offset <= startOfDeclarations) {
- _addSuggestions(
- [Keyword.EXPORT, Keyword.IMPORT, Keyword.PART], DART_RELEVANCE_HIGH);
- }
- if (request.offset >= endOfDirectives) {
- _addSuggestions([
- Keyword.ABSTRACT,
- Keyword.CLASS,
- Keyword.CONST,
- Keyword.FINAL,
- Keyword.TYPEDEF,
- Keyword.VAR
- ], DART_RELEVANCE_HIGH);
- }
- }
-
- @override
- visitNode(AstNode node) {
- if (_isOffsetAfterNode(node)) {
- node.parent.accept(this);
- }
- }
-
- visitSimpleIdentifier(SimpleIdentifier node) {
- identifier = node;
- node.parent.accept(this);
- }
-
- void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
- if (identifier != null && node.beginToken == identifier.beginToken) {
- AstNode unit = node.parent;
- if (unit is CompilationUnit) {
- CompilationUnitMember previous;
- for (CompilationUnitMember member in unit.declarations) {
- if (member == node && previous is ClassDeclaration) {
- if (previous.endToken.isSynthetic) {
- // Partial keywords (simple identifirs) that are part of a
- // class declaration can be parsed
- // as a TypeName in a TopLevelVariableDeclaration
- _addClassDeclarationKeywords(previous);
- return;
- }
- }
- previous = member;
- }
- // Partial keywords (simple identifiers) can be parsed
- // as a TypeName in a TopLevelVariableDeclaration
- unit.accept(this);
- }
- }
- }
-
- void visitTypeName(TypeName node) {
- node.parent.accept(this);
- }
-
- void visitVariableDeclarationList(VariableDeclarationList node) {
- node.parent.accept(this);
- }
-
- void _addClassDeclarationKeywords(ClassDeclaration node) {
- // Very simplistic suggestion because analyzer will warn if
- // the extends / with / implements keywords are out of order
- if (node.extendsClause == null) {
- _addSuggestion(Keyword.EXTENDS, DART_RELEVANCE_HIGH);
- } else if (node.withClause == null) {
- _addSuggestion(Keyword.WITH, DART_RELEVANCE_HIGH);
- }
- if (node.implementsClause == null) {
- _addSuggestion(Keyword.IMPLEMENTS, DART_RELEVANCE_HIGH);
- }
- }
-
- void _addSuggestion(Keyword keyword,
- [int relevance = DART_RELEVANCE_DEFAULT]) {
- String completion = keyword.syntax;
- request.addSuggestion(new CompletionSuggestion(
- CompletionSuggestionKind.KEYWORD,
- relevance, completion, completion.length, 0, false, false));
- }
-
- void _addSuggestions(List<Keyword> keywords,
- [int relevance = DART_RELEVANCE_KEYWORD]) {
- keywords.forEach((Keyword keyword) {
- _addSuggestion(keyword, relevance);
- });
- }
-
- bool _isOffsetAfterNode(AstNode node) {
- if (request.offset == node.end) {
- Token token = node.endToken;
- if (token != null && !token.isSynthetic) {
- if (token.lexeme == ';' || token.lexeme == '}') {
- return true;
- }
- }
- }
- return false;
- }
-
- static bool _isInClassMemberBody(AstNode node) {
- while (true) {
- AstNode body = node.getAncestor((n) => n is FunctionBody);
- if (body == null) {
- return false;
- }
- AstNode parent = body.parent;
- if (parent is ConstructorDeclaration || parent is MethodDeclaration) {
- return true;
- }
- node = parent;
- }
- }
-}
diff --git a/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
new file mode 100644
index 0000000..b979b8b
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
@@ -0,0 +1,202 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.completion.contributor.dart.keyword;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+
+/**
+ * A contributor for calculating `completion.getSuggestions` request results
+ * for the local library in which the completion is requested.
+ */
+class KeywordContributor extends DartCompletionContributor {
+ @override
+ bool computeFast(DartCompletionRequest request) {
+ request.target.containingNode.accept(new _KeywordVisitor(request));
+ return true;
+ }
+
+ @override
+ Future<bool> computeFull(DartCompletionRequest request) {
+ return new Future.value(false);
+ }
+}
+
+/**
+ * A vistor for generating keyword suggestions.
+ */
+class _KeywordVisitor extends GeneralizingAstVisitor {
+ final DartCompletionRequest request;
+ final Object entity;
+
+ _KeywordVisitor(DartCompletionRequest request)
+ : this.request = request,
+ this.entity = request.target.entity;
+
+ @override
+ visitBlock(Block node) {
+ if (_isInClassMemberBody(node)) {
+ _addSuggestions([Keyword.SUPER, Keyword.THIS,]);
+ }
+ _addSuggestions([
+ Keyword.ASSERT,
+ Keyword.CASE,
+ Keyword.CONTINUE,
+ Keyword.DO,
+ Keyword.FINAL,
+ Keyword.FOR,
+ Keyword.IF,
+ Keyword.NEW,
+ Keyword.RETHROW,
+ Keyword.RETURN,
+ Keyword.SWITCH,
+ Keyword.THROW,
+ Keyword.TRY,
+ Keyword.VAR,
+ Keyword.VOID,
+ Keyword.WHILE
+ ]);
+ }
+
+ @override
+ visitClassDeclaration(ClassDeclaration node) {
+ // Don't suggest class name
+ if (entity == node.name) {
+ return;
+ }
+ if (entity == node.rightBracket || entity is ClassMember) {
+ _addSuggestions([
+ Keyword.CONST,
+ Keyword.DYNAMIC,
+ Keyword.FACTORY,
+ Keyword.FINAL,
+ Keyword.GET,
+ Keyword.OPERATOR,
+ Keyword.SET,
+ Keyword.STATIC,
+ Keyword.VAR,
+ Keyword.VOID
+ ]);
+ return;
+ }
+ _addClassDeclarationKeywords(node);
+ }
+
+ @override
+ visitCompilationUnit(CompilationUnit node) {
+ var previousMember = null;
+ for (var member in node.childEntities) {
+ if (entity == member) {
+ break;
+ }
+ previousMember = member;
+ }
+ if (previousMember is ClassDeclaration) {
+ if (previousMember.leftBracket == null ||
+ previousMember.leftBracket.isSynthetic) {
+ // If the prior member is an unfinished class declaration
+ // then the user is probably finishing that
+ _addClassDeclarationKeywords(previousMember);
+ return;
+ }
+ }
+ if (previousMember is ImportDirective) {
+ if (previousMember.semicolon == null ||
+ previousMember.semicolon.isSynthetic) {
+ // If the prior member is an unfinished import directive
+ // then the user is probably finishing that
+ _addImportDirectiveKeywords(previousMember);
+ return;
+ }
+ }
+ if (previousMember == null || previousMember is Directive) {
+ if (previousMember == null &&
+ !node.directives.any((d) => d is LibraryDirective)) {
+ _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
+ }
+ _addSuggestions(
+ [Keyword.EXPORT, Keyword.IMPORT, Keyword.PART], DART_RELEVANCE_HIGH);
+ }
+ if (entity == null || entity is Declaration) {
+ _addSuggestions([
+ Keyword.ABSTRACT,
+ Keyword.CLASS,
+ Keyword.CONST,
+ Keyword.DYNAMIC,
+ Keyword.FINAL,
+ Keyword.TYPEDEF,
+ Keyword.VAR,
+ Keyword.VOID
+ ], DART_RELEVANCE_HIGH);
+ }
+ }
+
+ @override
+ visitImportDirective(ImportDirective node) {
+ if (entity == node.asKeyword) {
+ if (node.deferredKeyword == null) {
+ _addSuggestion(Keyword.DEFERRED, DART_RELEVANCE_HIGH);
+ }
+ }
+ if (entity == node.semicolon || node.combinators.contains(entity)) {
+ _addImportDirectiveKeywords(node);
+ }
+ }
+
+ void _addImportDirectiveKeywords(ImportDirective node) {
+ if (node.asKeyword == null) {
+ _addSuggestion(Keyword.AS, DART_RELEVANCE_HIGH);
+ if (node.deferredKeyword == null) {
+ _addSuggestion(Keyword.DEFERRED, DART_RELEVANCE_HIGH);
+ }
+ }
+ }
+
+ void _addClassDeclarationKeywords(ClassDeclaration node) {
+ // Very simplistic suggestion because analyzer will warn if
+ // the extends / with / implements keywords are out of order
+ if (node.extendsClause == null) {
+ _addSuggestion(Keyword.EXTENDS, DART_RELEVANCE_HIGH);
+ } else if (node.withClause == null) {
+ _addSuggestion(Keyword.WITH, DART_RELEVANCE_HIGH);
+ }
+ if (node.implementsClause == null) {
+ _addSuggestion(Keyword.IMPLEMENTS, DART_RELEVANCE_HIGH);
+ }
+ }
+
+ void _addSuggestion(Keyword keyword,
+ [int relevance = DART_RELEVANCE_DEFAULT]) {
+ String completion = keyword.syntax;
+ request.addSuggestion(new CompletionSuggestion(
+ CompletionSuggestionKind.KEYWORD, relevance, completion,
+ completion.length, 0, false, false));
+ }
+
+ void _addSuggestions(List<Keyword> keywords,
+ [int relevance = DART_RELEVANCE_KEYWORD]) {
+ keywords.forEach((Keyword keyword) {
+ _addSuggestion(keyword, relevance);
+ });
+ }
+
+ bool _isInClassMemberBody(AstNode node) {
+ while (true) {
+ AstNode body = node.getAncestor((n) => n is FunctionBody);
+ if (body == null) {
+ return false;
+ }
+ AstNode parent = body.parent;
+ if (parent is ConstructorDeclaration || parent is MethodDeclaration) {
+ return true;
+ }
+ node = parent;
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart b/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart
index ef36304..d00921a 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library services.completion.computer.dart.local.Declaration.visitor;
+library services.completion.dart.local.declaration.visitor;
import 'package:analysis_server/src/services/completion/suggestion_builder.dart';
import 'package:analyzer/src/generated/ast.dart';
diff --git a/pkg/analysis_server/lib/src/services/completion/local_computer.dart b/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
similarity index 94%
rename from pkg/analysis_server/lib/src/services/completion/local_computer.dart
rename to pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
index 5602d81..12cdd5e 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library services.completion.computer.dart.local;
+library services.completion.contributor.dart.local;
import 'dart:async';
@@ -77,32 +77,34 @@
}
/**
- * A computer for calculating `completion.getSuggestions` request results
+ * A contributor for calculating `completion.getSuggestions` request results
* for the local library in which the completion is requested.
*/
-class LocalComputer extends DartCompletionComputer {
+class LocalReferenceContributor extends DartCompletionContributor {
@override
bool computeFast(DartCompletionRequest request) {
OpType optype = request.optype;
// Collect suggestions from the specific child [AstNode] that contains
// the completion offset and all of its parents recursively.
- if (optype.includeReturnValueSuggestions ||
- optype.includeTypeNameSuggestions ||
- optype.includeVoidReturnSuggestions) {
- _LocalVisitor localVisitor =
- new _LocalVisitor(request, request.offset, optype);
- localVisitor.visit(request.node);
- }
- if (optype.includeStatementLabelSuggestions ||
- optype.includeCaseLabelSuggestions) {
- _LabelVisitor labelVisitor = new _LabelVisitor(request,
- optype.includeStatementLabelSuggestions,
- optype.includeCaseLabelSuggestions);
- labelVisitor.visit(request.node);
- }
- if (optype.includeConstructorSuggestions) {
- new _ConstructorVisitor(request).visit(request.node);
+ if (!optype.isPrefixed) {
+ if (optype.includeReturnValueSuggestions ||
+ optype.includeTypeNameSuggestions ||
+ optype.includeVoidReturnSuggestions) {
+ _LocalVisitor localVisitor =
+ new _LocalVisitor(request, request.offset, optype);
+ localVisitor.visit(request.target.containingNode);
+ }
+ if (optype.includeStatementLabelSuggestions ||
+ optype.includeCaseLabelSuggestions) {
+ _LabelVisitor labelVisitor = new _LabelVisitor(request,
+ optype.includeStatementLabelSuggestions,
+ optype.includeCaseLabelSuggestions);
+ labelVisitor.visit(request.target.containingNode);
+ }
+ if (optype.includeConstructorSuggestions) {
+ new _ConstructorVisitor(request).visit(request.target.containingNode);
+ }
}
// If target is an argument in an argument list
@@ -429,11 +431,6 @@
final DartCompletionRequest request;
final OpType optype;
- /**
- * The simple identifier that is being completed, or `null` if none.
- */
- SimpleIdentifier targetId;
-
_LocalVisitor(this.request, int offset, this.optype) : super(offset);
@override
@@ -631,13 +628,6 @@
}
}
- @override
- void visitSimpleIdentifier(SimpleIdentifier node) {
- // Record the visited identifier so as not to suggest it
- targetId = node;
- return super.visitSimpleIdentifier(node);
- }
-
void _addParameterInfo(
CompletionSuggestion suggestion, FormalParameterList parameters) {
var paramList = parameters.parameters;
@@ -676,7 +666,7 @@
CompletionSuggestion _addSuggestion(SimpleIdentifier id, TypeName returnType,
bool isDeprecated, int defaultRelevance, {ClassDeclaration classDecl}) {
- if (id != null && !identical(id, targetId)) {
+ if (id != null) {
String completion = id.name;
if (completion != null && completion.length > 0 && completion != '_') {
CompletionSuggestion suggestion = new CompletionSuggestion(
diff --git a/pkg/analysis_server/lib/src/services/completion/optype.dart b/pkg/analysis_server/lib/src/services/completion/optype.dart
index 83ef718..84bced9 100644
--- a/pkg/analysis_server/lib/src/services/completion/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/optype.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library services.completion.computer.dart.optype;
+library services.completion.dart.optype;
import 'package:analysis_server/src/services/completion/completion_target.dart';
import 'package:analyzer/src/generated/ast.dart';
@@ -21,11 +21,6 @@
bool includeConstructorSuggestions = false;
/**
- * Indicates whether invocation suggestions should be included.
- */
- bool includeInvocationSuggestions = false;
-
- /**
* Indicates whether type names should be suggested.
*/
bool includeTypeNameSuggestions = false;
@@ -53,6 +48,11 @@
bool includeCaseLabelSuggestions = false;
/**
+ * Indicates whether the completion target is prefixed.
+ */
+ bool isPrefixed = false;
+
+ /**
* Determine the suggestions that should be made based upon the given
* [CompletionTarget] and [offset].
*/
@@ -70,8 +70,7 @@
*/
bool get includeOnlyTypeNameSuggestions => includeTypeNameSuggestions &&
!includeReturnValueSuggestions &&
- !includeVoidReturnSuggestions &&
- !includeInvocationSuggestions;
+ !includeVoidReturnSuggestions;
}
class _OpTypeAstVisitor extends GeneralizingAstVisitor {
@@ -100,7 +99,9 @@
optype.includeTypeNameSuggestions = true;
optype.includeReturnValueSuggestions = true;
} else if (identical(entity, node.constructorName)) {
- optype.includeInvocationSuggestions = true;
+ optype.includeTypeNameSuggestions = true;
+ optype.includeReturnValueSuggestions = true;
+ optype.isPrefixed = true;
}
}
@@ -161,7 +162,16 @@
@override
void visitCascadeExpression(CascadeExpression node) {
if (node.cascadeSections.contains(entity)) {
- optype.includeInvocationSuggestions = true;
+ optype.includeReturnValueSuggestions = true;
+ optype.includeVoidReturnSuggestions = true;
+ optype.isPrefixed = true;
+ }
+ }
+
+ @override
+ void visitCatchClause(CatchClause node) {
+ if (identical(entity, node.exceptionType)) {
+ optype.includeTypeNameSuggestions = true;
}
}
@@ -204,7 +214,8 @@
if (type != null) {
SimpleIdentifier prefix = type.name;
if (prefix != null) {
- optype.includeInvocationSuggestions = true;
+ optype.includeConstructorSuggestions = true;
+ optype.isPrefixed = true;
}
}
}
@@ -297,7 +308,6 @@
@override
void visitFormalParameterList(FormalParameterList node) {
- optype.includeReturnValueSuggestions = true;
optype.includeTypeNameSuggestions = true;
}
@@ -402,12 +412,19 @@
@override
void visitMethodInvocation(MethodInvocation node) {
- if (identical(entity, node.period) && offset > node.period.offset) {
+ bool isThis = node.target is ThisExpression;
+ if (identical(entity, node.operator) && offset > node.operator.offset) {
// The cursor is between the two dots of a ".." token, so we need to
// generate the completions we would generate after a "." token.
- optype.includeInvocationSuggestions = true;
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = !isThis;
+ optype.includeVoidReturnSuggestions = true;
+ optype.isPrefixed = true;
} else if (identical(entity, node.methodName)) {
- optype.includeInvocationSuggestions = true;
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = !isThis;
+ optype.includeVoidReturnSuggestions = true;
+ optype.isPrefixed = true;
}
}
@@ -446,7 +463,15 @@
@override
void visitPrefixedIdentifier(PrefixedIdentifier node) {
if (identical(entity, node.identifier)) {
- optype.includeInvocationSuggestions = true;
+ optype.isPrefixed = true;
+ if (node.parent is TypeName && node.parent.parent is ConstructorName) {
+ optype.includeConstructorSuggestions = true;
+ } else {
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = true;
+ optype.includeVoidReturnSuggestions =
+ node.parent is ExpressionStatement;
+ }
}
}
@@ -460,12 +485,25 @@
@override
void visitPropertyAccess(PropertyAccess node) {
+ bool isThis = node.target is ThisExpression;
+ if (node.realTarget is SimpleIdentifier && node.realTarget.isSynthetic) {
+ // If the access has no target (empty string)
+ // then don't suggest anything
+ return;
+ }
if (identical(entity, node.operator) && offset > node.operator.offset) {
// The cursor is between the two dots of a ".." token, so we need to
// generate the completions we would generate after a "." token.
- optype.includeInvocationSuggestions = true;
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = !isThis;
+ optype.includeVoidReturnSuggestions = true;
+ optype.isPrefixed = true;
} else if (identical(entity, node.propertyName)) {
- optype.includeInvocationSuggestions = true;
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions =
+ !isThis && (node.parent is! CascadeExpression);
+ optype.includeVoidReturnSuggestions = true;
+ optype.isPrefixed = true;
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart b/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart
similarity index 84%
rename from pkg/analysis_server/lib/src/services/completion/invocation_computer.dart
rename to pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart
index 9d154ec..cb6ccf4 100644
--- a/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library services.completion.computer.dart.invocation;
+library services.completion.contributor.dart.invocation;
import 'dart:async';
@@ -13,22 +13,25 @@
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
-import '../../protocol_server.dart' show CompletionSuggestionKind;
+import '../../protocol_server.dart' as protocol;
+import '../../protocol_server.dart'
+ show CompletionSuggestion, CompletionSuggestionKind;
/**
- * A computer for calculating invocation / access suggestions
+ * A contributor for calculating invocation / access suggestions
* `completion.getSuggestions` request results.
*/
-class InvocationComputer extends DartCompletionComputer {
+class PrefixedElementContributor extends DartCompletionContributor {
SuggestionBuilder builder;
@override
bool computeFast(DartCompletionRequest request) {
OpType optype = request.optype;
- if (optype.includeInvocationSuggestions) {
- builder = request.node.accept(new _InvocationAstVisitor(request));
+ if (optype.isPrefixed) {
+ builder = request.target.containingNode
+ .accept(new _InvocationAstVisitor(request));
if (builder != null) {
- return builder.computeFast(request.node);
+ return builder.computeFast(request.target.containingNode);
}
}
@@ -38,7 +41,7 @@
@override
Future<bool> computeFull(DartCompletionRequest request) {
if (builder != null) {
- return builder.computeFull(request.node);
+ return builder.computeFull(request.target.containingNode);
}
return new Future.value(false);
}
@@ -56,9 +59,6 @@
@override
Future<bool> computeFull(AstNode node) {
- if (node is SimpleIdentifier) {
- node = node.parent;
- }
if (node is MethodInvocation) {
node = (node as MethodInvocation).realTarget;
} else if (node is PropertyAccess) {
@@ -89,7 +89,7 @@
_InvocationAstVisitor(this.request);
@override
- visitConstructorName(ConstructorName node) {
+ SuggestionBuilder visitConstructorName(ConstructorName node) {
// some PrefixedIdentifier nodes are transformed into
// ConstructorName nodes during the resolution process.
return new _PrefixedIdentifierSuggestionBuilder(request);
@@ -116,11 +116,6 @@
SuggestionBuilder visitPropertyAccess(PropertyAccess node) {
return new _ExpressionSuggestionBuilder(request);
}
-
- @override
- SuggestionBuilder visitSimpleIdentifier(SimpleIdentifier node) {
- return node.parent.accept(this);
- }
}
/**
@@ -254,9 +249,6 @@
@override
Future<bool> computeFull(AstNode node) {
- if (node is SimpleIdentifier) {
- node = node.parent;
- }
if (node is ConstructorName) {
// some PrefixedIdentifier nodes are transformed into
// ConstructorName nodes during the resolution process.
@@ -313,8 +305,6 @@
@override
Future<bool> visitPrefixElement(PrefixElement element) {
- //TODO (danrubel) reimplement to use prefixElement.importedLibraries
- // once that accessor is implemented and available in Dart
bool modified = false;
// Find the import directive with the given prefix
for (Directive directive in request.unit.directives) {
@@ -323,9 +313,26 @@
if (directive.prefix.name == element.name) {
// Suggest elements from the imported library
LibraryElement library = directive.uriElement;
- LibraryElementSuggestionBuilder.suggestionsFor(
- request, CompletionSuggestionKind.INVOCATION, library);
+ LibraryElementSuggestionBuilder.suggestionsFor(request,
+ CompletionSuggestionKind.INVOCATION, library,
+ request.target.containingNode.parent is TypeName);
modified = true;
+ if (directive.deferredKeyword != null) {
+ String completion = 'loadLibrary';
+ CompletionSuggestion suggestion = new CompletionSuggestion(
+ CompletionSuggestionKind.INVOCATION, DART_RELEVANCE_DEFAULT,
+ completion, completion.length, 0, false, false,
+ parameterNames: [],
+ parameterTypes: [],
+ requiredParameterCount: 0,
+ hasNamedParameters: false,
+ returnType: 'void');
+ suggestion.element = new protocol.Element(
+ protocol.ElementKind.FUNCTION, completion,
+ protocol.Element.makeFlags(),
+ parameters: '()', returnType: 'void');
+ request.addSuggestion(suggestion);
+ }
}
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
index e882474..ac87e30 100644
--- a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
@@ -180,7 +180,11 @@
void addSuggestion(Element element, {int relevance: DART_RELEVANCE_DEFAULT}) {
if (element.isPrivate) {
LibraryElement elementLibrary = element.library;
- LibraryElement unitLibrary = request.unit.element.library;
+ CompilationUnitElement unitElem = request.unit.element;
+ if (unitElem == null) {
+ return;
+ }
+ LibraryElement unitLibrary = unitElem.library;
if (elementLibrary != unitLibrary) {
return;
}
@@ -373,7 +377,7 @@
*/
static void suggestionsFor(DartCompletionRequest request, DartType type) {
CompilationUnit compilationUnit =
- request.node.getAncestor((AstNode node) => node is CompilationUnit);
+ request.target.containingNode.getAncestor((n) => n is CompilationUnit);
LibraryElement library = compilationUnit.element.library;
if (type is DynamicTypeImpl) {
type = request.cache.objectClassElement.type;
@@ -394,8 +398,9 @@
with ElementSuggestionBuilder {
final DartCompletionRequest request;
final CompletionSuggestionKind kind;
+ final bool typesOnly;
- LibraryElementSuggestionBuilder(this.request, this.kind);
+ LibraryElementSuggestionBuilder(this.request, this.kind, this.typesOnly);
@override
visitClassElement(ClassElement element) {
@@ -414,7 +419,9 @@
@override
visitFunctionElement(FunctionElement element) {
- addSuggestion(element);
+ if (!typesOnly) {
+ addSuggestion(element);
+ }
}
@override
@@ -424,16 +431,19 @@
@override
visitTopLevelVariableElement(TopLevelVariableElement element) {
- addSuggestion(element);
+ if (!typesOnly) {
+ addSuggestion(element);
+ }
}
/**
* Add suggestions for the visible members in the given library
*/
static void suggestionsFor(DartCompletionRequest request,
- CompletionSuggestionKind kind, LibraryElement library) {
+ CompletionSuggestionKind kind, LibraryElement library, bool typesOnly) {
if (library != null) {
- library.visitChildren(new LibraryElementSuggestionBuilder(request, kind));
+ library.visitChildren(
+ new LibraryElementSuggestionBuilder(request, kind, typesOnly));
}
}
}
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index f71a98f..f84e1f7a 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -57,6 +57,8 @@
const AssistKind('CONVERT_INTO_IS_NOT', 30, "Convert into is!");
static const CONVERT_INTO_IS_NOT_EMPTY = const AssistKind(
'CONVERT_INTO_IS_NOT_EMPTY', 30, "Convert into 'isNotEmpty'");
+ static const ENCAPSULATE_FIELD =
+ const AssistKind('ENCAPSULATE_FIELD', 30, "Encapsulate field");
static const EXCHANGE_OPERANDS =
const AssistKind('EXCHANGE_OPERANDS', 30, "Exchange operands");
static const EXTRACT_CLASS =
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 63287c4..324ab85 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -85,6 +85,7 @@
_addProposal_convertToIsNot_onIs();
_addProposal_convertToIsNot_onNot();
_addProposal_convertToIsNotEmpty();
+ _addProposal_encapsulateField();
_addProposal_exchangeOperands();
_addProposal_importAddShow();
_addProposal_introduceLocalTestedType();
@@ -660,6 +661,7 @@
isEmptyAccess.parent as PrefixExpression;
// should be !
if (prefixExpression.operator.type != TokenType.BANG) {
+ _coverageMarker();
return;
}
// do replace
@@ -669,6 +671,79 @@
_addAssist(AssistKind.CONVERT_INTO_IS_NOT_EMPTY, []);
}
+ void _addProposal_encapsulateField() {
+ // find FieldDeclaration
+ FieldDeclaration fieldDeclaraton =
+ node.getAncestor((x) => x is FieldDeclaration);
+ if (fieldDeclaraton == null) {
+ _coverageMarker();
+ return;
+ }
+ // not interesting for static
+ if (fieldDeclaraton.isStatic) {
+ _coverageMarker();
+ return;
+ }
+ // has a parse error
+ VariableDeclarationList variableList = fieldDeclaraton.fields;
+ if (variableList.keyword == null && variableList.type == null) {
+ _coverageMarker();
+ return;
+ }
+ // not interesting for final
+ if (variableList.isFinal) {
+ _coverageMarker();
+ return;
+ }
+ // should have exactly one field
+ List<VariableDeclaration> fields = variableList.variables;
+ if (fields.length != 1) {
+ _coverageMarker();
+ return;
+ }
+ VariableDeclaration field = fields.first;
+ SimpleIdentifier nameNode = field.name;
+ FieldElement fieldElement = nameNode.staticElement;
+ // should have a public name
+ String name = nameNode.name;
+ if (Identifier.isPrivateName(name)) {
+ _coverageMarker();
+ return;
+ }
+ // should be on the name
+ if (nameNode != node) {
+ _coverageMarker();
+ return;
+ }
+ // rename field
+ _addReplaceEdit(rangeNode(nameNode), '_$name');
+ // update references in constructors
+ ClassDeclaration classDeclaration = fieldDeclaraton.parent;
+ for (ClassMember member in classDeclaration.members) {
+ if (member is ConstructorDeclaration) {
+ for (FormalParameter parameter in member.parameters.parameters) {
+ ParameterElement parameterElement = parameter.element;
+ if (parameterElement is FieldFormalParameterElement &&
+ parameterElement.field == fieldElement) {
+ _addReplaceEdit(rangeNode(parameter.identifier), '_$name');
+ }
+ }
+ }
+ }
+ // add accessors
+ String eol2 = eol + eol;
+ String typeNameCode =
+ variableList.type != null ? _getNodeText(variableList.type) + ' ' : '';
+ String getterCode = '$eol2 ${typeNameCode}get $name => _$name;';
+ String setterCode = '$eol2'
+ ' void set $name(${typeNameCode}$name) {$eol'
+ ' _$name = $name;$eol'
+ ' }';
+ _addInsertEdit(fieldDeclaraton.end, getterCode + setterCode);
+ // add proposal
+ _addAssist(AssistKind.ENCAPSULATE_FIELD, []);
+ }
+
void _addProposal_exchangeOperands() {
// check that user invokes quick assist on binary expression
if (node is! BinaryExpression) {
@@ -1126,50 +1201,48 @@
}
void _addProposal_removeTypeAnnotation() {
- AstNode typeStart = null;
- AstNode typeEnd = null;
+ VariableDeclarationList variableList;
// try top-level variable
{
TopLevelVariableDeclaration declaration =
node.getAncestor((node) => node is TopLevelVariableDeclaration);
if (declaration != null) {
- TypeName typeNode = declaration.variables.type;
- if (typeNode != null) {
- VariableDeclaration field = declaration.variables.variables[0];
- typeStart = declaration;
- typeEnd = field;
- }
+ variableList = declaration.variables;
}
}
// try class field
- {
+ if (variableList == null) {
FieldDeclaration fieldDeclaration =
node.getAncestor((node) => node is FieldDeclaration);
if (fieldDeclaration != null) {
- TypeName typeNode = fieldDeclaration.fields.type;
- if (typeNode != null) {
- VariableDeclaration field = fieldDeclaration.fields.variables[0];
- typeStart = fieldDeclaration;
- typeEnd = field;
- }
+ variableList = fieldDeclaration.fields;
}
}
// try local variable
- {
+ if (variableList == null) {
VariableDeclarationStatement statement =
node.getAncestor((node) => node is VariableDeclarationStatement);
if (statement != null) {
- TypeName typeNode = statement.variables.type;
- if (typeNode != null) {
- VariableDeclaration variable = statement.variables.variables[0];
- typeStart = typeNode;
- typeEnd = variable;
- }
+ variableList = statement.variables;
}
}
+ if (variableList == null) {
+ _coverageMarker();
+ return;
+ }
+ // we need a type
+ TypeName typeNode = variableList.type;
+ if (typeNode == null) {
+ _coverageMarker();
+ return;
+ }
// add edit
- if (typeStart != null && typeEnd != null) {
- SourceRange typeRange = rangeStartStart(typeStart, typeEnd);
+ Token keyword = variableList.keyword;
+ VariableDeclaration firstVariable = variableList.variables[0];
+ SourceRange typeRange = rangeStartStart(typeNode, firstVariable);
+ if (keyword != null && keyword.lexeme != 'var') {
+ _addReplaceEdit(typeRange, '');
+ } else {
_addReplaceEdit(typeRange, 'var ');
}
// add proposal
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 0ff70e6..f38c00c9 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -376,6 +376,9 @@
}
ClassDeclaration classDeclaration =
node.getAncestor((node) => node is ClassDeclaration);
+ if (classDeclaration == null) {
+ return;
+ }
// prepare names of uninitialized final fields
List<String> fieldNames = <String>[];
for (ClassMember member in classDeclaration.members) {
@@ -450,7 +453,7 @@
}
ClassElement targetElement = targetType.element as ClassElement;
String targetFile = targetElement.source.fullName;
- ClassDeclaration targetClass = targetElement.node;
+ ClassDeclaration targetClass = getParsedClassElementNode(targetElement);
_ConstructorLocation targetLocation =
_prepareNewConstructorLocation(targetClass);
// build method source
@@ -504,7 +507,7 @@
}
ClassElement targetElement = targetType.element as ClassElement;
String targetFile = targetElement.source.fullName;
- ClassDeclaration targetClass = targetElement.node;
+ ClassDeclaration targetClass = getParsedClassElementNode(targetElement);
_ConstructorLocation targetLocation =
_prepareNewConstructorLocation(targetClass);
// build method source
@@ -675,6 +678,9 @@
}
void _addFix_createField() {
+ if (node is! SimpleIdentifier) {
+ return;
+ }
SimpleIdentifier nameNode = node;
String name = nameNode.name;
// prepare target Expression
@@ -713,7 +719,7 @@
}
utils.targetClassElement = targetClassElement;
// prepare target ClassDeclaration
- AstNode targetTypeNode = targetClassElement.node;
+ AstNode targetTypeNode = getParsedClassElementNode(targetClassElement);
if (targetTypeNode is! ClassDeclaration) {
return;
}
@@ -802,6 +808,9 @@
}
void _addFix_createGetter() {
+ if (node is! SimpleIdentifier) {
+ return;
+ }
SimpleIdentifier nameNode = node;
String name = nameNode.name;
if (!nameNode.inGetterContext()) {
@@ -843,7 +852,7 @@
}
utils.targetClassElement = targetClassElement;
// prepare target ClassDeclaration
- AstNode targetTypeNode = targetClassElement.node;
+ AstNode targetTypeNode = getParsedClassElementNode(targetClassElement);
if (targetTypeNode is! ClassDeclaration) {
return;
}
@@ -902,6 +911,9 @@
}
void _addFix_createLocalVariable() {
+ if (node is! SimpleIdentifier) {
+ return;
+ }
SimpleIdentifier nameNode = node;
String name = nameNode.name;
// if variable is assigned, convert assignment into declaration
@@ -1123,7 +1135,7 @@
void _addFix_importLibrary(FixKind kind, String importPath) {
CompilationUnitElement libraryUnitElement =
unitLibraryElement.definingCompilationUnit;
- CompilationUnit libraryUnit = libraryUnitElement.node;
+ CompilationUnit libraryUnit = getParsedUnit(libraryUnitElement);
// prepare new import location
int offset = 0;
String prefix;
@@ -1655,7 +1667,8 @@
staticModifier = target.bestElement.kind == ElementKind.CLASS;
}
// prepare insert offset
- ClassDeclaration targetClassNode = targetClassElement.node;
+ ClassDeclaration targetClassNode =
+ getParsedClassElementNode(targetClassElement);
prefix = ' ';
insertOffset = targetClassNode.end - 1;
if (targetClassNode.members.isEmpty) {
@@ -1967,7 +1980,8 @@
// prepare environment
Source targetSource = targetClassElement.source;
// prepare insert offset
- ClassDeclaration targetClassNode = targetClassElement.node;
+ ClassDeclaration targetClassNode =
+ getParsedClassElementNode(targetClassElement);
int insertOffset = targetClassNode.end - 1;
// prepare prefix
String prefix = ' ';
@@ -2385,9 +2399,8 @@
static void _addSuperTypeProposals(
SourceBuilder sb, Set<DartType> alreadyAdded, DartType type) {
if (type != null &&
- !alreadyAdded.contains(type) &&
- type.element is ClassElement) {
- alreadyAdded.add(type);
+ type.element is ClassElement &&
+ alreadyAdded.add(type)) {
ClassElement element = type.element as ClassElement;
sb.addSuggestion(LinkedEditSuggestionKind.TYPE, element.name);
_addSuperTypeProposals(sb, alreadyAdded, element.supertype);
diff --git a/pkg/analysis_server/lib/src/services/correction/namespace.dart b/pkg/analysis_server/lib/src/services/correction/namespace.dart
index 899fae0..305052a 100644
--- a/pkg/analysis_server/lib/src/services/correction/namespace.dart
+++ b/pkg/analysis_server/lib/src/services/correction/namespace.dart
@@ -152,7 +152,7 @@
MethodInvocation invocation = parent;
if (invocation.target == prefixNode) {
usedElement = invocation.methodName.staticElement;
- info.periodEnd = invocation.period.end;
+ info.periodEnd = invocation.operator.end;
}
}
// we need used Element
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index c19a4c8..ba7a858 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -27,7 +27,8 @@
*/
void addLibraryImports(SourceChange change, LibraryElement targetLibrary,
Set<LibraryElement> libraries) {
- CompilationUnit libUnit = targetLibrary.definingCompilationUnit.node;
+ CompilationUnitElement libUnitElement = targetLibrary.definingCompilationUnit;
+ CompilationUnit libUnit = getParsedUnit(libUnitElement);
// prepare new import location
int offset = 0;
String prefix;
@@ -113,6 +114,16 @@
}
/**
+ * Returns the EOL to use for the given [code].
+ */
+String getCodeEndOfLine(String code) {
+ if (code.contains('\r\n')) {
+ return '\r\n';
+ }
+ return '\n';
+}
+
+/**
* TODO(scheglov) replace with nodes once there will be [CompilationUnit.getComments].
*
* Returns [SourceRange]s of all comments in [unit].
@@ -250,6 +261,9 @@
if (parent is ParenthesizedExpression) {
return 0;
}
+ if (parent is IndexExpression && parent.index == node) {
+ return 0;
+ }
return getExpressionPrecedence(parent);
}
@@ -419,6 +433,41 @@
}
/**
+ * Returns a parsed [AstNode] for the given [classElement].
+ *
+ * The resulting AST structure may or may not be resolved.
+ */
+AstNode getParsedClassElementNode(ClassElement classElement) {
+ CompilationUnitElement unitElement =
+ classElement.getAncestor((e) => e is CompilationUnitElement);
+ CompilationUnit unit = getParsedUnit(unitElement);
+ int offset = classElement.nameOffset;
+ AstNode classNameNode = new NodeLocator.con1(offset).searchWithin(unit);
+ if (classElement.isEnum) {
+ return classNameNode.getAncestor((node) => node is EnumDeclaration);
+ } else {
+ return classNameNode.getAncestor(
+ (node) => node is ClassDeclaration || node is ClassTypeAlias);
+ }
+}
+
+/**
+ * Returns a parsed [CompilationUnit] for the given [unitElement].
+ *
+ * The resulting AST structure may or may not be resolved.
+ * If it is not resolved, then at least the given [unitElement] will be set.
+ */
+CompilationUnit getParsedUnit(CompilationUnitElement unitElement) {
+ AnalysisContext context = unitElement.context;
+ Source source = unitElement.source;
+ CompilationUnit unit = context.parseCompilationUnit(source);
+ if (unit.element == null) {
+ unit.element = unitElement;
+ }
+ return unit;
+}
+
+/**
* Returns a [PropertyAccessorElement] if the given [SimpleIdentifier] is a
* reference to a property, or `null` in the other case.
*/
diff --git a/pkg/analysis_server/lib/src/services/index/store/codec.dart b/pkg/analysis_server/lib/src/services/index/store/codec.dart
index 97e4dbb..0283594 100644
--- a/pkg/analysis_server/lib/src/services/index/store/codec.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/codec.dart
@@ -7,7 +7,6 @@
import 'dart:collection';
import 'package:analysis_server/src/services/index/index.dart';
-import 'package:analysis_server/src/services/index/store/collection.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -67,76 +66,98 @@
* A helper that encodes/decodes [Element]s to/from integers.
*/
class ElementCodec {
+ static const int _CONSTRUCTOR_KIND_BASE = -100;
+
final StringCodec _stringCodec;
- /**
- * A table mapping element encodings to a single integer.
- */
- final IntArrayToIntMap _pathToIndex = new IntArrayToIntMap();
-
- /**
- * A list that works as a mapping of integers to element encodings.
- */
- final List<List<int>> _indexToPath = <List<int>>[];
-
ElementCodec(this._stringCodec);
/**
- * Returns an [Element] that corresponds to the given location.
- *
- * @param context the [AnalysisContext] to find [Element] in
- * @param index an integer corresponding to the [Element]
- * @return the [Element] or `null`
+ * Returns an [Element] that corresponds to the given identifiers.
*/
- Element decode(AnalysisContext context, int index) {
- List<int> path = _indexToPath[index];
- List<String> components = _getLocationComponents(path);
- ElementLocation location = new ElementLocationImpl.con3(components);
- return context.getElement(location);
+ Element decode(AnalysisContext context, int fileId, int offset, int kindId) {
+ String filePath = _stringCodec.decode(fileId);
+ List<Source> unitSources = context.getSourcesWithFullName(filePath);
+ for (Source unitSource in unitSources) {
+ List<Source> libSources = context.getLibrariesContaining(unitSource);
+ for (Source libSource in libSources) {
+ LibraryElement libraryElement = context.getLibraryElement(libSource);
+ if (libraryElement == null) {
+ return null;
+ }
+ if (kindId == ElementKind.LIBRARY.ordinal) {
+ return libraryElement;
+ } else if (kindId == ElementKind.COMPILATION_UNIT.ordinal) {
+ for (CompilationUnitElement unit in libraryElement.units) {
+ if (unit.source.fullName == filePath) {
+ return unit;
+ }
+ }
+ return null;
+ } else {
+ Element element = libraryElement.getElementAt(offset);
+ if (element == null) {
+ return null;
+ }
+ if (element is ClassElement && kindId <= _CONSTRUCTOR_KIND_BASE) {
+ int constructorIndex = -1 * (kindId - _CONSTRUCTOR_KIND_BASE);
+ return element.constructors[constructorIndex];
+ }
+ if (element is PropertyInducingElement) {
+ if (kindId == ElementKind.GETTER.ordinal) {
+ return element.getter;
+ }
+ if (kindId == ElementKind.SETTER.ordinal) {
+ return element.setter;
+ }
+ }
+ return element;
+ }
+ }
+ }
+ return null;
}
/**
- * Returns a unique integer that corresponds to the given [Element].
- *
- * If [forKey] is `true` then [element] is a part of a key, so it should use
- * file paths instead of [Element] location URIs.
+ * Returns the first component of the [element] id.
+ * In the most cases it is an encoding of the [element]'s file path.
+ * If the given [element] is not defined in a file, returns `-1`.
*/
- int encode(Element element, bool forKey) {
+ int encode1(Element element) {
+ Source source = element.source;
+ if (source == null) {
+ return -1;
+ }
+ String filePath = source.fullName;
+ return _stringCodec.encode(filePath);
+ }
+
+ /**
+ * Returns the second component of the [element] id.
+ * In the most cases it is the [element]'s name offset.
+ */
+ int encode2(Element element) {
if (element is NameElement) {
String name = element.name;
- int nameId = _stringCodec.encode(name);
- return _encodePath(<int>[nameId]);
+ return _stringCodec.encode(name);
}
- // check the location has a cached id
- ElementLocationImpl location = element.location;
- if (!identical(location.indexOwner, this)) {
- location.indexKeyId = null;
- location.indexLocationId = null;
+ if (element is ConstructorElement) {
+ return element.enclosingElement.nameOffset;
}
- if (forKey) {
- int id = location.indexKeyId;
- if (id != null) {
- return id;
- }
- } else {
- int id = location.indexLocationId;
- if (id != null) {
- return id;
- }
+ return element.nameOffset;
+ }
+
+ /**
+ * Returns the third component of the [element] id.
+ * In the most cases it is the [element]'s kind.
+ */
+ int encode3(Element element) {
+ if (element is ConstructorElement) {
+ ClassElement classElement = element.enclosingElement;
+ int constructorIndex = classElement.constructors.indexOf(element);
+ return _CONSTRUCTOR_KIND_BASE - constructorIndex;
}
- // prepare an id
- List<int> path = _getLocationPath(element, location, forKey);
- int index = _encodePath(path);
- // put the id into the location
- if (forKey) {
- location.indexOwner = this;
- location.indexKeyId = index;
- } else {
- location.indexOwner = this;
- location.indexLocationId = index;
- }
- // done
- return index;
+ return element.kind.ordinal;
}
/**
@@ -154,114 +175,6 @@
return elementNameId;
}
}
-
- /**
- * Returns a list with the location components of the element with the
- * given encoded ID.
- */
- List<String> inspect_decodePath(int id) {
- List<int> path = _indexToPath[id];
- return _getLocationComponents(path);
- }
-
- /**
- * Returns a map of element IDs to their locations for elements with
- * the [requiredName].
- */
- Map<int, List<String>> inspect_getElements(String requiredName) {
- Map<int, List<String>> result = <int, List<String>>{};
- for (int i = 0; i < _indexToPath.length; i++) {
- List<int> path = _indexToPath[i];
- int nameIndex = path[path.length - 1];
- if (nameIndex >= 0) {
- String name = _stringCodec.decode(nameIndex);
- if (name == requiredName) {
- result[i] = path.map(_stringCodec.decode).toList();
- }
- }
- }
- return result;
- }
-
- int _encodePath(List<int> path) {
- int index = _pathToIndex[path];
- if (index == null) {
- index = _indexToPath.length;
- _pathToIndex[path] = index;
- _indexToPath.add(path);
- }
- return index;
- }
-
- List<String> _getLocationComponents(List<int> path) {
- int length = path.length;
- List<String> components = new List<String>();
- for (int i = 0; i < length; i++) {
- int componentId = path[i];
- String component = _stringCodec.decode(componentId);
- if (i < length - 1 && path[i + 1] < 0) {
- component += '@${(-path[i + 1])}';
- i++;
- }
- components.add(component);
- }
- return components;
- }
-
- /**
- * If [usePath] is `true` then [Source] path should be used instead of URI.
- */
- List<int> _getLocationPath(
- Element element, ElementLocation location, bool usePath) {
- // prepare the location components
- List<String> components = location.components;
- if (usePath) {
- LibraryElement library = element.library;
- if (library != null) {
- components = components.toList();
- components[0] = library.source.fullName;
- for (Element e = element; e != null; e = e.enclosingElement) {
- if (e is CompilationUnitElement) {
- components[1] = e.source.fullName;
- break;
- }
- }
- }
- }
- // encode the location
- int length = components.length;
- if (_hasLocalOffset(components)) {
- List<int> path = new List<int>();
- for (String component in components) {
- int atOffset = component.indexOf('@');
- if (atOffset == -1) {
- path.add(_stringCodec.encode(component));
- } else {
- String preAtString = component.substring(0, atOffset);
- String atString = component.substring(atOffset + 1);
- path.add(_stringCodec.encode(preAtString));
- path.add(-1 * int.parse(atString));
- }
- }
- return path;
- } else {
- List<int> path = new List<int>.filled(length, 0);
- for (int i = 0; i < length; i++) {
- String component = components[i];
- path[i] = _stringCodec.encode(component);
- }
- return path;
- }
- }
-
- static bool _hasLocalOffset(List<String> components) {
- for (String component in components) {
- if (component.indexOf('@') != -1) {
- return true;
- }
- }
- return false;
- }
}
/**
diff --git a/pkg/analysis_server/lib/src/services/index/store/memory_node_manager.dart b/pkg/analysis_server/lib/src/services/index/store/memory_node_manager.dart
index 27832d7..500626b 100644
--- a/pkg/analysis_server/lib/src/services/index/store/memory_node_manager.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/memory_node_manager.dart
@@ -12,9 +12,15 @@
import 'package:analyzer/src/generated/engine.dart';
class MemoryNodeManager implements NodeManager {
- StringCodec _stringCodec = new StringCodec();
- ContextCodec _contextCodec = new ContextCodec();
- ElementCodec _elementCodec;
+ @override
+ StringCodec stringCodec = new StringCodec();
+
+ @override
+ ContextCodec contextCodec = new ContextCodec();
+
+ @override
+ ElementCodec elementCodec;
+
RelationshipCodec _relationshipCodec;
int _locationCount = 0;
@@ -22,18 +28,8 @@
final Map<String, IndexNode> _nodes = new HashMap<String, IndexNode>();
MemoryNodeManager() {
- _elementCodec = new ElementCodec(_stringCodec);
- _relationshipCodec = new RelationshipCodec(_stringCodec);
- }
-
- @override
- ContextCodec get contextCodec {
- return _contextCodec;
- }
-
- @override
- ElementCodec get elementCodec {
- return _elementCodec;
+ elementCodec = new ElementCodec(stringCodec);
+ _relationshipCodec = new RelationshipCodec(stringCodec);
}
@override
@@ -42,11 +38,6 @@
}
@override
- StringCodec get stringCodec {
- return _stringCodec;
- }
-
- @override
void clear() {
_nodes.clear();
}
diff --git a/pkg/analysis_server/lib/src/services/index/store/split_store.dart b/pkg/analysis_server/lib/src/services/index/store/split_store.dart
index ab2f025..6610d8a 100644
--- a/pkg/analysis_server/lib/src/services/index/store/split_store.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/split_store.dart
@@ -17,20 +17,24 @@
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_general.dart';
class _TopElementData {
final String name;
- final int elementId;
+ final int elementId1;
+ final int elementId2;
+ final int elementId3;
factory _TopElementData(ElementCodec elementCodec, Element element) {
- return new _TopElementData._(
- element.name, elementCodec.encode(element, false));
+ return new _TopElementData._(element.name, elementCodec.encode1(element),
+ elementCodec.encode2(element), elementCodec.encode3(element));
}
- _TopElementData._(this.name, this.elementId);
+ _TopElementData._(
+ this.name, this.elementId1, this.elementId2, this.elementId3);
Element getElement(AnalysisContext context, ElementCodec elementCodec) {
- return elementCodec.decode(context, elementId);
+ return elementCodec.decode(context, elementId1, elementId2, elementId3);
}
}
@@ -156,17 +160,23 @@
}
RelationKeyData _readElementRelationKey(_DataInputStream stream) {
- int elementId = stream.readInt();
+ int elementId1 = stream.readInt();
+ int elementId2 = stream.readInt();
+ int elementId3 = stream.readInt();
int relationshipId = stream.readInt();
- return new RelationKeyData.forData(elementId, relationshipId);
+ return new RelationKeyData.forData(
+ elementId1, elementId2, elementId3, relationshipId);
}
LocationData _readLocationData(_DataInputStream stream) {
- int elementId = stream.readInt();
+ int elementId1 = stream.readInt();
+ int elementId2 = stream.readInt();
+ int elementId3 = stream.readInt();
int offset = stream.readInt();
int length = stream.readInt();
int flags = stream.readInt();
- return new LocationData.forData(elementId, offset, length, flags);
+ return new LocationData.forData(
+ elementId1, elementId2, elementId3, offset, length, flags);
}
IndexNode _readNode(_DataInputStream stream) {
@@ -204,7 +214,9 @@
}
void _writeElementRelationKey(_DataOutputStream stream, RelationKeyData key) {
- stream.writeInt(key.elementId);
+ stream.writeInt(key.elementId1);
+ stream.writeInt(key.elementId2);
+ stream.writeInt(key.elementId3);
stream.writeInt(key.relationshipId);
}
@@ -224,7 +236,9 @@
_writeElementRelationKey(stream, key);
stream.writeInt(locations.length);
for (LocationData location in locations) {
- stream.writeInt(location.elementId);
+ stream.writeInt(location.elementId1);
+ stream.writeInt(location.elementId2);
+ stream.writeInt(location.elementId3);
stream.writeInt(location.offset);
stream.writeInt(location.length);
stream.writeInt(location.flags);
@@ -305,18 +319,19 @@
*/
List<InspectLocation> inspect_getRelations(String name, int elementId) {
List<InspectLocation> result = <InspectLocation>[];
- _relations.forEach((RelationKeyData key, locations) {
- if (key.elementId == elementId) {
- for (LocationData location in locations) {
- Relationship relationship =
- _relationshipCodec.decode(key.relationshipId);
- List<String> path =
- _elementCodec.inspect_decodePath(location.elementId);
- result.add(new InspectLocation(name, relationship, path,
- location.offset, location.length, location.flags));
- }
- }
- });
+ // TODO(scheglov) restore index inspections?
+// _relations.forEach((RelationKeyData key, locations) {
+// if (key.elementId == elementId) {
+// for (LocationData location in locations) {
+// Relationship relationship =
+// _relationshipCodec.decode(key.relationshipId);
+// List<String> path =
+// _elementCodec.inspect_decodePath(location.elementId);
+// result.add(new InspectLocation(name, relationship, path,
+// location.offset, location.length, location.flags));
+// }
+// }
+// });
return result;
}
@@ -361,15 +376,20 @@
static const int _FLAG_QUALIFIED = 1 << 0;
static const int _FLAG_RESOLVED = 1 << 1;
- final int elementId;
+ final int elementId1;
+ final int elementId2;
+ final int elementId3;
final int offset;
final int length;
final int flags;
- LocationData.forData(this.elementId, this.offset, this.length, this.flags);
+ LocationData.forData(this.elementId1, this.elementId2, this.elementId3,
+ this.offset, this.length, this.flags);
LocationData.forObject(ElementCodec elementCodec, Location location)
- : elementId = elementCodec.encode(location.element, false),
+ : elementId1 = elementCodec.encode1(location.element),
+ elementId2 = elementCodec.encode2(location.element),
+ elementId3 = elementCodec.encode3(location.element),
offset = location.offset,
length = location.length,
flags = (location.isQualified ? _FLAG_QUALIFIED : 0) |
@@ -377,7 +397,13 @@
@override
int get hashCode {
- return 31 * (31 * elementId + offset) + length;
+ int hash = 0;
+ hash = JenkinsSmiHash.combine(hash, elementId1);
+ hash = JenkinsSmiHash.combine(hash, elementId2);
+ hash = JenkinsSmiHash.combine(hash, elementId3);
+ hash = JenkinsSmiHash.combine(hash, offset);
+ hash = JenkinsSmiHash.combine(hash, length);
+ return JenkinsSmiHash.finish(hash);
}
@override
@@ -386,7 +412,9 @@
return false;
}
LocationData other = obj;
- return other.elementId == elementId &&
+ return other.elementId1 == elementId1 &&
+ other.elementId2 == elementId2 &&
+ other.elementId3 == elementId3 &&
other.offset == offset &&
other.length == length &&
other.flags == flags;
@@ -396,7 +424,8 @@
* Returns a {@link Location} that is represented by this {@link LocationData}.
*/
Location getLocation(AnalysisContext context, ElementCodec elementCodec) {
- Element element = elementCodec.decode(context, elementId);
+ Element element =
+ elementCodec.decode(context, elementId1, elementId2, elementId3);
if (element == null) {
return null;
}
@@ -461,20 +490,35 @@
* An [Element] to [Location] relation key.
*/
class RelationKeyData {
- final int elementId;
+ final int elementId1;
+ final int elementId2;
+ final int elementId3;
final int relationshipId;
- RelationKeyData.forData(this.elementId, this.relationshipId);
+ RelationKeyData.forData(
+ this.elementId1, this.elementId2, this.elementId3, this.relationshipId);
RelationKeyData.forObject(ElementCodec elementCodec,
RelationshipCodec relationshipCodec, Element element,
Relationship relationship)
- : elementId = elementCodec.encode(element, true),
+ : elementId1 = elementCodec.encode1(element),
+ elementId2 = elementCodec.encode2(element),
+ elementId3 = elementCodec.encode3(element),
relationshipId = relationshipCodec.encode(relationship);
@override
int get hashCode {
- return 31 * elementId + relationshipId;
+ int hash = 0;
+ hash = JenkinsSmiHash.combine(hash, elementId1);
+ hash = JenkinsSmiHash.combine(hash, elementId2);
+ hash = JenkinsSmiHash.combine(hash, elementId3);
+ hash = JenkinsSmiHash.combine(hash, relationshipId);
+ return JenkinsSmiHash.finish(hash);
+ }
+
+ @override
+ String toString() {
+ return 'Key($elementId2, $elementId2, $elementId3, $relationshipId)';
}
@override
@@ -483,7 +527,9 @@
return false;
}
RelationKeyData other = obj;
- return other.elementId == elementId &&
+ return other.elementId1 == elementId1 &&
+ other.elementId2 == elementId2 &&
+ other.elementId3 == elementId3 &&
other.relationshipId == relationshipId;
}
}
@@ -746,42 +792,44 @@
String name) {
Map<List<String>, List<InspectLocation>> result =
<List<String>, List<InspectLocation>>{};
- // prepare elements
- Map<int, List<String>> elementMap = _elementCodec.inspect_getElements(name);
- // prepare relations with each element
- List<Future> futures = <Future>[];
- if (_nodeManager is FileNodeManager) {
- List<String> nodeNames =
- (_nodeManager as FileNodeManager).inspect_getAllNodeNames();
- nodeNames.forEach((nodeName) {
- Future<IndexNode> nodeFuture = _nodeManager.getNode(nodeName);
- Future relationsFuture = nodeFuture.then((node) {
- if (node != null) {
- elementMap.forEach((int elementId, List<String> elementPath) {
- List<InspectLocation> relations =
- node.inspect_getRelations(nodeName, elementId);
- List<InspectLocation> resultLocations = result[elementPath];
- if (resultLocations == null) {
- resultLocations = <InspectLocation>[];
- result[elementPath] = resultLocations;
- }
- resultLocations.addAll(relations);
- });
- }
- });
- futures.add(relationsFuture);
- });
- }
- // wait for all nodex
- return Future.wait(futures).then((_) {
- return result;
- });
+ // TODO(scheglov) restore index inspections?
+ return new Future.value(result);
+// // prepare elements
+// Map<int, List<String>> elementMap = _elementCodec.inspect_getElements(name);
+// // prepare relations with each element
+// List<Future> futures = <Future>[];
+// if (_nodeManager is FileNodeManager) {
+// List<String> nodeNames =
+// (_nodeManager as FileNodeManager).inspect_getAllNodeNames();
+// nodeNames.forEach((nodeName) {
+// Future<IndexNode> nodeFuture = _nodeManager.getNode(nodeName);
+// Future relationsFuture = nodeFuture.then((node) {
+// if (node != null) {
+// elementMap.forEach((int elementId, List<String> elementPath) {
+// List<InspectLocation> relations =
+// node.inspect_getRelations(nodeName, elementId);
+// List<InspectLocation> resultLocations = result[elementPath];
+// if (resultLocations == null) {
+// resultLocations = <InspectLocation>[];
+// result[elementPath] = resultLocations;
+// }
+// resultLocations.addAll(relations);
+// });
+// }
+// });
+// futures.add(relationsFuture);
+// });
+// }
+// // wait for all nodex
+// return Future.wait(futures).then((_) {
+// return result;
+// });
}
@override
void recordRelationship(
Element element, Relationship relationship, Location location) {
- if (element == null || element.location == null) {
+ if (element == null || element is MultiplyDefinedElement) {
return;
}
if (location == null) {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index da4e4e4..0603b43 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -22,6 +22,7 @@
import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/resolver.dart' show ExitDetector;
import 'package:analyzer/src/generated/scanner.dart';
@@ -62,6 +63,7 @@
final CompilationUnit unit;
final int selectionOffset;
final int selectionLength;
+ AnalysisContext context;
CompilationUnitElement unitElement;
LibraryElement libraryElement;
SourceRange selectionRange;
@@ -69,6 +71,7 @@
Set<LibraryElement> librariesToImport = new Set<LibraryElement>();
String returnType;
+ String variableType;
String name;
bool extractAll = true;
bool canCreateGetter = false;
@@ -77,13 +80,23 @@
final List<int> offsets = <int>[];
final List<int> lengths = <int>[];
- Set<String> _usedNames = new Set<String>();
+ /**
+ * The map of local names to their visibility ranges.
+ */
+ Map<String, List<SourceRange>> _localNames = <String, List<SourceRange>>{};
+
+ /**
+ * The set of names that are referenced without any qualifier.
+ */
+ Set<String> _unqualifiedNames = new Set<String>();
+
Set<String> _excludedNames = new Set<String>();
List<RefactoringMethodParameter> _parameters = <RefactoringMethodParameter>[];
Map<String, RefactoringMethodParameter> _parametersMap =
<String, RefactoringMethodParameter>{};
Map<String, List<SourceRange>> _parameterReferencesMap =
<String, List<SourceRange>>{};
+ bool _hasAwait = false;
DartType _returnType;
String _returnVariableName;
AstNode _parentMember;
@@ -97,6 +110,7 @@
this.selectionOffset, this.selectionLength) {
unitElement = unit.element;
libraryElement = unitElement.library;
+ context = libraryElement.context;
selectionRange = new SourceRange(selectionOffset, selectionLength);
utils = new CorrectionUtils(unit);
}
@@ -173,6 +187,7 @@
}
// prepare parts
result.addStatus(_initializeParameters());
+ _initializeHasAwait();
_initializeReturnType();
// occurrences
_initializeOccurrences();
@@ -217,17 +232,17 @@
} else {
StringBuffer sb = new StringBuffer();
// may be returns value
- if (_selectionStatements != null && returnType != 'void') {
+ if (_selectionStatements != null && variableType != null) {
// single variable assignment / return statement
if (_returnVariableName != null) {
String occurrenceName =
occurence._parameterOldToOccurrenceName[_returnVariableName];
// may be declare variable
if (!_parametersMap.containsKey(_returnVariableName)) {
- if (returnType.isEmpty) {
+ if (variableType.isEmpty) {
sb.write('var ');
} else {
- sb.write(returnType);
+ sb.write(variableType);
sb.write(' ');
}
}
@@ -238,6 +253,10 @@
sb.write('return ');
}
}
+ // await
+ if (_hasAwait) {
+ sb.write('await ');
+ }
// invocation itself
sb.write(name);
if (!createGetter) {
@@ -293,6 +312,8 @@
declarationSource += ';';
}
}
+ // optional 'async' body modifier
+ String asyncKeyword = _hasAwait ? ' async' : '';
// expression
if (_selectionExpression != null) {
// add return type
@@ -300,15 +321,15 @@
annotations += '$returnType ';
}
// just return expression
- declarationSource =
- '${annotations}${signature} => ${returnExpressionSource};';
+ declarationSource = '$annotations$signature$asyncKeyword => ';
+ declarationSource += '$returnExpressionSource;';
}
// statements
if (_selectionStatements != null) {
if (returnType.isNotEmpty) {
annotations += returnType + ' ';
}
- declarationSource = '${annotations}${signature} {${eol}';
+ declarationSource = '$annotations$signature$asyncKeyword {$eol';
declarationSource += returnExpressionSource;
if (_returnVariableName != null) {
declarationSource +=
@@ -356,7 +377,7 @@
return result;
}
}
- if (_usedNames.contains(parameter.name)) {
+ if (_isParameterNameConflictWithBody(parameter)) {
result.addError(format(
"'{0}' is already used as a name in the selected code",
parameter.name));
@@ -523,6 +544,16 @@
return utils.getTypeSource(type, librariesToImport);
}
+ void _initializeHasAwait() {
+ _HasAwaitVisitor visitor = new _HasAwaitVisitor();
+ if (_selectionExpression != null) {
+ _selectionExpression.accept(visitor);
+ } else if (_selectionStatements != null) {
+ _selectionStatements.forEach((statement) => statement.accept(visitor));
+ }
+ _hasAwait = visitor.result;
+ }
+
/**
* Fills [_occurrences] field.
*/
@@ -600,15 +631,33 @@
}
void _initializeReturnType() {
+ InterfaceType futureType = context.typeProvider.futureType;
if (_selectionFunctionExpression != null) {
+ variableType = '';
returnType = '';
} else if (_returnType == null) {
- returnType = 'void';
+ variableType = null;
+ if (_hasAwait) {
+ returnType = _getTypeCode(futureType);
+ } else {
+ returnType = 'void';
+ }
+ } else if (_returnType.isDynamic) {
+ variableType = '';
+ if (_hasAwait) {
+ returnType = _getTypeCode(futureType);
+ } else {
+ returnType = '';
+ }
} else {
- returnType = _getTypeCode(_returnType);
- }
- if (returnType == 'dynamic') {
- returnType = '';
+ variableType = _getTypeCode(_returnType);
+ if (_hasAwait) {
+ if (_returnType.element != futureType.element) {
+ returnType = _getTypeCode(futureType.substitute4([_returnType]));
+ }
+ } else {
+ returnType = variableType;
+ }
}
}
@@ -628,6 +677,26 @@
return analyzer.status.isOK;
}
+ bool _isParameterNameConflictWithBody(RefactoringMethodParameter parameter) {
+ String id = parameter.id;
+ String name = parameter.name;
+ List<SourceRange> parameterRanges = _parameterReferencesMap[id];
+ List<SourceRange> otherRanges = _localNames[name];
+ for (SourceRange parameterRange in parameterRanges) {
+ if (otherRanges != null) {
+ for (SourceRange otherRange in otherRanges) {
+ if (parameterRange.intersects(otherRange)) {
+ return true;
+ }
+ }
+ }
+ }
+ if (_unqualifiedNames.contains(name)) {
+ return true;
+ }
+ return false;
+ }
+
/**
* Checks if [element] is referenced after [selectionRange].
*/
@@ -855,6 +924,23 @@
}
}
+class _HasAwaitVisitor extends GeneralizingAstVisitor {
+ bool result = false;
+
+ @override
+ visitAwaitExpression(AwaitExpression node) {
+ result = true;
+ }
+
+ @override
+ visitForEachStatement(ForEachStatement node) {
+ if (node.awaitKeyword != null) {
+ result = true;
+ }
+ super.visitForEachStatement(node);
+ }
+}
+
class _HasReturnStatementVisitor extends RecursiveAstVisitor {
bool hasReturn = false;
@@ -973,56 +1059,64 @@
}
}
-class _InitializeParametersVisitor extends GeneralizingAstVisitor<Object> {
+class _InitializeParametersVisitor extends GeneralizingAstVisitor {
final ExtractMethodRefactoringImpl ref;
final List<VariableElement> assignedUsedVariables;
_InitializeParametersVisitor(this.ref, this.assignedUsedVariables);
@override
- Object visitSimpleIdentifier(SimpleIdentifier node) {
+ void visitSimpleIdentifier(SimpleIdentifier node) {
SourceRange nodeRange = rangeNode(node);
- if (ref.selectionRange.covers(nodeRange)) {
- // analyze local variable
- VariableElement variableElement =
- getLocalOrParameterVariableElement(node);
- if (variableElement != null) {
- // name of the named expression
- if (isNamedExpressionName(node)) {
- return null;
- }
- // if declared outside, add parameter
- if (!ref._isDeclaredInSelection(variableElement)) {
- String variableName = variableElement.displayName;
- // add parameter
- RefactoringMethodParameter parameter =
- ref._parametersMap[variableName];
- if (parameter == null) {
- DartType parameterType = node.bestType;
- String parameterTypeCode = ref._getTypeCode(parameterType);
- parameter = new RefactoringMethodParameter(
- RefactoringMethodParameterKind.REQUIRED, parameterTypeCode,
- variableName, id: variableName);
- ref._parameters.add(parameter);
- ref._parametersMap[variableName] = parameter;
- }
- // add reference to parameter
- ref._addParameterReference(variableName, nodeRange);
- }
- // remember, if assigned and used after selection
- if (isLeftHandOfAssignment(node) &&
- ref._isUsedAfterSelection(variableElement)) {
- if (!assignedUsedVariables.contains(variableElement)) {
- assignedUsedVariables.add(variableElement);
- }
- }
+ if (!ref.selectionRange.covers(nodeRange)) {
+ return;
+ }
+ String name = node.name;
+ // analyze local variable
+ VariableElement variableElement = getLocalOrParameterVariableElement(node);
+ if (variableElement != null) {
+ // name of the named expression
+ if (isNamedExpressionName(node)) {
+ return;
}
- // remember declaration names
- if (node.inDeclarationContext()) {
- ref._usedNames.add(node.name);
+ // if declared outside, add parameter
+ if (!ref._isDeclaredInSelection(variableElement)) {
+ // add parameter
+ RefactoringMethodParameter parameter = ref._parametersMap[name];
+ if (parameter == null) {
+ DartType parameterType = node.bestType;
+ String parameterTypeCode = ref._getTypeCode(parameterType);
+ parameter = new RefactoringMethodParameter(
+ RefactoringMethodParameterKind.REQUIRED, parameterTypeCode, name,
+ id: name);
+ ref._parameters.add(parameter);
+ ref._parametersMap[name] = parameter;
+ }
+ // add reference to parameter
+ ref._addParameterReference(name, nodeRange);
+ }
+ // remember, if assigned and used after selection
+ if (isLeftHandOfAssignment(node) &&
+ ref._isUsedAfterSelection(variableElement)) {
+ if (!assignedUsedVariables.contains(variableElement)) {
+ assignedUsedVariables.add(variableElement);
+ }
}
}
- return null;
+ // remember information for conflicts checking
+ if (variableElement is LocalElement) {
+ // declared local elements
+ LocalElement localElement = variableElement as LocalElement;
+ if (node.inDeclarationContext()) {
+ ref._localNames.putIfAbsent(name, () => <SourceRange>[]);
+ ref._localNames[name].add(localElement.visibleRange);
+ }
+ } else {
+ // unqualified non-local names
+ if (!node.isQualified) {
+ ref._unqualifiedNames.add(name);
+ }
+ }
}
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
index a9b6e79..350517a 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
@@ -145,14 +145,6 @@
int initOffset = initializer.contentsOffset;
int initLength = initializer.contentsEnd - initOffset;
codeForReference = utils.getText(initOffset, initLength);
- // drop leading multiline EOL
- if (initializer.isMultiline) {
- if (codeForReference.startsWith('\n')) {
- codeForReference = codeForReference.substring(1);
- } else if (codeForReference.startsWith('\r\n')) {
- codeForReference = codeForReference.substring(2);
- }
- }
} else if (_shouldBeExpressionInterpolation(parent, initializer)) {
codeForReference = '{$initializerCode}';
} else {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
index e58b535d..6f910a9 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
@@ -14,6 +14,7 @@
import 'package:analysis_server/src/services/refactoring/refactoring_internal.dart';
import 'package:analysis_server/src/services/refactoring/rename.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -76,10 +77,38 @@
List<SourceReference> references = getSourceReferences(matches);
for (SourceReference reference in references) {
if (newName.isEmpty) {
- reference.addEdit(change, newName);
+ reference.addEdit(change, '');
} else {
- reference.addEdit(change, "${newName}.");
+ SimpleIdentifier interpolationIdentifier =
+ _getInterpolationIdentifier(reference);
+ if (interpolationIdentifier != null) {
+ doSourceChange_addElementEdit(change, reference.element,
+ new SourceEdit(interpolationIdentifier.offset,
+ interpolationIdentifier.length,
+ '{$newName.${interpolationIdentifier.name}}'));
+ } else {
+ reference.addEdit(change, '$newName.');
+ }
}
}
}
+
+ /**
+ * If the given [reference] is before an interpolated [SimpleIdentifier] in
+ * an [InterpolationExpression] without surrounding curly brackets, return it.
+ * Otherwise return `null`.
+ */
+ SimpleIdentifier _getInterpolationIdentifier(SourceReference reference) {
+ Source source = reference.element.source;
+ CompilationUnit unit = context.parseCompilationUnit(source);
+ NodeLocator nodeLocator = new NodeLocator.con1(reference.range.offset);
+ AstNode node = nodeLocator.searchWithin(unit);
+ if (node is SimpleIdentifier) {
+ AstNode parent = node.parent;
+ if (parent is InterpolationExpression && parent.rightBracket == null) {
+ return node;
+ }
+ }
+ return null;
+ }
}
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 121f148..927bdee 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -6,8 +6,9 @@
environment:
sdk: '>=1.0.0 <2.0.0'
dependencies:
- analyzer: 0.25.0-dev.1
+ analyzer: '>=0.24.1-alpha.0 <0.25.0'
args: '>=0.12.1 <0.13.0'
+ dart_style: '>=0.1.7 <0.2.0'
logging: any
path: any
watcher: any
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index 423d8d7..bb9a85a 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -44,9 +44,9 @@
UriResolver resourceResolver;
AnalysisContext context;
- Source addSource(String path, String content) {
+ Source addSource(String path, String content, [Uri uri]) {
File file = provider.newFile(path, content);
- Source source = file.createSource();
+ Source source = file.createSource(uri);
ChangeSet changeSet = new ChangeSet();
changeSet.addedSource(source);
context.applyChanges(changeSet);
diff --git a/pkg/analysis_server/test/abstract_single_unit.dart b/pkg/analysis_server/test/abstract_single_unit.dart
index 51bd183..6d0e7a0 100644
--- a/pkg/analysis_server/test/abstract_single_unit.dart
+++ b/pkg/analysis_server/test/abstract_single_unit.dart
@@ -23,9 +23,9 @@
CompilationUnitElement testUnitElement;
LibraryElement testLibraryElement;
- void addTestSource(String code) {
+ void addTestSource(String code, [Uri uri]) {
testCode = code;
- testSource = addSource(testFile, code);
+ testSource = addSource(testFile, code, uri);
}
void assertNoErrorsInSource(Source source) {
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index d499a4c..6428832 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -129,7 +129,7 @@
expect(hover.containingLibraryPath, testFile);
expect(hover.containingClassDescription, 'A');
expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
- expect(hover.elementDescription, 'A.mmm(int a, String b) → List<String>');
+ expect(hover.elementDescription, 'mmm(int a, String b) → List<String>');
expect(hover.elementKind, 'method');
// types
expect(hover.staticType, '(int, String) → List<String>');
@@ -157,7 +157,7 @@
// element
expect(hover.containingLibraryName, 'my.library');
expect(hover.containingLibraryPath, testFile);
- expect(hover.elementDescription, 'A.mmm(int a, String b) → List<String>');
+ expect(hover.elementDescription, 'mmm(int a, String b) → List<String>');
expect(hover.elementKind, 'method');
// types
expect(hover.staticType, isNull);
@@ -203,8 +203,9 @@
''');
return prepareHover('vvv);').then((HoverInformation hover) {
// element
- expect(hover.containingLibraryName, 'my.library');
- expect(hover.containingLibraryPath, testFile);
+ expect(hover.containingLibraryName, isNull);
+ expect(hover.containingLibraryPath, isNull);
+ expect(hover.containingClassDescription, isNull);
expect(hover.dartdoc, isNull);
expect(hover.elementDescription, 'dynamic vvv');
expect(hover.elementKind, 'local variable');
@@ -214,6 +215,31 @@
});
}
+ test_expression_variable_inMethod() {
+ addTestFile('''
+library my.library;
+class A {
+ m() {
+ num vvv = 42;
+ }
+}
+''');
+ return prepareHover('vvv = 42').then((HoverInformation hover) {
+ // element
+ expect(hover.containingLibraryName, isNull);
+ expect(hover.containingLibraryPath, isNull);
+ expect(hover.containingClassDescription, isNull);
+ expect(hover.dartdoc, isNull);
+ expect(hover.elementDescription, 'num vvv');
+ expect(hover.elementKind, 'local variable');
+ // types
+ expect(hover.staticType, 'num');
+ expect(hover.propagatedType, 'int');
+ // no parameter
+ expect(hover.parameter, isNull);
+ });
+ }
+
test_instanceCreation_implicit() {
addTestFile('''
library my.library;
diff --git a/pkg/analysis_server/test/analysis/notification_overrides_test.dart b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
index 7875504..17a1e49 100644
--- a/pkg/analysis_server/test/analysis/notification_overrides_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
@@ -138,6 +138,40 @@
});
}
+ test_definedInInterface_ofInterface() {
+ addTestFile('''
+class A {
+ m() {} // in A
+}
+class B implements A {}
+class C implements B {
+ m() {} // in C
+}
+''');
+ return prepareOverrides().then((_) {
+ assertHasOverride('m() {} // in C');
+ assertNoSuperMember();
+ assertHasInterfaceMember('m() {} // in A');
+ });
+ }
+
+ test_definedInInterface_ofSuper() {
+ addTestFile('''
+class A {
+ m() {} // in A
+}
+class B implements A {}
+class C extends B {
+ m() {} // in C
+}
+''');
+ return prepareOverrides().then((_) {
+ assertHasOverride('m() {} // in C');
+ assertNoSuperMember();
+ assertHasInterfaceMember('m() {} // in A');
+ });
+ }
+
test_interface_method_direct_multiple() {
addTestFile('''
class IA {
@@ -323,6 +357,20 @@
});
}
+ test_super_method_superTypeCycle() {
+ addTestFile('''
+class A extends B {
+ m() {} // in A
+}
+class B extends A {
+ m() {} // in B
+}
+''');
+ return prepareOverrides().then((_) {
+ // must finish
+ });
+ }
+
test_super_setterBySetter() {
addTestFile('''
class A {
diff --git a/pkg/analysis_server/test/analysis/reanalyze_test.dart b/pkg/analysis_server/test/analysis/reanalyze_test.dart
index 0041e82..2e85d6d 100644
--- a/pkg/analysis_server/test/analysis/reanalyze_test.dart
+++ b/pkg/analysis_server/test/analysis/reanalyze_test.dart
@@ -59,7 +59,7 @@
// re-analyzed.
filesErrors.remove(testFile);
// Reanalyze.
- server.reanalyze();
+ server.reanalyze(null);
return waitForTasksFinished();
}).then((_) {
// The file should have been reanalyzed.
diff --git a/pkg/analysis_server/test/analysis/update_content_test.dart b/pkg/analysis_server/test/analysis/update_content_test.dart
index 694b9e2..226b6c1 100644
--- a/pkg/analysis_server/test/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/analysis/update_content_test.dart
@@ -7,7 +7,10 @@
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/services/index/index.dart';
+import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
import 'package:typed_mock/typed_mock.dart';
import 'package:unittest/unittest.dart';
@@ -104,7 +107,7 @@
verify(server.index.indexUnit(anyObject, testUnitMatcher)).times(2);
}
- test_multiple_contexts() {
+ test_multiple_contexts() async {
String fooPath = '/project1/foo.dart';
resourceProvider.newFile(fooPath, '''
library foo;
@@ -123,7 +126,8 @@
Request request = new AnalysisSetAnalysisRootsParams(
['/project1', '/project2'], []).toRequest('0');
handleSuccessfulRequest(request);
- return waitForTasksFinished().then((_) {
+ {
+ await server.onAnalysisComplete;
// Files foo.dart and bar.dart should both have errors, since they both
// call f() with the wrong number of arguments.
expect(filesErrors[fooPath], hasLength(1));
@@ -135,13 +139,42 @@
f() {}
''')
});
- return waitForTasksFinished();
- }).then((_) {
+ }
+ {
+ await server.onAnalysisComplete;
// The overlay should have been propagated to both contexts, causing both
// foo.dart and bar.dart to be reanalyzed and found to be free of errors.
expect(filesErrors[fooPath], isEmpty);
expect(filesErrors[barPath], isEmpty);
- });
+ }
+ }
+
+ test_overlayOnly() async {
+ String filePath = '/User/project1/test.dart';
+ Folder folder1 = resourceProvider.newFolder('/User/project1');
+ Folder folder2 = resourceProvider.newFolder('/User/project2');
+ Request request = new AnalysisSetAnalysisRootsParams(
+ [folder1.path, folder2.path], []).toRequest('0');
+ handleSuccessfulRequest(request);
+ // exactly 2 contexts
+ expect(server.folderMap, hasLength(2));
+ AnalysisContext context1 = server.folderMap[folder1];
+ AnalysisContext context2 = server.folderMap[folder2];
+ // no sources
+ expect(_getUserSources(context1), isEmpty);
+ expect(_getUserSources(context2), isEmpty);
+ // add an overlay - new Source in context1
+ server.updateContent('1', {filePath: new AddContentOverlay('')});
+ {
+ List<Source> sources = _getUserSources(context1);
+ expect(sources, hasLength(1));
+ expect(sources[0].fullName, filePath);
+ }
+ expect(_getUserSources(context2), isEmpty);
+ // remove the overlay - no sources
+ server.updateContent('2', {filePath: new RemoveContentOverlay()});
+ expect(_getUserSources(context1), isEmpty);
+ expect(_getUserSources(context2), isEmpty);
}
test_sendNoticesAfterNopChange() async {
@@ -180,6 +213,16 @@
// errors should have been resent
expect(filesErrors, isNotEmpty);
}
+
+ List<Source> _getUserSources(AnalysisContext context) {
+ List<Source> sources = <Source>[];
+ context.sources.forEach((source) {
+ if (source.fullName.startsWith('/User/')) {
+ sources.add(source);
+ }
+ });
+ return sources;
+ }
}
class _ArgumentMatcher_CompilationUnit extends ArgumentMatcher {
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index efd1c16..374f47b 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -203,7 +203,7 @@
File bar = resourceProvider.newFile('/bar/bar.dart', 'library lib;');
Source barSource = bar.createSource();
server.setAnalysisRoots('0', ['/foo', '/bar'], [], {});
- return pumpEventQueue(40).then((_) {
+ return pumpEventQueue(50).then((_) {
expect(server.statusAnalyzing, isFalse);
// Make sure getAnalysisContext returns the proper context for each.
AnalysisContext fooContext =
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index cc43193..de752be 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -644,10 +644,10 @@
}''', <String>["1+HttpResponse"]);
buildTests('testCommentSnippets083', '''
-main() {(.!1)}''', <String>["1-toString"], failingTests: '1');
+main() {(.!1)}''', <String>["1-toString"]);
buildTests('testCommentSnippets083a', '''
-main() { .!1 }''', <String>["1-toString"], failingTests: '1');
+main() { .!1 }''', <String>["1-toString"]);
buildTests('testCommentSnippets083b', '''
main() { null.!1 }''', <String>["1+toString"], failingTests: '1');
@@ -1835,7 +1835,7 @@
"B-Ctype",
"C+Bclass",
"C-Eclass"
- ], failingTests: '12345679ABC');
+ ], failingTests: '23467ABC');
// keywords
buildTests('test009', '''
@@ -1852,7 +1852,7 @@
"5+TestFn2",
"6+num",
"7+typedef"
- ], failingTests: '12347');
+ ], failingTests: '1234');
buildTests('test010', '''
class test !8<!1t !2 !3extends String,!4 List,!5 !6>!7 {}
@@ -1927,7 +1927,7 @@
"8+==",
"9+==",
"0+k"
- ], failingTests: '5689');
+ ], failingTests: '689');
// keywords
buildTests('test014', '''
@@ -1969,7 +1969,7 @@
"J+if",
"K+else",
"L+return"
- ], failingTests: '123456789ABCDEFGHJKL');
+ ], failingTests: '59BCHK');
// operators in function
buildTests('test015', '''f(a,b,c) => a + b * c !1;''', <String>["1+=="],
@@ -1995,11 +1995,11 @@
"6+hide",
"7+show",
"8-null"
- ], failingTests: '1234567');
+ ], failingTests: '1567');
// keywords
buildTests('test018', '''!1part !2of foo;''', <String>["1+part", "2+of"],
- failingTests: '12');
+ failingTests: '2');
buildTests('test019', '''
var truefalse = 0;
@@ -2011,11 +2011,9 @@
buildTests('test020', '''var x = null.!1''', <String>["1+toString"],
failingTests: '1');
- buildTests('test021', '''var x = .!1''', <String>["1-toString"],
- failingTests: '1');
+ buildTests('test021', '''var x = .!1''', <String>["1-toString"]);
- buildTests('test022', '''var x = .!1;''', <String>["1-toString"],
- failingTests: '1');
+ buildTests('test022', '''var x = .!1;''', <String>["1-toString"]);
buildTests('test023', '''
class Map{getKeys(){}}
@@ -2100,8 +2098,7 @@
buildTests('test031',
'''class Caster {} m() {try {} on Cas!1ter catch (CastBlock) {!2}}''',
- <String>["1+Caster", "1-CastBlock", "2+Caster", "2+CastBlock"],
- failingTests: '1');
+ <String>["1+Caster", "1-CastBlock", "2+Caster", "2+CastBlock"]);
buildTests('test032', '''
const ONE = 1;
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 61a3c09..4a4ec36 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -32,10 +32,17 @@
* The name of the 'bin' directory.
*/
static const String BIN_NAME = 'bin';
+
+ /**
+ * The name of the 'example' directory.
+ */
+ static const String EXAMPLE_NAME = 'example';
+
/**
* The name of the 'lib' directory.
*/
static const String LIB_NAME = 'lib';
+
/**
* The name of the 'src' directory.
*/
@@ -122,7 +129,7 @@
return pumpEventQueue().then((_) {
expect(manager.currentContextPaths.toList(), [projPath]);
manager.now++;
- manager.refresh();
+ manager.refresh(null);
return pumpEventQueue().then((_) {
expect(manager.currentContextPaths.toList(), [projPath]);
expect(manager.currentContextTimestamps[projPath], manager.now);
@@ -144,7 +151,7 @@
expect(manager.currentContextPaths.toSet(),
[subdir1Path, subdir2Path, projPath].toSet());
manager.now++;
- manager.refresh();
+ manager.refresh(null);
return pumpEventQueue().then((_) {
expect(manager.currentContextPaths.toSet(),
[subdir1Path, subdir2Path, projPath].toSet());
@@ -155,6 +162,31 @@
});
}
+ test_refresh_oneContext() {
+ // create two contexts with pubspec.yaml files
+ String pubspecPath = posix.join(projPath, 'pubspec.yaml');
+ resourceProvider.newFile(pubspecPath, 'pubspec1');
+
+ String proj2Path = '/my/proj2';
+ resourceProvider.newFolder(proj2Path);
+ String pubspec2Path = posix.join(proj2Path, 'pubspec.yaml');
+ resourceProvider.newFile(pubspec2Path, 'pubspec2');
+
+ List<String> roots = <String>[projPath, proj2Path];
+ manager.setRoots(roots, <String>[], <String, String>{});
+ return pumpEventQueue().then((_) {
+ expect(manager.currentContextPaths.toList(), unorderedEquals(roots));
+ int then = manager.now;
+ manager.now++;
+ manager.refresh([resourceProvider.getResource(proj2Path)]);
+ return pumpEventQueue().then((_) {
+ expect(manager.currentContextPaths.toList(), unorderedEquals(roots));
+ expect(manager.currentContextTimestamps[projPath], then);
+ expect(manager.currentContextTimestamps[proj2Path], manager.now);
+ });
+ });
+ }
+
void test_setRoots_addFolderWithDartFile() {
String filePath = posix.join(projPath, 'foo.dart');
resourceProvider.newFile(filePath, 'contents');
@@ -184,6 +216,34 @@
expect(filePaths, isEmpty);
}
+ void test_setRoots_addFolderWithNestedPubspec() {
+ String examplePath = newFolder([projPath, EXAMPLE_NAME]);
+ String libPath = newFolder([projPath, LIB_NAME]);
+
+ newFile([projPath, PUBSPEC_NAME]);
+ newFile([libPath, 'main.dart']);
+ newFile([examplePath, PUBSPEC_NAME]);
+ newFile([examplePath, 'example.dart']);
+
+ packageMapProvider.packageMap['proj'] =
+ [resourceProvider.getResource(libPath)];
+
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+ expect(manager.currentContextPaths, hasLength(2));
+
+ expect(manager.currentContextPaths, contains(projPath));
+ Set<Source> projSources = manager.currentContextSources[projPath];
+ expect(projSources, hasLength(1));
+ expect(projSources.first.uri.toString(), 'package:proj/main.dart');
+
+ expect(manager.currentContextPaths, contains(examplePath));
+ Set<Source> exampleSources = manager.currentContextSources[examplePath];
+ expect(exampleSources, hasLength(1));
+ expect(exampleSources.first.uri.toString(),
+ 'file:///my/proj/example/example.dart');
+ }
+
void test_setRoots_addFolderWithoutPubspec() {
packageMapProvider.packageMap = null;
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
@@ -215,9 +275,8 @@
newFile([srcPath, 'internal.dart']);
String testFilePath = newFile([testPath, 'main_test.dart']);
- packageMapProvider.packageMap['proj'] = [
- resourceProvider.getResource(libPath)
- ];
+ packageMapProvider.packageMap['proj'] =
+ [resourceProvider.getResource(libPath)];
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
Set<Source> sources = manager.currentContextSources[projPath];
@@ -276,8 +335,9 @@
List<String> excludedPaths = <String>[];
manager.setRoots(includedPaths, excludedPaths, <String, String>{});
_checkPackageMap(projPath, equals(packageMapProvider.packageMap));
- manager.setRoots(includedPaths,
- excludedPaths, <String, String>{projPath: packageRootPath});
+ manager.setRoots(includedPaths, excludedPaths, <String, String>{
+ projPath: packageRootPath
+ });
_checkPackageRoot(projPath, equals(packageRootPath));
}
@@ -290,8 +350,9 @@
projPath: packageRootPath1
});
_checkPackageRoot(projPath, equals(packageRootPath1));
- manager.setRoots(includedPaths,
- excludedPaths, <String, String>{projPath: packageRootPath2});
+ manager.setRoots(includedPaths, excludedPaths, <String, String>{
+ projPath: packageRootPath2
+ });
_checkPackageRoot(projPath, equals(packageRootPath2));
}
@@ -419,26 +480,6 @@
manager.assertContextFiles(project, [fileA, fileB]);
}
- void test_setRoots_ignoreSubContext_ofSubContext() {
- // prepare paths
- String root = '/root';
- String rootFile = '$root/root.dart';
- String subProject = '$root/sub';
- String subPubspec = '$subProject/pubspec.yaml';
- String subFile = '$subProject/bin/sub.dart';
- String subSubPubspec = '$subProject/subsub/pubspec.yaml';
- // create files
- resourceProvider.newFile(rootFile, 'library root;');
- resourceProvider.newFile(subPubspec, 'pubspec');
- resourceProvider.newFile(subFile, 'library sub;');
- resourceProvider.newFile(subSubPubspec, 'pubspec');
- // set roots
- manager.setRoots(<String>[root], <String>[], <String, String>{});
- manager.assertContextPaths([root, subProject]);
- manager.assertContextFiles(root, [rootFile]);
- manager.assertContextFiles(subProject, [subFile]);
- }
-
void test_setRoots_newFolderWithPackageRoot() {
String packageRootPath = '/package';
manager.setRoots(<String>[projPath], <String>[], <String, String>{
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index a41e086..7037f60 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -321,9 +321,8 @@
library lib_a;
class A {}
''');
- packageMapProvider.packageMap['pkgA'] = [
- resourceProvider.getResource('/packages/pkgA')
- ];
+ packageMapProvider.packageMap['pkgA'] =
+ [resourceProvider.getResource('/packages/pkgA')];
addTestFile('''
import 'package:pkgA/libA.dart';
main(A a) {
@@ -647,6 +646,30 @@
expect(filesHighlights[pkgFileA], isNotEmpty);
}
+ test_afterAnalysis_packageFile_notUsed() async {
+ String pkgFile = '/packages/pkgA/lib/libA.dart';
+ resourceProvider.newFile(pkgFile, '''
+library lib_a;
+class A {}
+''');
+ packageMapProvider.packageMap = {
+ 'pkgA': [(resourceProvider.newFolder('/packages/pkgA/lib'))]
+ };
+ //
+ addTestFile('// no "pkgA" reference');
+ createProject();
+ // wait for analysis, no results initially
+ await waitForTasksFinished();
+ expect(filesHighlights[pkgFile], isNull);
+ // make it a priority file, so make analyzable
+ server.setPriorityFiles('0', [pkgFile]);
+ // subscribe
+ addAnalysisSubscription(AnalysisService.HIGHLIGHTS, pkgFile);
+ await server.onAnalysisComplete;
+ // there are results
+ expect(filesHighlights[pkgFile], isNotEmpty);
+ }
+
test_afterAnalysis_sdkFile() async {
String file = '/lib/core/core.dart';
addTestFile('// no matter');
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index b594773..e727c6c 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -253,8 +253,13 @@
List<CompletionSuggestion> suggestions = [];
bool suggestionsDone = false;
- String addTestFile(String content) {
+ String addTestFile(String content, {offset}) {
completionOffset = content.indexOf('^');
+ if (offset != null) {
+ expect(completionOffset, -1, reason: 'cannot supply offset and ^');
+ completionOffset = offset;
+ return super.addTestFile(content);
+ }
expect(completionOffset, isNot(equals(-1)), reason: 'missing ^');
int nextOffset = content.indexOf('^', completionOffset + 1);
expect(nextOffset, equals(-1), reason: 'too many ^');
@@ -436,6 +441,16 @@
});
}
+ test_offset_past_eof() {
+ addTestFile('main() { }', offset: 300);
+ return getSuggestions().then((_) {
+ expect(replacementOffset, equals(300));
+ expect(replacementLength, equals(0));
+ expect(suggestionsDone, true);
+ expect(suggestions.length, 0);
+ });
+ }
+
test_overrides() {
addFile('/libA.dart', 'class A {m() {}}');
addTestFile('''
@@ -587,6 +602,11 @@
return source.contents;
}
+ @override
+ bool exists(Source source) {
+ return source != null && source.exists();
+ }
+
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
diff --git a/pkg/analysis_server/test/integration/analysis/get_hover_test.dart b/pkg/analysis_server/test/integration/analysis/get_hover_test.dart
index 1046157..7b5be4d 100644
--- a/pkg/analysis_server/test/integration/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/get_hover_test.dart
@@ -62,8 +62,8 @@
* expected propagated type of the element.
*/
checkHover(String target, int length, List<String> descriptionRegexps,
- String kind, List<String> staticTypeRegexps, {bool isCore: false,
- String docRegexp: null, bool isLiteral: false,
+ String kind, List<String> staticTypeRegexps, {bool isLocal: false,
+ bool isCore: false, String docRegexp: null, bool isLiteral: false,
List<String> parameterRegexps: null, propagatedType: null}) {
int offset = text.indexOf(target);
return sendAnalysisGetHover(pathname, offset).then((result) {
@@ -74,7 +74,7 @@
if (isCore) {
expect(basename(info.containingLibraryPath), equals('core.dart'));
expect(info.containingLibraryName, equals('dart.core'));
- } else if (isLiteral) {
+ } else if (isLocal || isLiteral) {
expect(info.containingLibraryPath, isNull);
expect(info.containingLibraryName, isNull);
} else {
@@ -141,52 +141,44 @@
// request is made. So wait for analysis to finish before testing anything.
return analysisFinished.then((_) {
List<Future> tests = [];
- tests.add(checkHover('topLevelVar;', 11,
- ['List', 'topLevelVar'], 'top level variable', ['List']));
- tests.add(checkHover('func(', 4, [
- 'func',
- 'int',
- 'param'
- ], 'function', ['int', 'void'], docRegexp: 'Documentation for func'));
+ tests.add(checkHover('topLevelVar;', 11, [
+ 'List',
+ 'topLevelVar'
+ ], 'top level variable', ['List']));
+ tests.add(checkHover(
+ 'func(', 4, ['func', 'int', 'param'], 'function', ['int', 'void'],
+ docRegexp: 'Documentation for func'));
tests.add(checkHover('int param', 3, ['int'], 'class', ['int'],
isCore: true, docRegexp: '.*'));
tests.add(checkHover('param)', 5, ['int', 'param'], 'parameter', ['int'],
- docRegexp: 'Documentation for func'));
+ isLocal: true, docRegexp: 'Documentation for func'));
tests.add(checkHover('num localVar', 3, ['num'], 'class', ['num'],
isCore: true, docRegexp: '.*'));
- tests.add(checkHover('localVar =', 8, [
- 'num',
- 'localVar'
- ], 'local variable', ['num'], propagatedType: 'int'));
+ tests.add(checkHover(
+ 'localVar =', 8, ['num', 'localVar'], 'local variable', ['num'],
+ isLocal: true, propagatedType: 'int'));
tests.add(checkHover('topLevelVar.length;', 11, [
'List',
'topLevelVar'
], 'top level variable', ['List']));
- tests.add(checkHover('length;', 6, [
- 'get',
- 'length',
- 'int'
- ], 'getter', ['int'], isCore: true, docRegexp: '.*'));
- tests.add(checkHover('length =', 6, [
- 'set',
- 'length',
- 'int'
- ], 'setter', ['int'], isCore: true, docRegexp: '.*'));
+ tests.add(checkHover(
+ 'length;', 6, ['get', 'length', 'int'], 'getter', ['int'],
+ isCore: true, docRegexp: '.*'));
+ tests.add(checkHover(
+ 'length =', 6, ['set', 'length', 'int'], 'setter', ['int'],
+ isCore: true, docRegexp: '.*'));
tests.add(checkHover('param;', 5, ['int', 'param'], 'parameter', ['int'],
- docRegexp: 'Documentation for func', parameterRegexps: ['.*']));
+ isLocal: true,
+ docRegexp: 'Documentation for func',
+ parameterRegexps: ['.*']));
tests.add(checkHover('add(', 3, ['List', 'add'], 'method', null,
isCore: true, docRegexp: '.*'));
- tests.add(checkHover('localVar)', 8, [
- 'num',
- 'localVar'
- ], 'local variable', [
- 'num'
- ], parameterRegexps: ['.*'], propagatedType: 'int'));
- tests.add(checkHover('func(35', 4, [
- 'func',
- 'int',
- 'param'
- ], 'function', null, docRegexp: 'Documentation for func'));
+ tests.add(checkHover(
+ 'localVar)', 8, ['num', 'localVar'], 'local variable', ['num'],
+ isLocal: true, parameterRegexps: ['.*'], propagatedType: 'int'));
+ tests.add(checkHover(
+ 'func(35', 4, ['func', 'int', 'param'], 'function', null,
+ docRegexp: 'Documentation for func'));
tests.add(checkHover('35', 2, null, null, ['int'],
isLiteral: true, parameterRegexps: ['int', 'param']));
tests.add(checkNoHover('comment'));
diff --git a/pkg/analysis_server/test/integration/completion/get_suggestions_test.dart b/pkg/analysis_server/test/integration/completion/get_suggestions_test.dart
index 3cdb189..d9c85c1 100644
--- a/pkg/analysis_server/test/integration/completion/get_suggestions_test.dart
+++ b/pkg/analysis_server/test/integration/completion/get_suggestions_test.dart
@@ -4,8 +4,7 @@
library test.integration.completion.get.suggestions;
-import 'dart:async';
-
+import 'package:analysis_server/src/protocol.dart';
import 'package:unittest/unittest.dart';
import '../../reflective_tests.dart';
@@ -17,35 +16,102 @@
@reflectiveTest
class Test extends AbstractAnalysisServerIntegrationTest {
- fail_test_getSuggestions_string_var() {
- // See dartbug.com/20188
- String pathname = sourcePath('test.dart');
- String text = r'''
-var test = '';
-main() {
- test.
-}
-''';
- writeFile(pathname, text);
- standardAnalysisSetup();
+ String path;
+ String content;
+ int completionOffset;
- return analysisFinished.then((_) {
- return sendCompletionGetSuggestions(
- pathname, text.indexOf('test.') + 'test.'.length).then((result) {
- // Since the feature doesn't work yet, just pause for a second to
- // collect the output of the analysis server, and then stop the test.
- // TODO(paulberry): finish writing the integration test once the feature
- // it more complete.
- return new Future.delayed(new Duration(seconds: 1), () {
- fail('test not completed yet');
- });
- });
- });
+ void setTestSource(String relPath, String content) {
+ path = sourcePath(relPath);
+ expect(completionOffset, isNull, reason: 'Call addTestUnit exactly once');
+ completionOffset = content.indexOf('^');
+ expect(completionOffset, isNot(equals(-1)), reason: 'missing ^');
+ int nextOffset = content.indexOf('^', completionOffset + 1);
+ expect(nextOffset, equals(-1), reason: 'too many ^');
+ this.content = content.substring(0, completionOffset) +
+ content.substring(completionOffset + 1);
}
- test_placeholder() {
- // The unit test framework freaks out if there are no tests, so this is a
- // placeholder until we have a passing test.
- // TODO(paulberry): remove this.
+ test_getSuggestions() async {
+ setTestSource('test.dart', r'''
+String test = '';
+main() {
+ test.^
+}
+''');
+ writeFile(path, content);
+ await standardAnalysisSetup();
+ await analysisFinished;
+ CompletionGetSuggestionsResult result =
+ await sendCompletionGetSuggestions(path, completionOffset);
+ String completionId = result.id;
+ CompletionResultsParams param = await onCompletionResults.firstWhere(
+ (CompletionResultsParams param) =>
+ param.id == completionId && param.isLast);
+ expect(param.replacementOffset, completionOffset);
+ expect(param.replacementLength, 0);
+ param.results.firstWhere(
+ (CompletionSuggestion suggestion) => suggestion.completion == 'length');
+ }
+
+ test_getSuggestions_onlyOverlay() async {
+ setTestSource('test.dart', r'''
+String test = '';
+main() {
+ test.^
+}
+''');
+ // Create an overlay but do not write the file to "disk"
+ // writeFile(pathname, text);
+ await standardAnalysisSetup();
+ await sendAnalysisUpdateContent({path: new AddContentOverlay(content)});
+ await analysisFinished;
+ CompletionGetSuggestionsResult result =
+ await sendCompletionGetSuggestions(path, completionOffset);
+ String completionId = result.id;
+ CompletionResultsParams param = await onCompletionResults.firstWhere(
+ (CompletionResultsParams param) =>
+ param.id == completionId && param.isLast);
+ expect(param.replacementOffset, completionOffset);
+ expect(param.replacementLength, 0);
+ param.results.firstWhere(
+ (CompletionSuggestion suggestion) => suggestion.completion == 'length');
+ }
+
+ test_getSuggestions_onlyOverlay_noWait() async {
+ setTestSource('test.dart', r'''
+String test = '';
+main() {
+ test.^
+}
+''');
+ // Create an overlay but do not write the file to "disk"
+ // writeFile(pathname, text);
+ // Don't wait for any results except the completion notifications
+ standardAnalysisSetup(subscribeStatus: false);
+ sendAnalysisUpdateContent({path: new AddContentOverlay(content)});
+ sendCompletionGetSuggestions(path, completionOffset);
+ CompletionResultsParams param = await onCompletionResults
+ .firstWhere((CompletionResultsParams param) => param.isLast);
+ expect(param.replacementOffset, completionOffset);
+ expect(param.replacementLength, 0);
+ param.results.firstWhere(
+ (CompletionSuggestion suggestion) => suggestion.completion == 'length');
+ }
+
+ test_getSuggestions_sourceMissing_noWait() {
+ path = sourcePath('does_not_exist.dart');
+ // Do not write the file to "disk"
+ // writeFile(pathname, text);
+ // Don't wait for any results except the completion notifications
+ standardAnalysisSetup(subscribeStatus: false);
+ // Missing file and no overlay
+ //sendAnalysisUpdateContent({path: new AddContentOverlay(content)});
+ var errorToken = 'exception from server';
+ return sendCompletionGetSuggestions(path, 0).catchError((e) {
+ // Exception expected
+ return errorToken;
+ }).then((result) {
+ expect(result, same(errorToken));
+ });
}
}
diff --git a/pkg/analysis_server/test/integration/protocol_matchers.dart b/pkg/analysis_server/test/integration/protocol_matchers.dart
index 1909ee9..83314f9 100644
--- a/pkg/analysis_server/test/integration/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/protocol_matchers.dart
@@ -1022,6 +1022,7 @@
* "enableAsync": optional bool
* "enableDeferredLoading": optional bool
* "enableEnums": optional bool
+ * "enableNullAwareOperators": optional bool
* "generateDart2jsHints": optional bool
* "generateHints": optional bool
* "generateLints": optional bool
@@ -1032,6 +1033,7 @@
"enableAsync": isBool,
"enableDeferredLoading": isBool,
"enableEnums": isBool,
+ "enableNullAwareOperators": isBool,
"generateDart2jsHints": isBool,
"generateHints": isBool,
"generateLints": isBool
@@ -1821,6 +1823,7 @@
* CONTENT_MODIFIED
* FORMAT_INVALID_FILE
* GET_ERRORS_INVALID_FILE
+ * INVALID_ANALYSIS_ROOT
* INVALID_EXECUTION_CONTEXT
* INVALID_OVERLAY_CHANGE
* INVALID_PARAMETER
@@ -1833,6 +1836,7 @@
* SORT_MEMBERS_PARSE_ERRORS
* UNANALYZED_PRIORITY_FILES
* UNKNOWN_REQUEST
+ * UNKNOWN_SOURCE
* UNSUPPORTED_FEATURE
* }
*/
@@ -1840,6 +1844,7 @@
"CONTENT_MODIFIED",
"FORMAT_INVALID_FILE",
"GET_ERRORS_INVALID_FILE",
+ "INVALID_ANALYSIS_ROOT",
"INVALID_EXECUTION_CONTEXT",
"INVALID_OVERLAY_CHANGE",
"INVALID_PARAMETER",
@@ -1852,6 +1857,7 @@
"SORT_MEMBERS_PARSE_ERRORS",
"UNANALYZED_PRIORITY_FILES",
"UNKNOWN_REQUEST",
+ "UNKNOWN_SOURCE",
"UNSUPPORTED_FEATURE"
]);
diff --git a/pkg/analysis_server/test/mock_sdk.dart b/pkg/analysis_server/test/mock_sdk.dart
index 920cb32..2cdebda 100644
--- a/pkg/analysis_server/test/mock_sdk.dart
+++ b/pkg/analysis_server/test/mock_sdk.dart
@@ -16,6 +16,7 @@
library dart.core;
import 'dart:async';
+import 'dart:_internal';
class Object {
bool operator ==(other) => identical(this, other);
@@ -51,6 +52,7 @@
num operator +(num other);
num operator -(num other);
num operator *(num other);
+ num operator %(num other);
num operator /(num other);
int toInt();
num abs();
@@ -98,6 +100,15 @@
external bool identical(Object a, Object b);
void print(Object object) {}
+
+class Uri {
+ static List<int> parseIPv6Address(String host, [int start = 0, int end]) {
+ int parseHex(int start, int end) {
+ return 0;
+ }
+ return null;
+ }
+}
''');
static const _MockSdkLibrary LIB_ASYNC = const _MockSdkLibrary('dart:async',
@@ -143,6 +154,7 @@
num min(num a, num b) => 0;
num max(num a, num b) => 0;
external double cos(num x);
+external num pow(num x, num exponent);
external double sin(num x);
external double sqrt(num x);
class Random {
@@ -158,6 +170,12 @@
class HtmlElement {}
''');
+ static const _MockSdkLibrary LIB_INTERNAL = const _MockSdkLibrary(
+ 'dart:_internal', '/lib/internal/internal.dart', '''
+library dart._internal;
+external void printToConsole(String line);
+''');
+
static const List<SdkLibrary> LIBRARIES = const [
LIB_CORE,
LIB_ASYNC,
@@ -165,6 +183,7 @@
LIB_CONVERT,
LIB_MATH,
LIB_HTML,
+ LIB_INTERNAL,
];
final resource.MemoryResourceProvider provider =
@@ -263,7 +282,8 @@
"dart:async": "/lib/async/async.dart",
"dart:collection": "/lib/collection/collection.dart",
"dart:convert": "/lib/convert/convert.dart",
- "dart:math": "/lib/math/math.dart"
+ "dart:math": "/lib/math/math.dart",
+ "dart:_internal": "/lib/internal/internal.dart",
};
String path = uriToPath[dartUri];
@@ -299,7 +319,7 @@
bool get isImplementation => throw unimplemented;
@override
- bool get isInternal => throw unimplemented;
+ bool get isInternal => shortName.startsWith('dart:_');
@override
bool get isShared => throw unimplemented;
diff --git a/pkg/analysis_server/test/services/completion/arglist_computer_test.dart b/pkg/analysis_server/test/services/completion/arglist_computer_test.dart
deleted file mode 100644
index 67e3814..0000000
--- a/pkg/analysis_server/test/services/completion/arglist_computer_test.dart
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library test.services.completion.dart.arglist;
-
-import 'package:analysis_server/src/protocol.dart';
-import 'package:analysis_server/src/services/completion/arglist_computer.dart';
-import 'package:unittest/unittest.dart';
-
-import '../../reflective_tests.dart';
-import 'completion_test_util.dart';
-
-main() {
- groupSep = ' | ';
- runReflectiveTests(ArgListComputerTest);
-}
-
-@reflectiveTest
-class ArgListComputerTest extends AbstractCompletionTest {
- @override
- void setUpComputer() {
- computer = new ArgListComputer();
- }
-
- test_ArgumentList_imported_function_0() {
- // ArgumentList MethodInvocation ExpressionStatement Block
- addSource('/libA.dart', '''
- library A;
- bool hasLength(int expected) { }
- expect() { }
- void baz() { }''');
- addTestSource('''
- import '/libA.dart'
- class B { }
- String bar() => true;
- void main() {expect(^)}''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
- });
- }
-
-// test_ArgumentList_imported_function_1() {
-// // ArgumentList MethodInvocation ExpressionStatement Block
-// addSource('/libA.dart', '''
-// library A;
-// bool hasLength(int expected) { }
-// expect(String arg) { }
-// void baz() { }''');
-// addTestSource('''
-// import '/libA.dart'
-// class B { }
-// String bar() => true;
-// void main() {expect(^)}''');
-// computeFast();
-// return computeFull((bool result) {
-// assertSuggestArgumentList(['arg'], ['String']);
-// });
-// }
-
- test_ArgumentList_local_function_1() {
- // ArgumentList MethodInvocation ExpressionStatement Block
- addSource('/libA.dart', '''
- library A;
- bool hasLength(int expected) { }
- void baz() { }''');
- addTestSource('''
- import '/libA.dart'
- expect(arg) { }
- class B { }
- String bar() => true;
- void main() {expect(^)}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArgumentList(['arg'], ['dynamic']);
- });
- }
-
- test_ArgumentList_local_method_0() {
- // ArgumentList MethodInvocation ExpressionStatement Block
- addSource('/libA.dart', '''
- library A;
- bool hasLength(int expected) { }
- void baz() { }''');
- addTestSource('''
- import '/libA.dart'
- class B {
- expect() { }
- void foo() {expect(^)}}
- String bar() => true;''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
- });
- }
-
- test_ArgumentList_local_method_2() {
- // ArgumentList MethodInvocation ExpressionStatement Block
- addSource('/libA.dart', '''
- library A;
- bool hasLength(int expected) { }
- void baz() { }''');
- addTestSource('''
- import '/libA.dart'
- class B {
- expect(arg, int blat) { }
- void foo() {expect(^)}}
- String bar() => true;''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArgumentList(['arg', 'blat'], ['dynamic', 'int']);
- });
- }
-}
diff --git a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
new file mode 100644
index 0000000..64979d6
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
@@ -0,0 +1,455 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.services.completion.dart.arglist;
+
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/services/completion/arglist_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../reflective_tests.dart';
+import 'completion_test_util.dart';
+
+main() {
+ groupSep = ' | ';
+ runReflectiveTests(ArgListContributorTest);
+}
+
+@reflectiveTest
+class ArgListContributorTest extends AbstractCompletionTest {
+ void assertNoOtherSuggestions(Iterable<CompletionSuggestion> expected) {
+ for (CompletionSuggestion suggestion in request.suggestions) {
+ if (!expected.contains(suggestion)) {
+ failedCompletion('did not expect completion: '
+ '${suggestion.completion}\n $suggestion');
+ }
+ }
+ }
+
+ void assertSuggestArgumentList(
+ List<String> paramNames, List<String> paramTypes) {
+ CompletionSuggestionKind csKind = CompletionSuggestionKind.ARGUMENT_LIST;
+ CompletionSuggestion cs = getSuggest(csKind: csKind);
+ if (cs == null) {
+ failedCompletion('expected completion $csKind', request.suggestions);
+ }
+ assertSuggestArgumentList_params(
+ paramNames, paramTypes, cs.parameterNames, cs.parameterTypes);
+ expect(cs.relevance, DART_RELEVANCE_HIGH);
+ assertNoOtherSuggestions([cs]);
+ }
+
+ void assertSuggestArgumentList_params(List<String> expectedNames,
+ List<String> expectedTypes, List<String> actualNames,
+ List<String> actualTypes) {
+ if (actualNames != null &&
+ actualNames.length == expectedNames.length &&
+ actualTypes != null &&
+ actualTypes.length == expectedTypes.length) {
+ int index = 0;
+ while (index < expectedNames.length) {
+ if (actualNames[index] != expectedNames[index] ||
+ actualTypes[index] != expectedTypes[index]) {
+ break;
+ }
+ ++index;
+ }
+ if (index == expectedNames.length) {
+ return;
+ }
+ }
+ StringBuffer msg = new StringBuffer();
+ msg.writeln('Argument list not the same');
+ msg.writeln(' Expected names: $expectedNames');
+ msg.writeln(' found: $actualNames');
+ msg.writeln(' Expected types: $expectedTypes');
+ msg.writeln(' found: $actualTypes');
+ fail(msg.toString());
+ }
+
+ /**
+ * Assert that the specified suggestions are the only suggestions.
+ */
+ void assertSuggestArguments({List<String> namedArguments}) {
+ List<CompletionSuggestion> expected = new List<CompletionSuggestion>();
+ for (String name in namedArguments) {
+ expected.add(assertSuggest('$name: ',
+ csKind: CompletionSuggestionKind.NAMED_ARGUMENT,
+ relevance: DART_RELEVANCE_PARAMETER));
+ }
+ assertNoOtherSuggestions(expected);
+ }
+
+ @override
+ void setUpContributor() {
+ contributor = new ArgListContributor();
+ }
+
+ test_ArgumentList_getter() {
+ addTestSource('class A {int get foo => 7; main() {foo(^)}');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_imported_function_0() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource('/libA.dart', '''
+ library A;
+ bool hasLength(int expected) { }
+ expect() { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ class B { }
+ String bar() => true;
+ void main() {expect(a^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_imported_function_1() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource('/libA.dart', '''
+ library A;
+ bool hasLength(int expected) { }
+ expect(String arg) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ class B { }
+ String bar() => true;
+ void main() {expect(^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArgumentList(['arg'], ['String']);
+ });
+ }
+
+ test_ArgumentList_imported_function_2() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource('/libA.dart', '''
+ library A;
+ bool hasLength(int expected) { }
+ expect(String arg1, int arg2) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ class B { }
+ String bar() => true;
+ void main() {expect(^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArgumentList(['arg1', 'arg2'], ['String', 'int']);
+ });
+ }
+
+ test_ArgumentList_imported_function_3() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource('/libA.dart', '''
+ library A;
+ bool hasLength(int expected) { }
+ expect(String arg1, int arg2, {bool arg3}) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ class B { }
+ String bar() => true;
+ void main() {expect(^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArgumentList(['arg1', 'arg2'], ['String', 'int']);
+ });
+ }
+
+ test_ArgumentList_imported_function_3a() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource('/libA.dart', '''
+ library A;
+ bool hasLength(int expected) { }
+ expect(String arg1, int arg2, {bool arg3}) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ class B { }
+ String bar() => true;
+ void main() {expect('hello', ^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_imported_function_3b() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource('/libA.dart', '''
+ library A;
+ bool hasLength(int expected) { }
+ expect(String arg1, int arg2, {bool arg3}) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ class B { }
+ String bar() => true;
+ void main() {expect('hello', ^x)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_imported_function_3c() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource('/libA.dart', '''
+ library A;
+ bool hasLength(int expected) { }
+ expect(String arg1, int arg2, {bool arg3}) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ class B { }
+ String bar() => true;
+ void main() {expect('hello', x^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_imported_function_3d() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource('/libA.dart', '''
+ library A;
+ bool hasLength(int expected) { }
+ expect(String arg1, int arg2, {bool arg3}) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ class B { }
+ String bar() => true;
+ void main() {expect('hello', x ^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_imported_function_named_param() {
+ //
+ addTestSource('main() { int.parse("16", ^);}');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArguments(namedArguments: ['radix', 'onError']);
+ });
+ }
+
+ test_ArgumentList_imported_function_named_param1() {
+ //
+ addTestSource('main() { int.parse("16", r^);}');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArguments(namedArguments: ['radix', 'onError']);
+ });
+ }
+
+ test_ArgumentList_imported_function_named_param2() {
+ //
+ addTestSource('main() { int.parse("16", radix: 7, ^);}');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArguments(namedArguments: ['onError']);
+ });
+ }
+
+ test_ArgumentList_imported_function_named_param2a() {
+ //
+ addTestSource('main() { int.parse("16", radix: ^);}');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_local_function_1() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addTestSource('''
+ import '/libA.dart'
+ expect(arg) { }
+ class B { }
+ String bar() => true;
+ void main() {expect(^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArgumentList(['arg'], ['dynamic']);
+ });
+ }
+
+ test_ArgumentList_local_function_2() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addTestSource('''
+ import '/libA.dart'
+ expect(arg1, int arg2) { }
+ class B { }
+ String bar() => true;
+ void main() {expect(^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArgumentList(['arg1', 'arg2'], ['dynamic', 'int']);
+ });
+ }
+
+ test_ArgumentList_local_function_3() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addTestSource('''
+ import '/libA.dart'
+ expect(arg1, int arg2) { }
+ class B { }
+ String bar() => true;
+ void main() {expect(^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArgumentList(['arg1', 'arg2'], ['dynamic', 'int']);
+ });
+ }
+
+ test_ArgumentList_local_function_3a() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addTestSource('''
+ import '/libA.dart'
+ expect(arg1, int arg2, {bool arg3}) { }
+ class B { }
+ String bar() => true;
+ void main() {expect('hello', ^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_local_function_3b() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addTestSource('''
+ import '/libA.dart'
+ expect(arg1, int arg2, {bool arg3}) { }
+ class B { }
+ String bar() => true;
+ void main() {expect('hello', ^x)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_local_function_3c() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addTestSource('''
+ import '/libA.dart'
+ expect(arg1, int arg2, {bool arg3}) { }
+ class B { }
+ String bar() => true;
+ void main() {expect('hello', x^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_local_function_3d() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addTestSource('''
+ import '/libA.dart'
+ expect(arg1, int arg2, {bool arg3}) { }
+ class B { }
+ String bar() => true;
+ void main() {expect('hello', x ^)}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_local_function_named_param() {
+ //
+ addTestSource('''
+f(v,{int radix, int onError(String s)}){}
+main() { f("16", ^);}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArguments(namedArguments: ['radix', 'onError']);
+ });
+ }
+
+ test_ArgumentList_local_function_named_param1() {
+ //
+ addTestSource('''
+f(v,{int radix, int onError(String s)}){}
+main() { f("16", r^);}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArguments(namedArguments: ['radix', 'onError']);
+ });
+ }
+
+ test_ArgumentList_local_function_named_param2() {
+ //
+ addTestSource('''
+f(v,{int radix, int onError(String s)}){}
+main() { f("16", radix: 7, ^);}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArguments(namedArguments: ['onError']);
+ });
+ }
+
+ test_ArgumentList_local_function_named_param2a() {
+ //
+ addTestSource('''
+f(v,{int radix, int onError(String s)}){}
+main() { f("16", radix: ^);}''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_local_method_0() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource('/libA.dart', '''
+ library A;
+ bool hasLength(int expected) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ class B {
+ expect() { }
+ void foo() {expect(^)}}
+ String bar() => true;''');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_ArgumentList_local_method_2() {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource('/libA.dart', '''
+ library A;
+ bool hasLength(int expected) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ class B {
+ expect(arg, int blat) { }
+ void foo() {expect(^)}}
+ String bar() => true;''');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggestArgumentList(['arg', 'blat'], ['dynamic', 'int']);
+ });
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/combinator_computer_test.dart b/pkg/analysis_server/test/services/completion/combinator_contributor_test.dart
similarity index 94%
rename from pkg/analysis_server/test/services/completion/combinator_computer_test.dart
rename to pkg/analysis_server/test/services/completion/combinator_contributor_test.dart
index d924f81..01df6a0 100644
--- a/pkg/analysis_server/test/services/completion/combinator_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/combinator_contributor_test.dart
@@ -5,7 +5,7 @@
library test.services.completion.dart.combinator;
import 'package:analysis_server/src/protocol.dart';
-import 'package:analysis_server/src/services/completion/combinator_computer.dart';
+import 'package:analysis_server/src/services/completion/combinator_contributor.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:unittest/unittest.dart';
@@ -14,14 +14,14 @@
main() {
groupSep = ' | ';
- runReflectiveTests(CombinatorComputerTest);
+ runReflectiveTests(CombinatorContributorTest);
}
@reflectiveTest
-class CombinatorComputerTest extends AbstractCompletionTest {
+class CombinatorContributorTest extends AbstractCompletionTest {
@override
- void setUpComputer() {
- computer = new CombinatorComputer();
+ void setUpContributor() {
+ contributor = new CombinatorContributor();
}
test_Block_inherited_local() {
diff --git a/pkg/analysis_server/test/services/completion/completion_computer_test.dart b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
index 37afa8f..50fee60 100644
--- a/pkg/analysis_server/test/services/completion/completion_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
@@ -46,8 +46,8 @@
Source source;
CompletionPerformance perf;
DartCompletionManager manager;
- MockCompletionComputer computer1;
- MockCompletionComputer computer2;
+ MockCompletionContributor contributor1;
+ MockCompletionContributor contributor2;
CompletionSuggestion suggestion1;
CompletionSuggestion suggestion2;
bool _continuePerformingAnalysis = true;
@@ -78,25 +78,25 @@
}
test_compute_fastAndFull() {
- computer1 = new MockCompletionComputer(suggestion1, null);
- computer2 = new MockCompletionComputer(null, suggestion2);
- manager.computers = [computer1, computer2];
+ contributor1 = new MockCompletionContributor(suggestion1, null);
+ contributor2 = new MockCompletionContributor(null, suggestion2);
+ manager.contributors = [contributor1, contributor2];
int count = 0;
bool done = false;
CompletionRequest completionRequest = new CompletionRequest(0, perf);
manager.results(completionRequest).listen((CompletionResult r) {
switch (++count) {
case 1:
- computer1.assertCalls(context, source, 0, searchEngine);
- computer2.assertCalls(context, source, 0, searchEngine);
+ contributor1.assertCalls(context, source, 0, searchEngine);
+ contributor2.assertCalls(context, source, 0, searchEngine);
expect(r.last, isFalse);
expect(r.suggestions, hasLength(1));
expect(r.suggestions, contains(suggestion1));
resolveLibrary();
break;
case 2:
- computer1.assertFull(0);
- computer2.assertFull(1);
+ contributor1.assertFull(0);
+ contributor2.assertFull(1);
expect(r.last, isTrue);
expect(r.suggestions, hasLength(2));
expect(r.suggestions, contains(suggestion1));
@@ -115,17 +115,17 @@
}
test_compute_fastOnly() {
- computer1 = new MockCompletionComputer(suggestion1, null);
- computer2 = new MockCompletionComputer(suggestion2, null);
- manager.computers = [computer1, computer2];
+ contributor1 = new MockCompletionContributor(suggestion1, null);
+ contributor2 = new MockCompletionContributor(suggestion2, null);
+ manager.contributors = [contributor1, contributor2];
int count = 0;
bool done = false;
CompletionRequest completionRequest = new CompletionRequest(0, perf);
manager.results(completionRequest).listen((CompletionResult r) {
switch (++count) {
case 1:
- computer1.assertCalls(context, source, 0, searchEngine);
- computer2.assertCalls(context, source, 0, searchEngine);
+ contributor1.assertCalls(context, source, 0, searchEngine);
+ contributor2.assertCalls(context, source, 0, searchEngine);
expect(r.last, isTrue);
expect(r.suggestions, hasLength(2));
expect(r.suggestions, contains(suggestion1));
@@ -152,14 +152,14 @@
}
}
-class MockCompletionComputer extends DartCompletionComputer {
+class MockCompletionContributor extends DartCompletionContributor {
final CompletionSuggestion fastSuggestion;
final CompletionSuggestion fullSuggestion;
int fastCount = 0;
int fullCount = 0;
DartCompletionRequest request;
- MockCompletionComputer(this.fastSuggestion, this.fullSuggestion);
+ MockCompletionContributor(this.fastSuggestion, this.fullSuggestion);
assertCalls(AnalysisContext context, Source source, int offset,
SearchEngine searchEngine) {
diff --git a/pkg/analysis_server/test/services/completion/completion_target_test.dart b/pkg/analysis_server/test/services/completion/completion_target_test.dart
index 0bf95cf..e673466 100644
--- a/pkg/analysis_server/test/services/completion/completion_target_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_target_test.dart
@@ -138,6 +138,30 @@
assertTarget('}', '{}');
}
+ test_FormalParameter_partialType() {
+ // SimpleIdentifier PrefixedIdentifier TypeName
+ addTestSource('foo(b.^ f) { }');
+ assertTarget('f', 'b.f');
+ }
+
+ test_FormalParameter_partialType2() {
+ // SimpleIdentifier PrefixedIdentifier TypeName
+ addTestSource('foo(b.z^ f) { }');
+ assertTarget('z', 'b.z');
+ }
+
+ test_FormalParameter_partialType3() {
+ // SimpleIdentifier PrefixedIdentifier TypeName
+ addTestSource('foo(b.^) { }');
+ assertTarget('', 'b.');
+ }
+
+ test_FormalParameterList() {
+ // Token FormalParameterList FunctionExpression
+ addTestSource('foo(^) { }');
+ assertTarget(')', '()');
+ }
+
test_FunctionDeclaration_inLineComment() {
// Comment CompilationUnit
addTestSource('''
diff --git a/pkg/analysis_server/test/services/completion/completion_test_util.dart b/pkg/analysis_server/test/services/completion/completion_test_util.dart
index 40d31a8..e2af4d8 100644
--- a/pkg/analysis_server/test/services/completion/completion_test_util.dart
+++ b/pkg/analysis_server/test/services/completion/completion_test_util.dart
@@ -11,10 +11,11 @@
import 'package:analysis_server/src/protocol.dart' hide Element, ElementKind;
import 'package:analysis_server/src/services/completion/common_usage_computer.dart';
import 'package:analysis_server/src/services/completion/completion_manager.dart';
+import 'package:analysis_server/src/services/completion/completion_target.dart';
import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/imported_computer.dart';
-import 'package:analysis_server/src/services/completion/invocation_computer.dart';
+import 'package:analysis_server/src/services/completion/imported_reference_contributor.dart';
+import 'package:analysis_server/src/services/completion/prefixed_element_contributor.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/local_memory_index.dart';
import 'package:analysis_server/src/services/search/search_engine_internal.dart';
@@ -35,7 +36,7 @@
abstract class AbstractCompletionTest extends AbstractContextTest {
Index index;
SearchEngineImpl searchEngine;
- DartCompletionComputer computer;
+ DartCompletionContributor contributor;
String testFile = '/completionTest.dart';
Source testSource;
CompilationUnit testUnit;
@@ -130,46 +131,6 @@
return cs;
}
- void assertSuggestArgumentList(
- List<String> paramNames, List<String> paramTypes) {
- CompletionSuggestionKind csKind = CompletionSuggestionKind.ARGUMENT_LIST;
- CompletionSuggestion cs = getSuggest(csKind: csKind);
- if (cs == null) {
- failedCompletion('expected completion $csKind', request.suggestions);
- }
- assertSuggestArgumentList_params(
- paramNames, paramTypes, cs.parameterNames, cs.parameterTypes);
- expect(cs.relevance, DART_RELEVANCE_HIGH);
- }
-
- void assertSuggestArgumentList_params(List<String> expectedNames,
- List<String> expectedTypes, List<String> actualNames,
- List<String> actualTypes) {
- if (actualNames != null &&
- actualNames.length == expectedNames.length &&
- actualTypes != null &&
- actualTypes.length == expectedTypes.length) {
- int index = 0;
- while (index < expectedNames.length) {
- if (actualNames[index] != expectedNames[index] ||
- actualTypes[index] != expectedTypes[index]) {
- break;
- }
- ++index;
- }
- if (index == expectedNames.length) {
- return;
- }
- }
- StringBuffer msg = new StringBuffer();
- msg.writeln('Argument list not the same');
- msg.writeln(' Expected names: $expectedNames');
- msg.writeln(' found: $actualNames');
- msg.writeln(' Expected types: $expectedTypes');
- msg.writeln(' found: $actualTypes');
- fail(msg.toString());
- }
-
CompletionSuggestion assertSuggestClass(String name,
{int relevance: DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
@@ -320,7 +281,7 @@
CompletionSuggestion assertSuggestLibraryPrefix(String prefix,
[int relevance = DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
- // Library prefix should only be suggested by ImportedComputer
+ // Library prefix should only be suggested by ImportedReferenceContributor
return assertNotSuggested(prefix);
}
@@ -349,7 +310,7 @@
CompletionSuggestion assertSuggestNamedConstructor(
String name, String returnType, [int relevance = DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
- if (computer is InvocationComputer) {
+ if (contributor is PrefixedElementContributor) {
CompletionSuggestion cs =
assertSuggest(name, csKind: kind, relevance: relevance);
protocol.Element element = cs.element;
@@ -412,7 +373,7 @@
void assertSuggestTopLevelVarGetterSetter(String name, String returnType,
[int relevance = DART_RELEVANCE_DEFAULT]) {
- if (computer is ImportedComputer) {
+ if (contributor is ImportedReferenceContributor) {
assertSuggestGetter(name, returnType);
assertSuggestSetter(name);
} else {
@@ -423,7 +384,7 @@
bool computeFast() {
_computeFastCalled = true;
_completionManager = new DartCompletionManager(context, searchEngine,
- testSource, cache, [computer], new CommonUsageComputer({}));
+ testSource, cache, [contributor], new CommonUsageComputer({}));
var result = _completionManager.computeFast(request);
expect(request.replacementOffset, isNotNull);
expect(request.replacementLength, isNotNull);
@@ -435,7 +396,7 @@
expect(computeFast(), isFalse);
}
resolve(fullAnalysis);
- return computer.computeFull(request).then(assertFunction);
+ return contributor.computeFull(request).then(assertFunction);
}
void failedCompletion(String message,
@@ -519,8 +480,8 @@
context.getResolvedCompilationUnit(testSource, library);
if (unit != null) {
request.unit = unit;
- request.node =
- new NodeLocator.con1(completionOffset).searchWithin(unit);
+ request.target =
+ new CompletionTarget.forOffset(unit, completionOffset);
resolved = true;
if (!fullAnalysis) {
break;
@@ -541,21 +502,21 @@
super.setUp();
index = createLocalMemoryIndex();
searchEngine = new SearchEngineImpl(index);
- setUpComputer();
+ setUpContributor();
}
- void setUpComputer();
+ void setUpContributor();
}
/**
- * Common tests for `ImportedTypeComputerTest`, `InvocationComputerTest`,
- * and `LocalComputerTest`.
+ * Common tests for `ImportedTypeContributorTest`, `InvocationContributorTest`,
+ * and `LocalContributorTest`.
*/
abstract class AbstractSelectorSuggestionTest extends AbstractCompletionTest {
/**
- * Assert that the ImportedComputer uses cached results to produce identical
- * suggestions to the original set of suggestions.
+ * Assert that the ImportedReferenceContributor uses cached results
+ * to produce identical suggestions to the original set of suggestions.
*/
void assertCachedCompute(_) {
// Subclasses override
@@ -564,7 +525,7 @@
CompletionSuggestion assertSuggestImportedClass(String name,
{CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
int relevance: DART_RELEVANCE_DEFAULT}) {
- if (computer is ImportedComputer) {
+ if (contributor is ImportedReferenceContributor) {
return assertSuggestClass(name, relevance: relevance, kind: kind);
} else {
return assertNotSuggested(name);
@@ -592,7 +553,7 @@
String name, String returnType, [bool isDeprecated = false,
int relevance = DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
- if (computer is ImportedComputer) {
+ if (contributor is ImportedReferenceContributor) {
return assertSuggestFunctionTypeAlias(
name, returnType, isDeprecated, relevance, kind);
} else {
@@ -620,7 +581,7 @@
CompletionSuggestion assertSuggestImportedTopLevelVar(
String name, String returnType, [int relevance = DART_RELEVANCE_DEFAULT,
CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
- if (computer is ImportedComputer) {
+ if (contributor is ImportedReferenceContributor) {
return assertSuggestTopLevelVar(name, returnType, relevance, kind);
} else {
return assertNotSuggested(name);
@@ -629,7 +590,7 @@
CompletionSuggestion assertSuggestInvocationClass(String name,
[int relevance = DART_RELEVANCE_DEFAULT]) {
- if (computer is InvocationComputer) {
+ if (contributor is PrefixedElementContributor) {
return assertSuggestClass(name, relevance: relevance);
} else {
return assertNotSuggested(name);
@@ -644,7 +605,7 @@
CompletionSuggestion assertSuggestInvocationGetter(
String name, String returnType,
{int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
- if (computer is InvocationComputer) {
+ if (contributor is PrefixedElementContributor) {
return assertSuggestGetter(name, returnType,
relevance: relevance, isDeprecated: isDeprecated);
} else {
@@ -655,7 +616,7 @@
CompletionSuggestion assertSuggestInvocationMethod(
String name, String declaringType, String returnType,
[int relevance = DART_RELEVANCE_DEFAULT]) {
- if (computer is InvocationComputer) {
+ if (contributor is PrefixedElementContributor) {
return assertSuggestMethod(name, declaringType, returnType,
relevance: relevance);
} else {
@@ -665,7 +626,7 @@
CompletionSuggestion assertSuggestInvocationSetter(String name,
[int relevance = DART_RELEVANCE_DEFAULT]) {
- if (computer is InvocationComputer) {
+ if (contributor is PrefixedElementContributor) {
return assertSuggestSetter(name);
} else {
return assertNotSuggested(name);
@@ -675,7 +636,7 @@
CompletionSuggestion assertSuggestInvocationTopLevelVar(
String name, String returnType,
[int relevance = DART_RELEVANCE_DEFAULT]) {
- if (computer is InvocationComputer) {
+ if (contributor is PrefixedElementContributor) {
return assertSuggestTopLevelVar(name, returnType, relevance);
} else {
return assertNotSuggested(name);
@@ -1210,7 +1171,7 @@
export "dart:math" hide max;
class A {int x;}
@deprecated D1() {int x;}
- class _B { }''');
+ class _B {boo() { partBoo() {}} }''');
addSource('/testCD.dart', '''
String T1;
var _T2;
@@ -1232,7 +1193,7 @@
int T5;
var _T6;
String get T7 => 'hello';
- set T8(int value) { }
+ set T8(int value) { partT8() {} }
Z D2() {int x;}
class X {
int get clog => 8;
@@ -1259,10 +1220,12 @@
// Don't suggest locals out of scope
assertNotSuggested('r');
assertNotSuggested('x');
+ assertNotSuggested('partT8');
assertSuggestImportedClass('A');
assertNotSuggested('_B');
assertSuggestImportedClass('C');
+ assertNotSuggested('partBoo');
// hidden element suggested as low relevance
// but imported results are partially filtered
//assertSuggestImportedClass('D', COMPLETION_RELEVANCE_LOW);
@@ -1282,7 +1245,7 @@
// 'num',
// false,
// COMPLETION_RELEVANCE_LOW);
- if (computer is ImportedComputer) {
+ if (contributor is ImportedReferenceContributor) {
// TODO(danrubel) should be top level var suggestion
assertSuggestGetter('T1', 'String');
}
@@ -1298,6 +1261,9 @@
assertSuggestLocalSetter('blog');
// TODO (danrubel) suggest HtmlElement as low relevance
assertNotSuggested('HtmlElement');
+ assertSuggestImportedClass('Uri');
+ assertNotSuggested('parseIPv6Address');
+ assertNotSuggested('parseHex');
});
}
@@ -1385,7 +1351,7 @@
// Block BlockFunctionBody MethodDeclaration ClassDeclaration
addSource('/testB.dart', '''
lib B;
- class F { var f1; f2() { } get f3 => 0; set f4(fx) { } }
+ class F { var f1; f2() { } get f3 => 0; set f4(fx) { } var _pf; }
class E extends F { var e1; e2() { } }
class I { int i1; i2() { } }
class M { var m1; int m2() { } }''');
@@ -1438,6 +1404,58 @@
});
}
+ test_Block_local_function() {
+ addSource('/testAB.dart', '''
+ export "dart:math" hide max;
+ class A {int x;}
+ @deprecated D1() {int x;}
+ class _B {boo() { partBoo() {}} }''');
+ addSource('/testCD.dart', '''
+ String T1;
+ var _T2;
+ class C { }
+ class D { }''');
+ addSource('/testEEF.dart', '''
+ class EE { }
+ class F { }''');
+ addSource('/testG.dart', 'class G { }');
+ addSource('/testH.dart', '''
+ class H { }
+ int T3;
+ var _T4;'''); // not imported
+ addTestSource('''
+ import "/testAB.dart";
+ import "/testCD.dart" hide D;
+ import "/testEEF.dart" show EE;
+ import "/testG.dart" as g;
+ int T5;
+ var _T6;
+ String get T7 => 'hello';
+ set T8(int value) { partT8() {} }
+ Z D2() {int x;}
+ class X {
+ int get clog => 8;
+ set blog(value) { }
+ a() {
+ var f;
+ localF(int arg1) { }
+ {var x;}
+ p^ var r;
+ }
+ void b() { }}
+ class Z { }''');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset - 1);
+ expect(request.replacementLength, 1);
+
+ assertNotSuggested('partT8');
+ assertNotSuggested('partBoo');
+ assertNotSuggested('parseIPv6Address');
+ assertNotSuggested('parseHex');
+ });
+ }
+
test_Block_unimported() {
addSource('/testAB.dart', 'class Foo { }');
addTestSource('class C {foo(){F^}}');
@@ -1545,6 +1563,33 @@
});
}
+ test_CatchClause_onType() {
+ // TypeName CatchClause TryStatement
+ addTestSource('class A {a() {try{var x;} on ^ {}}}');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertSuggestLocalClass('A');
+ assertSuggestImportedClass('Object');
+ assertNotSuggested('a');
+ assertNotSuggested('x');
+ });
+ }
+
+ test_CatchClause_onType_noBrackets() {
+ // TypeName CatchClause TryStatement
+ addTestSource('class A {a() {try{var x;} on ^}}');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertSuggestLocalClass('A');
+ assertSuggestImportedClass('Object');
+ assertNotSuggested('x');
+ });
+ }
+
test_CatchClause_typed() {
// Block CatchClause TryStatement
addTestSource('class A {a() {try{var x;} on E catch (e) {^}}}');
@@ -2060,11 +2105,11 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- assertSuggestLocalFunction('foo', null);
- assertSuggestLocalMethod('a', 'A', null);
+ assertNotSuggested('foo');
+ assertNotSuggested('a');
assertSuggestLocalClass('A');
assertSuggestImportedClass('String');
- assertSuggestImportedFunction('identical', 'bool');
+ assertNotSuggested('identical');
assertNotSuggested('bar');
});
}
@@ -2432,7 +2477,7 @@
expect(request.replacementLength, 0);
assertNotSuggested('Object');
// TODO(danrubel) should return top level var rather than getter
- if (computer is ImportedComputer) {
+ if (contributor is ImportedReferenceContributor) {
//assertSuggestImportedTopLevelVar('T1', 'int');
assertSuggestGetter('T1', 'int');
}
@@ -2467,7 +2512,7 @@
expect(request.replacementLength, 0);
assertSuggestImportedClass('Object');
// TODO(danrubel) should return top level var rather than getter
- if (computer is ImportedComputer) {
+ if (contributor is ImportedReferenceContributor) {
//assertSuggestImportedTopLevelVar('T1', 'int');
assertSuggestGetter('T1', 'int');
}
@@ -2624,7 +2669,7 @@
assertSuggestImportedFunction('nowIsIt', null);
assertNotSuggested('T1');
// TODO (danrubel) this really should be TopLevelVar not getter/setter
- if (computer is ImportedComputer) {
+ if (contributor is ImportedReferenceContributor) {
assertSuggestGetter('newT1', 'int');
}
assertNotSuggested('z');
@@ -2682,7 +2727,7 @@
expect(request.replacementLength, 0);
assertSuggestImportedClass('Object');
// TODO(danrubel) Should be top level variable
- if (computer is ImportedComputer) {
+ if (contributor is ImportedReferenceContributor) {
assertSuggestGetter('T1', 'int');
// assertSuggestImportedTopLevelVar('T1', 'int');
}
@@ -2715,7 +2760,7 @@
expect(request.replacementOffset, completionOffset - 1);
expect(request.replacementLength, 1);
// TODO(danrubel) Should be top level variable
- if (computer is ImportedComputer) {
+ if (contributor is ImportedReferenceContributor) {
assertSuggestGetter('T1', 'int');
// assertSuggestImportedTopLevelVar('T1', 'int');
}
@@ -2742,7 +2787,7 @@
expect(request.replacementOffset, completionOffset - 1);
expect(request.replacementLength, 1);
// TODO(danrubel) Should be top level variable
- if (computer is ImportedComputer) {
+ if (contributor is ImportedReferenceContributor) {
assertSuggestGetter('T1', 'int');
// assertSuggestImportedTopLevelVar('T1', 'int');
}
@@ -3238,6 +3283,60 @@
});
}
+ test_PrefixedIdentifier_library_typesOnly() {
+ // SimpleIdentifier PrefixedIdentifier TypeName
+ addSource('/testB.dart', '''
+ lib B;
+ var T1;
+ class X { }
+ class Y { }''');
+ addTestSource('''
+ import "/testB.dart" as b;
+ var T2;
+ class A { }
+ foo(b.^ f) {}''');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertSuggestInvocationClass('X');
+ assertSuggestInvocationClass('Y');
+ assertNotSuggested('T1');
+ assertNotSuggested('T2');
+ assertNotSuggested('Object');
+ assertNotSuggested('b');
+ assertNotSuggested('A');
+ assertNotSuggested('==');
+ });
+ }
+
+ test_PrefixedIdentifier_library_typesOnly2() {
+ // SimpleIdentifier PrefixedIdentifier TypeName
+ addSource('/testB.dart', '''
+ lib B;
+ var T1;
+ class X { }
+ class Y { }''');
+ addTestSource('''
+ import "/testB.dart" as b;
+ var T2;
+ class A { }
+ foo(b.^) {}''');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertSuggestInvocationClass('X');
+ assertSuggestInvocationClass('Y');
+ assertNotSuggested('T1');
+ assertNotSuggested('T2');
+ assertNotSuggested('Object');
+ assertNotSuggested('b');
+ assertNotSuggested('A');
+ assertNotSuggested('==');
+ });
+ }
+
test_PrefixedIdentifier_parameter() {
// SimpleIdentifier PrefixedIdentifier ExpressionStatement
addSource('/testB.dart', '''
@@ -3416,6 +3515,26 @@
});
}
+ test_PropertyAccess_noTarget() {
+ // SimpleIdentifier PropertyAccess ExpressionStatement
+ addSource('/testAB.dart', 'class Foo { }');
+ addTestSource('class C {foo(){.^}}');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
+ test_PropertyAccess_noTarget2() {
+ // SimpleIdentifier PropertyAccess ExpressionStatement
+ addSource('/testAB.dart', 'class Foo { }');
+ addTestSource('main() {.^}');
+ computeFast();
+ return computeFull((bool result) {
+ assertNoSuggestions();
+ });
+ }
+
test_PropertyAccess_selector() {
// SimpleIdentifier PropertyAccess ExpressionStatement Block
addTestSource('class A {a() {"hello".length.^}}');
diff --git a/pkg/analysis_server/test/services/completion/imported_computer_test.dart b/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart
similarity index 94%
rename from pkg/analysis_server/test/services/completion/imported_computer_test.dart
rename to pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart
index fd323e2..7551979 100644
--- a/pkg/analysis_server/test/services/completion/imported_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart
@@ -10,7 +10,7 @@
import 'package:analysis_server/src/services/completion/completion_manager.dart';
import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/imported_computer.dart';
+import 'package:analysis_server/src/services/completion/imported_reference_contributor.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -23,11 +23,11 @@
main() {
groupSep = ' | ';
- runReflectiveTests(ImportedComputerTest);
+ runReflectiveTests(ImportedReferenceContributorTest);
}
@reflectiveTest
-class ImportedComputerTest extends AbstractSelectorSuggestionTest {
+class ImportedReferenceContributorTest extends AbstractSelectorSuggestionTest {
void assertCached(String completion) {
DartCompletionCache cache = request.cache;
if (!isCached(cache.importedTypeSuggestions, completion) &&
@@ -39,12 +39,12 @@
}
/**
- * Assert that the ImportedComputer uses cached results to produce identical
- * suggestions to the original set of suggestions.
+ * Assert that the ImportedReferenceContributor uses cached results
+ * to produce identical suggestions to the original set of suggestions.
*/
@override
assertCachedCompute(_) {
- if (!(computer as ImportedComputer).shouldWaitForLowPrioritySuggestions) {
+ if (!(contributor as ImportedReferenceContributor).shouldWaitForLowPrioritySuggestions) {
return null;
}
expect(request.unit.element, isNotNull);
@@ -58,7 +58,7 @@
/*
* Calculate a new completion at the same location
*/
- setUpComputer();
+ setUpContributor();
int replacementOffset = request.replacementOffset;
int replacementLength = request.replacementLength;
request = new DartCompletionRequest(context, searchEngine, testSource,
@@ -98,7 +98,7 @@
// Results from cache might need to be adjusted
// if target is a function argument in an argument list
resolve(false);
- return computer.computeFull(request).then((bool result) {
+ return contributor.computeFull(request).then((bool result) {
expect(result, isTrue);
expect(request.unit.element, isNotNull);
assertResultsFromCache(oldSuggestions);
@@ -174,8 +174,9 @@
suggestions.any((CompletionSuggestion s) => s.completion == completion);
@override
- void setUpComputer() {
- computer = new ImportedComputer(shouldWaitForLowPrioritySuggestions: true);
+ void setUpContributor() {
+ contributor = new ImportedReferenceContributor(
+ shouldWaitForLowPrioritySuggestions: true);
}
@override
@@ -221,6 +222,18 @@
assertNotCached('e1');
assertNotCached('i2');
assertNotCached('m1');
+ assertNotCached('_pf');
+ });
+ }
+
+ test_internal_sdk_libs() {
+ addTestSource('main() {p^}');
+ computeFast();
+ return computeFull((bool result) {
+ assertSuggest('print');
+ assertSuggest('pow', relevance: DART_RELEVANCE_LOW);
+ // Do not suggest completions from internal SDK library
+ assertNotSuggested('printToConsole');
});
}
@@ -254,11 +267,12 @@
Z D2() {int x;}
class X {a() {var f; {var x;} ^ var r;} void b() { }}
class Z { }''');
- (computer as ImportedComputer).shouldWaitForLowPrioritySuggestions = false;
+ ImportedReferenceContributor contributor = this.contributor;
+ contributor.shouldWaitForLowPrioritySuggestions = false;
computeFast();
return computeFull((bool result) {
assertSuggestImportedClass('C');
- // Assert computer does not wait for or include low priority results
+ // Assert contributor does not wait for or include low priority results
// from non-imported libraries unless instructed to do so.
assertNotSuggested('H');
});
@@ -657,7 +671,7 @@
computeFast();
return computeFull((bool result) {
assertSuggestImportedClass('ClassInLocalContext');
- // Assert computer does not include results from 2nd context.
+ // Assert contributor does not include results from 2nd context.
assertNotSuggested('ClassFromAnotherContext');
});
}
diff --git a/pkg/analysis_server/test/services/completion/keyword_computer_test.dart b/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
similarity index 60%
rename from pkg/analysis_server/test/services/completion/keyword_computer_test.dart
rename to pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
index e044d9f..a7d881a 100644
--- a/pkg/analysis_server/test/services/completion/keyword_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
@@ -6,7 +6,7 @@
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/keyword_computer.dart';
+import 'package:analysis_server/src/services/completion/keyword_contributor.dart';
import 'package:analyzer/src/generated/scanner.dart';
import 'package:unittest/unittest.dart';
@@ -15,11 +15,65 @@
main() {
groupSep = ' | ';
- runReflectiveTests(KeywordComputerTest);
+ runReflectiveTests(KeywordContributorTest);
}
@reflectiveTest
-class KeywordComputerTest extends AbstractCompletionTest {
+class KeywordContributorTest extends AbstractCompletionTest {
+ static const List<Keyword> CLASS_BODY_KEYWORDS = const [
+ Keyword.CONST,
+ Keyword.DYNAMIC,
+ Keyword.FACTORY,
+ Keyword.FINAL,
+ Keyword.GET,
+ Keyword.OPERATOR,
+ Keyword.SET,
+ Keyword.STATIC,
+ Keyword.VAR,
+ Keyword.VOID
+ ];
+
+ static const List<Keyword> DECLARATION_KEYWORDS = const [
+ Keyword.ABSTRACT,
+ Keyword.CLASS,
+ Keyword.CONST,
+ Keyword.DYNAMIC,
+ Keyword.FINAL,
+ Keyword.TYPEDEF,
+ Keyword.VAR,
+ Keyword.VOID
+ ];
+
+ static const List<Keyword> DIRECTIVE_AND_DECLARATION_KEYWORDS = const [
+ Keyword.ABSTRACT,
+ Keyword.CLASS,
+ Keyword.CONST,
+ Keyword.DYNAMIC,
+ Keyword.EXPORT,
+ Keyword.FINAL,
+ Keyword.IMPORT,
+ Keyword.PART,
+ Keyword.TYPEDEF,
+ Keyword.VAR,
+ Keyword.VOID
+ ];
+
+ static const List<Keyword> DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS =
+ const [
+ Keyword.ABSTRACT,
+ Keyword.CLASS,
+ Keyword.CONST,
+ Keyword.DYNAMIC,
+ Keyword.EXPORT,
+ Keyword.FINAL,
+ Keyword.IMPORT,
+ Keyword.LIBRARY,
+ Keyword.PART,
+ Keyword.TYPEDEF,
+ Keyword.VAR,
+ Keyword.VOID
+ ];
+
static const List<Keyword> IN_BLOCK_IN_CLASS = const [
Keyword.ASSERT,
Keyword.CASE,
@@ -63,7 +117,7 @@
void assertSuggestKeywords(Iterable<Keyword> expectedKeywords,
[int relevance = DART_RELEVANCE_KEYWORD]) {
Set<Keyword> actualKeywords = new Set<Keyword>();
- request.suggestions.forEach((CompletionSuggestion s) {
+ for (CompletionSuggestion s in request.suggestions) {
if (s.kind == CompletionSuggestionKind.KEYWORD) {
Keyword k = Keyword.keywords[s.completion];
if (k == null) {
@@ -73,13 +127,8 @@
fail('Duplicate keyword suggested: ${s.completion}');
}
}
- expect(s.relevance, equals(relevance), reason: k.toString());
- expect(s.selectionOffset, equals(s.completion.length));
- expect(s.selectionLength, equals(0));
- expect(s.isDeprecated, equals(false));
- expect(s.isPotential, equals(false));
}
- });
+ }
if (expectedKeywords.any((k) => k is String)) {
StringBuffer msg = new StringBuffer();
msg.writeln('Expected set should be:');
@@ -97,69 +146,47 @@
_appendKeywords(msg, actualKeywords);
fail(msg.toString());
}
+ for (CompletionSuggestion s in request.suggestions) {
+ if (s.kind == CompletionSuggestionKind.KEYWORD) {
+ Keyword k = Keyword.keywords[s.completion];
+ expect(s.relevance, equals(relevance), reason: k.toString());
+ expect(s.selectionOffset, equals(s.completion.length));
+ expect(s.selectionLength, equals(0));
+ expect(s.isDeprecated, equals(false));
+ expect(s.isPotential, equals(false));
+ }
+ }
}
@override
- void setUpComputer() {
- computer = new KeywordComputer();
+ void setUpContributor() {
+ contributor = new KeywordContributor();
}
test_after_class() {
addTestSource('class A {} ^');
expect(computeFast(), isTrue);
- assertSuggestKeywords([
- Keyword.ABSTRACT,
- Keyword.CLASS,
- Keyword.CONST,
- Keyword.FINAL,
- Keyword.TYPEDEF,
- Keyword.VAR
- ], DART_RELEVANCE_HIGH);
+ assertSuggestKeywords(DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH);
}
test_after_class2() {
addTestSource('class A {} c^');
expect(computeFast(), isTrue);
- assertSuggestKeywords([
- Keyword.ABSTRACT,
- Keyword.CLASS,
- Keyword.CONST,
- Keyword.FINAL,
- Keyword.TYPEDEF,
- Keyword.VAR
- ], DART_RELEVANCE_HIGH);
+ assertSuggestKeywords(DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH);
}
test_after_import() {
- addTestSource('import foo; ^');
+ addTestSource('import "foo"; ^');
expect(computeFast(), isTrue);
- assertSuggestKeywords([
- Keyword.ABSTRACT,
- Keyword.CLASS,
- Keyword.CONST,
- Keyword.EXPORT,
- Keyword.FINAL,
- Keyword.IMPORT,
- Keyword.PART,
- Keyword.TYPEDEF,
- Keyword.VAR
- ], DART_RELEVANCE_HIGH);
+ assertSuggestKeywords(
+ DIRECTIVE_AND_DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH);
}
test_after_import2() {
- addTestSource('import foo; c^');
+ addTestSource('import "foo"; c^');
expect(computeFast(), isTrue);
- assertSuggestKeywords([
- Keyword.ABSTRACT,
- Keyword.CLASS,
- Keyword.CONST,
- Keyword.EXPORT,
- Keyword.FINAL,
- Keyword.IMPORT,
- Keyword.PART,
- Keyword.TYPEDEF,
- Keyword.VAR
- ], DART_RELEVANCE_HIGH);
+ assertSuggestKeywords(
+ DIRECTIVE_AND_DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH);
}
test_before_import() {
@@ -174,26 +201,36 @@
}
test_class() {
- addTestSource('class A ^');
- expect(computeFast(), isTrue);
- assertSuggestKeywords(
- [Keyword.EXTENDS, Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH);
- }
-
- test_class2() {
- addTestSource('class A e^');
- expect(computeFast(), isTrue);
- assertSuggestKeywords(
- [Keyword.EXTENDS, Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH);
- }
-
- test_class3() {
addTestSource('class A e^ { }');
expect(computeFast(), isTrue);
assertSuggestKeywords(
[Keyword.EXTENDS, Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH);
}
+ test_class_body() {
+ addTestSource('class A {^}');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords(CLASS_BODY_KEYWORDS);
+ }
+
+ test_class_body_beginning() {
+ addTestSource('class A {^ var foo;}');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords(CLASS_BODY_KEYWORDS);
+ }
+
+ test_class_body_between() {
+ addTestSource('class A {var bar; ^ var foo;}');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords(CLASS_BODY_KEYWORDS);
+ }
+
+ test_class_body_end() {
+ addTestSource('class A {var foo; ^}');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords(CLASS_BODY_KEYWORDS);
+ }
+
test_class_extends() {
addTestSource('class A extends foo ^');
expect(computeFast(), isTrue);
@@ -255,6 +292,27 @@
assertSuggestKeywords([]);
}
+ test_class_noBody() {
+ addTestSource('class A ^');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords(
+ [Keyword.EXTENDS, Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH);
+ }
+
+ test_class_noBody2() {
+ addTestSource('class A e^');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords(
+ [Keyword.EXTENDS, Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH);
+ }
+
+ test_class_noBody3() {
+ addTestSource('class A e^ String foo;');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords(
+ [Keyword.EXTENDS, Keyword.IMPLEMENTS], DART_RELEVANCE_HIGH);
+ }
+
test_class_with() {
addTestSource('class A extends foo with bar ^');
expect(computeFast(), isTrue);
@@ -282,18 +340,8 @@
test_empty() {
addTestSource('^');
expect(computeFast(), isTrue);
- assertSuggestKeywords([
- Keyword.ABSTRACT,
- Keyword.CLASS,
- Keyword.CONST,
- Keyword.EXPORT,
- Keyword.FINAL,
- Keyword.IMPORT,
- Keyword.LIBRARY,
- Keyword.PART,
- Keyword.TYPEDEF,
- Keyword.VAR
- ], DART_RELEVANCE_HIGH);
+ assertSuggestKeywords(
+ DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS, DART_RELEVANCE_HIGH);
}
test_function_body_inClass_constructorInitializer() {
@@ -356,37 +404,101 @@
assertSuggestKeywords(IN_BLOCK_NOT_IN_CLASS);
}
- test_in_class() {
- addTestSource('class A {^}');
+ test_import() {
+ addTestSource('import "foo" deferred as foo ^;');
expect(computeFast(), isTrue);
- assertSuggestKeywords([
- Keyword.CONST,
- Keyword.DYNAMIC,
- Keyword.FACTORY,
- Keyword.FINAL,
- Keyword.GET,
- Keyword.OPERATOR,
- Keyword.SET,
- Keyword.STATIC,
- Keyword.VAR,
- Keyword.VOID
- ]);
+ assertSuggestKeywords([], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_as() {
+ addTestSource('import "foo" deferred ^;');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.AS], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_as2() {
+ addTestSource('import "foo" deferred a^;');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.AS], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_as3() {
+ addTestSource('import "foo" deferred a^');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.AS], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_deferred() {
+ addTestSource('import "foo" ^ as foo;');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.DEFERRED], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_deferred2() {
+ addTestSource('import "foo" d^ as foo;');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.DEFERRED], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_deferred3() {
+ addTestSource('import "foo" d^ show foo;');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.AS, Keyword.DEFERRED], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_deferred4() {
+ addTestSource('import "foo" d^ hide foo;');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.AS, Keyword.DEFERRED], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_deferred5() {
+ addTestSource('import "foo" d^');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.AS, Keyword.DEFERRED], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_deferred6() {
+ addTestSource('import "foo" d^ import');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.AS, Keyword.DEFERRED], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_deferred_not() {
+ addTestSource('import "foo" as foo ^;');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_deferred_as() {
+ addTestSource('import "foo" ^;');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.AS, Keyword.DEFERRED], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_deferred_as2() {
+ addTestSource('import "foo" d^;');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.AS, Keyword.DEFERRED], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_deferred_as3() {
+ addTestSource('import "foo" ^');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.AS, Keyword.DEFERRED], DART_RELEVANCE_HIGH);
+ }
+
+ test_import_deferred_as4() {
+ addTestSource('import "foo" d^');
+ expect(computeFast(), isTrue);
+ assertSuggestKeywords([Keyword.AS, Keyword.DEFERRED], DART_RELEVANCE_HIGH);
}
test_library() {
addTestSource('library foo;^');
expect(computeFast(), isTrue);
- assertSuggestKeywords([
- Keyword.ABSTRACT,
- Keyword.CLASS,
- Keyword.CONST,
- Keyword.EXPORT,
- Keyword.FINAL,
- Keyword.IMPORT,
- Keyword.PART,
- Keyword.TYPEDEF,
- Keyword.VAR
- ], DART_RELEVANCE_HIGH);
+ assertSuggestKeywords(
+ DIRECTIVE_AND_DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH);
}
test_library_name() {
@@ -410,50 +522,22 @@
test_part_of() {
addTestSource('part of foo;^');
expect(computeFast(), isTrue);
- assertSuggestKeywords([
- Keyword.ABSTRACT,
- Keyword.CLASS,
- Keyword.CONST,
- Keyword.EXPORT,
- Keyword.FINAL,
- Keyword.IMPORT,
- Keyword.PART,
- Keyword.TYPEDEF,
- Keyword.VAR
- ], DART_RELEVANCE_HIGH);
+ assertSuggestKeywords(
+ DIRECTIVE_AND_DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH);
}
test_partial_class() {
addTestSource('cl^');
expect(computeFast(), isTrue);
- assertSuggestKeywords([
- Keyword.ABSTRACT,
- Keyword.CLASS,
- Keyword.CONST,
- Keyword.EXPORT,
- Keyword.FINAL,
- Keyword.IMPORT,
- Keyword.LIBRARY,
- Keyword.PART,
- Keyword.TYPEDEF,
- Keyword.VAR
- ], DART_RELEVANCE_HIGH);
+ assertSuggestKeywords(
+ DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS, DART_RELEVANCE_HIGH);
}
test_partial_class2() {
addTestSource('library a; cl^');
expect(computeFast(), isTrue);
- assertSuggestKeywords([
- Keyword.ABSTRACT,
- Keyword.CLASS,
- Keyword.CONST,
- Keyword.EXPORT,
- Keyword.FINAL,
- Keyword.IMPORT,
- Keyword.PART,
- Keyword.TYPEDEF,
- Keyword.VAR
- ], DART_RELEVANCE_HIGH);
+ assertSuggestKeywords(
+ DIRECTIVE_AND_DECLARATION_KEYWORDS, DART_RELEVANCE_HIGH);
}
void _appendKeywords(StringBuffer msg, Iterable<Keyword> keywords) {
diff --git a/pkg/analysis_server/test/services/completion/local_computer_test.dart b/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
similarity index 96%
rename from pkg/analysis_server/test/services/completion/local_computer_test.dart
rename to pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
index e0aca46..0fe8047 100644
--- a/pkg/analysis_server/test/services/completion/local_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
@@ -6,7 +6,7 @@
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/local_computer.dart';
+import 'package:analysis_server/src/services/completion/local_reference_contributor.dart';
import 'package:unittest/unittest.dart';
import '../../reflective_tests.dart';
@@ -14,11 +14,11 @@
main() {
groupSep = ' | ';
- runReflectiveTests(LocalComputerTest);
+ runReflectiveTests(LocalReferenceContributorTest);
}
@reflectiveTest
-class LocalComputerTest extends AbstractSelectorSuggestionTest {
+class LocalReferenceContributorTest extends AbstractSelectorSuggestionTest {
@override
CompletionSuggestion assertSuggestLocalClass(String name,
{CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
@@ -94,7 +94,7 @@
CompletionSuggestion assertSuggestLocalVariable(
String name, String returnType,
{int relevance: DART_RELEVANCE_LOCAL_VARIABLE}) {
- // Local variables should only be suggested by LocalComputer
+ // Local variables should only be suggested by LocalReferenceContributor
CompletionSuggestion cs = assertSuggest(name,
csKind: CompletionSuggestionKind.INVOCATION, relevance: relevance);
expect(cs.returnType, returnType != null ? returnType : 'dynamic');
@@ -145,8 +145,23 @@
}
@override
- void setUpComputer() {
- computer = new LocalComputer();
+ void setUpContributor() {
+ contributor = new LocalReferenceContributor();
+ }
+
+ test_missing_params_function() {
+ addTestSource('int f1{} main(){f^}');
+ expect(computeFast(), isTrue);
+ }
+
+ test_missing_params_method() {
+ addTestSource('class C1{int f1{} main(){f^}}');
+ expect(computeFast(), isTrue);
+ }
+
+ test_missing_params_constructor() {
+ addTestSource('class C1{C1{} main(){C^}}');
+ expect(computeFast(), isTrue);
}
test_break_ignores_outer_functions_using_closure() {
diff --git a/pkg/analysis_server/test/services/completion/optype_test.dart b/pkg/analysis_server/test/services/completion/optype_test.dart
index a2634b1..ff74539 100644
--- a/pkg/analysis_server/test/services/completion/optype_test.dart
+++ b/pkg/analysis_server/test/services/completion/optype_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library test.services.completion.computer.dart.optype;
+library test.services.completion.contributor.dart.optype;
import 'package:analysis_server/src/services/completion/completion_target.dart';
import 'package:analysis_server/src/services/completion/optype.dart';
@@ -42,23 +42,20 @@
visitor = new OpType.forCompletion(completionTarget, offset);
}
- void assertOpType({bool invocation: false, bool returnValue: false,
+ void assertOpType({bool prefixed: false, bool returnValue: false,
bool typeNames: false, bool voidReturn: false, bool statementLabel: false,
bool caseLabel: false, bool constructors: false}) {
- expect(visitor.includeInvocationSuggestions, equals(invocation),
- reason: 'invocation');
- expect(visitor.includeReturnValueSuggestions, equals(returnValue),
+ expect(visitor.includeReturnValueSuggestions, returnValue,
reason: 'returnValue');
- expect(visitor.includeTypeNameSuggestions, equals(typeNames),
- reason: 'typeNames');
- expect(visitor.includeVoidReturnSuggestions, equals(voidReturn),
+ expect(visitor.includeTypeNameSuggestions, typeNames, reason: 'typeNames');
+ expect(visitor.includeVoidReturnSuggestions, voidReturn,
reason: 'voidReturn');
- expect(visitor.includeStatementLabelSuggestions, equals(statementLabel),
+ expect(visitor.includeStatementLabelSuggestions, statementLabel,
reason: 'statementLabel');
- expect(visitor.includeCaseLabelSuggestions, equals(caseLabel),
- reason: 'caseLabel');
- expect(visitor.includeConstructorSuggestions, equals(constructors),
+ expect(visitor.includeCaseLabelSuggestions, caseLabel, reason: 'caseLabel');
+ expect(visitor.includeConstructorSuggestions, constructors,
reason: 'constructors');
+ expect(visitor.isPrefixed, prefixed, reason: 'prefixed');
}
test_Annotation() {
@@ -80,6 +77,12 @@
assertOpType(returnValue: true, typeNames: true);
}
+ test_ArgumentList_prefixedIdentifier() {
+ // SimpleIdentifier PrefixedIdentifier ArgumentList
+ addTestSource('void main() {expect(aa.^)}');
+ assertOpType(returnValue: true, typeNames: true, prefixed: true);
+ }
+
test_AsExpression() {
// SimpleIdentifier TypeName AsExpression
addTestSource('class A {var b; X _c; foo() {var a; (a as ^).foo();}');
@@ -230,19 +233,20 @@
// looks like a cascade to the parser
// but the user is trying to get completions for a non-cascade
main() {A a; a.^.z}''');
- assertOpType(invocation: true);
+ assertOpType(
+ returnValue: true, typeNames: true, voidReturn: true, prefixed: true);
}
test_CascadeExpression_selector2() {
// SimpleIdentifier PropertyAccess CascadeExpression ExpressionStatement
addTestSource('main() {A a; a..^z}');
- assertOpType(invocation: true);
+ assertOpType(returnValue: true, voidReturn: true, prefixed: true);
}
test_CascadeExpression_selector2_withTrailingReturn() {
// PropertyAccess CascadeExpression ExpressionStatement Block
addTestSource('main() {A a; a..^ return}');
- assertOpType(invocation: true);
+ assertOpType(returnValue: true, voidReturn: true, prefixed: true);
}
test_CascadeExpression_target() {
@@ -251,6 +255,18 @@
assertOpType(returnValue: true, typeNames: true, voidReturn: true);
}
+ test_CatchClause_onType() {
+ // TypeName CatchClause TryStatement
+ addTestSource('class A {a() {try{var x;} on ^ {}}}');
+ assertOpType(typeNames: true);
+ }
+
+ test_CatchClause_onType_noBrackets() {
+ // TypeName CatchClause TryStatement
+ addTestSource('class A {a() {try{var x;} on ^}}');
+ assertOpType(typeNames: true);
+ }
+
test_CatchClause_typed() {
// Block CatchClause TryStatement
addTestSource('class A {a() {try{var x;} on E catch (e) {^}}}');
@@ -332,7 +348,7 @@
// SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
// InstanceCreationExpression
addTestSource('main() {new X.^}');
- assertOpType(invocation: true);
+ assertOpType(constructors: true, prefixed: true);
}
test_ConstructorName_name_resolved() {
@@ -346,14 +362,14 @@
// SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
// InstanceCreationExpression
addTestSource('main() {new String.fr^omCharCodes([]);}', resolved: true);
- assertOpType(invocation: true);
+ assertOpType(constructors: true, prefixed: true);
}
test_ConstructorName_unresolved() {
// SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
// InstanceCreationExpression
addTestSource('main() {new String.fr^omCharCodes([]);}');
- assertOpType(invocation: true);
+ assertOpType(constructors: true, prefixed: true);
}
test_Continue_after_label() {
@@ -475,10 +491,28 @@
assertOpType(typeNames: true);
}
+ test_FormalParameter_partialType() {
+ // FormalParameterList MethodDeclaration
+ addTestSource('class A {a(b.^ f) { }}');
+ assertOpType(returnValue: true, typeNames: true, prefixed: true);
+ }
+
+ test_FormalParameter_partialType2() {
+ // FormalParameterList MethodDeclaration
+ addTestSource('class A {a(b.z^ f) { }}');
+ assertOpType(returnValue: true, typeNames: true, prefixed: true);
+ }
+
+ test_FormalParameter_partialType3() {
+ // FormalParameterList MethodDeclaration
+ addTestSource('class A {a(b.^) { }}');
+ assertOpType(returnValue: true, typeNames: true, prefixed: true);
+ }
+
test_FormalParameterList() {
// FormalParameterList MethodDeclaration
addTestSource('class A {a(^) { }}');
- assertOpType(returnValue: true, typeNames: true);
+ assertOpType(typeNames: true);
}
test_ForStatement_condition() {
@@ -696,7 +730,7 @@
test_IfStatement_invocation() {
// SimpleIdentifier PrefixIdentifier IfStatement
addTestSource('main() {var a; if (a.^) something}');
- assertOpType(invocation: true);
+ assertOpType(returnValue: true, typeNames: true, prefixed: true);
}
test_ImplementsClause() {
@@ -762,7 +796,7 @@
test_InterpolationExpression_prefix_selector() {
// SimpleIdentifier PrefixedIdentifier InterpolationExpression
addTestSource('main() {String name; print("hello \${name.^}");}');
- assertOpType(invocation: true);
+ assertOpType(returnValue: true, typeNames: true, prefixed: true);
}
test_InterpolationExpression_prefix_target() {
@@ -991,7 +1025,8 @@
// no semicolon between completion point and next statement
set _s2(I x) {x.^ m(null);}
}''');
- assertOpType(invocation: true);
+ assertOpType(
+ returnValue: true, typeNames: true, voidReturn: true, prefixed: true);
}
test_PostfixExpression() {
@@ -1003,13 +1038,15 @@
test_PrefixedIdentifier_class_const() {
// SimpleIdentifier PrefixedIdentifier ExpressionStatement Block
addTestSource('main() {A.^}');
- assertOpType(invocation: true);
+ assertOpType(
+ returnValue: true, typeNames: true, voidReturn: true, prefixed: true);
}
test_PrefixedIdentifier_class_imported() {
// SimpleIdentifier PrefixedIdentifier ExpressionStatement
addTestSource('main() {A a; a.^}');
- assertOpType(invocation: true);
+ assertOpType(
+ returnValue: true, typeNames: true, voidReturn: true, prefixed: true);
}
test_PrefixedIdentifier_prefix() {
@@ -1021,13 +1058,33 @@
test_PropertyAccess_expression() {
// SimpleIdentifier MethodInvocation PropertyAccess ExpressionStatement
addTestSource('class A {a() {"hello".to^String().length}}');
- assertOpType(invocation: true);
+ assertOpType(
+ returnValue: true, typeNames: true, voidReturn: true, prefixed: true);
+ }
+
+ test_PropertyAccess_noTarget() {
+ // SimpleIdentifier PropertyAccess ExpressionStatement
+ addTestSource('main() {.^}');
+ assertOpType();
+ }
+
+ test_PropertyAccess_noTarget2() {
+ // SimpleIdentifier PropertyAccess CascadeExpressions
+ addTestSource('main() {.^.}');
+ assertOpType();
+ }
+
+ test_PropertyAccess_noTarget3() {
+ // SimpleIdentifier PropertyAccess CascadeExpressions
+ addTestSource('main() {..^}');
+ assertOpType();
}
test_PropertyAccess_selector() {
// SimpleIdentifier PropertyAccess ExpressionStatement Block
addTestSource('class A {a() {"hello".length.^}}');
- assertOpType(invocation: true);
+ assertOpType(
+ returnValue: true, typeNames: true, voidReturn: true, prefixed: true);
}
test_ReturnStatement() {
@@ -1039,7 +1096,7 @@
test_SimpleFormalParameter() {
// SimpleIdentifier SimpleFormalParameter FormalParameterList
addTestSource('mth() { PNGS.sort((String a, Str^) => a.compareTo(b)); }');
- assertOpType(returnValue: true, typeNames: true);
+ assertOpType(typeNames: true);
}
test_SwitchCase() {
@@ -1062,16 +1119,16 @@
// no semicolon between completion point and next statement
set s1(I x) {} set _s2(I x) {this.^ m(null);}
}''');
- assertOpType(invocation: true);
+ assertOpType(returnValue: true, voidReturn: true, prefixed: true);
}
test_ThisExpression_constructor() {
- // MethodInvocation ExpressionStatement Block
+ // SimpleIdentifier PropertyAccess ExpressionStatement
addTestSource('''
class A implements I {
A() {this.^}
}''');
- assertOpType(invocation: true);
+ assertOpType(returnValue: true, voidReturn: true, prefixed: true);
}
test_ThrowExpression() {
diff --git a/pkg/analysis_server/test/services/completion/invocation_computer_test.dart b/pkg/analysis_server/test/services/completion/prefixed_element_contributor_test.dart
similarity index 95%
rename from pkg/analysis_server/test/services/completion/invocation_computer_test.dart
rename to pkg/analysis_server/test/services/completion/prefixed_element_contributor_test.dart
index 16fcb6ec..790d1ca 100644
--- a/pkg/analysis_server/test/services/completion/invocation_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/prefixed_element_contributor_test.dart
@@ -8,7 +8,7 @@
import 'package:analysis_server/src/protocol.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/invocation_computer.dart';
+import 'package:analysis_server/src/services/completion/prefixed_element_contributor.dart';
import 'package:unittest/unittest.dart';
import '../../reflective_tests.dart';
@@ -16,11 +16,11 @@
main() {
groupSep = ' | ';
- runReflectiveTests(InvocationComputerTest);
+ runReflectiveTests(PrefixedElementContributorTest);
}
@reflectiveTest
-class InvocationComputerTest extends AbstractSelectorSuggestionTest {
+class PrefixedElementContributorTest extends AbstractSelectorSuggestionTest {
@override
CompletionSuggestion assertSuggestInvocationField(String name, String type,
{int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
@@ -70,8 +70,8 @@
}
@override
- void setUpComputer() {
- computer = new InvocationComputer();
+ void setUpContributor() {
+ contributor = new PrefixedElementContributor();
}
test_generic_field() {
@@ -142,6 +142,7 @@
addTestSource('import "dart:async" as bar; foo() {bar.^}');
return computeFull((bool result) {
assertSuggestClass('Future');
+ assertNotSuggested('loadLibrary');
});
}
@@ -153,6 +154,15 @@
});
}
+ test_libraryPrefix_deferred() {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('import "dart:async" deferred as bar; foo() {bar.^}');
+ return computeFull((bool result) {
+ assertSuggestClass('Future');
+ assertSuggestFunction('loadLibrary', 'void');
+ });
+ }
+
test_local() {
addTestSource('foo() {String x = "bar"; x.^}');
return computeFull((bool result) {
diff --git a/pkg/analysis_server/test/services/completion/test_all.dart b/pkg/analysis_server/test/services/completion/test_all.dart
index 269e8c0..f7c58bc 100644
--- a/pkg/analysis_server/test/services/completion/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/test_all.dart
@@ -6,16 +6,16 @@
import 'package:unittest/unittest.dart';
-import 'arglist_computer_test.dart' as arglist_test;
-import 'combinator_computer_test.dart' as combinator_test;
+import 'arglist_contributor_test.dart' as arglist_test;
+import 'combinator_contributor_test.dart' as combinator_test;
import 'common_usage_computer_test.dart' as common_usage_computer_test;
import 'completion_computer_test.dart' as completion_computer_test;
import 'completion_manager_test.dart' as completion_manager_test;
import 'completion_target_test.dart' as completion_target_test;
-import 'imported_computer_test.dart' as imported_test;
-import 'invocation_computer_test.dart' as invocation_test;
-import 'keyword_computer_test.dart' as keyword_test;
-import 'local_computer_test.dart' as local_test;
+import 'imported_reference_contributor_test.dart' as imported_test;
+import 'prefixed_element_contributor_test.dart' as invocation_test;
+import 'keyword_contributor_test.dart' as keyword_test;
+import 'local_reference_contributor_test.dart' as local_test;
import 'optype_test.dart' as optype_test;
/// Utility for manually running all tests.
diff --git a/pkg/analysis_server/test/services/correction/assist_test.dart b/pkg/analysis_server/test/services/correction/assist_test.dart
index 52764fe..a7d8534 100644
--- a/pkg/analysis_server/test/services/correction/assist_test.dart
+++ b/pkg/analysis_server/test/services/correction/assist_test.dart
@@ -1290,6 +1290,28 @@
''');
}
+ void test_convertToIsNotEmpty_wrong_noBang() {
+ verifyNoTestUnitErrors = false;
+ resolveTestUnit('''
+main(String str) {
+ ~str.isEmpty;
+}
+''');
+ assertNoAssistAt('isEmpty;', AssistKind.CONVERT_INTO_IS_NOT_EMPTY);
+ }
+
+ void test_convertToIsNotEmpty_wrong_noIsNotEmpty() {
+ resolveTestUnit('''
+class A {
+ bool get isEmpty => false;
+}
+main(A a) {
+ !a.isEmpty;
+}
+''');
+ assertNoAssistAt('isEmpty;', AssistKind.CONVERT_INTO_IS_NOT_EMPTY);
+ }
+
void test_convertToIsNotEmpty_wrong_notInPrefixExpression() {
resolveTestUnit('''
main(String str) {
@@ -1308,16 +1330,120 @@
assertNoAssistAt('isEven;', AssistKind.CONVERT_INTO_IS_NOT_EMPTY);
}
- void test_convertToIsNotEmpty_wrote_noIsNotEmpty() {
+ void test_encapsulateField_BAD_alreadyPrivate() {
resolveTestUnit('''
class A {
- bool get isEmpty => false;
+ int _test = 42;
}
main(A a) {
- !a.isEmpty;
+ print(a._test);
}
''');
- assertNoAssistAt('isEmpty;', AssistKind.CONVERT_INTO_IS_NOT_EMPTY);
+ assertNoAssistAt('_test =', AssistKind.ENCAPSULATE_FIELD);
+ }
+
+ void test_encapsulateField_BAD_final() {
+ resolveTestUnit('''
+class A {
+ final int test = 42;
+}
+''');
+ assertNoAssistAt('test =', AssistKind.ENCAPSULATE_FIELD);
+ }
+
+ void test_encapsulateField_BAD_multipleFields() {
+ resolveTestUnit('''
+class A {
+ int aaa, bbb, ccc;
+}
+main(A a) {
+ print(a.bbb);
+}
+''');
+ assertNoAssistAt('bbb, ', AssistKind.ENCAPSULATE_FIELD);
+ }
+
+ void test_encapsulateField_BAD_notOnName() {
+ resolveTestUnit('''
+class A {
+ int test = 1 + 2 + 3;
+}
+''');
+ assertNoAssistAt('+ 2', AssistKind.ENCAPSULATE_FIELD);
+ }
+
+ void test_encapsulateField_BAD_parseError() {
+ verifyNoTestUnitErrors = false;
+ resolveTestUnit('''
+class A {
+ int; // marker
+}
+main(A a) {
+ print(a.test);
+}
+''');
+ assertNoAssistAt('; // marker', AssistKind.ENCAPSULATE_FIELD);
+ }
+
+ void test_encapsulateField_BAD_static() {
+ resolveTestUnit('''
+class A {
+ static int test = 42;
+}
+''');
+ assertNoAssistAt('test =', AssistKind.ENCAPSULATE_FIELD);
+ }
+
+ void test_encapsulateField_OK_hasType() {
+ resolveTestUnit('''
+class A {
+ int test = 42;
+ A(this.test);
+}
+main(A a) {
+ print(a.test);
+}
+''');
+ assertHasAssistAt('test = 42', AssistKind.ENCAPSULATE_FIELD, '''
+class A {
+ int _test = 42;
+
+ int get test => _test;
+
+ void set test(int test) {
+ _test = test;
+ }
+ A(this._test);
+}
+main(A a) {
+ print(a.test);
+}
+''');
+ }
+
+ void test_encapsulateField_OK_noType() {
+ resolveTestUnit('''
+class A {
+ var test = 42;
+}
+main(A a) {
+ print(a.test);
+}
+''');
+ assertHasAssistAt('test = 42', AssistKind.ENCAPSULATE_FIELD, '''
+class A {
+ var _test = 42;
+
+ get test => _test;
+
+ void set test(test) {
+ _test = test;
+ }
+}
+main(A a) {
+ print(a.test);
+}
+''');
}
void test_exchangeBinaryExpressionArguments_OK_compare() {
@@ -2324,6 +2450,19 @@
''');
}
+ void test_removeTypeAnnotation_classField_OK_final() {
+ resolveTestUnit('''
+class A {
+ final int v = 1;
+}
+''');
+ assertHasAssistAt('v = ', AssistKind.REMOVE_TYPE_ANNOTATION, '''
+class A {
+ final v = 1;
+}
+''');
+ }
+
void test_removeTypeAnnotation_localVariable_OK() {
resolveTestUnit('''
main() {
@@ -2337,6 +2476,32 @@
''');
}
+ void test_removeTypeAnnotation_localVariable_OK_const() {
+ resolveTestUnit('''
+main() {
+ const int v = 1;
+}
+''');
+ assertHasAssistAt('int ', AssistKind.REMOVE_TYPE_ANNOTATION, '''
+main() {
+ const v = 1;
+}
+''');
+ }
+
+ void test_removeTypeAnnotation_localVariable_OK_final() {
+ resolveTestUnit('''
+main() {
+ final int v = 1;
+}
+''');
+ assertHasAssistAt('int ', AssistKind.REMOVE_TYPE_ANNOTATION, '''
+main() {
+ final v = 1;
+}
+''');
+ }
+
void test_removeTypeAnnotation_topLevelVariable_OK() {
resolveTestUnit('''
int V = 1;
@@ -2346,6 +2511,15 @@
''');
}
+ void test_removeTypeAnnotation_topLevelVariable_OK_final() {
+ resolveTestUnit('''
+final int V = 1;
+''');
+ assertHasAssistAt('int ', AssistKind.REMOVE_TYPE_ANNOTATION, '''
+final V = 1;
+''');
+ }
+
void test_replaceConditionalWithIfElse_OK_assignment() {
resolveTestUnit('''
main() {
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index aa12e4d..6589220 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -421,6 +421,22 @@
_assertLinkedGroup(change.linkedEditGroups[0], ['named(int ', 'named(1']);
}
+ void test_createConstructorForFinalFields_inTopLevelMethod() {
+ resolveTestUnit('''
+main() {
+ final int v;
+}
+''');
+ assertNoFix(FixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS);
+ }
+
+ void test_createConstructorForFinalFields_topLevelField() {
+ resolveTestUnit('''
+final int v;
+''');
+ assertNoFix(FixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS);
+ }
+
void test_createConstructorSuperExplicit() {
resolveTestUnit('''
class A {
@@ -2396,6 +2412,17 @@
''');
}
+ void test_noException_1() {
+ resolveTestUnit('''
+main(p) {
+ p i s Null;
+}''');
+ List<AnalysisError> errors = context.computeErrors(testSource);
+ for (var error in errors) {
+ computeFixes(testUnit, error);
+ }
+ }
+
void test_removeParentheses_inGetterDeclaration() {
resolveTestUnit('''
class A {
diff --git a/pkg/analysis_server/test/services/index/store/codec_test.dart b/pkg/analysis_server/test/services/index/store/codec_test.dart
index 1ad0e42..b02f669 100644
--- a/pkg/analysis_server/test/services/index/store/codec_test.dart
+++ b/pkg/analysis_server/test/services/index/store/codec_test.dart
@@ -8,7 +8,6 @@
import 'package:analysis_server/src/services/index/store/codec.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart';
import 'package:unittest/unittest.dart';
import '../../../abstract_single_unit.dart';
@@ -72,6 +71,289 @@
codec = new ElementCodec(stringCodec);
}
+ void test_encode_CompilationUnitElement() {
+ addSource('/my_part.dart', '''
+part of my_lib;
+''');
+ resolveTestUnit('''
+library my_lib;
+part 'my_part.dart';
+''');
+ // defining unit
+ {
+ Element element = testLibraryElement.definingCompilationUnit;
+ expect(element.source.fullName, '/test.dart');
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, element.nameOffset);
+ expect(id3, ElementKind.COMPILATION_UNIT.ordinal);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+ // part
+ {
+ Element element = testLibraryElement.parts[0];
+ expect(element.source.fullName, '/my_part.dart');
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, element.nameOffset);
+ expect(id3, ElementKind.COMPILATION_UNIT.ordinal);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+ }
+
+ void test_encode_ConstructorElement_default_real() {
+ resolveTestUnit('''
+class A {
+ A();
+}
+''');
+ ClassElement classA = findElement('A');
+ ConstructorElement element = classA.constructors[0];
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, classA.nameOffset);
+ expect(id3, -100);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+
+ void test_encode_ConstructorElement_default_synthetic() {
+ resolveTestUnit('''
+class A {
+}
+''');
+ ClassElement classA = findElement('A');
+ ConstructorElement element = classA.constructors[0];
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, classA.nameOffset);
+ expect(id3, -100);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+
+ void test_encode_ConstructorElement_named_real() {
+ resolveTestUnit('''
+class A {
+ A.aaa();
+ A.bbb();
+}
+''');
+ ClassElement classA = findElement('A');
+ // A.aaa()
+ {
+ ConstructorElement element = classA.getNamedConstructor('aaa');
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, classA.nameOffset);
+ expect(id3, -100);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+ // A.bbb()
+ {
+ ConstructorElement element = classA.getNamedConstructor('bbb');
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, classA.nameOffset);
+ expect(id3, -101);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+ }
+
+ void test_encode_ConstructorElement_named_synthetic() {
+ resolveTestUnit('''
+class A {
+ A.aaa();
+ A.bbb();
+}
+class M {}
+class X = A with M;
+''');
+ ClassElement classX = findElement('X');
+ // X.aaa()
+ {
+ ConstructorElement element = classX.getNamedConstructor('aaa');
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, classX.nameOffset);
+ expect(id3, -100);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+ // X.bbb()
+ {
+ ConstructorElement element = classX.getNamedConstructor('bbb');
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, classX.nameOffset);
+ expect(id3, -101);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+ }
+
+ void test_encode_getter_real() {
+ resolveTestUnit('''
+class A {
+ int get test => 42;
+}
+''');
+ PropertyAccessorElement element = findElement('test', ElementKind.GETTER);
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, element.nameOffset);
+ expect(id3, ElementKind.GETTER.ordinal);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+
+ void test_encode_getter_synthetic() {
+ resolveTestUnit('''
+class A {
+ int test;
+}
+''');
+ FieldElement field = findElement('test', ElementKind.FIELD);
+ PropertyAccessorElement element = field.getter;
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, element.nameOffset);
+ expect(id3, ElementKind.GETTER.ordinal);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+
+ void test_encode_LibraryElement() {
+ resolveTestUnit('''
+class A {
+ test() {}
+}
+''');
+ Element element = testLibraryElement;
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, element.nameOffset);
+ expect(id3, ElementKind.LIBRARY.ordinal);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+
+ void test_encode_MethodElement() {
+ resolveTestUnit('''
+class A {
+ test() {}
+}
+''');
+ Element element = findElement('test');
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, element.nameOffset);
+ expect(id3, ElementKind.METHOD.ordinal);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+
+ void test_encode_NameElement() {
+ Element element = new NameElement('test');
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, -1);
+ expect(id2, isNonNegative);
+ expect(id3, ElementKind.NAME.ordinal);
+ }
+
+ void test_encode_nullLibraryElement() {
+ resolveTestUnit('''
+test() {}
+''');
+ Element element = findElement('test');
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ context.setContents(testSource, '');
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, isNull);
+ }
+
+ void test_encode_setter_real() {
+ resolveTestUnit('''
+class A {
+ void set test(x) {}
+}
+''');
+ PropertyAccessorElement element = findElement('test=', ElementKind.SETTER);
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, element.nameOffset);
+ expect(id3, ElementKind.SETTER.ordinal);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+
+ void test_encode_setter_synthetic() {
+ resolveTestUnit('''
+class A {
+ int test;
+}
+''');
+ FieldElement field = findElement('test', ElementKind.FIELD);
+ PropertyAccessorElement element = field.setter;
+ int id1 = codec.encode1(element);
+ int id2 = codec.encode2(element);
+ int id3 = codec.encode3(element);
+ expect(id1, isNonNegative);
+ expect(id2, element.nameOffset);
+ expect(id3, ElementKind.SETTER.ordinal);
+ // decode
+ Element element2 = codec.decode(context, id1, id2, id3);
+ expect(element2, element);
+ }
+
void test_encodeHash_notLocal() {
resolveTestUnit('''
class A {
@@ -95,140 +377,6 @@
expect(id_fooA == id_fooB, isTrue);
expect(id_fooA == id_bar, isFalse);
}
-
- void test_field() {
- resolveTestUnit('''
-class A {
- int field;
-}
-''');
- FieldElement field = findElement('field', ElementKind.FIELD);
- PropertyAccessorElement getter = field.getter;
- PropertyAccessorElement setter = field.setter;
- {
- int id = codec.encode(getter, false);
- expect(codec.decode(context, id), getter);
- }
- {
- int id = codec.encode(setter, false);
- expect(codec.decode(context, id), setter);
- }
- {
- int id = codec.encode(field, false);
- expect(codec.decode(context, id), field);
- }
- }
-
- void test_filePackage_uriMix() {
- MethodElement buildMethodElement(Source source) {
- CompilationUnitElementImpl unitElement =
- new CompilationUnitElementImpl('file.dart');
- LibraryElementImpl libraryElement =
- new LibraryElementImpl(null, 'lib', 0);
- ClassElementImpl classElement = new ClassElementImpl('A', 0);
- MethodElementImpl methodElement = new MethodElementImpl('m', 0);
- unitElement.source = source;
- libraryElement.definingCompilationUnit = unitElement;
- unitElement.types = [classElement];
- classElement.methods = [methodElement];
- return methodElement;
- }
- // file:
- int fileId;
- {
- Source source = new _TestSource('/my/file.dart', 'file:///my/file.dart');
- var methodElement = buildMethodElement(source);
- fileId = codec.encode(methodElement, true);
- }
- // package:
- int packageId;
- {
- Source source =
- new _TestSource('/my/file.dart', 'package:my_pkg/file.dart');
- var methodElement = buildMethodElement(source);
- packageId = codec.encode(methodElement, true);
- }
- // should be the same
- expect(packageId, fileId);
- }
-
- void test_localLocalVariable() {
- resolveTestUnit('''
-main() {
- {
- foo() {
- int bar; // A
- }
- }
- {
- foo() {
- int bar; // B
- }
- }
-}
-''');
- {
- LocalVariableElement element = findNodeElementAtString('bar; // A', null);
- int id = codec.encode(element, false);
- expect(codec.decode(context, id), element);
- }
- {
- LocalVariableElement element = findNodeElementAtString('bar; // B', null);
- int id = codec.encode(element, false);
- expect(codec.decode(context, id), element);
- }
- // check strings, "foo" as a single string, no "foo@17" or "bar@35"
- expect(stringCodec.nameToIndex, hasLength(4));
- expect(stringCodec.nameToIndex, containsPair('file:///test.dart', 0));
- expect(stringCodec.nameToIndex, containsPair('main', 1));
- expect(stringCodec.nameToIndex, containsPair('foo', 2));
- expect(stringCodec.nameToIndex, containsPair('bar', 3));
- }
-
- void test_localVariable() {
- resolveTestUnit('''
-main() {
- {
- int foo; // A
- }
- {
- int foo; // B
- }
-}
-''');
- {
- LocalVariableElement element = findNodeElementAtString('foo; // A', null);
- int id = codec.encode(element, false);
- expect(codec.decode(context, id), element);
- }
- {
- LocalVariableElement element = findNodeElementAtString('foo; // B', null);
- int id = codec.encode(element, false);
- expect(codec.decode(context, id), element);
- }
- // check strings, "foo" as a single string, no "foo@21" or "foo@47"
- expect(stringCodec.nameToIndex, hasLength(3));
- expect(stringCodec.nameToIndex, containsPair('file:///test.dart', 0));
- expect(stringCodec.nameToIndex, containsPair('main', 1));
- expect(stringCodec.nameToIndex, containsPair('foo', 2));
- }
-
- void test_notLocal() {
- resolveTestUnit('''
-main() {
- int foo;
-}
-''');
- LocalVariableElement element = findElement('foo');
- int id = codec.encode(element, false);
- expect(codec.encode(element, false), id);
- expect(codec.decode(context, id), element);
- // check strings
- expect(stringCodec.nameToIndex, hasLength(3));
- expect(stringCodec.nameToIndex, containsPair('file:///test.dart', 0));
- expect(stringCodec.nameToIndex, containsPair('main', 1));
- expect(stringCodec.nameToIndex, containsPair('foo', 2));
- }
}
@reflectiveTest
@@ -258,12 +406,3 @@
expect(codec.decode(idB), 'bbb');
}
}
-
-class _TestSource implements Source {
- final String fullName;
- final String encoding;
-
- _TestSource(this.fullName, this.encoding);
-
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
diff --git a/pkg/analysis_server/test/services/index/store/split_store_test.dart b/pkg/analysis_server/test/services/index/store/split_store_test.dart
index 1bb66fb..28352ae 100644
--- a/pkg/analysis_server/test/services/index/store/split_store_test.dart
+++ b/pkg/analysis_server/test/services/index/store/split_store_test.dart
@@ -172,15 +172,12 @@
Future putFuture;
{
// prepare relations
- int elementIdA = 0;
- int elementIdB = 1;
- int elementIdC = 2;
int relationshipId = relationshipCodec.encode(relationship);
RelationKeyData key =
- new RelationKeyData.forData(elementIdA, relationshipId);
+ new RelationKeyData.forData(0, 1, 2, relationshipId);
List<LocationData> locations = [
- new LocationData.forData(elementIdB, 1, 10, 2),
- new LocationData.forData(elementIdC, 2, 20, 3)
+ new LocationData.forData(3, 4, 5, 1, 10, 2),
+ new LocationData.forData(6, 7, 8, 2, 20, 3)
];
Map<RelationKeyData, List<LocationData>> relations = {key: locations};
// prepare Node
@@ -236,10 +233,14 @@
}
Element _mockElement() {
- int elementId = nextElementId++;
+ int id1 = nextElementId++;
+ int id2 = nextElementId++;
+ int id3 = nextElementId++;
Element element = new MockElement();
- when(elementCodec.encode(element, anyBool)).thenReturn(elementId);
- when(elementCodec.decode(context, elementId)).thenReturn(element);
+ when(elementCodec.encode1(element)).thenReturn(id1);
+ when(elementCodec.encode2(element)).thenReturn(id2);
+ when(elementCodec.encode3(element)).thenReturn(id3);
+ when(elementCodec.decode(context, id1, id2, id3)).thenReturn(element);
return element;
}
}
@@ -300,15 +301,12 @@
Relationship relationship = Relationship.getRelationship('my-relationship');
// record
{
- int elementIdA = 0;
- int elementIdB = 1;
- int elementIdC = 2;
int relationshipId = relationshipCodec.encode(relationship);
RelationKeyData key =
- new RelationKeyData.forData(elementIdA, relationshipId);
+ new RelationKeyData.forData(0, 1, 2, relationshipId);
List<LocationData> locations = [
- new LocationData.forData(elementIdB, 1, 10, 2),
- new LocationData.forData(elementIdC, 2, 20, 3)
+ new LocationData.forData(3, 4, 5, 1, 10, 2),
+ new LocationData.forData(6, 7, 8, 2, 20, 3)
];
node.relations = {key: locations};
}
@@ -320,10 +318,14 @@
}
Element _mockElement() {
- int elementId = nextElementId++;
+ int id1 = nextElementId++;
+ int id2 = nextElementId++;
+ int id3 = nextElementId++;
Element element = new MockElement();
- when(elementCodec.encode(element, anyBool)).thenReturn(elementId);
- when(elementCodec.decode(context, elementId)).thenReturn(element);
+ when(elementCodec.encode1(element)).thenReturn(id1);
+ when(elementCodec.encode2(element)).thenReturn(id2);
+ when(elementCodec.encode3(element)).thenReturn(id3);
+ when(elementCodec.decode(context, id1, id2, id3)).thenReturn(element);
return element;
}
}
@@ -336,8 +338,8 @@
void test_newForData() {
Element element = new MockElement();
- when(elementCodec.decode(context, 0)).thenReturn(element);
- LocationData locationData = new LocationData.forData(0, 1, 2, 0);
+ when(elementCodec.decode(context, 11, 12, 13)).thenReturn(element);
+ LocationData locationData = new LocationData.forData(11, 12, 13, 1, 2, 0);
Location location = locationData.getLocation(context, elementCodec);
expect(location.element, element);
expect(location.offset, 1);
@@ -349,8 +351,10 @@
void test_newForObject() {
// prepare Element
Element element = new MockElement();
- when(elementCodec.encode(element, anyBool)).thenReturn(42);
- when(elementCodec.decode(context, 42)).thenReturn(element);
+ when(elementCodec.encode1(element)).thenReturn(11);
+ when(elementCodec.encode2(element)).thenReturn(12);
+ when(elementCodec.encode3(element)).thenReturn(13);
+ when(elementCodec.decode(context, 11, 12, 13)).thenReturn(element);
// create
Location location = new Location(element, 1, 2);
LocationData locationData =
@@ -358,7 +362,8 @@
// touch 'hashCode'
locationData.hashCode;
// ==
- expect(locationData == new LocationData.forData(42, 1, 2, 2), isTrue);
+ expect(
+ locationData == new LocationData.forData(11, 12, 13, 1, 2, 2), isTrue);
// getLocation()
{
Location newLocation = locationData.getLocation(context, elementCodec);
@@ -368,7 +373,7 @@
}
// no Element - no Location
{
- when(elementCodec.decode(context, 42)).thenReturn(null);
+ when(elementCodec.decode(context, 11, 12, 13)).thenReturn(null);
Location newLocation = locationData.getLocation(context, elementCodec);
expect(newLocation, isNull);
}
@@ -417,24 +422,25 @@
StringCodec stringCodec = new StringCodec();
void test_newFromData() {
- RelationKeyData keyData = new RelationKeyData.forData(1, 2);
+ RelationKeyData keyData = new RelationKeyData.forData(11, 12, 13, 2);
// equals
expect(keyData == this, isFalse);
- expect(keyData == new RelationKeyData.forData(10, 20), isFalse);
+ expect(keyData == new RelationKeyData.forData(11, 12, 13, 20), isFalse);
expect(keyData == keyData, isTrue);
- expect(keyData == new RelationKeyData.forData(1, 2), isTrue);
+ expect(keyData == new RelationKeyData.forData(11, 12, 13, 2), isTrue);
}
void test_newFromObjects() {
// prepare Element
Element element;
- int elementId = 2;
{
element = new MockElement();
ElementLocation location = new ElementLocationImpl.con3(['foo', 'bar']);
when(element.location).thenReturn(location);
when(context.getElement(location)).thenReturn(element);
- when(elementCodec.encode(element, anyBool)).thenReturn(elementId);
+ when(elementCodec.encode1(element)).thenReturn(11);
+ when(elementCodec.encode2(element)).thenReturn(12);
+ when(elementCodec.encode3(element)).thenReturn(13);
}
// prepare relationship
Relationship relationship = Relationship.getRelationship('my-relationship');
@@ -447,9 +453,9 @@
keyData.hashCode;
// equals
expect(keyData == this, isFalse);
- expect(keyData == new RelationKeyData.forData(10, 20), isFalse);
+ expect(keyData == new RelationKeyData.forData(11, 12, 13, 20), isFalse);
expect(keyData == keyData, isTrue);
- expect(keyData == new RelationKeyData.forData(elementId, relationshipId),
+ expect(keyData == new RelationKeyData.forData(11, 12, 13, relationshipId),
isTrue);
}
}
@@ -457,29 +463,20 @@
@reflectiveTest
class _SplitIndexStoreTest {
AnalysisContext contextA = new MockAnalysisContext('contextA');
-
AnalysisContext contextB = new MockAnalysisContext('contextB');
-
AnalysisContext contextC = new MockAnalysisContext('contextC');
Element elementA = new MockElement('elementA');
Element elementB = new MockElement('elementB');
-
Element elementC = new MockElement('elementC');
Element elementD = new MockElement('elementD');
- ElementLocation elementLocationA =
- new ElementLocationImpl.con3(['/home/user/sourceA.dart', 'ClassA']);
- ElementLocation elementLocationB =
- new ElementLocationImpl.con3(['/home/user/sourceB.dart', 'ClassB']);
- ElementLocation elementLocationC =
- new ElementLocationImpl.con3(['/home/user/sourceC.dart', 'ClassC']);
- ElementLocation elementLocationD =
- new ElementLocationImpl.con3(['/home/user/sourceD.dart', 'ClassD']);
+
HtmlElement htmlElementA = new MockHtmlElement();
HtmlElement htmlElementB = new MockHtmlElement();
LibraryElement libraryElement = new MockLibraryElement();
Source librarySource = new MockSource('librarySource');
CompilationUnitElement libraryUnitElement = new MockCompilationUnitElement();
+ ElementCodec elementCodec = new MockElementCodec();
MemoryNodeManager nodeManager = new MemoryNodeManager();
Relationship relationship = Relationship.getRelationship('test-relationship');
Source sourceA = new MockSource('sourceA');
@@ -493,14 +490,27 @@
CompilationUnitElement unitElementD = new MockCompilationUnitElement();
void setUp() {
+ nodeManager.elementCodec = elementCodec;
store = new SplitIndexStore(nodeManager);
+ when(elementCodec.encode1(elementA)).thenReturn(11);
+ when(elementCodec.encode2(elementA)).thenReturn(12);
+ when(elementCodec.encode3(elementA)).thenReturn(13);
+ when(elementCodec.encode1(elementB)).thenReturn(21);
+ when(elementCodec.encode2(elementB)).thenReturn(22);
+ when(elementCodec.encode3(elementB)).thenReturn(23);
+ when(elementCodec.encode1(elementC)).thenReturn(31);
+ when(elementCodec.encode2(elementC)).thenReturn(32);
+ when(elementCodec.encode3(elementC)).thenReturn(33);
+ when(elementCodec.encode1(elementD)).thenReturn(41);
+ when(elementCodec.encode2(elementD)).thenReturn(42);
+ when(elementCodec.encode3(elementD)).thenReturn(43);
+ when(elementCodec.decode(contextA, 11, 12, 13)).thenReturn(elementA);
+ when(elementCodec.decode(contextA, 21, 22, 23)).thenReturn(elementB);
+ when(elementCodec.decode(contextA, 31, 32, 33)).thenReturn(elementC);
+ when(elementCodec.decode(contextA, 41, 42, 43)).thenReturn(elementD);
when(contextA.isDisposed).thenReturn(false);
when(contextB.isDisposed).thenReturn(false);
when(contextC.isDisposed).thenReturn(false);
- when(contextA.getElement(elementLocationA)).thenReturn(elementA);
- when(contextA.getElement(elementLocationB)).thenReturn(elementB);
- when(contextA.getElement(elementLocationC)).thenReturn(elementC);
- when(contextA.getElement(elementLocationD)).thenReturn(elementD);
when(librarySource.fullName).thenReturn('/home/user/librarySource.dart');
when(sourceA.fullName).thenReturn('/home/user/sourceA.dart');
when(sourceB.fullName).thenReturn('/home/user/sourceB.dart');
@@ -510,10 +520,6 @@
when(elementB.context).thenReturn(contextA);
when(elementC.context).thenReturn(contextA);
when(elementD.context).thenReturn(contextA);
- when(elementA.location).thenReturn(elementLocationA);
- when(elementB.location).thenReturn(elementLocationB);
- when(elementC.location).thenReturn(elementLocationC);
- when(elementD.location).thenReturn(elementLocationD);
when(elementA.enclosingElement).thenReturn(unitElementA);
when(elementB.enclosingElement).thenReturn(unitElementB);
when(elementC.enclosingElement).thenReturn(unitElementC);
@@ -555,8 +561,9 @@
store.aboutToIndexDart(contextA, libraryUnitElement);
store.doneIndex();
}
- return store.getRelationships(elementA, relationship).then(
- (List<Location> locations) {
+ return store
+ .getRelationships(elementA, relationship)
+ .then((List<Location> locations) {
assertLocations(locations, []);
});
}
@@ -622,8 +629,9 @@
store.doneIndex();
}
// "A" and "B" locations
- return store.getRelationships(elementA, relationship).then(
- (List<Location> locations) {
+ return store
+ .getRelationships(elementA, relationship)
+ .then((List<Location> locations) {
assertLocations(locations, [locationA, locationB]);
});
}
@@ -714,8 +722,9 @@
store.recordRelationship(elementA, relationship, locationB);
store.doneIndex();
}
- return store.getRelationships(elementA, relationship).then(
- (List<Location> locations) {
+ return store
+ .getRelationships(elementA, relationship)
+ .then((List<Location> locations) {
assertLocations(locations, [locationA, locationB]);
});
}
@@ -725,8 +734,9 @@
store.aboutToIndexDart(contextA, unitElementA);
store.recordRelationship(elementA, relationship, locationA);
store.doneIndex();
- return store.getRelationships(elementA, relationship).then(
- (List<Location> locations) {
+ return store
+ .getRelationships(elementA, relationship)
+ .then((List<Location> locations) {
assertLocations(locations, [locationA]);
});
}
@@ -738,8 +748,9 @@
store.recordRelationship(elementA, relationship, locationA);
store.recordRelationship(elementA, relationship, locationB);
store.doneIndex();
- return store.getRelationships(elementA, relationship).then(
- (List<Location> locations) {
+ return store
+ .getRelationships(elementA, relationship)
+ .then((List<Location> locations) {
assertLocations(locations, [locationA, locationB]);
});
}
@@ -804,8 +815,9 @@
}).then((_) {
// remove "librarySource"
store.removeSource(contextA, librarySource);
- return store.getRelationships(elementA, relationship).then(
- (List<Location> locations) {
+ return store
+ .getRelationships(elementA, relationship)
+ .then((List<Location> locations) {
assertLocations(locations, []);
});
});
@@ -842,8 +854,9 @@
}).then((_) {
// remove "A" source
store.removeSource(contextA, sourceA);
- return store.getRelationships(elementA, relationship).then(
- (List<Location> locations) {
+ return store
+ .getRelationships(elementA, relationship)
+ .then((List<Location> locations) {
assertLocations(locations, [locationB, locationC]);
});
});
@@ -870,8 +883,9 @@
}).then((_) {
// remove "librarySource"
store.removeSources(contextA, new SingleSourceContainer(librarySource));
- return store.getRelationships(elementA, relationship).then(
- (List<Location> locations) {
+ return store
+ .getRelationships(elementA, relationship)
+ .then((List<Location> locations) {
assertLocations(locations, []);
});
});
@@ -912,8 +926,8 @@
}
void test_universe_aboutToIndex() {
- when(contextA.getElement(elementLocationA)).thenReturn(elementA);
- when(contextB.getElement(elementLocationB)).thenReturn(elementB);
+ when(elementCodec.decode(contextA, 11, 12, 13)).thenReturn(elementA);
+ when(elementCodec.decode(contextB, 21, 22, 23)).thenReturn(elementB);
{
store.aboutToIndexDart(contextA, unitElementA);
store.recordTopLevelDeclaration(elementA);
@@ -941,8 +955,8 @@
}
void test_universe_clear() {
- when(contextA.getElement(elementLocationA)).thenReturn(elementA);
- when(contextB.getElement(elementLocationB)).thenReturn(elementB);
+ when(elementCodec.decode(contextA, 11, 12, 13)).thenReturn(elementA);
+ when(elementCodec.decode(contextB, 21, 22, 23)).thenReturn(elementB);
{
store.aboutToIndexDart(contextA, unitElementA);
store.recordTopLevelDeclaration(elementA);
@@ -967,8 +981,8 @@
}
void test_universe_removeContext() {
- when(contextA.getElement(elementLocationA)).thenReturn(elementA);
- when(contextB.getElement(elementLocationB)).thenReturn(elementB);
+ when(elementCodec.decode(contextA, 11, 12, 13)).thenReturn(elementA);
+ when(elementCodec.decode(contextB, 21, 22, 23)).thenReturn(elementB);
{
store.aboutToIndexDart(contextA, unitElementA);
store.recordTopLevelDeclaration(elementA);
@@ -993,8 +1007,8 @@
}
void test_universe_removeSource() {
- when(contextA.getElement(elementLocationA)).thenReturn(elementA);
- when(contextB.getElement(elementLocationB)).thenReturn(elementB);
+ when(elementCodec.decode(contextA, 11, 12, 13)).thenReturn(elementA);
+ when(elementCodec.decode(contextB, 21, 22, 23)).thenReturn(elementB);
{
store.aboutToIndexDart(contextA, unitElementA);
store.recordTopLevelDeclaration(elementA);
diff --git a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
index bec57bd..68ec6ec 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
@@ -384,7 +384,31 @@
return _assertFinalConditionsError("Parameter 'dup' already exists");
}
- test_bad_parameterName_inUse() async {
+ test_bad_parameterName_inUse_function() async {
+ indexTestUnit('''
+main() {
+ int v1 = 1;
+ int v2 = 2;
+// start
+ f(v1, v2);
+// end
+}
+f(a, b) {}
+''');
+ _createRefactoringForStartEndComments();
+ // update parameters
+ await refactoring.checkInitialConditions();
+ {
+ List<RefactoringMethodParameter> parameters = _getParametersCopy();
+ expect(parameters, hasLength(2));
+ parameters[0].name = 'f';
+ refactoring.parameters = parameters;
+ }
+ return _assertFinalConditionsError(
+ "'f' is already used as a name in the selected code");
+ }
+
+ test_bad_parameterName_inUse_localVariable() async {
indexTestUnit('''
main() {
int v1 = 1;
@@ -407,6 +431,32 @@
"'a' is already used as a name in the selected code");
}
+ test_bad_parameterName_inUse_method() async {
+ indexTestUnit('''
+class A {
+ main() {
+ int v1 = 1;
+ int v2 = 2;
+ // start
+ m(v1, v2);
+ // end
+ }
+ m(a, b) {}
+}
+''');
+ _createRefactoringForStartEndComments();
+ // update parameters
+ await refactoring.checkInitialConditions();
+ {
+ List<RefactoringMethodParameter> parameters = _getParametersCopy();
+ expect(parameters, hasLength(2));
+ parameters[0].name = 'm';
+ refactoring.parameters = parameters;
+ }
+ return _assertFinalConditionsError(
+ "'m' is already used as a name in the selected code");
+ }
+
test_bad_selectionEndsInSomeNode() {
indexTestUnit('''
main() {
@@ -1137,6 +1187,29 @@
''');
}
+ test_singleExpression_hasAwait() {
+ indexTestUnit('''
+import 'dart:async';
+Future<int> getValue() => 42;
+main() async {
+ int v = await getValue();
+ print(v);
+}
+''');
+ _createRefactoringForString('await getValue()');
+ // apply refactoring
+ return _assertSuccessfulRefactoring('''
+import 'dart:async';
+Future<int> getValue() => 42;
+main() async {
+ int v = await res();
+ print(v);
+}
+
+Future<int> res() async => await getValue();
+''');
+ }
+
test_singleExpression_ignore_assignmentLeftHandSize() {
indexTestUnit('''
main() {
@@ -2091,6 +2164,133 @@
await assertRefactoringConditionsOK();
}
+ test_statements_hasAwait_dynamicReturnType() {
+ indexTestUnit('''
+import 'dart:async';
+Future getValue() => 42;
+main() async {
+// start
+ var v = await getValue();
+// end
+ print(v);
+}
+''');
+ _createRefactoringForStartEndComments();
+ // apply refactoring
+ return _assertSuccessfulRefactoring('''
+import 'dart:async';
+Future getValue() => 42;
+main() async {
+// start
+ var v = await res();
+// end
+ print(v);
+}
+
+Future res() async {
+ var v = await getValue();
+ return v;
+}
+''');
+ }
+
+ test_statements_hasAwait_expression() {
+ indexTestUnit('''
+import 'dart:async';
+Future<int> getValue() => 42;
+main() async {
+// start
+ int v = await getValue();
+ v += 2;
+// end
+ print(v);
+}
+''');
+ _createRefactoringForStartEndComments();
+ // apply refactoring
+ return _assertSuccessfulRefactoring('''
+import 'dart:async';
+Future<int> getValue() => 42;
+main() async {
+// start
+ int v = await res();
+// end
+ print(v);
+}
+
+Future<int> res() async {
+ int v = await getValue();
+ v += 2;
+ return v;
+}
+''');
+ }
+
+ test_statements_hasAwait_forEach() {
+ indexTestUnit('''
+import 'dart:async';
+Stream<int> getValueStream() => null;
+main() async {
+// start
+ int sum = 0;
+ await for (int v in getValueStream()) {
+ sum += v;
+ }
+// end
+ print(sum);
+}
+''');
+ _createRefactoringForStartEndComments();
+ // apply refactoring
+ return _assertSuccessfulRefactoring('''
+import 'dart:async';
+Stream<int> getValueStream() => null;
+main() async {
+// start
+ int sum = await res();
+// end
+ print(sum);
+}
+
+Future<int> res() async {
+ int sum = 0;
+ await for (int v in getValueStream()) {
+ sum += v;
+ }
+ return sum;
+}
+''');
+ }
+
+ test_statements_hasAwait_voidReturnType() {
+ indexTestUnit('''
+import 'dart:async';
+Future<int> getValue() => 42;
+main() async {
+// start
+ int v = await getValue();
+ print(v);
+// end
+}
+''');
+ _createRefactoringForStartEndComments();
+ // apply refactoring
+ return _assertSuccessfulRefactoring('''
+import 'dart:async';
+Future<int> getValue() => 42;
+main() async {
+// start
+ await res();
+// end
+}
+
+Future res() async {
+ int v = await getValue();
+ print(v);
+}
+''');
+ }
+
test_statements_inSwitchMember() {
indexTestUnit('''
class A {
@@ -2213,6 +2413,24 @@
''');
}
+ test_statements_parameters_noLocalVariableConflict() async {
+ indexTestUnit('''
+int f(int x) {
+ int y = x + 1;
+// start
+ if (y % 2 == 0) {
+ int y = x + 2;
+ return y;
+ } else {
+ return y;
+ }
+// end
+}
+''');
+ _createRefactoringForStartEndComments();
+ await assertRefactoringConditionsOK();
+ }
+
test_statements_return_last() {
indexTestUnit('''
main() {
diff --git a/pkg/analysis_server/test/services/refactoring/inline_local_test.dart b/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
index 8e8b6ab..2a3c104 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
@@ -257,6 +257,29 @@
''');
}
+ test_OK_intoStringInterpolation_string_multiLineIntoMulti_leadingSpaces() {
+ indexTestUnit(r"""
+main() {
+ String a = '''\ \
+a
+a''';
+ String b = '''
+$a
+bbb''';
+}
+""");
+ _createRefactoring('a =');
+ // validate change
+ return assertSuccessfulRefactoring(r"""
+main() {
+ String b = '''
+a
+a
+bbb''';
+}
+""");
+ }
+
test_OK_intoStringInterpolation_string_multiLineIntoMulti_unixEOL() {
indexTestUnit(r"""
main() {
@@ -511,6 +534,42 @@
''');
}
+ test_OK_parenthesis_intoIndexExpression_index() {
+ indexTestUnit('''
+main() {
+ var items = [];
+ var test = 1 + 2;
+ items[test] * 5;
+}
+''');
+ _createRefactoring('test =');
+ // validate change
+ return assertSuccessfulRefactoring('''
+main() {
+ var items = [];
+ items[1 + 2] * 5;
+}
+''');
+ }
+
+ test_OK_parenthesis_intoParenthesizedExpression() {
+ indexTestUnit('''
+f(m, x, y) {
+ int test = x as int;
+ m[test] = y;
+ return m[test];
+}
+''');
+ _createRefactoring('test =');
+ // validate change
+ return assertSuccessfulRefactoring('''
+f(m, x, y) {
+ m[x as int] = y;
+ return m[x as int];
+}
+''');
+ }
+
test_OK_parenthesis_negate_intoNegate() {
indexTestUnit('''
main() {
diff --git a/pkg/analysis_server/test/services/refactoring/rename_import_test.dart b/pkg/analysis_server/test/services/refactoring/rename_import_test.dart
index b2a54c6..fdf4be9 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_import_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_import_test.dart
@@ -66,6 +66,50 @@
''');
}
+ test_createChange_add_interpolationExpression_hasCurlyBrackets() {
+ indexTestUnit(r'''
+import 'dart:async';
+main() {
+ Future f;
+ print('Future type: ${Future}');
+}
+''');
+ // configure refactoring
+ _createRefactoring("import 'dart:async");
+ expect(refactoring.refactoringName, 'Rename Import Prefix');
+ refactoring.newName = 'newName';
+ // validate change
+ return assertSuccessfulRefactoring(r'''
+import 'dart:async' as newName;
+main() {
+ newName.Future f;
+ print('Future type: ${newName.Future}');
+}
+''');
+ }
+
+ test_createChange_add_interpolationExpression_noCurlyBrackets() {
+ indexTestUnit(r'''
+import 'dart:async';
+main() {
+ Future f;
+ print('Future type: $Future');
+}
+''');
+ // configure refactoring
+ _createRefactoring("import 'dart:async");
+ expect(refactoring.refactoringName, 'Rename Import Prefix');
+ refactoring.newName = 'newName';
+ // validate change
+ return assertSuccessfulRefactoring(r'''
+import 'dart:async' as newName;
+main() {
+ newName.Future f;
+ print('Future type: ${newName.Future}');
+}
+''');
+ }
+
test_createChange_change_className() {
indexTestUnit('''
import 'dart:math' as test;
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index fa512df..87c9949 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -1,4 +1,3 @@
-
<html>
<head>
<meta charset="UTF-8"/>
@@ -6,7 +5,7 @@
</head>
<body>
<h1>Analysis Server API Specification</h1>
- <h1 style="color:#999999">Version <version>1.5.0</version></h1>
+ <h1 style="color:#999999">Version <version>1.6.0</version></h1>
<p>
This document contains a specification of the API provided by the
analysis server. The API in this document is currently under
@@ -1935,7 +1934,7 @@
<object>
<field name="enableAsync" optional="true">
<ref>bool</ref>
- <p><b><i>Deprecated</i></b>/<p>
+ <p><b><i>Deprecated</i></b></p>
<p>
True if the client wants to enable support for the
proposed async feature.
@@ -1943,7 +1942,7 @@
</field>
<field name="enableDeferredLoading" optional="true">
<ref>bool</ref>
- <p><b><i>Deprecated</i></b>/<p>
+ <p><b><i>Deprecated</i></b></p>
<p>
True if the client wants to enable support for the
proposed deferred loading feature.
@@ -1951,12 +1950,19 @@
</field>
<field name="enableEnums" optional="true">
<ref>bool</ref>
- <p><b><i>Deprecated</i></b>/<p>
+ <p><b><i>Deprecated</i></b></p>
<p>
True if the client wants to enable support for the
proposed enum feature.
</p>
</field>
+ <field name="enableNullAwareOperators" optional="true">
+ <ref>bool</ref>
+ <p>
+ True if the client wants to enable support for the
+ proposed "null aware operators" feature.
+ </p>
+ </field>
<field name="generateDart2jsHints" optional="true">
<ref>bool</ref>
<p>
@@ -3127,6 +3133,13 @@
</p>
</value>
<value>
+ <code>INVALID_ANALYSIS_ROOT</code>
+ <p>
+ A path passed as an argument to a request (such as
+ analysis.reanalyze) is required to be an analysis root, but isn't.
+ </p>
+ </value>
+ <value>
<code>INVALID_EXECUTION_CONTEXT</code>
<p>
The context root used to create an execution context does not
@@ -3223,6 +3236,13 @@
</p>
</value>
<value>
+ <code>UNKNOWN_SOURCE</code>
+ <p>
+ The analysis server was requested to perform an action
+ on a source that does not exist.
+ </p>
+ </value>
+ <value>
<code>UNSUPPORTED_FEATURE</code>
<p>
The analysis server was requested to perform an action
diff --git a/pkg/analyzer/lib/options.dart b/pkg/analyzer/lib/options.dart
index 1f7543e..06aaa84 100644
--- a/pkg/analyzer/lib/options.dart
+++ b/pkg/analyzer/lib/options.dart
@@ -27,6 +27,11 @@
final bool displayVersion;
/**
+ * Whether to enable null-aware operators (DEP 9).
+ */
+ final bool enableNullAwareOperators;
+
+ /**
* Whether to strictly follow the specification when generating warnings on
* "call" methods (fixes dartbug.com/21938).
*/
@@ -86,6 +91,7 @@
this.definedVariables = definedVariables,
disableHints = args['no-hints'],
displayVersion = args['version'],
+ enableNullAwareOperators = args['enable-null-aware-operators'],
enableStrictCallChecks = args['enable-strict-call-checks'],
enableTypeChecks = args['enable_type_checks'],
ignoreUnrecognizedFlags = args['ignore-unrecognized-flags'],
@@ -213,6 +219,11 @@
defaultsTo: false,
negatable: false,
hide: true)
+ ..addFlag('enable-null-aware-operators',
+ help: 'Enable support for null-aware operators (DEP 9)',
+ defaultsTo: false,
+ negatable: false,
+ hide: true)
..addFlag('enable-strict-call-checks',
help: 'Fix issue 21938',
defaultsTo: false,
diff --git a/pkg/analyzer/lib/src/analyzer_impl.dart b/pkg/analyzer/lib/src/analyzer_impl.dart
index 173d18a..1ecfd83 100644
--- a/pkg/analyzer/lib/src/analyzer_impl.dart
+++ b/pkg/analyzer/lib/src/analyzer_impl.dart
@@ -211,6 +211,7 @@
AnalysisOptionsImpl contextOptions = new AnalysisOptionsImpl();
contextOptions.cacheSize = _MAX_CACHE_SIZE;
contextOptions.hint = !options.disableHints;
+ contextOptions.enableNullAwareOperators = options.enableNullAwareOperators;
contextOptions.enableStrictCallChecks = options.enableStrictCallChecks;
contextOptions.analyzeFunctionBodiesPredicate =
_analyzeFunctionBodiesPredicate;
diff --git a/pkg/analyzer/lib/src/generated/ast.dart b/pkg/analyzer/lib/src/generated/ast.dart
index f202e83..909400d 100644
--- a/pkg/analyzer/lib/src/generated/ast.dart
+++ b/pkg/analyzer/lib/src/generated/ast.dart
@@ -497,7 +497,7 @@
* then return the parameter element representing the parameter to which the
* value of the given expression will be bound. Otherwise, return `null`.
*/
- @deprecated // Use "expression.propagatedParameterElement"
+ @deprecated // Use "expression.staticParameterElement"
ParameterElement getStaticParameterElementFor(Expression expression) {
return _getStaticParameterElementFor(expression);
}
@@ -865,7 +865,7 @@
* representing the parameter to which the value of the right operand will be
* bound. Otherwise, return `null`.
*/
- @deprecated // Use "expression.propagatedParameterElement"
+ @deprecated // Use "expression.staticParameterElement"
ParameterElement get staticParameterElementForRightHandSide {
return _staticParameterElementForRightHandSide;
}
@@ -1432,7 +1432,7 @@
@override
MethodInvocation visitMethodInvocation(MethodInvocation node) =>
- new MethodInvocation(cloneNode(node.target), cloneToken(node.period),
+ new MethodInvocation(cloneNode(node.target), cloneToken(node.operator),
cloneNode(node.methodName), cloneNode(node.argumentList));
@override
@@ -2323,7 +2323,7 @@
bool visitMethodInvocation(MethodInvocation node) {
MethodInvocation other = _other as MethodInvocation;
return isEqualNodes(node.target, other.target) &&
- isEqualTokens(node.period, other.period) &&
+ isEqualTokens(node.operator, other.operator) &&
isEqualNodes(node.methodName, other.methodName) &&
isEqualNodes(node.argumentList, other.argumentList);
}
@@ -3344,7 +3344,7 @@
* representing the parameter to which the value of the right operand will be
* bound. Otherwise, return `null`.
*/
- @deprecated // Use "expression.propagatedParameterElement"
+ @deprecated // Use "expression.staticParameterElement"
ParameterElement get staticParameterElementForRightOperand {
return _staticParameterElementForRightOperand;
}
@@ -3995,7 +3995,7 @@
* > [ImplementsClause]?
* > '{' [ClassMember]* '}'
*/
-class ClassDeclaration extends CompilationUnitMember {
+class ClassDeclaration extends NamedCompilationUnitMember {
/**
* The 'abstract' keyword, or `null` if the keyword was absent.
*/
@@ -4007,11 +4007,6 @@
Token classKeyword;
/**
- * The name of the class being declared.
- */
- SimpleIdentifier _name;
-
- /**
* The type parameters for the class, or `null` if the class does not have any
* type parameters.
*/
@@ -4071,8 +4066,7 @@
TypeParameterList typeParameters, ExtendsClause extendsClause,
WithClause withClause, ImplementsClause implementsClause,
this.leftBracket, List<ClassMember> members, this.rightBracket)
- : super(comment, metadata) {
- _name = _becomeParentOf(name);
+ : super(comment, metadata, name) {
_typeParameters = _becomeParentOf(typeParameters);
_extendsClause = _becomeParentOf(extendsClause);
_withClause = _becomeParentOf(withClause);
@@ -4146,18 +4140,6 @@
NodeList<ClassMember> get members => _members;
/**
- * Return the name of the class being declared.
- */
- SimpleIdentifier get name => _name;
-
- /**
- * Set the name of the class being declared to the given [identifier].
- */
- void set name(SimpleIdentifier identifier) {
- _name = _becomeParentOf(identifier);
- }
-
- /**
* Return the native clause for this class, or `null` if the class does not
* have a native clause.
*/
@@ -4295,11 +4277,6 @@
*/
class ClassTypeAlias extends TypeAlias {
/**
- * The name of the class being declared.
- */
- SimpleIdentifier _name;
-
- /**
* The type parameters for the class, or `null` if the class does not have any
* type parameters.
*/
@@ -4344,8 +4321,7 @@
SimpleIdentifier name, TypeParameterList typeParameters, this.equals,
this.abstractKeyword, TypeName superclass, WithClause withClause,
ImplementsClause implementsClause, Token semicolon)
- : super(comment, metadata, keyword, semicolon) {
- _name = _becomeParentOf(name);
+ : super(comment, metadata, keyword, name, semicolon) {
_typeParameters = _becomeParentOf(typeParameters);
_superclass = _becomeParentOf(superclass);
_withClause = _becomeParentOf(withClause);
@@ -4387,18 +4363,6 @@
bool get isAbstract => abstractKeyword != null;
/**
- * Return the name of the class being declared.
- */
- SimpleIdentifier get name => _name;
-
- /**
- * Set the name of the class being declared to the given [identifier].
- */
- void set name(SimpleIdentifier name) {
- _name = _becomeParentOf(name);
- }
-
- /**
* Return the name of the superclass of the class being declared.
*/
TypeName get superclass => _superclass;
@@ -4843,7 +4807,8 @@
}
/**
- * A node that declares a name within the scope of a compilation unit.
+ * A node that declares one or more names within the scope of a compilation
+ * unit.
*
* > compilationUnitMember ::=
* > [ClassDeclaration]
@@ -5061,9 +5026,7 @@
// numeric, string, boolean, or {@code null}
if (leftOperand is bool && rightOperand is bool) {
return leftOperand != rightOperand;
- } else if (leftOperand is int && rightOperand is int) {
- return leftOperand != rightOperand;
- } else if (leftOperand is double && rightOperand is double) {
+ } else if (leftOperand is num && rightOperand is num) {
return leftOperand != rightOperand;
} else if (leftOperand is String && rightOperand is String) {
return leftOperand != rightOperand;
@@ -5087,25 +5050,19 @@
// numeric, string, boolean, or {@code null}
if (leftOperand is bool && rightOperand is bool) {
return leftOperand == rightOperand;
- } else if (leftOperand is int && rightOperand is int) {
- return leftOperand == rightOperand;
- } else if (leftOperand is double && rightOperand is double) {
+ } else if (leftOperand is num && rightOperand is num) {
return leftOperand == rightOperand;
} else if (leftOperand is String && rightOperand is String) {
return leftOperand == rightOperand;
}
} else if (node.operator.type == TokenType.GT) {
// numeric or {@code null}
- if (leftOperand is int && rightOperand is int) {
- return leftOperand.compareTo(rightOperand) > 0;
- } else if (leftOperand is double && rightOperand is double) {
+ if (leftOperand is num && rightOperand is num) {
return leftOperand.compareTo(rightOperand) > 0;
}
} else if (node.operator.type == TokenType.GT_EQ) {
// numeric or {@code null}
- if (leftOperand is int && rightOperand is int) {
- return leftOperand.compareTo(rightOperand) >= 0;
- } else if (leftOperand is double && rightOperand is double) {
+ if (leftOperand is num && rightOperand is num) {
return leftOperand.compareTo(rightOperand) >= 0;
}
} else if (node.operator.type == TokenType.GT_GT) {
@@ -5115,16 +5072,12 @@
}
} else if (node.operator.type == TokenType.LT) {
// numeric or {@code null}
- if (leftOperand is int && rightOperand is int) {
- return leftOperand.compareTo(rightOperand) < 0;
- } else if (leftOperand is double && rightOperand is double) {
+ if (leftOperand is num && rightOperand is num) {
return leftOperand.compareTo(rightOperand) < 0;
}
} else if (node.operator.type == TokenType.LT_EQ) {
// numeric or {@code null}
- if (leftOperand is int && rightOperand is int) {
- return leftOperand.compareTo(rightOperand) <= 0;
- } else if (leftOperand is double && rightOperand is double) {
+ if (leftOperand is num && rightOperand is num) {
return leftOperand.compareTo(rightOperand) <= 0;
}
} else if (node.operator.type == TokenType.LT_LT) {
@@ -5134,52 +5087,32 @@
}
} else if (node.operator.type == TokenType.MINUS) {
// numeric or {@code null}
- if (leftOperand is int && rightOperand is int) {
- return leftOperand - rightOperand;
- } else if (leftOperand is double && rightOperand is double) {
+ if (leftOperand is num && rightOperand is num) {
return leftOperand - rightOperand;
}
} else if (node.operator.type == TokenType.PERCENT) {
// numeric or {@code null}
- if (leftOperand is int && rightOperand is int) {
+ if (leftOperand is num && rightOperand is num) {
return leftOperand.remainder(rightOperand);
- } else if (leftOperand is double && rightOperand is double) {
- return leftOperand % rightOperand;
}
} else if (node.operator.type == TokenType.PLUS) {
// numeric or {@code null}
- if (leftOperand is int && rightOperand is int) {
- return leftOperand + rightOperand;
- } else if (leftOperand is double && rightOperand is double) {
+ if (leftOperand is num && rightOperand is num) {
return leftOperand + rightOperand;
}
} else if (node.operator.type == TokenType.STAR) {
// numeric or {@code null}
- if (leftOperand is int && rightOperand is int) {
- return leftOperand * rightOperand;
- } else if (leftOperand is double && rightOperand is double) {
+ if (leftOperand is num && rightOperand is num) {
return leftOperand * rightOperand;
}
} else if (node.operator.type == TokenType.SLASH) {
// numeric or {@code null}
- if (leftOperand is int && rightOperand is int) {
- if (rightOperand != 0) {
- return leftOperand ~/ rightOperand;
- } else {
- return leftOperand.toDouble() / rightOperand.toDouble();
- }
- } else if (leftOperand is double && rightOperand is double) {
+ if (leftOperand is num && rightOperand is num) {
return leftOperand / rightOperand;
}
} else if (node.operator.type == TokenType.TILDE_SLASH) {
// numeric or {@code null}
- if (leftOperand is int && rightOperand is int) {
- if (rightOperand != 0) {
- return leftOperand ~/ rightOperand;
- } else {
- return 0;
- }
- } else if (leftOperand is double && rightOperand is double) {
+ if (leftOperand is num && rightOperand is num) {
return leftOperand ~/ rightOperand;
}
} else {}
@@ -5201,11 +5134,7 @@
@override
Object visitInterpolationExpression(InterpolationExpression node) {
Object value = node.expression.accept(this);
- if (value == null ||
- value is bool ||
- value is String ||
- value is int ||
- value is double) {
+ if (value == null || value is bool || value is String || value is num) {
return value;
}
return NOT_A_CONSTANT;
@@ -5278,9 +5207,7 @@
} else if (node.operator.type == TokenType.MINUS) {
if (operand == null) {
return null;
- } else if (operand is int) {
- return -operand;
- } else if (operand is double) {
+ } else if (operand is num) {
return -operand;
}
} else {}
@@ -5347,6 +5274,18 @@
}
/**
+ * Object representing a "const" instance creation expression, and its
+ * evaluation result. This is used as the AnalysisTarget for constant
+ * evaluation of instance creation expressions.
+ */
+class ConstantInstanceCreationHandle {
+ /**
+ * The result of evaluating the constant.
+ */
+ EvaluationResultImpl evaluationResult;
+}
+
+/**
* A constructor declaration.
*
* > constructorDeclaration ::=
@@ -5897,8 +5836,8 @@
}
/**
- * A node that represents the declaration of a name. Each declared name is
- * visible within a name scope.
+ * A node that represents the declaration of one or more names. Each declared
+ * name is visible within a name scope.
*/
abstract class Declaration extends AnnotatedNode {
/**
@@ -6626,18 +6565,13 @@
* > enumType ::=
* > metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
*/
-class EnumDeclaration extends CompilationUnitMember {
+class EnumDeclaration extends NamedCompilationUnitMember {
/**
* The 'enum' keyword.
*/
Token enumKeyword;
/**
- * The name of the enumeration.
- */
- SimpleIdentifier _name;
-
- /**
* The left curly bracket.
*/
Token leftBracket;
@@ -6661,8 +6595,7 @@
EnumDeclaration(Comment comment, List<Annotation> metadata, this.enumKeyword,
SimpleIdentifier name, this.leftBracket,
List<EnumConstantDeclaration> constants, this.rightBracket)
- : super(comment, metadata) {
- _name = _becomeParentOf(name);
+ : super(comment, metadata, name) {
_constants = new NodeList<EnumConstantDeclaration>(this, constants);
}
@@ -6705,18 +6638,6 @@
enumKeyword = token;
}
- /**
- * Return the name of the enumeration.
- */
- SimpleIdentifier get name => _name;
-
- /**
- * Set the name of the enumeration to the given [name].
- */
- void set name(SimpleIdentifier name) {
- _name = _becomeParentOf(name);
- }
-
@override
accept(AstVisitor visitor) => visitor.visitEnumDeclaration(this);
@@ -7932,7 +7853,7 @@
* > functionSignature ::=
* > [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
*/
-class FunctionDeclaration extends CompilationUnitMember {
+class FunctionDeclaration extends NamedCompilationUnitMember {
/**
* The token representing the 'external' keyword, or `null` if this is not an
* external function.
@@ -7951,11 +7872,6 @@
Token propertyKeyword;
/**
- * The name of the function, or `null` if the function is not named.
- */
- SimpleIdentifier _name;
-
- /**
* The function expression being wrapped.
*/
FunctionExpression _functionExpression;
@@ -7971,9 +7887,8 @@
FunctionDeclaration(Comment comment, List<Annotation> metadata,
this.externalKeyword, TypeName returnType, this.propertyKeyword,
SimpleIdentifier name, FunctionExpression functionExpression)
- : super(comment, metadata) {
+ : super(comment, metadata, name) {
_returnType = _becomeParentOf(returnType);
- _name = _becomeParentOf(name);
_functionExpression = _becomeParentOf(functionExpression);
}
@@ -8032,18 +7947,6 @@
(propertyKeyword as KeywordToken).keyword == Keyword.SET;
/**
- * Return the name of the function, or `null` if the function is not named.
- */
- SimpleIdentifier get name => _name;
-
- /**
- * Set the name of the function to the given [identifier].
- */
- void set name(SimpleIdentifier identifier) {
- _name = _becomeParentOf(identifier);
- }
-
- /**
* Return the return type of the function, or `null` if no return type was
* declared.
*/
@@ -8336,11 +8239,6 @@
TypeName _returnType;
/**
- * The name of the function type being declared.
- */
- SimpleIdentifier _name;
-
- /**
* The type parameters for the function type, or `null` if the function type
* does not have any type parameters.
*/
@@ -8362,9 +8260,8 @@
TypeName returnType, SimpleIdentifier name,
TypeParameterList typeParameters, FormalParameterList parameters,
Token semicolon)
- : super(comment, metadata, keyword, semicolon) {
+ : super(comment, metadata, keyword, name, semicolon) {
_returnType = _becomeParentOf(returnType);
- _name = _becomeParentOf(name);
_typeParameters = _becomeParentOf(typeParameters);
_parameters = _becomeParentOf(parameters);
}
@@ -8383,18 +8280,6 @@
_name != null ? (_name.staticElement as FunctionTypeAliasElement) : null;
/**
- * Return the name of the function type being declared.
- */
- SimpleIdentifier get name => _name;
-
- /**
- * Set the name of the function type being declared to the given [name].
- */
- void set name(SimpleIdentifier name) {
- _name = _becomeParentOf(name);
- }
-
- /**
* Return the parameters associated with the function type.
*/
FormalParameterList get parameters => _parameters;
@@ -8606,7 +8491,7 @@
@override
R visitClassDeclaration(ClassDeclaration node) =>
- visitCompilationUnitMember(node);
+ visitNamedCompilationUnitMember(node);
R visitClassMember(ClassMember node) => visitDeclaration(node);
@@ -8676,7 +8561,7 @@
@override
R visitEnumDeclaration(EnumDeclaration node) =>
- visitCompilationUnitMember(node);
+ visitNamedCompilationUnitMember(node);
@override
R visitExportDirective(ExportDirective node) => visitNamespaceDirective(node);
@@ -8715,7 +8600,7 @@
@override
R visitFunctionDeclaration(FunctionDeclaration node) =>
- visitCompilationUnitMember(node);
+ visitNamedCompilationUnitMember(node);
@override
R visitFunctionDeclarationStatement(FunctionDeclarationStatement node) =>
@@ -8801,6 +8686,9 @@
@override
R visitMethodInvocation(MethodInvocation node) => visitExpression(node);
+ R visitNamedCompilationUnitMember(NamedCompilationUnitMember node) =>
+ visitCompilationUnitMember(node);
+
@override
R visitNamedExpression(NamedExpression node) => visitExpression(node);
@@ -8919,7 +8807,7 @@
@override
R visitTryStatement(TryStatement node) => visitStatement(node);
- R visitTypeAlias(TypeAlias node) => visitCompilationUnitMember(node);
+ R visitTypeAlias(TypeAlias node) => visitNamedCompilationUnitMember(node);
@override
R visitTypeArgumentList(TypeArgumentList node) => visitNode(node);
@@ -10007,7 +9895,7 @@
@override
MethodInvocation visitMethodInvocation(MethodInvocation node) {
MethodInvocation copy = new MethodInvocation(_cloneNode(node.target),
- _mapToken(node.period), _cloneNode(node.methodName),
+ _mapToken(node.operator), _cloneNode(node.methodName),
_cloneNode(node.argumentList));
copy.propagatedType = node.propagatedType;
copy.staticType = node.staticType;
@@ -10663,9 +10551,10 @@
ConstructorElement staticElement;
/**
- * The result of evaluating this expression, if it is constant.
+ * The [ConstantInstanceCreationHandle] holding the result of evaluating this
+ * expression, if it is constant.
*/
- EvaluationResultImpl evaluationResult;
+ ConstantInstanceCreationHandle constantHandle;
/**
* Initialize a newly created instance creation expression.
@@ -10713,6 +10602,16 @@
Token get endToken => _argumentList.endToken;
/**
+ * The result of evaluating this expression, if it is constant.
+ */
+ EvaluationResultImpl get evaluationResult {
+ if (constantHandle != null) {
+ return constantHandle.evaluationResult;
+ }
+ return null;
+ }
+
+ /**
* Return `true` if this creation expression is used to invoke a constant
* constructor.
*/
@@ -10898,15 +10797,8 @@
* Return the offset of the after-last contents character.
*/
int get contentsEnd {
- int end = contents.end;
String lexeme = contents.lexeme;
- if (StringUtilities.endsWith3(lexeme, 0x22, 0x22, 0x22) ||
- StringUtilities.endsWith3(lexeme, 0x27, 0x27, 0x27)) {
- end -= 3;
- } else {
- end -= 1;
- }
- return end;
+ return offset + new StringLexemeHelper(lexeme, true, true).end;
}
/**
@@ -10915,16 +10807,7 @@
int get contentsOffset {
int offset = contents.offset;
String lexeme = contents.lexeme;
- if (lexeme.codeUnitAt(0) == 0x72) {
- offset += 1;
- }
- if (StringUtilities.startsWith3(lexeme, offset, 0x22, 0x22, 0x22) ||
- StringUtilities.startsWith3(lexeme, offset, 0x27, 0x27, 0x27)) {
- offset += 3;
- } else {
- offset += 1;
- }
- return offset;
+ return offset + new StringLexemeHelper(lexeme, true, true).start;
}
@override
@@ -11798,10 +11681,12 @@
Expression _target;
/**
- * The period that separates the target from the method name, or `null` if
- * there is no target.
+ * The operator that separates the target from the method name, or `null`
+ * if there is no target. In an ordinary method invocation this will be a
+ * period ('.'). In a cascade section this will be the cascade operator
+ * ('..').
*/
- Token period;
+ Token operator;
/**
* The name of the method being invoked.
@@ -11814,11 +11699,11 @@
ArgumentList _argumentList;
/**
- * Initialize a newly created method invocation. The [target] and [period] can
- * be `null` if there is no target.
+ * Initialize a newly created method invocation. The [target] and [operator]
+ * can be `null` if there is no target.
*/
- MethodInvocation(Expression target, this.period, SimpleIdentifier methodName,
- ArgumentList argumentList) {
+ MethodInvocation(Expression target, this.operator,
+ SimpleIdentifier methodName, ArgumentList argumentList) {
_target = _becomeParentOf(target);
_methodName = _becomeParentOf(methodName);
_argumentList = _becomeParentOf(argumentList);
@@ -11840,8 +11725,8 @@
Token get beginToken {
if (_target != null) {
return _target.beginToken;
- } else if (period != null) {
- return period;
+ } else if (operator != null) {
+ return operator;
}
return _methodName.beginToken;
}
@@ -11849,7 +11734,7 @@
@override
Iterable get childEntities => new ChildEntities()
..add(_target)
- ..add(period)
+ ..add(operator)
..add(_methodName)
..add(_argumentList);
@@ -11862,7 +11747,7 @@
* that is a [CascadeExpression].
*/
bool get isCascaded =>
- period != null && period.type == TokenType.PERIOD_PERIOD;
+ operator != null && operator.type == TokenType.PERIOD_PERIOD;
/**
* Return the name of the method being invoked.
@@ -11876,6 +11761,30 @@
_methodName = _becomeParentOf(identifier);
}
+ /**
+ * The operator that separates the target from the method name, or `null`
+ * if there is no target. In an ordinary method invocation this will be a
+ * period ('.'). In a cascade section this will be the cascade operator
+ * ('..').
+ *
+ * Deprecated: use [operator] instead.
+ */
+ @deprecated
+ Token get period => operator;
+
+ /**
+ * The operator that separates the target from the method name, or `null`
+ * if there is no target. In an ordinary method invocation this will be a
+ * period ('.'). In a cascade section this will be the cascade operator
+ * ('..').
+ *
+ * Deprecated: use [operator] instead.
+ */
+ @deprecated
+ void set period(Token value) {
+ operator = value;
+ }
+
@override
int get precedence => 15;
@@ -11929,6 +11838,39 @@
}
/**
+ * A node that declares a single name within the scope of a compilation unit.
+ */
+abstract class NamedCompilationUnitMember extends CompilationUnitMember {
+ /**
+ * The name of the member being declared.
+ */
+ SimpleIdentifier _name;
+
+ /**
+ * Initialize a newly created compilation unit member with the given [name].
+ * Either or both of the [comment] and [metadata] can be `null` if the member
+ * does not have the corresponding attribute.
+ */
+ NamedCompilationUnitMember(
+ Comment comment, List<Annotation> metadata, SimpleIdentifier name)
+ : super(comment, metadata) {
+ _name = _becomeParentOf(name);
+ }
+
+ /**
+ * Return the name of the member being declared.
+ */
+ SimpleIdentifier get name => _name;
+
+ /**
+ * Set the name of the member being declared to the given [identifier].
+ */
+ void set name(SimpleIdentifier identifier) {
+ _name = _becomeParentOf(identifier);
+ }
+}
+
+/**
* An expression that has a name associated with it. They are used in method
* invocations when there are named parameters.
*
@@ -16505,58 +16447,22 @@
Iterable get childEntities => new ChildEntities()..add(literal);
@override
- int get contentsEnd {
- return contentsOffset + value.length;
- }
+ int get contentsEnd => offset + _helper.end;
@override
- int get contentsOffset {
- int contentsOffset = 0;
- if (isRaw) {
- contentsOffset += 1;
- }
- if (isMultiline) {
- contentsOffset += 3;
- } else {
- contentsOffset += 1;
- }
- return offset + contentsOffset;
- }
+ int get contentsOffset => offset + _helper.start;
@override
Token get endToken => literal;
@override
- bool get isMultiline {
- String lexeme = literal.lexeme;
- if (lexeme.length < 3) {
- return false;
- }
- // skip 'r'
- int offset = 0;
- if (isRaw) {
- offset = 1;
- }
- // check prefix
- return StringUtilities.startsWith3(lexeme, offset, 0x22, 0x22, 0x22) ||
- StringUtilities.startsWith3(lexeme, offset, 0x27, 0x27, 0x27);
- }
+ bool get isMultiline => _helper.isMultiline;
@override
- bool get isRaw => literal.lexeme.codeUnitAt(0) == 0x72;
+ bool get isRaw => _helper.isRaw;
@override
- bool get isSingleQuoted {
- String lexeme = literal.lexeme;
- if (lexeme.isEmpty) {
- return false;
- }
- int codeZero = lexeme.codeUnitAt(0);
- if (codeZero == 0x72) {
- return lexeme.length > 1 && lexeme.codeUnitAt(1) == 0x27;
- }
- return codeZero == 0x27;
- }
+ bool get isSingleQuoted => _helper.isSingleQuoted;
@override
bool get isSynthetic => literal.isSynthetic;
@@ -16573,6 +16479,10 @@
_value = StringUtilities.intern(_value);
}
+ StringLexemeHelper get _helper {
+ return new StringLexemeHelper(literal.lexeme, true, true);
+ }
+
@override
accept(AstVisitor visitor) => visitor.visitSimpleStringLiteral(this);
@@ -16602,6 +16512,7 @@
/**
* Return the offset of the first contents character.
+ * If the string is multiline, then leading whitespaces are skipped.
*/
int get contentsOffset;
@@ -16696,24 +16607,18 @@
Token get endToken => _elements.endToken;
@override
- bool get isMultiline {
- InterpolationString element = _elements.first;
- String lexeme = element.contents.lexeme;
- if (lexeme.length < 3) {
- return false;
- }
- return StringUtilities.startsWith3(lexeme, 0, 0x22, 0x22, 0x22) ||
- StringUtilities.startsWith3(lexeme, 0, 0x27, 0x27, 0x27);
- }
+ bool get isMultiline => _firstHelper.isMultiline;
@override
bool get isRaw => false;
@override
- bool get isSingleQuoted {
+ bool get isSingleQuoted => _firstHelper.isSingleQuoted;
+
+ StringLexemeHelper get _firstHelper {
InterpolationString lastString = _elements.first;
String lexeme = lastString.contents.lexeme;
- return StringUtilities.startsWithChar(lexeme, 0x27);
+ return new StringLexemeHelper(lexeme, true, false);
}
@override
@@ -16731,6 +16636,101 @@
}
/**
+ * A helper for analyzing string lexemes.
+ */
+class StringLexemeHelper {
+ final String lexeme;
+ final bool isFirst;
+ final bool isLast;
+
+ bool isRaw = false;
+ bool isSingleQuoted = false;
+ bool isMultiline = false;
+ int start = 0;
+ int end;
+
+ StringLexemeHelper(this.lexeme, this.isFirst, this.isLast) {
+ if (isFirst) {
+ isRaw = StringUtilities.startsWithChar(lexeme, 0x72);
+ if (isRaw) {
+ start++;
+ }
+ if (StringUtilities.startsWith3(lexeme, start, 0x27, 0x27, 0x27)) {
+ isSingleQuoted = true;
+ isMultiline = true;
+ start += 3;
+ start = _trimInitialWhitespace(start);
+ } else if (StringUtilities.startsWith3(lexeme, start, 0x22, 0x22, 0x22)) {
+ isSingleQuoted = false;
+ isMultiline = true;
+ start += 3;
+ start = _trimInitialWhitespace(start);
+ } else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x27) {
+ isSingleQuoted = true;
+ isMultiline = false;
+ start++;
+ } else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x22) {
+ isSingleQuoted = false;
+ isMultiline = false;
+ start++;
+ }
+ }
+ end = lexeme.length;
+ if (isLast) {
+ if (start + 3 <= end &&
+ (StringUtilities.endsWith3(lexeme, 0x22, 0x22, 0x22) ||
+ StringUtilities.endsWith3(lexeme, 0x27, 0x27, 0x27))) {
+ end -= 3;
+ } else if (start + 1 <= end &&
+ (StringUtilities.endsWithChar(lexeme, 0x22) ||
+ StringUtilities.endsWithChar(lexeme, 0x27))) {
+ end -= 1;
+ }
+ }
+ }
+
+ /**
+ * Given the [lexeme] for a multi-line string whose content begins at the
+ * given [start] index, return the index of the first character that is
+ * included in the value of the string. According to the specification:
+ *
+ * If the first line of a multiline string consists solely of the whitespace
+ * characters defined by the production WHITESPACE 20.1), possibly prefixed
+ * by \, then that line is ignored, including the new line at its end.
+ */
+ int _trimInitialWhitespace(int start) {
+ int length = lexeme.length;
+ int index = start;
+ while (index < length) {
+ int currentChar = lexeme.codeUnitAt(index);
+ if (currentChar == 0x0D) {
+ if (index + 1 < length && lexeme.codeUnitAt(index + 1) == 0x0A) {
+ return index + 2;
+ }
+ return index + 1;
+ } else if (currentChar == 0x0A) {
+ return index + 1;
+ } else if (currentChar == 0x5C) {
+ if (index + 1 >= length) {
+ return start;
+ }
+ currentChar = lexeme.codeUnitAt(index + 1);
+ if (currentChar != 0x0D &&
+ currentChar != 0x0A &&
+ currentChar != 0x09 &&
+ currentChar != 0x20) {
+ return start;
+ }
+ } else if (currentChar != 0x09 && currentChar != 0x20) {
+ return start;
+ }
+ index++;
+ }
+ return start;
+ }
+}
+
+/**
* A string literal expression.
*
* > stringLiteral ::=
@@ -18105,7 +18105,10 @@
if (node.isCascaded) {
_writer.print("..");
} else {
- _visitNodeWithSuffix(node.target, ".");
+ if (node.target != null) {
+ node.target.accept(this);
+ _writer.print(node.operator.lexeme);
+ }
}
_visitNode(node.methodName);
_visitNode(node.argumentList);
@@ -18194,7 +18197,7 @@
_writer.print("..");
} else {
_visitNode(node.target);
- _writer.print('.');
+ _writer.print(node.operator.lexeme);
}
_visitNode(node.propertyName);
return null;
@@ -18672,7 +18675,7 @@
* > classTypeAlias
* > | functionTypeAlias
*/
-abstract class TypeAlias extends CompilationUnitMember {
+abstract class TypeAlias extends NamedCompilationUnitMember {
/**
* The token representing the 'typedef' keyword.
*/
@@ -18689,8 +18692,8 @@
* attribute.
*/
TypeAlias(Comment comment, List<Annotation> metadata, this.typedefKeyword,
- this.semicolon)
- : super(comment, metadata);
+ SimpleIdentifier name, this.semicolon)
+ : super(comment, metadata, name);
@override
Token get endToken => semicolon;
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index c5b413d..7c866c1 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -144,6 +144,48 @@
}
/**
+ * An [AstCloner] that copies the necessary information from the AST to allow
+ * constants to be evaluated.
+ */
+class ConstantAstCloner extends AstCloner {
+ ConstantAstCloner() : super(true);
+
+ @override
+ InstanceCreationExpression visitInstanceCreationExpression(
+ InstanceCreationExpression node) {
+ InstanceCreationExpression expression =
+ super.visitInstanceCreationExpression(node);
+ expression.constantHandle = node.constantHandle;
+ return expression;
+ }
+
+ @override
+ RedirectingConstructorInvocation visitRedirectingConstructorInvocation(
+ RedirectingConstructorInvocation node) {
+ RedirectingConstructorInvocation invocation =
+ super.visitRedirectingConstructorInvocation(node);
+ invocation.staticElement = node.staticElement;
+ return invocation;
+ }
+
+ @override
+ SimpleIdentifier visitSimpleIdentifier(SimpleIdentifier node) {
+ SimpleIdentifier identifier = super.visitSimpleIdentifier(node);
+ identifier.staticElement = node.staticElement;
+ return identifier;
+ }
+
+ @override
+ SuperConstructorInvocation visitSuperConstructorInvocation(
+ SuperConstructorInvocation node) {
+ SuperConstructorInvocation invocation =
+ super.visitSuperConstructorInvocation(node);
+ invocation.staticElement = node.staticElement;
+ return invocation;
+ }
+}
+
+/**
* Instances of the class `ConstantEvaluator` evaluate constant expressions to
* produce their compile-time value. According to the Dart Language
* Specification:
@@ -240,8 +282,8 @@
* A table mapping constant variable elements to the declarations of those
* variables.
*/
- final HashMap<VariableElement, VariableDeclaration> variableMap =
- new HashMap<VariableElement, VariableDeclaration>();
+ final HashMap<PotentiallyConstVariableElement, VariableDeclaration> variableMap =
+ new HashMap<PotentiallyConstVariableElement, VariableDeclaration>();
/**
* A table mapping constant constructors to the declarations of those
@@ -294,9 +336,8 @@
super.visitVariableDeclaration(node);
Expression initializer = node.initializer;
if (initializer != null && node.isConst) {
- VariableElement element = node.element;
- if (element != null) {
- variableMap[element] = node;
+ if (node.element != null) {
+ variableMap[node.element as PotentiallyConstVariableElement] = node;
}
}
return null;
@@ -365,7 +406,7 @@
/**
* A table mapping constant variables to the declarations of those variables.
*/
- HashMap<VariableElement, VariableDeclaration> _variableDeclarationMap;
+ HashMap<PotentiallyConstVariableElement, VariableDeclaration> _variableDeclarationMap;
/**
* A table mapping constant constructors to the declarations of those
@@ -440,8 +481,19 @@
referenceGraph.addNode(declaration);
declaration.initializer.accept(referenceFinder);
});
- constructorDeclarationMap.forEach((ConstructorElement element,
+ constructorDeclarationMap.forEach((ConstructorElementImpl element,
ConstructorDeclaration declaration) {
+ element.isCycleFree = false;
+ ConstructorElement redirectedConstructor =
+ _getConstRedirectedConstructor(element);
+ if (redirectedConstructor != null) {
+ ConstructorElement redirectedConstructorBase =
+ _getConstructorBase(redirectedConstructor);
+ ConstructorDeclaration redirectedConstructorDeclaration =
+ findConstructorDeclaration(redirectedConstructorBase);
+ referenceGraph.addEdge(declaration, redirectedConstructorDeclaration);
+ return;
+ }
ReferenceFinder referenceFinder = new ReferenceFinder(declaration,
referenceGraph, _variableDeclarationMap, constructorDeclarationMap);
referenceGraph.addNode(declaration);
@@ -488,7 +540,6 @@
if (constructor == null) {
continue;
}
- constructor = _followConstantRedirectionChain(constructor);
ConstructorDeclaration declaration =
findConstructorDeclaration(constructor);
// An instance creation expression depends both on the constructor and
@@ -600,18 +651,20 @@
void _computeValueFor(AstNode constNode) {
beforeComputeValue(constNode);
if (constNode is VariableDeclaration) {
- VariableDeclaration declaration = constNode;
- VariableElement element = declaration.element;
+ VariableElement element = constNode.element;
RecordingErrorListener errorListener = new RecordingErrorListener();
ErrorReporter errorReporter =
new ErrorReporter(errorListener, element.source);
DartObjectImpl dartObject =
- declaration.initializer.accept(createConstantVisitor(errorReporter));
+ (element as PotentiallyConstVariableElement).constantInitializer
+ .accept(createConstantVisitor(errorReporter));
if (dartObject != null) {
if (!_runtimeTypeMatch(dartObject, element.type)) {
- errorReporter.reportErrorForNode(
- CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH,
- declaration, [dartObject.type, element.type]);
+ errorReporter.reportErrorForElement(
+ CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH, element, [
+ dartObject.type,
+ element.type
+ ]);
}
}
(element as VariableElementImpl).evaluationResult =
@@ -623,7 +676,8 @@
// Couldn't resolve the constructor so we can't compute a value.
// No problem - the error has already been reported.
// But we still need to store an evaluation result.
- expression.evaluationResult = new EvaluationResultImpl.con1(null);
+ expression.constantHandle.evaluationResult =
+ new EvaluationResultImpl.con1(null);
return;
}
RecordingErrorListener errorListener = new RecordingErrorListener();
@@ -635,16 +689,17 @@
DartObjectImpl result = _evaluateConstructorCall(constNode,
expression.argumentList.arguments, constructor, constantVisitor,
errorReporter);
- expression.evaluationResult =
+ expression.constantHandle.evaluationResult =
new EvaluationResultImpl.con2(result, errorListener.errors);
} else if (constNode is ConstructorDeclaration) {
- ConstructorDeclaration declaration = constNode;
- NodeList<ConstructorInitializer> initializers = declaration.initializers;
- ConstructorElementImpl constructor =
- declaration.element as ConstructorElementImpl;
- constructor.constantInitializers =
- new ConstantValueComputer_InitializerCloner()
- .cloneNodeList(initializers);
+ // No evaluation needs to be done; constructor declarations are only in
+ // the dependency graph to ensure that any constants referred to in
+ // initializer lists and parameter defaults are evaluated before
+ // invocations of the constructor. However we do need to annotate the
+ // element as being free of constant evaluation cycles so that later code
+ // will know that it is safe to evaluate.
+ ConstructorElementImpl constructor = constNode.element;
+ constructor.isCycleFree = true;
} else if (constNode is FormalParameter) {
if (constNode is DefaultFormalParameter) {
DefaultFormalParameter parameter = constNode;
@@ -742,6 +797,14 @@
DartObjectImpl _evaluateConstructorCall(AstNode node,
NodeList<Expression> arguments, ConstructorElement constructor,
ConstantVisitor constantVisitor, ErrorReporter errorReporter) {
+ if (!_getConstructorBase(constructor).isCycleFree) {
+ // It's not safe to evaluate this constructor, so bail out.
+ // TODO(paulberry): ensure that a reasonable error message is produced
+ // in this case, as well as other cases involving constant expression
+ // circularities (e.g. "compile-time constant expression depends on
+ // itself")
+ return new DartObjectImpl.validWithUnknownValue(constructor.returnType);
+ }
int argumentCount = arguments.length;
List<DartObjectImpl> argumentValues =
new List<DartObjectImpl>(argumentCount);
@@ -819,11 +882,10 @@
// In the former case, the best we can do is consider it an unknown value.
// In the latter case, the error has already been reported, so considering
// it an unknown value will suppress further errors.
- return constantVisitor._validWithUnknownValue(definingClass);
+ return new DartObjectImpl.validWithUnknownValue(definingClass);
}
beforeGetConstantInitializers(constructor);
- ConstructorElementImpl constructorBase =
- _getConstructorBase(constructor) as ConstructorElementImpl;
+ ConstructorElementImpl constructorBase = _getConstructorBase(constructor);
List<ConstructorInitializer> initializers =
constructorBase.constantInitializers;
if (initializers == null) {
@@ -832,7 +894,7 @@
// const instance using a non-const constructor, or the node we're
// visiting is involved in a cycle). The error has already been reported,
// so consider it an unknown value to suppress further errors.
- return constantVisitor._validWithUnknownValue(definingClass);
+ return new DartObjectImpl.validWithUnknownValue(definingClass);
}
HashMap<String, DartObjectImpl> fieldMap =
new HashMap<String, DartObjectImpl>();
@@ -985,34 +1047,22 @@
ConstructorElement constructor) {
HashSet<ConstructorElement> constructorsVisited =
new HashSet<ConstructorElement>();
- while (constructor.isFactory) {
- if (identical(
- constructor.enclosingElement.type, typeProvider.symbolType)) {
- // The dart:core.Symbol has a const factory constructor that redirects
- // to dart:_internal.Symbol. That in turn redirects to an external
- // const constructor, which we won't be able to evaluate.
- // So stop following the chain of redirections at dart:core.Symbol, and
- // let [evaluateInstanceCreationExpression] handle it specially.
- break;
- }
- constructorsVisited.add(constructor);
+ while (true) {
ConstructorElement redirectedConstructor =
- constructor.redirectedConstructor;
+ _getConstRedirectedConstructor(constructor);
if (redirectedConstructor == null) {
- // This can happen if constructor is an external factory constructor.
break;
- }
- if (!redirectedConstructor.isConst) {
- // Delegating to a non-const constructor--this is not allowed (and
- // is checked elsewhere--see
- // [ErrorVerifier.checkForRedirectToNonConstConstructor()]).
- break;
- }
- if (constructorsVisited.contains(redirectedConstructor)) {
- // Cycle in redirecting factory constructors--this is not allowed
- // and is checked elsewhere--see
- // [ErrorVerifier.checkForRecursiveFactoryRedirect()]).
- break;
+ } else {
+ ConstructorElement constructorBase = _getConstructorBase(constructor);
+ constructorsVisited.add(constructorBase);
+ ConstructorElement redirectedConstructorBase =
+ _getConstructorBase(redirectedConstructor);
+ if (constructorsVisited.contains(redirectedConstructorBase)) {
+ // Cycle in redirecting factory constructors--this is not allowed
+ // and is checked elsewhere--see
+ // [ErrorVerifier.checkForRecursiveFactoryRedirect()]).
+ break;
+ }
}
constructor = redirectedConstructor;
}
@@ -1029,7 +1079,39 @@
// TODO(brianwilkerson) Implement this.
}
- ConstructorElement _getConstructorBase(ConstructorElement constructor) {
+ /**
+ * If [constructor] redirects to another const constructor, return the
+ * const constructor it redirects to. Otherwise return `null`.
+ */
+ ConstructorElement _getConstRedirectedConstructor(
+ ConstructorElement constructor) {
+ if (!constructor.isFactory) {
+ return null;
+ }
+ if (identical(constructor.enclosingElement.type, typeProvider.symbolType)) {
+ // The dart:core.Symbol has a const factory constructor that redirects
+ // to dart:_internal.Symbol. That in turn redirects to an external
+ // const constructor, which we won't be able to evaluate.
+ // So stop following the chain of redirections at dart:core.Symbol, and
+ // let [evaluateInstanceCreationExpression] handle it specially.
+ return null;
+ }
+ ConstructorElement redirectedConstructor =
+ constructor.redirectedConstructor;
+ if (redirectedConstructor == null) {
+ // This can happen if constructor is an external factory constructor.
+ return null;
+ }
+ if (!redirectedConstructor.isConst) {
+ // Delegating to a non-const constructor--this is not allowed (and
+ // is checked elsewhere--see
+ // [ErrorVerifier.checkForRedirectToNonConstConstructor()]).
+ return null;
+ }
+ return redirectedConstructor;
+ }
+
+ ConstructorElementImpl _getConstructorBase(ConstructorElement constructor) {
while (constructor is ConstructorMember) {
constructor = (constructor as ConstructorMember).baseElement;
}
@@ -1060,51 +1142,6 @@
}
/**
- * An [AstCloner] that copies the necessary information from the AST to allow
- * const constructor initializers to be evaluated.
- */
-class ConstantValueComputer_InitializerCloner extends AstCloner {
- // TODO(brianwilkerson) Investigate replacing uses of this class with uses of
- // AstCloner and ResolutionCopier.
-
- ConstantValueComputer_InitializerCloner() : super(true);
-
- @override
- InstanceCreationExpression visitInstanceCreationExpression(
- InstanceCreationExpression node) {
- InstanceCreationExpression expression =
- super.visitInstanceCreationExpression(node);
- expression.evaluationResult = node.evaluationResult;
- return expression;
- }
-
- @override
- RedirectingConstructorInvocation visitRedirectingConstructorInvocation(
- RedirectingConstructorInvocation node) {
- RedirectingConstructorInvocation invocation =
- super.visitRedirectingConstructorInvocation(node);
- invocation.staticElement = node.staticElement;
- return invocation;
- }
-
- @override
- SimpleIdentifier visitSimpleIdentifier(SimpleIdentifier node) {
- SimpleIdentifier identifier = super.visitSimpleIdentifier(node);
- identifier.staticElement = node.staticElement;
- return identifier;
- }
-
- @override
- SuperConstructorInvocation visitSuperConstructorInvocation(
- SuperConstructorInvocation node) {
- SuperConstructorInvocation invocation =
- super.visitSuperConstructorInvocation(node);
- invocation.staticElement = node.staticElement;
- return invocation;
- }
-}
-
-/**
* A visitor used to evaluate constant expressions to produce their compile-time
* value. According to the Dart Language Specification: <blockquote> A constant
* expression is one of the following:
@@ -1334,7 +1371,7 @@
}
ParameterizedType thenType = thenResult.type;
ParameterizedType elseType = elseResult.type;
- return _validWithUnknownValue(
+ return new DartObjectImpl.validWithUnknownValue(
thenType.getLeastUpperBound(elseType) as InterfaceType);
}
@@ -1628,7 +1665,9 @@
}
return new DartObjectImpl(functionType, new FunctionState(function));
}
- } else if (element is ClassElement || element is FunctionTypeAliasElement) {
+ } else if (element is ClassElement ||
+ element is FunctionTypeAliasElement ||
+ element is DynamicElementImpl) {
return new DartObjectImpl(_typeProvider.typeType, new TypeState(element));
}
// TODO(brianwilkerson) Figure out which error to report.
@@ -1636,22 +1675,6 @@
return null;
}
- DartObjectImpl _validWithUnknownValue(InterfaceType type) {
- if (type.element.library.isDartCore) {
- String typeName = type.name;
- if (typeName == "bool") {
- return new DartObjectImpl(type, BoolState.UNKNOWN_VALUE);
- } else if (typeName == "double") {
- return new DartObjectImpl(type, DoubleState.UNKNOWN_VALUE);
- } else if (typeName == "int") {
- return new DartObjectImpl(type, IntState.UNKNOWN_VALUE);
- } else if (typeName == "String") {
- return new DartObjectImpl(type, StringState.UNKNOWN_VALUE);
- }
- }
- return new DartObjectImpl(type, GenericState.UNKNOWN_VALUE);
- }
-
/**
* Return the value of the given [expression], or a representation of 'null'
* if the expression cannot be evaluated.
@@ -2101,6 +2124,25 @@
*/
DartObjectImpl(this.type, this._state);
+ /**
+ * Create an object to represent an unknown value.
+ */
+ factory DartObjectImpl.validWithUnknownValue(InterfaceType type) {
+ if (type.element.library.isDartCore) {
+ String typeName = type.name;
+ if (typeName == "bool") {
+ return new DartObjectImpl(type, BoolState.UNKNOWN_VALUE);
+ } else if (typeName == "double") {
+ return new DartObjectImpl(type, DoubleState.UNKNOWN_VALUE);
+ } else if (typeName == "int") {
+ return new DartObjectImpl(type, IntState.UNKNOWN_VALUE);
+ } else if (typeName == "String") {
+ return new DartObjectImpl(type, StringState.UNKNOWN_VALUE);
+ }
+ }
+ return new DartObjectImpl(type, GenericState.UNKNOWN_VALUE);
+ }
+
@override
bool get boolValue {
if (_state is BoolState) {
@@ -4764,7 +4806,7 @@
/**
* A table mapping constant variables to the declarations of those variables.
*/
- final HashMap<VariableElement, VariableDeclaration> _variableDeclarationMap;
+ final HashMap<PotentiallyConstVariableElement, VariableDeclaration> _variableDeclarationMap;
/**
* A table mapping constant constructors to the declarations of those
@@ -5027,6 +5069,9 @@
String get typeName => "Type";
@override
+ Element get value => _element;
+
+ @override
bool operator ==(Object object) =>
object is TypeState && (_element == object._element);
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 082415c..9c94c92 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -89,12 +89,13 @@
int internalHashCode(List<DartType> visitedTypes) => hashCode;
@override
- bool internalIsMoreSpecificThan(DartType type, bool withDynamic,
- Set<TypeImpl_TypePair> visitedTypePairs) => true;
+ bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
+ Set<Element> typeExpansions, bool withDynamic = false,
+ Set<Element> visitedElements]) => true;
@override
- bool internalIsSubtypeOf(
- DartType type, Set<TypeImpl_TypePair> visitedTypePairs) => true;
+ bool isSubtypeOf(DartType type,
+ [Set<Element> thisExpansions, Set<Element> typeExpansions]) => true;
@override
bool isSupertypeOf(DartType type) => false;
@@ -225,7 +226,7 @@
* so parsing and resolving will be performed.
*/
@override
- AstNode get node;
+ NamedCompilationUnitMember get node;
/**
* Return the superclass of this class, or `null` if the class represents the
@@ -701,7 +702,7 @@
}
@override
- AstNode get node {
+ NamedCompilationUnitMember get node {
if (isEnum) {
return getNodeMatching((node) => node is EnumDeclaration);
} else {
@@ -1493,7 +1494,7 @@
/**
* A [FieldElement] for a 'const' field that has an initializer.
*/
-class ConstFieldElementImpl extends FieldElementImpl {
+class ConstFieldElementImpl extends FieldElementImpl with ConstVariableElement {
/**
* The result of evaluating this variable's initializer.
*/
@@ -1523,16 +1524,23 @@
* A [LocalVariableElement] for a local 'const' variable that has an
* initializer.
*/
-class ConstLocalVariableElementImpl extends LocalVariableElementImpl {
+class ConstLocalVariableElementImpl extends LocalVariableElementImpl
+ with ConstVariableElement {
/**
* The result of evaluating this variable's initializer.
*/
EvaluationResultImpl _result;
/**
+ * Initialize a newly created local variable element to have the given [name]
+ * and [offset].
+ */
+ ConstLocalVariableElementImpl(String name, int offset) : super(name, offset);
+
+ /**
* Initialize a newly created local variable element to have the given [name].
*/
- ConstLocalVariableElementImpl(Identifier name) : super.forNode(name);
+ ConstLocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);
@override
EvaluationResultImpl get evaluationResult => _result;
@@ -1629,6 +1637,12 @@
int nameEnd;
/**
+ * True if this constructor has been found by constant evaluation to be free
+ * of redirect cycles, and is thus safe to evaluate.
+ */
+ bool isCycleFree = false;
+
+ /**
* Initialize a newly created constructor element to have the given [name] and
* [offset].
*/
@@ -1826,7 +1840,8 @@
* A [TopLevelVariableElement] for a top-level 'const' variable that has an
* initializer.
*/
-class ConstTopLevelVariableElementImpl extends TopLevelVariableElementImpl {
+class ConstTopLevelVariableElementImpl extends TopLevelVariableElementImpl
+ with ConstVariableElement {
/**
* The result of evaluating this variable's initializer.
*/
@@ -1848,6 +1863,30 @@
}
/**
+ * Mixin used by elements that represent constant variables and have
+ * initializers.
+ *
+ * Note that in correct Dart code, all constant variables must have
+ * initializers. However, analyzer also needs to handle incorrect Dart code,
+ * in which case there might be some constant variables that lack initializers.
+ * This interface is only used for constant variables that have initializers.
+ *
+ * This class is not intended to be part of the public API for analyzer.
+ */
+abstract class ConstVariableElement implements PotentiallyConstVariableElement {
+ /**
+ * If this element represents a constant variable, and it has an initializer,
+ * a copy of the initializer for the constant. Otherwise `null`.
+ *
+ * Note that in correct Dart code, all constant variables must have
+ * initializers. However, analyzer also needs to handle incorrect Dart code,
+ * in which case there might be some constant variables that lack
+ * initializers.
+ */
+ Expression constantInitializer;
+}
+
+/**
* The type associated with elements in the element model.
*/
abstract class DartType {
@@ -2071,8 +2110,9 @@
int internalHashCode(List<DartType> visitedTypes) => hashCode;
@override
- bool internalIsMoreSpecificThan(DartType type, bool withDynamic,
- Set<TypeImpl_TypePair> visitedTypePairs) {
+ bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
+ Set<Element> typeExpansions, bool withDynamic = false,
+ Set<Element> visitedElements]) {
// T is S
if (identical(this, type)) {
return true;
@@ -2082,8 +2122,8 @@
}
@override
- bool internalIsSubtypeOf(
- DartType type, Set<TypeImpl_TypePair> visitedTypePairs) => true;
+ bool isSubtypeOf(DartType type,
+ [Set<Element> thisExpansions, Set<Element> typeExpansions]) => true;
@override
bool isSupertypeOf(DartType type) => true;
@@ -3732,7 +3772,7 @@
* A concrete implementation of a [FieldElement].
*/
class FieldElementImpl extends PropertyInducingElementImpl
- implements FieldElement {
+ with PotentiallyConstVariableElement implements FieldElement {
/**
* An empty list of field elements.
*/
@@ -4769,8 +4809,20 @@
}
@override
- bool internalIsMoreSpecificThan(DartType type, bool withDynamic,
- Set<TypeImpl_TypePair> visitedTypePairs) {
+ bool isAssignableTo(DartType type,
+ [Set<Element> thisExpansions, Set<Element> typeExpansions]) {
+ // A function type T may be assigned to a function type S, written T <=> S,
+ // iff T <: S.
+ return isSubtypeOf(type, thisExpansions, typeExpansions);
+ }
+
+ @override
+ bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
+ Set<Element> typeExpansions, bool withDynamic = false,
+ Set<Element> visitedElements]) {
+ // Note: visitedElements is only used for breaking recursion in the type
+ // hierarchy; we don't use it when recursing into the function type.
+
// trivial base cases
if (type == null) {
return false;
@@ -4779,9 +4831,6 @@
type.isDartCoreFunction ||
type.isObject) {
return true;
- } else if (type is UnionType) {
- return (type as UnionTypeImpl).internalUnionTypeIsLessSpecificThan(
- this, withDynamic, visitedTypePairs);
} else if (type is! FunctionType) {
return false;
} else if (this == type) {
@@ -4789,106 +4838,129 @@
}
FunctionType t = this;
FunctionType s = type as FunctionType;
- List<DartType> tTypes = t.normalParameterTypes;
- List<DartType> tOpTypes = t.optionalParameterTypes;
- List<DartType> sTypes = s.normalParameterTypes;
- List<DartType> sOpTypes = s.optionalParameterTypes;
- // If one function has positional and the other has named parameters,
- // return false.
- if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) ||
- (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
- return false;
+ if (thisExpansions == null) {
+ thisExpansions = new HashSet<Element>();
+ } else if (thisExpansions.contains(this.element)) {
+ // [this] contains a reference to itself, which is illegal (and is
+ // checked elsewhere). To avoid cascading errors, consider T to be a
+ // subtype of S.
+ return true;
}
- // named parameters case
- if (t.namedParameterTypes.length > 0) {
- // check that the number of required parameters are equal, and check that
- // every t_i is more specific than every s_i
- if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
+ if (typeExpansions == null) {
+ typeExpansions = new HashSet<Element>();
+ } else if (typeExpansions.contains(type.element)) {
+ // [type] contains a reference to itself, which is illegal (and is
+ // checked elsewhere). To avoid cascading errors, consider T to be a
+ // subtype of S.
+ return true;
+ }
+ thisExpansions.add(this.element);
+ typeExpansions.add(type.element);
+ try {
+ List<DartType> tTypes = t.normalParameterTypes;
+ List<DartType> tOpTypes = t.optionalParameterTypes;
+ List<DartType> sTypes = s.normalParameterTypes;
+ List<DartType> sOpTypes = s.optionalParameterTypes;
+ // If one function has positional and the other has named parameters,
+ // return false.
+ if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) ||
+ (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
return false;
- } else if (t.normalParameterTypes.length > 0) {
- for (int i = 0; i < tTypes.length; i++) {
- if (!(tTypes[i] as TypeImpl).isMoreSpecificThan2(
- sTypes[i], withDynamic, visitedTypePairs)) {
+ }
+ // named parameters case
+ if (t.namedParameterTypes.length > 0) {
+ // check that the number of required parameters are equal, and check that
+ // every t_i is more specific than every s_i
+ if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
+ return false;
+ } else if (t.normalParameterTypes.length > 0) {
+ for (int i = 0; i < tTypes.length; i++) {
+ if (!(tTypes[i] as TypeImpl).isMoreSpecificThan(
+ sTypes[i], thisExpansions, typeExpansions, withDynamic)) {
+ return false;
+ }
+ }
+ }
+ Map<String, DartType> namedTypesT = t.namedParameterTypes;
+ Map<String, DartType> namedTypesS = s.namedParameterTypes;
+ // if k >= m is false, return false: the passed function type has more
+ // named parameter types than this
+ if (namedTypesT.length < namedTypesS.length) {
+ return false;
+ }
+ // Loop through each element in S verifying that T has a matching
+ // parameter name and that the corresponding type is more specific then
+ // the type in S.
+ for (String keyS in namedTypesS.keys) {
+ DartType typeT = namedTypesT[keyS];
+ if (typeT == null) {
+ return false;
+ }
+ if (!(typeT as TypeImpl).isMoreSpecificThan(
+ namedTypesS[keyS], thisExpansions, typeExpansions, withDynamic)) {
return false;
}
}
- }
- Map<String, DartType> namedTypesT = t.namedParameterTypes;
- Map<String, DartType> namedTypesS = s.namedParameterTypes;
- // if k >= m is false, return false: the passed function type has more
- // named parameter types than this
- if (namedTypesT.length < namedTypesS.length) {
+ } else if (s.namedParameterTypes.length > 0) {
return false;
- }
- // Loop through each element in S verifying that T has a matching
- // parameter name and that the corresponding type is more specific then
- // the type in S.
- for (String keyS in namedTypesS.keys) {
- DartType typeT = namedTypesT[keyS];
- if (typeT == null) {
- return false;
- }
- if (!(typeT as TypeImpl).isMoreSpecificThan2(
- namedTypesS[keyS], withDynamic, visitedTypePairs)) {
- return false;
- }
- }
- } else if (s.namedParameterTypes.length > 0) {
- return false;
- } else {
- // positional parameter case
- int tArgLength = tTypes.length + tOpTypes.length;
- int sArgLength = sTypes.length + sOpTypes.length;
- // Check that the total number of parameters in t is greater than or equal
- // to the number of parameters in s and that the number of required
- // parameters in s is greater than or equal to the number of required
- // parameters in t.
- if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
- return false;
- }
- if (tOpTypes.length == 0 && sOpTypes.length == 0) {
- // No positional arguments, don't copy contents to new array
- for (int i = 0; i < sTypes.length; i++) {
- if (!(tTypes[i] as TypeImpl).isMoreSpecificThan2(
- sTypes[i], withDynamic, visitedTypePairs)) {
- return false;
- }
- }
} else {
- // Else, we do have positional parameters, copy required and positional
- // parameter types into arrays to do the compare (for loop below).
- List<DartType> tAllTypes = new List<DartType>(sArgLength);
- for (int i = 0; i < tTypes.length; i++) {
- tAllTypes[i] = tTypes[i];
+ // positional parameter case
+ int tArgLength = tTypes.length + tOpTypes.length;
+ int sArgLength = sTypes.length + sOpTypes.length;
+ // Check that the total number of parameters in t is greater than or equal
+ // to the number of parameters in s and that the number of required
+ // parameters in s is greater than or equal to the number of required
+ // parameters in t.
+ if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
+ return false;
}
- for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
- tAllTypes[i] = tOpTypes[j];
- }
- List<DartType> sAllTypes = new List<DartType>(sArgLength);
- for (int i = 0; i < sTypes.length; i++) {
- sAllTypes[i] = sTypes[i];
- }
- for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
- sAllTypes[i] = sOpTypes[j];
- }
- for (int i = 0; i < sAllTypes.length; i++) {
- if (!(tAllTypes[i] as TypeImpl).isMoreSpecificThan2(
- sAllTypes[i], withDynamic, visitedTypePairs)) {
- return false;
+ if (tOpTypes.length == 0 && sOpTypes.length == 0) {
+ // No positional arguments, don't copy contents to new array
+ for (int i = 0; i < sTypes.length; i++) {
+ if (!(tTypes[i] as TypeImpl).isMoreSpecificThan(
+ sTypes[i], thisExpansions, typeExpansions, withDynamic)) {
+ return false;
+ }
+ }
+ } else {
+ // Else, we do have positional parameters, copy required and positional
+ // parameter types into arrays to do the compare (for loop below).
+ List<DartType> tAllTypes = new List<DartType>(sArgLength);
+ for (int i = 0; i < tTypes.length; i++) {
+ tAllTypes[i] = tTypes[i];
+ }
+ for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
+ tAllTypes[i] = tOpTypes[j];
+ }
+ List<DartType> sAllTypes = new List<DartType>(sArgLength);
+ for (int i = 0; i < sTypes.length; i++) {
+ sAllTypes[i] = sTypes[i];
+ }
+ for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
+ sAllTypes[i] = sOpTypes[j];
+ }
+ for (int i = 0; i < sAllTypes.length; i++) {
+ if (!(tAllTypes[i] as TypeImpl).isMoreSpecificThan(
+ sAllTypes[i], thisExpansions, typeExpansions, withDynamic)) {
+ return false;
+ }
}
}
}
+ DartType tRetType = t.returnType;
+ DartType sRetType = s.returnType;
+ return sRetType.isVoid ||
+ (tRetType as TypeImpl).isMoreSpecificThan(
+ sRetType, thisExpansions, typeExpansions, withDynamic);
+ } finally {
+ thisExpansions.remove(this.element);
+ typeExpansions.remove(type.element);
}
- DartType tRetType = t.returnType;
- DartType sRetType = s.returnType;
- return sRetType.isVoid ||
- (tRetType as TypeImpl).isMoreSpecificThan2(
- sRetType, withDynamic, visitedTypePairs);
}
@override
- bool internalIsSubtypeOf(
- DartType type, Set<TypeImpl_TypePair> visitedTypePairs) {
+ bool isSubtypeOf(DartType type,
+ [Set<Element> thisExpansions, Set<Element> typeExpansions]) {
// trivial base cases
if (type == null) {
return false;
@@ -4897,9 +4969,6 @@
type.isDartCoreFunction ||
type.isObject) {
return true;
- } else if (type is UnionType) {
- return (type as UnionTypeImpl).internalUnionTypeIsSuperTypeOf(
- this, visitedTypePairs);
} else if (type is! FunctionType) {
return false;
} else if (this == type) {
@@ -4907,113 +4976,127 @@
}
FunctionType t = this;
FunctionType s = type as FunctionType;
- List<DartType> tTypes = t.normalParameterTypes;
- List<DartType> tOpTypes = t.optionalParameterTypes;
- List<DartType> sTypes = s.normalParameterTypes;
- List<DartType> sOpTypes = s.optionalParameterTypes;
- // If one function has positional and the other has named parameters,
- // return false.
- if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) ||
- (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
- return false;
+ if (thisExpansions == null) {
+ thisExpansions = new HashSet<Element>();
+ } else if (thisExpansions.contains(this.element)) {
+ // [this] contains a reference to itself, which is illegal (and is
+ // checked elsewhere). To avoid cascading errors, consider T to be a
+ // subtype of S.
+ return true;
}
- // named parameters case
- if (t.namedParameterTypes.length > 0) {
- // check that the number of required parameters are equal,
- // and check that every t_i is assignable to every s_i
- if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
+ if (typeExpansions == null) {
+ typeExpansions = new HashSet<Element>();
+ } else if (typeExpansions.contains(type.element)) {
+ // [type] contains a reference to itself, which is illegal (and is
+ // checked elsewhere). To avoid cascading errors, consider T to be a
+ // subtype of S.
+ return true;
+ }
+ thisExpansions.add(this.element);
+ typeExpansions.add(type.element);
+ try {
+ List<DartType> tTypes = t.normalParameterTypes;
+ List<DartType> tOpTypes = t.optionalParameterTypes;
+ List<DartType> sTypes = s.normalParameterTypes;
+ List<DartType> sOpTypes = s.optionalParameterTypes;
+ // If one function has positional and the other has named parameters,
+ // return false.
+ if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) ||
+ (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
return false;
- } else if (t.normalParameterTypes.length > 0) {
- for (int i = 0; i < tTypes.length; i++) {
- if (!(tTypes[i] as TypeImpl).isAssignableTo2(
- sTypes[i], visitedTypePairs)) {
+ }
+ // named parameters case
+ if (t.namedParameterTypes.length > 0) {
+ // check that the number of required parameters are equal,
+ // and check that every t_i is assignable to every s_i
+ if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
+ return false;
+ } else if (t.normalParameterTypes.length > 0) {
+ for (int i = 0; i < tTypes.length; i++) {
+ if (!(tTypes[i] as TypeImpl).isAssignableTo(
+ sTypes[i], thisExpansions, typeExpansions)) {
+ return false;
+ }
+ }
+ }
+ Map<String, DartType> namedTypesT = t.namedParameterTypes;
+ Map<String, DartType> namedTypesS = s.namedParameterTypes;
+ // if k >= m is false, return false: the passed function type has more
+ // named parameter types than this
+ if (namedTypesT.length < namedTypesS.length) {
+ return false;
+ }
+ // Loop through each element in S verifying that T has a matching
+ // parameter name and that the corresponding type is assignable to the
+ // type in S.
+ for (String keyS in namedTypesS.keys) {
+ DartType typeT = namedTypesT[keyS];
+ if (typeT == null) {
+ return false;
+ }
+ if (!(typeT as TypeImpl).isAssignableTo(
+ namedTypesS[keyS], thisExpansions, typeExpansions)) {
return false;
}
}
- }
- Map<String, DartType> namedTypesT = t.namedParameterTypes;
- Map<String, DartType> namedTypesS = s.namedParameterTypes;
- // if k >= m is false, return false: the passed function type has more
- // named parameter types than this
- if (namedTypesT.length < namedTypesS.length) {
+ } else if (s.namedParameterTypes.length > 0) {
return false;
- }
- // Loop through each element in S verifying that T has a matching
- // parameter name and that the corresponding type is assignable to the
- // type in S.
- for (String keyS in namedTypesS.keys) {
- DartType typeT = namedTypesT[keyS];
- if (typeT == null) {
- return false;
- }
- if (!(typeT as TypeImpl).isAssignableTo2(
- namedTypesS[keyS], visitedTypePairs)) {
- return false;
- }
- }
- } else if (s.namedParameterTypes.length > 0) {
- return false;
- } else {
- // positional parameter case
- int tArgLength = tTypes.length + tOpTypes.length;
- int sArgLength = sTypes.length + sOpTypes.length;
- // Check that the total number of parameters in t is greater than or equal
- // to the number of parameters in s and that the number of required
- // parameters in s is greater than or equal to the number of required
- // parameters in t.
- if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
- return false;
- }
- if (tOpTypes.length == 0 && sOpTypes.length == 0) {
- // No positional arguments, don't copy contents to new array
- for (int i = 0; i < sTypes.length; i++) {
- if (!(tTypes[i] as TypeImpl).isAssignableTo2(
- sTypes[i], visitedTypePairs)) {
- return false;
- }
- }
} else {
- // Else, we do have positional parameters, copy required and positional
- // parameter types into arrays to do the compare (for loop below).
- List<DartType> tAllTypes = new List<DartType>(sArgLength);
- for (int i = 0; i < tTypes.length; i++) {
- tAllTypes[i] = tTypes[i];
+ // positional parameter case
+ int tArgLength = tTypes.length + tOpTypes.length;
+ int sArgLength = sTypes.length + sOpTypes.length;
+ // Check that the total number of parameters in t is greater than or
+ // equal to the number of parameters in s and that the number of
+ // required parameters in s is greater than or equal to the number of
+ // required parameters in t.
+ if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
+ return false;
}
- for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
- tAllTypes[i] = tOpTypes[j];
- }
- List<DartType> sAllTypes = new List<DartType>(sArgLength);
- for (int i = 0; i < sTypes.length; i++) {
- sAllTypes[i] = sTypes[i];
- }
- for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
- sAllTypes[i] = sOpTypes[j];
- }
- for (int i = 0; i < sAllTypes.length; i++) {
- if (!(tAllTypes[i] as TypeImpl).isAssignableTo2(
- sAllTypes[i], visitedTypePairs)) {
- return false;
+ if (tOpTypes.length == 0 && sOpTypes.length == 0) {
+ // No positional arguments, don't copy contents to new array
+ for (int i = 0; i < sTypes.length; i++) {
+ if (!(tTypes[i] as TypeImpl).isAssignableTo(
+ sTypes[i], thisExpansions, typeExpansions)) {
+ return false;
+ }
+ }
+ } else {
+ // Else, we do have positional parameters, copy required and
+ // positional parameter types into arrays to do the compare (for loop
+ // below).
+ List<DartType> tAllTypes = new List<DartType>(sArgLength);
+ for (int i = 0; i < tTypes.length; i++) {
+ tAllTypes[i] = tTypes[i];
+ }
+ for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
+ tAllTypes[i] = tOpTypes[j];
+ }
+ List<DartType> sAllTypes = new List<DartType>(sArgLength);
+ for (int i = 0; i < sTypes.length; i++) {
+ sAllTypes[i] = sTypes[i];
+ }
+ for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
+ sAllTypes[i] = sOpTypes[j];
+ }
+ for (int i = 0; i < sAllTypes.length; i++) {
+ if (!(tAllTypes[i] as TypeImpl).isAssignableTo(
+ sAllTypes[i], thisExpansions, typeExpansions)) {
+ return false;
+ }
}
}
}
+ DartType tRetType = t.returnType;
+ DartType sRetType = s.returnType;
+ return sRetType.isVoid ||
+ (tRetType as TypeImpl).isAssignableTo(
+ sRetType, thisExpansions, typeExpansions);
+ } finally {
+ thisExpansions.remove(this.element);
+ typeExpansions.remove(type.element);
}
- DartType tRetType = t.returnType;
- DartType sRetType = s.returnType;
- return sRetType.isVoid ||
- (tRetType as TypeImpl).isAssignableTo2(sRetType, visitedTypePairs);
}
- /**
- * Return `true` if this type is assignable to the given [type]. A function
- * type <i>T</i> may be assigned to a function type <i>S</i>, written <i>T</i>
- * ⇔ <i>S</i>, iff <i>T</i> <: <i>S</i> (Function Types section of spec).
- * Note that this is more restrictive than the "may be assigned to" rule for
- * interface types.
- */
- @override
- bool isAssignableTo(DartType type) =>
- isSubtypeOf2(type, new HashSet<TypeImpl_TypePair>());
-
@override
FunctionTypeImpl substitute2(
List<DartType> argumentTypes, List<DartType> parameterTypes) {
@@ -6086,111 +6169,6 @@
int internalHashCode(List<DartType> visitedTypes) => hashCode;
@override
- bool internalIsMoreSpecificThan(DartType type, bool withDynamic,
- Set<TypeImpl_TypePair> visitedTypePairs) {
- //
- // S is dynamic.
- // The test to determine whether S is dynamic is done here because dynamic
- // is not an instance of InterfaceType.
- //
- if (type.isDynamic) {
- return true;
- } else if (type is UnionType) {
- return (type as UnionTypeImpl).internalUnionTypeIsLessSpecificThan(
- this, withDynamic, visitedTypePairs);
- } else if (type is! InterfaceType) {
- return false;
- }
- return _isMoreSpecificThan(type as InterfaceType,
- new HashSet<ClassElement>(), withDynamic, visitedTypePairs);
- }
-
- @override
- bool internalIsSubtypeOf(
- DartType type, Set<TypeImpl_TypePair> visitedTypePairs) {
- //
- // T is a subtype of S, written T <: S, iff [bottom/dynamic]T << S
- //
- if (type.isDynamic) {
- return true;
- } else if (type is TypeParameterType) {
- return false;
- } else if (type is UnionType) {
- return (type as UnionTypeImpl).internalUnionTypeIsSuperTypeOf(
- this, visitedTypePairs);
- } else if (type is FunctionType) {
- // This implementation assumes transitivity
- // for function type subtyping on the RHS, but a literal reading
- // of the spec does not specify this. More precisely:
- // if T <: F1 and F1 <: F2 and F1 and F2 are function types,
- // then we assume T <: F2.
- //
- // From the Function Types section of the spec:
- //
- // If a type I includes an instance method named call(), and the type of
- // call() is the function type F, then I is considered to be a
- // subtype of F.
- //
- // However, the section on Interface Types says
- //
- // T is a subtype of S, written T <: S, iff [bottom/dynamic]T << S.
- //
- // after giving rules for << (pronounced "more specific than").
- // However, the "only if" direction of the "iff" in the definition of <:
- // seems to be contradicted by the special case <: rule quoted from the
- // Function Types section: I see no rule for << which tells us that
- // I << F if I has call() at type F.
- //
- // After defining <: , the spec then
- // emphasizes that unlike the relation <<, the relation <: is not
- // transitive in general:
- //
- // Note that <: is not a partial order on types, it is only binary
- // relation on types.
- // This is because <: is not transitive.
- // If it was, the subtype rule would have a cycle.
- //
- // For example: List <: List<String> and List<int> <: List,
- // but List<int> is not a subtype of List<String>.
- // Although <: is not a partial order on types, it does contain a
- // partial order, namely <<.
- // This means that, barring raw types, intuition about classical subtype
- // rules does apply.
- //
- // There is no other occurrence of the word "raw" in relation to types in
- // the spec that I can find, but presumably it's a reference to
- //
- // http://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html
- //
- // so e.g. non-generic types are never raw. As pointed out by paulberry,
- // it's not clear whether a type like T<int, dynamic> should be considered
- // raw or not. On the one hand, it doesn't correspond to a
- // "raw"-in-the-Java-sense occurrence of T, which would instead
- // be T<dynamic, dynamic>; on the other hand, it's treated differently
- // by <: and << when occurring on the left hand side.
- ClassElement element = this.element;
- InheritanceManager manager = new InheritanceManager(element.library);
- FunctionType callType = manager.lookupMemberType(this, "call");
- if (callType != null) {
- // A more literal reading of the spec would give something like
- //
- // return callType.equals(type)
- //
- // here, but that causes 101 errors in the external tests
- // (tools/test.py --mode release --compiler dartanalyzer --runtime none)
- return callType.isSubtypeOf(type);
- }
- return false;
- } else if (type is! InterfaceType) {
- return false;
- } else if (this == type) {
- return true;
- }
- return _isSubtypeOf(
- type as InterfaceType, new HashSet<ClassElement>(), visitedTypePairs);
- }
-
- @override
bool isDirectSupertypeOf(InterfaceType type) {
InterfaceType i = this;
InterfaceType j = type;
@@ -6239,6 +6217,109 @@
}
@override
+ bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
+ Set<Element> typeExpansions, bool withDynamic = false,
+ Set<Element> visitedElements]) {
+ //
+ // S is dynamic.
+ // The test to determine whether S is dynamic is done here because dynamic
+ // is not an instance of InterfaceType.
+ //
+ if (type.isDynamic) {
+ return true;
+ }
+ //
+ // A type T is more specific than a type S, written T << S,
+ // if one of the following conditions is met:
+ //
+ // Reflexivity: T is S.
+ //
+ if (this == type) {
+ return true;
+ }
+ if (type is InterfaceType) {
+ //
+ // T is bottom. (This case is handled by the class BottomTypeImpl.)
+ //
+ // Direct supertype: S is a direct supertype of T.
+ //
+ if (type.isDirectSupertypeOf(this)) {
+ return true;
+ }
+ //
+ // Covariance: T is of the form I<T1, ..., Tn> and S is of the form
+ // I<S1, ..., Sn> and Ti << Si, 1 <= i <= n.
+ //
+ ClassElement tElement = this.element;
+ ClassElement sElement = type.element;
+ if (tElement == sElement) {
+ List<DartType> tArguments = typeArguments;
+ List<DartType> sArguments = type.typeArguments;
+ if (tArguments.length != sArguments.length) {
+ return false;
+ }
+ for (int i = 0; i < tArguments.length; i++) {
+ if (!(tArguments[i] as TypeImpl).isMoreSpecificThan(
+ sArguments[i], thisExpansions, typeExpansions, withDynamic)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ //
+ // Transitivity: T << U and U << S.
+ //
+ // First check for infinite loops
+ if (element == null) {
+ return false;
+ }
+ if (visitedElements == null) {
+ visitedElements = new HashSet<ClassElement>();
+ } else if (visitedElements.contains(element)) {
+ return false;
+ }
+ visitedElements.add(element);
+ try {
+ // Iterate over all of the types U that are more specific than T because
+ // they are direct supertypes of T and return true if any of them are more
+ // specific than S.
+ InterfaceTypeImpl supertype = superclass;
+ if (supertype != null &&
+ supertype.isMoreSpecificThan(type, thisExpansions, typeExpansions,
+ withDynamic, visitedElements)) {
+ return true;
+ }
+ for (InterfaceTypeImpl interfaceType in interfaces) {
+ if (interfaceType.isMoreSpecificThan(type, thisExpansions,
+ typeExpansions, withDynamic, visitedElements)) {
+ return true;
+ }
+ }
+ for (InterfaceTypeImpl mixinType in mixins) {
+ if (mixinType.isMoreSpecificThan(type, thisExpansions, typeExpansions,
+ withDynamic, visitedElements)) {
+ return true;
+ }
+ }
+ // If a type I includes an instance method named `call`, and the type of
+ // `call` is the function type F, then I is considered to be more specific
+ // than F.
+ MethodElement callMethod = getMethod('call');
+ if (callMethod != null && !callMethod.isStatic) {
+ FunctionTypeImpl callType = callMethod.type;
+ if (callType.isMoreSpecificThan(type, thisExpansions, typeExpansions,
+ withDynamic, visitedElements)) {
+ return true;
+ }
+ }
+ return false;
+ } finally {
+ visitedElements.remove(element);
+ }
+ }
+
+ @override
ConstructorElement lookUpConstructor(
String constructorName, LibraryElement library) {
// prepare base ConstructorElement
@@ -6404,145 +6485,6 @@
substitute2(argumentTypes, typeArguments);
/**
- * Return `true` if the given element has an instance method named 'call'.
- */
- bool _hasCallMethod(ClassElement elementT) {
- MethodElement method = elementT.lookUpMethod(
- FunctionElement.CALL_METHOD_NAME, elementT.library);
- return method != null && !method.isStatic;
- }
-
- bool _isMoreSpecificThan(InterfaceType s,
- HashSet<ClassElement> visitedClasses, bool withDynamic,
- Set<TypeImpl_TypePair> visitedTypePairs) {
- //
- // A type T is more specific than a type S, written T << S,
- // if one of the following conditions is met:
- //
- // Reflexivity: T is S.
- //
- if (this == s) {
- return true;
- }
- //
- // T is bottom. (This case is handled by the class BottomTypeImpl.)
- //
- // Direct supertype: S is a direct supertype of T.
- //
- if (s.isDirectSupertypeOf(this)) {
- return true;
- }
- //
- // Covariance: T is of the form I<T1, ..., Tn> and S is of the form
- // I<S1, ..., Sn> and Ti << Si, 1 <= i <= n.
- //
- ClassElement tElement = this.element;
- ClassElement sElement = s.element;
- if (tElement == sElement) {
- List<DartType> tArguments = typeArguments;
- List<DartType> sArguments = s.typeArguments;
- if (tArguments.length != sArguments.length) {
- return false;
- }
- for (int i = 0; i < tArguments.length; i++) {
- if (!(tArguments[i] as TypeImpl).isMoreSpecificThan2(
- sArguments[i], withDynamic, visitedTypePairs)) {
- return false;
- }
- }
- return true;
- }
- //
- // Transitivity: T << U and U << S.
- //
- // First check for infinite loops
- ClassElement element = this.element;
- if (element == null || visitedClasses.contains(element)) {
- return false;
- }
- visitedClasses.add(element);
- // Iterate over all of the types U that are more specific than T because
- // they are direct supertypes of T and return true if any of them are more
- // specific than S.
- InterfaceType supertype = superclass;
- if (supertype != null &&
- (supertype as InterfaceTypeImpl)._isMoreSpecificThan(
- s, visitedClasses, withDynamic, visitedTypePairs)) {
- return true;
- }
- for (InterfaceType interfaceType in interfaces) {
- if ((interfaceType as InterfaceTypeImpl)._isMoreSpecificThan(
- s, visitedClasses, withDynamic, visitedTypePairs)) {
- return true;
- }
- }
- for (InterfaceType mixinType in mixins) {
- if ((mixinType as InterfaceTypeImpl)._isMoreSpecificThan(
- s, visitedClasses, withDynamic, visitedTypePairs)) {
- return true;
- }
- }
- return false;
- }
-
- bool _isSubtypeOf(InterfaceType type, HashSet<ClassElement> visitedClasses,
- Set<TypeImpl_TypePair> visitedTypePairs) {
- InterfaceType typeT = this;
- InterfaceType typeS = type;
- ClassElement elementT = element;
- if (elementT == null || visitedClasses.contains(elementT)) {
- return false;
- }
- visitedClasses.add(elementT);
- if (typeT == typeS) {
- return true;
- } else if (elementT == typeS.element) {
- // For each of the type arguments return true if all type args from T is
- // a subtype of all types from S.
- List<DartType> typeTArgs = typeT.typeArguments;
- List<DartType> typeSArgs = typeS.typeArguments;
- if (typeTArgs.length != typeSArgs.length) {
- // This case covers the case where two objects are being compared that
- // have a different number of parameterized types.
- return false;
- }
- for (int i = 0; i < typeTArgs.length; i++) {
- // Recursively call isSubtypeOf the type arguments and return false if
- // the T argument is not a subtype of the S argument.
- if (!(typeTArgs[i] as TypeImpl).isSubtypeOf2(
- typeSArgs[i], visitedTypePairs)) {
- return false;
- }
- }
- return true;
- } else if (typeS.isDartCoreFunction && _hasCallMethod(elementT)) {
- return true;
- }
- InterfaceType supertype = superclass;
- // The type is Object, return false.
- if (supertype != null &&
- (supertype as InterfaceTypeImpl)._isSubtypeOf(
- typeS, visitedClasses, visitedTypePairs)) {
- return true;
- }
- List<InterfaceType> interfaceTypes = interfaces;
- for (InterfaceType interfaceType in interfaceTypes) {
- if ((interfaceType as InterfaceTypeImpl)._isSubtypeOf(
- typeS, visitedClasses, visitedTypePairs)) {
- return true;
- }
- }
- List<InterfaceType> mixinTypes = mixins;
- for (InterfaceType mixinType in mixinTypes) {
- if ((mixinType as InterfaceTypeImpl)._isSubtypeOf(
- typeS, visitedClasses, visitedTypePairs)) {
- return true;
- }
- }
- return false;
- }
-
- /**
* Return the length of the longest inheritance path from the given [type] to
* Object.
*
@@ -6780,7 +6722,7 @@
bool get isDartCore;
/**
- * Return `true` if this library is the dart:core library.
+ * Return `true` if this library is part of the SDK.
*/
bool get isInSdk;
@@ -6824,6 +6766,11 @@
List<LibraryElement> get visibleLibraries;
/**
+ * Return the element at the given [offset], maybe `null` if no such element.
+ */
+ Element getElementAt(int offset);
+
+ /**
* Return a list containing all of the imports that share the given [prefix],
* or an empty array if there are no such imports.
*/
@@ -6893,6 +6840,11 @@
FunctionElement _loadLibraryFunction;
/**
+ * A map from offsets to elements of this library at these offsets.
+ */
+ final Map<int, Element> _offsetToElementMap = new HashMap<int, Element>();
+
+ /**
* The export [Namespace] of this library, `null` if it has not been
* computed yet.
*/
@@ -7167,6 +7119,13 @@
@override
accept(ElementVisitor visitor) => visitor.visitLibraryElement(this);
+ /**
+ * This method is invoked after this library was incrementally resolved.
+ */
+ void afterIncrementalResolution() {
+ _offsetToElementMap.clear();
+ }
+
@override
ElementImpl getChild(String identifier) {
if ((_definingCompilationUnit as CompilationUnitElementImpl).identifier ==
@@ -7192,6 +7151,14 @@
}
@override
+ Element getElementAt(int offset) {
+ if (_offsetToElementMap.isEmpty) {
+ accept(new _BuildOffsetToElementMap(_offsetToElementMap));
+ }
+ return _offsetToElementMap[offset];
+ }
+
+ @override
List<ImportElement> getImportsWithPrefix(PrefixElement prefixElement) {
int count = _imports.length;
List<ImportElement> importList = new List<ImportElement>();
@@ -7335,7 +7302,7 @@
* A concrete implementation of a [LocalVariableElement].
*/
class LocalVariableElementImpl extends VariableElementImpl
- implements LocalVariableElement {
+ with PotentiallyConstVariableElement implements LocalVariableElement {
/**
* An empty list of field elements.
*/
@@ -7677,8 +7644,6 @@
@override
void appendTo(StringBuffer buffer) {
- buffer.write(enclosingElement.displayName);
- buffer.write(".");
buffer.write(displayName);
super.appendTo(buffer);
}
@@ -8527,6 +8492,27 @@
}
/**
+ * Interface used by elements that might represent constant variables.
+ *
+ * This class may be used as a mixin in the case where [constInitializer] is
+ * known to return null.
+ *
+ * This class is not intended to be part of the public API for analyzer.
+ */
+abstract class PotentiallyConstVariableElement {
+ /**
+ * If this element represents a constant variable, and it has an initializer,
+ * a copy of the initializer for the constant. Otherwise `null`.
+ *
+ * Note that in correct Dart code, all constant variables must have
+ * initializers. However, analyzer also needs to handle incorrect Dart code,
+ * in which case there might be some constant variables that lack
+ * initializers.
+ */
+ Expression get constantInitializer => null;
+}
+
+/**
* A prefix used to import one or more libraries into another library.
*/
abstract class PrefixElement implements Element {
@@ -9307,7 +9293,7 @@
* A concrete implementation of a [TopLevelVariableElement].
*/
class TopLevelVariableElementImpl extends PropertyInducingElementImpl
- implements TopLevelVariableElement {
+ with PotentiallyConstVariableElement implements TopLevelVariableElement {
/**
* An empty list of top-level variable elements.
*/
@@ -9410,118 +9396,68 @@
int internalHashCode(List<DartType> visitedTypes);
- bool internalIsMoreSpecificThan(
- DartType type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs);
-
- bool internalIsSubtypeOf(
- DartType type, Set<TypeImpl_TypePair> visitedTypePairs);
-
- @override
- bool isAssignableTo(DartType type) =>
- isAssignableTo2(type, new HashSet<TypeImpl_TypePair>());
-
/**
- * Return `true` if this type is assignable to the given [type]. A type
- * <i>T</i> may be assigned to a type <i>S</i>, written <i>T</i> ⇔
- * <i>S</i>, iff either <i>T</i> <: <i>S</i> or <i>S</i> <: <i>T</i>
- * (Interface Types section of spec).
+ * Return `true` if this type is assignable to the given [type] (written in
+ * the spec as "T <=> S", where T=[this] and S=[type]).
*
- * The given set of [visitedTypePairs] of types (T1, T2), where each pair
- * indicates that we invoked this method because we are in the process of
- * answering the question of whether T1 is a subtype of T2, is used to prevent
- * infinite loops.
+ * The sets [thisExpansions] and [typeExpansions], if given, are the sets of
+ * function type aliases that have been expanded so far in the process of
+ * reaching [this] and [type], respectively. These are used to avoid
+ * infinite regress when analyzing invalid code; since the language spec
+ * forbids a typedef from referring to itself directly or indirectly, we can
+ * use these as sets of function type aliases that don't need to be expanded.
*/
- bool isAssignableTo2(DartType type, Set<TypeImpl_TypePair> visitedTypePairs) {
- // Strictness matters for union types on the LHS, but not for union types
- // on the RHS.
- if (this is UnionType) {
- if (AnalysisEngine.instance.strictUnionTypes) {
- // *Every* element on the LHS must be assignable to the RHS.
- // We recursively fall into the next case when the RHS is also a union:
- // the order here is important!
- for (DartType left in (this as UnionType).elements) {
- // Would have to cast to [TypeImpl] to call the [visitedTypePairs]
- // version here.
- if (!left.isAssignableTo(type)) {
- return false;
- }
- }
- return true;
- } else {
- // *Some* element on the LHS must be assignable to the RHS.
- for (DartType left in (this as UnionType).elements) {
- // Would have to cast to [TypeImpl] to call the [visitedTypePairs]
- // version here.
- if (left.isAssignableTo(type)) {
- return true;
- }
- }
- return false;
- }
- } else if (type is UnionType) {
- // The LHS, which is not a union, must be assignable to *some* element
- // on the RHS.
- for (DartType right in type.elements) {
- if (this.isAssignableTo2(right, visitedTypePairs)) {
- return true;
- }
- }
- return false;
- } else {
- // For non union types we use the language spec definition of [<=>].
- return isSubtypeOf2(type, visitedTypePairs) ||
- (type as TypeImpl).isSubtypeOf2(this, visitedTypePairs);
- }
+ @override
+ bool isAssignableTo(TypeImpl type,
+ [Set<Element> thisExpansions, Set<Element> typeExpansions]) {
+ // An interface type T may be assigned to a type S, written T <=> S, iff
+ // either T <: S or S <: T.
+ return isSubtypeOf(type, thisExpansions, typeExpansions) ||
+ type.isSubtypeOf(this, typeExpansions, thisExpansions);
}
+ /**
+ * Return `true` if this type is more specific than the given [type] (written
+ * in the spec as "T << S", where T=[this] and S=[type]).
+ *
+ * The sets [thisExpansions] and [typeExpansions], if given, are the sets of
+ * function type aliases that have been expanded so far in the process of
+ * reaching [this] and [type], respectively. These are used to avoid
+ * infinite regress when analyzing invalid code; since the language spec
+ * forbids a typedef from referring to itself directly or indirectly, we can
+ * use these as sets of function type aliases that don't need to be expanded.
+ *
+ * If [withDynamic] is `true`, then "dynamic" should be considered as a
+ * subtype of any type (as though "dynamic" had been replaced with bottom).
+ *
+ * The set [visitedElements], if given, is the set of classes and type
+ * parameters that have been visited so far while examining the class
+ * hierarchy of [this]. This is used to avoid infinite regress when
+ * analyzing invalid code; since the language spec forbids loops in the class
+ * hierarchy, we can use this as a set of classes that don't need to be
+ * examined when walking the class hierarchy.
+ */
@override
- bool isMoreSpecificThan(DartType type) =>
- isMoreSpecificThan2(type, false, new HashSet<TypeImpl_TypePair>());
+ bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
+ Set<Element> typeExpansions, bool withDynamic = false,
+ Set<Element> visitedElements]);
/**
- * Return `true` if this type is more specific than the given [type]. If
- * [withDynamic] is `true`, then "dynamic" should be considered as a subtype
- * of any type.
+ * Return `true` if this type is a subtype of the given [type] (written in
+ * the spec as "T <: S", where T=[this] and S=[type]).
*
- * The given set of [visitedTypePairs] of types (T1, T2), where each pair
- * indicates that we invoked this method because we are in the process of
- * answering the question of whether T1 is a subtype of T2, is used to prevent
- * infinite loops.
+ * The sets [thisExpansions] and [typeExpansions], if given, are the sets of
+ * function type aliases that have been expanded so far in the process of
+ * reaching [this] and [type], respectively. These are used to avoid
+ * infinite regress when analyzing invalid code; since the language spec
+ * forbids a typedef from referring to itself directly or indirectly, we can
+ * use these as sets of function type aliases that don't need to be expanded.
*/
- bool isMoreSpecificThan2(DartType type, bool withDynamic,
- Set<TypeImpl_TypePair> visitedTypePairs) {
- // If the visitedTypePairs already has the pair (this, type), return false
- TypeImpl_TypePair typePair = new TypeImpl_TypePair(this, type);
- if (!visitedTypePairs.add(typePair)) {
- return false;
- }
- bool result =
- internalIsMoreSpecificThan(type, withDynamic, visitedTypePairs);
- visitedTypePairs.remove(typePair);
- return result;
- }
-
@override
- bool isSubtypeOf(DartType type) =>
- isSubtypeOf2(type, new HashSet<TypeImpl_TypePair>());
-
- /**
- * Return `true` if this type is a subtype of the given [type].
- *
- * The given set of [visitedTypePairs] of types (T1, T2), where each pair
- * indicates that we invoked this method because we are in the process of
- * answering the question of whether T1 is a subtype of T2, is used to prevent
- * infinite loops.
- */
- bool isSubtypeOf2(DartType type, Set<TypeImpl_TypePair> visitedTypePairs) {
- // If the visitedTypePairs already has the pair (this, type), return false
- TypeImpl_TypePair typePair = new TypeImpl_TypePair(this, type);
- if (!visitedTypePairs.add(typePair)) {
- return false;
- }
- bool result = internalIsSubtypeOf(type, visitedTypePairs);
- visitedTypePairs.remove(typePair);
- return result;
+ bool isSubtypeOf(DartType type,
+ [Set<Element> thisExpansions, Set<Element> typeExpansions]) {
+ // For non-function types, T <: S iff [_|_/dynamic]T << S.
+ return isMoreSpecificThan(type, thisExpansions, typeExpansions, true);
}
@override
@@ -9581,66 +9517,6 @@
}
/**
- * A pair of types, used to prevent infinite recursion when performing certain
- * computations.
- */
-class TypeImpl_TypePair {
- /**
- * The first type in the pair.
- */
- final DartType _firstType;
-
- /**
- * The second type in the pair.
- */
- final DartType _secondType;
-
- /**
- * The hash code of the pair. This is cached on first access in order to
- * improve performance.
- */
- int _cachedHashCode;
-
- /**
- * Initialize a newly created pair of types to have the given [_firstType] and
- * [_secondType].
- */
- TypeImpl_TypePair(this._firstType, this._secondType);
-
- @override
- int get hashCode {
- if (_cachedHashCode == null) {
- int firstHashCode = 0;
- if (_firstType != null) {
- Element firstElement = _firstType.element;
- firstHashCode = firstElement == null ? 0 : firstElement.hashCode;
- }
- int secondHashCode = 0;
- if (_secondType != null) {
- Element secondElement = _secondType.element;
- secondHashCode = secondElement == null ? 0 : secondElement.hashCode;
- }
- _cachedHashCode = firstHashCode + secondHashCode;
- }
- return _cachedHashCode;
- }
-
- @override
- bool operator ==(Object object) {
- if (identical(object, this)) {
- return true;
- }
- if (object is TypeImpl_TypePair) {
- TypeImpl_TypePair typePair = object;
- return _firstType == typePair._firstType &&
- _secondType != null &&
- _secondType == typePair._secondType;
- }
- return false;
- }
-}
-
-/**
* A type parameter.
*/
abstract class TypeParameterElement implements Element {
@@ -9748,8 +9624,9 @@
int internalHashCode(List<DartType> visitedTypes) => hashCode;
@override
- bool internalIsMoreSpecificThan(
- DartType s, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
+ bool isMoreSpecificThan(DartType s, [Set<Element> thisExpansions,
+ Set<Element> typeExpansions, bool withDynamic = false,
+ Set<Element> visitedElements]) {
//
// A type T is more specific than a type S, written T << S,
// if one of the following conditions is met:
@@ -9764,33 +9641,10 @@
if (s.isDynamic) {
return true;
}
- return _isMoreSpecificThan(
- s, new HashSet<DartType>(), withDynamic, visitedTypePairs);
- }
-
- @override
- bool internalIsSubtypeOf(
- DartType type, Set<TypeImpl_TypePair> visitedTypePairs) =>
- isMoreSpecificThan2(type, true, new HashSet<TypeImpl_TypePair>());
-
- @override
- DartType substitute2(
- List<DartType> argumentTypes, List<DartType> parameterTypes) {
- int length = parameterTypes.length;
- for (int i = 0; i < length; i++) {
- if (parameterTypes[i] == this) {
- return argumentTypes[i];
- }
- }
- return this;
- }
-
- bool _isMoreSpecificThan(DartType s, Set<DartType> visitedTypes,
- bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
//
// T is a type parameter and S is the upper bound of T.
//
- DartType bound = element.bound;
+ TypeImpl bound = element.bound;
if (s == bound) {
return true;
}
@@ -9807,20 +9661,39 @@
//
// Transitivity: T << U and U << S.
//
- if (bound is TypeParameterTypeImpl) {
- TypeParameterTypeImpl boundTypeParameter = bound;
- // First check for infinite loops
- if (visitedTypes.contains(bound)) {
- return false;
- }
- visitedTypes.add(bound);
- // Then check upper bound.
- return boundTypeParameter._isMoreSpecificThan(
- s, visitedTypes, withDynamic, visitedTypePairs);
+ // First check for infinite loops
+ if (element == null) {
+ return false;
}
- // Check interface type.
- return (bound as TypeImpl).isMoreSpecificThan2(
- s, withDynamic, visitedTypePairs);
+ if (visitedElements == null) {
+ visitedElements = new HashSet<Element>();
+ } else if (visitedElements.contains(element)) {
+ return false;
+ }
+ visitedElements.add(element);
+ try {
+ return bound.isMoreSpecificThan(
+ s, thisExpansions, typeExpansions, withDynamic, visitedElements);
+ } finally {
+ visitedElements.remove(element);
+ }
+ }
+
+ @override
+ bool isSubtypeOf(DartType type,
+ [Set<Element> thisExpansions, Set<Element> typeExpansions]) =>
+ isMoreSpecificThan(type, thisExpansions, typeExpansions, true);
+
+ @override
+ DartType substitute2(
+ List<DartType> argumentTypes, List<DartType> parameterTypes) {
+ int length = parameterTypes.length;
+ for (int i = 0; i < length; i++) {
+ if (parameterTypes[i] == this) {
+ return argumentTypes[i];
+ }
+ }
+ return this;
}
/**
@@ -9893,8 +9766,9 @@
int internalHashCode(List<DartType> visitedTypes) => hashCode;
@override
- bool internalIsMoreSpecificThan(DartType type, bool withDynamic,
- Set<TypeImpl_TypePair> visitedTypePairs) {
+ bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
+ Set<Element> typeExpansions, bool withDynamic = false,
+ Set<Element> visitedElements]) {
// T is S
if (identical(this, type)) {
return true;
@@ -9904,8 +9778,8 @@
}
@override
- bool internalIsSubtypeOf(
- DartType type, Set<TypeImpl_TypePair> visitedTypePairs) => true;
+ bool isSubtypeOf(DartType type,
+ [Set<Element> thisExpansions, Set<Element> typeExpansions]) => true;
@override
bool isSupertypeOf(DartType type) => true;
@@ -9924,221 +9798,6 @@
}
/**
- * A union of other types. Union types are "flattened" in the sense that a union
- * type never contains another union type.
- */
-abstract class UnionType implements DartType {
- /**
- * Return an immutable view of the types in this union type.
- */
- Set<DartType> get elements;
-}
-
-/**
- * In addition to the methods of the `UnionType` interface we add a factory
- * method `union` for building unions.
- */
-class UnionTypeImpl extends TypeImpl implements UnionType {
- /**
- * The types in this union.
- */
- final Set<DartType> _types;
-
- /**
- * This constructor should only be called by the `union` factory: it does not
- * check that its argument [types] contains no union types.
- */
- UnionTypeImpl(this._types) : super(null, null);
-
- @override
- String get displayName {
- StringBuffer buffer = new StringBuffer();
- String prefix = "{";
- for (DartType t in _types) {
- buffer.write(prefix);
- buffer.write(t.displayName);
- prefix = ",";
- }
- buffer.write("}");
- return buffer.toString();
- }
-
- @override
- Set<DartType> get elements => _types;
-
- @override
- int get hashCode => _types.hashCode;
-
- @override
- bool operator ==(Object other) {
- if (other == null || other is! UnionType) {
- return false;
- } else if (identical(this, other)) {
- return true;
- } else {
- return javaSetEquals(_types, (other as UnionType).elements);
- }
- }
-
- @override
- void appendTo(StringBuffer buffer, Set<DartType> visitedTypes) {
- if (!visitedTypes.add(this)) {
- buffer.write(name == null ? '...' : name);
- return;
- }
- String prefix = "{";
- for (DartType type in _types) {
- buffer.write(prefix);
- (type as TypeImpl).appendTo(buffer, visitedTypes);
- prefix = ",";
- }
- buffer.write("}");
- }
-
- @override
- bool internalEquals(Object object, Set<ElementPair> visitedElementPairs) =>
- this == object;
-
- @override
- int internalHashCode(List<DartType> visitedTypes) => hashCode;
-
- @override
- bool internalIsMoreSpecificThan(DartType type, bool withDynamic,
- Set<TypeImpl_TypePair> visitedTypePairs) {
- // What version of subtyping do we want? See discussion below in
- // [internalIsSubtypeOf].
- if (AnalysisEngine.instance.strictUnionTypes) {
- // The less unsound version: all.
- for (DartType t in _types) {
- if (!(t as TypeImpl).internalIsMoreSpecificThan(
- type, withDynamic, visitedTypePairs)) {
- return false;
- }
- }
- return true;
- } else {
- // The more unsound version: any.
- for (DartType t in _types) {
- if ((t as TypeImpl).internalIsMoreSpecificThan(
- type, withDynamic, visitedTypePairs)) {
- return true;
- }
- }
- return false;
- }
- }
-
- @override
- bool internalIsSubtypeOf(
- DartType type, Set<TypeImpl_TypePair> visitedTypePairs) {
- if (AnalysisEngine.instance.strictUnionTypes) {
- // The less unsound version: all.
- //
- // For this version to make sense we also need to redefine assignment
- // compatibility [<=>].
- // See discussion above.
- for (DartType t in _types) {
- if (!(t as TypeImpl).internalIsSubtypeOf(type, visitedTypePairs)) {
- return false;
- }
- }
- return true;
- } else {
- // The more unsound version: any.
- for (DartType t in _types) {
- if ((t as TypeImpl).internalIsSubtypeOf(type, visitedTypePairs)) {
- return true;
- }
- }
- return false;
- }
- }
-
- /**
- * The more-specific-than test for union types on the RHS is uniform in
- * non-union LHSs. So, other `TypeImpl`s can call this method to implement
- * [internalIsMoreSpecificThan] for union types.
- */
- bool internalUnionTypeIsLessSpecificThan(DartType type, bool withDynamic,
- Set<TypeImpl_TypePair> visitedTypePairs) {
- // This implementation does not make sense when [type] is a union type,
- // at least for the "less unsound" version of [internalIsMoreSpecificThan]
- // above.
- if (type is UnionType) {
- throw new IllegalArgumentException("Only non-union types are supported.");
- }
- for (DartType t in _types) {
- if ((type as TypeImpl).internalIsMoreSpecificThan(
- t, withDynamic, visitedTypePairs)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * The supertype test for union types is uniform in non-union subtypes. So,
- * other `TypeImpl`s can call this method to implement `internalIsSubtypeOf`
- * for union types.
- */
- bool internalUnionTypeIsSuperTypeOf(
- DartType type, Set<TypeImpl_TypePair> visitedTypePairs) {
- // This implementation does not make sense when [type] is a union type,
- // at least for the "less unsound" version of [internalIsSubtypeOf] above.
- if (type is UnionType) {
- throw new IllegalArgumentException("Only non-union types are supported.");
- }
- for (DartType t in _types) {
- if ((type as TypeImpl).internalIsSubtypeOf(t, visitedTypePairs)) {
- return true;
- }
- }
- return false;
- }
-
- @override
- DartType substitute2(
- List<DartType> argumentTypes, List<DartType> parameterTypes) {
- List<DartType> out = new List<DartType>();
- for (DartType t in _types) {
- out.add(t.substitute2(argumentTypes, parameterTypes));
- }
- return union(out);
- }
-
- /**
- * Return the union of the given [types]. Any unions in the [types] will be
- * flattened in the returned union. If there is only one type after flattening
- * then it will be returned directly, instead of a singleton union. Nulls are
- * discarded, unless all types are null, in which case an exception is raised.
- */
- static DartType union(List<DartType> types) {
- Set<DartType> set = new HashSet<DartType>();
- for (DartType t in types) {
- if (t is UnionType) {
- set.addAll(t.elements);
- } else {
- if (t != null) {
- set.add(t);
- }
- }
- }
- if (set.length == 0) {
- // TODO(collinsn): better to return [null] here? The use case is e.g.
- //
- // union(null, null) ==> null;
- //
- // instead of raising an exception.
- throw new IllegalArgumentException("No known use case for empty unions.");
- } else if (set.length == 1) {
- return set.first;
- } else {
- return new UnionTypeImpl(set);
- }
- }
-}
-
-/**
* An element included into a library using some URI.
*/
abstract class UriReferencedElement implements Element {
@@ -10214,6 +9873,22 @@
bool get isFinal;
/**
+ * Return `true` if this variable is potentially mutated somewhere in a
+ * closure. This information is only available for local variables (including
+ * parameters) and only after the compilation unit containing the variable has
+ * been resolved.
+ */
+ bool get isPotentiallyMutatedInClosure;
+
+ /**
+ * Return `true` if this variable is potentially mutated somewhere in its
+ * scope. This information is only available for local variables (including
+ * parameters) and only after the compilation unit containing the variable has
+ * been resolved.
+ */
+ bool get isPotentiallyMutatedInScope;
+
+ /**
* Return the resolved [VariableDeclaration] node that declares this
* [VariableElement].
*
@@ -10314,20 +9989,10 @@
@override
bool get isFinal => hasModifier(Modifier.FINAL);
- /**
- * Return `true` if this variable is potentially mutated somewhere in a
- * closure. This information is only available for local variables (including
- * parameters) and only after the compilation unit containing the variable has
- * been resolved.
- */
+ @override
bool get isPotentiallyMutatedInClosure => false;
- /**
- * Return `true` if this variable is potentially mutated somewhere in its
- * scope. This information is only available for local variables (including
- * parameters) and only after the compilation unit containing the variable has
- * been resolved.
- */
+ @override
bool get isPotentiallyMutatedInScope => false;
@override
@@ -10380,6 +10045,14 @@
bool get isFinal => baseElement.isFinal;
@override
+ bool get isPotentiallyMutatedInClosure =>
+ baseElement.isPotentiallyMutatedInClosure;
+
+ @override
+ bool get isPotentiallyMutatedInScope =>
+ baseElement.isPotentiallyMutatedInScope;
+
+ @override
VariableDeclaration get node => baseElement.node;
@override
@@ -10439,16 +10112,13 @@
int internalHashCode(List<DartType> visitedTypes) => hashCode;
@override
- bool internalIsMoreSpecificThan(DartType type, bool withDynamic,
- Set<TypeImpl_TypePair> visitedTypePairs) => isSubtypeOf(type);
+ bool isMoreSpecificThan(DartType type, [Set<Element> thisExpansions,
+ Set<Element> typeExpansions, bool withDynamic = false,
+ Set<Element> visitedElements]) => isSubtypeOf(type);
@override
- bool internalIsSubtypeOf(
- DartType type, Set<TypeImpl_TypePair> visitedTypePairs) {
- if (type is UnionType) {
- return (type as UnionTypeImpl).internalUnionTypeIsSuperTypeOf(
- this, visitedTypePairs);
- }
+ bool isSubtypeOf(DartType type,
+ [Set<Element> thisExpansions, Set<Element> typeExpansions]) {
// The only subtype relations that pertain to void are therefore:
// void <: void (by reflexivity)
// bottom <: void (as bottom is a subtype of all types).
@@ -10460,3 +10130,21 @@
VoidTypeImpl substitute2(
List<DartType> argumentTypes, List<DartType> parameterTypes) => this;
}
+
+/**
+ * A visitor that visit all the elements recursively and fill the given [map].
+ */
+class _BuildOffsetToElementMap extends GeneralizingElementVisitor {
+ final Map<int, Element> map;
+
+ _BuildOffsetToElementMap(this.map);
+
+ @override
+ void visitElement(Element element) {
+ int offset = element.nameOffset;
+ if (offset != -1) {
+ map[offset] = element;
+ }
+ super.visitElement(element);
+ }
+}
diff --git a/pkg/analyzer/lib/src/generated/element_handle.dart b/pkg/analyzer/lib/src/generated/element_handle.dart
index d29787e..4c5acae 100644
--- a/pkg/analyzer/lib/src/generated/element_handle.dart
+++ b/pkg/analyzer/lib/src/generated/element_handle.dart
@@ -803,6 +803,9 @@
List<LibraryElement> get visibleLibraries => actualElement.visibleLibraries;
@override
+ Element getElementAt(int offset) => actualElement.getElementAt(offset);
+
+ @override
List<ImportElement> getImportsWithPrefix(PrefixElement prefixElement) =>
actualElement.getImportsWithPrefix(prefixElement);
@@ -1072,6 +1075,14 @@
bool get isFinal => actualElement.isFinal;
@override
+ bool get isPotentiallyMutatedInClosure =>
+ actualElement.isPotentiallyMutatedInClosure;
+
+ @override
+ bool get isPotentiallyMutatedInScope =>
+ actualElement.isPotentiallyMutatedInScope;
+
+ @override
VariableDeclaration get node => actualElement.node;
@override
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index afdf322..9009aae 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -146,7 +146,8 @@
Object visitAssignmentExpression(AssignmentExpression node) {
sc.Token operator = node.operator;
sc.TokenType operatorType = operator.type;
- if (operatorType != sc.TokenType.EQ) {
+ if (operatorType != sc.TokenType.EQ &&
+ operatorType != sc.TokenType.QUESTION_QUESTION_EQ) {
operatorType = _operatorFromCompoundAssignment(operatorType);
Expression leftHandSide = node.leftHandSide;
if (leftHandSide != null) {
@@ -592,10 +593,12 @@
propagatedType = _getPropagatedType(target);
//
// If this method invocation is of the form 'C.m' where 'C' is a class,
- // then we don't call resolveInvokedElement(..) which walks up the class
- // hierarchy, instead we just look for the member in the type only.
+ // then we don't call resolveInvokedElement(...) which walks up the class
+ // hierarchy, instead we just look for the member in the type only. This
+ // does not apply to conditional method invocation (i.e. 'C?.m(...)').
//
- ClassElementImpl typeReference = getTypeReference(target);
+ bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD;
+ ClassElementImpl typeReference = getTypeReference(target, isConditional);
if (typeReference != null) {
staticElement =
propagatedElement = _resolveElement(typeReference, methodName);
@@ -636,15 +639,6 @@
if (_enableHints && errorCode == null && staticElement == null) {
// The method lookup may have failed because there were multiple
// incompatible choices. In this case we don't want to generate a hint.
- if (propagatedElement == null && propagatedType is UnionType) {
- // TODO(collinsn): an improvement here is to make the propagated type
- // of the method call the union of the propagated types of all possible
- // calls.
- if (_lookupMethods(target, propagatedType, methodName.name).length >
- 1) {
- return null;
- }
- }
errorCode = _checkForInvocationError(target, false, propagatedElement);
if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) {
ClassElement classElementContext = null;
@@ -854,7 +848,7 @@
// Otherwise, the prefix is really an expression that happens to be a simple
// identifier and this is really equivalent to a property access node.
//
- _resolvePropertyAccess(prefix, identifier);
+ _resolvePropertyAccess(prefix, identifier, false);
return null;
}
@@ -910,7 +904,8 @@
return null;
}
SimpleIdentifier propertyName = node.propertyName;
- _resolvePropertyAccess(target, propertyName);
+ _resolvePropertyAccess(target, propertyName,
+ node.operator.type == sc.TokenType.QUESTION_PERIOD);
return null;
}
@@ -1719,13 +1714,6 @@
}
return _lookUpMethodInInterfaces(
interfaceType, false, methodName, new HashSet<ClassElement>());
- } else if (type is UnionType) {
- // TODO (collinsn): I want [computeMergedExecutableElement] to be general
- // and work with functions, methods, constructors, and property accessors.
- // However, I won't be able to assume it returns [MethodElement] here
- // then.
- return _maybeMergeExecutableElements(
- _lookupMethods(target, type, methodName)) as MethodElement;
}
return null;
}
@@ -1781,35 +1769,6 @@
}
/**
- * Look up all methods with the given [methodName] that are defined on the
- * given union [type].
- */
- Set<ExecutableElement> _lookupMethods(
- Expression target, UnionType type, String methodName) {
- Set<ExecutableElement> methods = new HashSet<ExecutableElement>();
- bool allElementsHaveMethod = true;
- for (DartType t in type.elements) {
- MethodElement m = _lookUpMethod(target, t, methodName);
- if (m != null) {
- methods.add(m);
- } else {
- allElementsHaveMethod = false;
- }
- }
- // For strict union types we require that all types in the union define the
- // method.
- if (AnalysisEngine.instance.strictUnionTypes) {
- if (allElementsHaveMethod) {
- return methods;
- } else {
- return new Set<ExecutableElement>();
- }
- } else {
- return methods;
- }
- }
-
- /**
* Look up the setter with the given [setterName] in the given [type]. Return
* the element representing the setter that was found, or `null` if there is
* no setter with the given name. The [target] is the target of the
@@ -2385,7 +2344,7 @@
*/
Element _resolveInvokedElementWithTarget(
Expression target, DartType targetType, SimpleIdentifier methodName) {
- if (targetType is InterfaceType || targetType is UnionType) {
+ if (targetType is InterfaceType) {
Element element = _lookUpMethod(target, targetType, methodName.name);
if (element == null) {
//
@@ -2442,17 +2401,18 @@
}
void _resolvePropertyAccess(
- Expression target, SimpleIdentifier propertyName) {
+ Expression target, SimpleIdentifier propertyName, bool isConditional) {
DartType staticType = _getStaticType(target);
DartType propagatedType = _getPropagatedType(target);
Element staticElement = null;
Element propagatedElement = null;
//
// If this property access is of the form 'C.m' where 'C' is a class,
- // then we don't call resolveProperty(..) which walks up the class
- // hierarchy, instead we just look for the member in the type only.
+ // then we don't call resolveProperty(...) which walks up the class
+ // hierarchy, instead we just look for the member in the type only. This
+ // does not apply to conditional property accesses (i.e. 'C?.m').
//
- ClassElementImpl typeReference = getTypeReference(target);
+ ClassElementImpl typeReference = getTypeReference(target, isConditional);
if (typeReference != null) {
// TODO(brianwilkerson) Why are we setting the propagated element here?
// It looks wrong.
@@ -2481,12 +2441,6 @@
_shouldReportMissingMember(propagatedType, propagatedElement) &&
!_memberFoundInSubclass(
propagatedType.element, propertyName.name, false, true);
- // TODO(collinsn): add support for errors on union types by extending
- // [lookupGetter] and [lookupSetter] in analogy with the earlier
- // [lookupMethod] extensions.
- if (propagatedType is UnionType) {
- shouldReportMissingMember_propagated = false;
- }
if (shouldReportMissingMember_static ||
shouldReportMissingMember_propagated) {
DartType staticOrPropagatedType =
@@ -2700,10 +2654,12 @@
/**
* Checks whether the given [expression] is a reference to a class. If it is
* then the element representing the class is returned, otherwise `null` is
- * returned.
+ * returned. [isConditional] indicates whether [expression] is to the left
+ * of a '?.' opertator.
*/
- static ClassElementImpl getTypeReference(Expression expression) {
- if (expression is Identifier) {
+ static ClassElementImpl getTypeReference(
+ Expression expression, bool isConditional) {
+ if (!isConditional && expression is Identifier) {
Element staticElement = expression.staticElement;
if (staticElement is ClassElementImpl) {
return staticElement;
@@ -2713,80 +2669,6 @@
}
/**
- * Helper function for `maybeMergeExecutableElements` that does the actual
- * merging. The [elementArrayToMerge] is the non-empty list of elements to
- * merge.
- */
- static ExecutableElement _computeMergedExecutableElement(
- List<ExecutableElement> elementArrayToMerge) {
- // Flatten methods structurally. Based on
- // [InheritanceManager.computeMergedExecutableElement] and
- // [InheritanceManager.createSyntheticExecutableElement].
- //
- // However, the approach we take here is much simpler, but expected to work
- // well in the common case. It degrades gracefully in the uncommon case,
- // by computing the type [dynamic] for the method, preventing any
- // hints from being generated (TODO: not done yet).
- //
- // The approach is: we require that each [ExecutableElement] has the
- // same shape: the same number of required, optional positional, and
- // optional named parameters, in the same positions, and with the named
- // parameters in the same order. We compute a type by unioning pointwise.
- ExecutableElement e_0 = elementArrayToMerge[0];
- List<ParameterElement> ps_0 = e_0.parameters;
- List<ParameterElementImpl> ps_out =
- new List<ParameterElementImpl>(ps_0.length);
- for (int j = 0; j < ps_out.length; j++) {
- ps_out[j] = new ParameterElementImpl(ps_0[j].name, 0);
- ps_out[j].synthetic = true;
- ps_out[j].type = ps_0[j].type;
- ps_out[j].parameterKind = ps_0[j].parameterKind;
- }
- DartType r_out = e_0.returnType;
- for (int i = 1; i < elementArrayToMerge.length; i++) {
- ExecutableElement e_i = elementArrayToMerge[i];
- r_out = UnionTypeImpl.union([r_out, e_i.returnType]);
- List<ParameterElement> ps_i = e_i.parameters;
- // Each function must have the same number of params.
- if (ps_0.length != ps_i.length) {
- return null;
- // TODO (collinsn): return an element representing [dynamic] here
- // instead.
- } else {
- // Each function must have the same kind of params, with the same names,
- // in the same order.
- for (int j = 0; j < ps_i.length; j++) {
- if (ps_0[j].parameterKind != ps_i[j].parameterKind ||
- !identical(ps_0[j].name, ps_i[j].name)) {
- return null;
- } else {
- // The output parameter type is the union of the input parameter
- // types.
- ps_out[j].type =
- UnionTypeImpl.union([ps_out[j].type, ps_i[j].type]);
- }
- }
- }
- }
- // TODO (collinsn): this code should work for functions and methods,
- // so we may want [FunctionElementImpl]
- // instead here in some cases?
- // And then there are constructors and property accessors.
- // Maybe the answer is to create a new subclass of [ExecutableElementImpl]
- // which is used for merged executable elements, in analogy with
- // [MultiplyInheritedMethodElementImpl] and
- // [MultiplyInheritedPropertyAcessorElementImpl].
- ExecutableElementImpl e_out = new MethodElementImpl(e_0.name, 0);
- e_out.synthetic = true;
- e_out.returnType = r_out;
- e_out.parameters = ps_out;
- e_out.type = new FunctionTypeImpl.con1(e_out);
- // Get NPE in [toString()] w/o this.
- e_out.enclosingElement = e_0.enclosingElement;
- return e_out;
- }
-
- /**
* Return `true` if the given [identifier] is the return type of a constructor
* declaration.
*/
@@ -2832,25 +2714,6 @@
}
return false;
}
-
- /**
- * Return a method representing the merge of the given [elements]. The type of
- * the merged element is the component-wise union of the types of the given
- * elements. If not all input elements have the same shape then `null` is
- * returned.
- */
- static ExecutableElement _maybeMergeExecutableElements(
- Set<ExecutableElement> elements) {
- List<ExecutableElement> elementArrayToMerge = new List.from(elements);
- if (elementArrayToMerge.length == 0) {
- return null;
- } else if (elementArrayToMerge.length == 1) {
- // If all methods are equal, don't bother building a new one.
- return elementArrayToMerge[0];
- } else {
- return _computeMergedExecutableElement(elementArrayToMerge);
- }
- }
}
/**
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index f2f12c6..4cd2f615 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -13,6 +13,7 @@
import 'package:analyzer/src/cancelable_future.dart';
import 'package:analyzer/src/generated/incremental_resolution_validator.dart';
+import 'package:analyzer/src/plugin/engine_plugin.dart';
import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer/src/task/task_dart.dart';
@@ -35,7 +36,6 @@
import 'source.dart';
import 'utilities_collection.dart';
import 'utilities_general.dart';
-import 'package:analyzer/src/plugin/engine_plugin.dart';
/**
* Used by [AnalysisOptions] to allow function bodies to be analyzed in some
@@ -1018,6 +1018,11 @@
TypeResolverVisitorFactory typeResolverVisitorFactory;
/**
+ * A factory to override how [LibraryResolver] is created.
+ */
+ LibraryResolverFactory libraryResolverFactory;
+
+ /**
* Initialize a newly created analysis context.
*/
AnalysisContextImpl() {
@@ -1043,6 +1048,8 @@
this._options.dart2jsHint != options.dart2jsHint ||
(this._options.hint && !options.hint) ||
this._options.preserveComments != options.preserveComments ||
+ this._options.enableNullAwareOperators !=
+ options.enableNullAwareOperators ||
this._options.enableStrictCallChecks != options.enableStrictCallChecks;
int cacheSize = options.cacheSize;
if (this._options.cacheSize != cacheSize) {
@@ -1068,6 +1075,7 @@
this._options.generateImplicitErrors = options.generateImplicitErrors;
this._options.generateSdkErrors = options.generateSdkErrors;
this._options.dart2jsHint = options.dart2jsHint;
+ this._options.enableNullAwareOperators = options.enableNullAwareOperators;
this._options.enableStrictCallChecks = options.enableStrictCallChecks;
this._options.hint = options.hint;
this._options.incremental = options.incremental;
@@ -1105,6 +1113,13 @@
for (int i = 0; i < count; i++) {
_priorityOrder[i] = sources[i];
}
+ // Ensure entries for every priority source.
+ for (var source in _priorityOrder) {
+ SourceEntry entry = _getReadableSourceEntry(source);
+ if (entry == null) {
+ _createSourceEntry(source, false);
+ }
+ }
}
}
@@ -4663,7 +4678,7 @@
Stopwatch perfCounter = new Stopwatch()..start();
PoorMansIncrementalResolver resolver = new PoorMansIncrementalResolver(
typeProvider, unitSource, dartEntry, oldUnit,
- analysisOptions.incrementalApi);
+ analysisOptions.incrementalApi, analysisOptions);
bool success = resolver.resolve(newCode);
AnalysisEngine.instance.instrumentationService.logPerformance(
AnalysisPerformanceKind.INCREMENTAL, perfCounter,
@@ -5724,17 +5739,6 @@
*/
final PartitionManager partitionManager = new PartitionManager();
- /**
- * A flag indicating whether union types should be used.
- */
- bool enableUnionTypes = false;
-
- /**
- * A flag indicating whether union types should have strict semantics. This
- * option has no effect when `enabledUnionTypes` is `false`.
- */
- bool strictUnionTypes = false;
-
AnalysisEngine._();
/**
@@ -5994,6 +5998,11 @@
bool get enableEnum;
/**
+ * Return `true` to enable null-aware operators (DEP 9).
+ */
+ bool get enableNullAwareOperators;
+
+ /**
* Return `true` to strictly follow the specification when generating
* warnings on "call" methods (fixes dartbug.com/21938).
*/
@@ -6087,6 +6096,11 @@
bool dart2jsHint = true;
/**
+ * A flag indicating whether null-aware operators should be parsed (DEP 9).
+ */
+ bool enableNullAwareOperators = false;
+
+ /**
* A flag indicating whether analysis is to strictly follow the specification
* when generating warnings on "call" methods (fixes dartbug.com/21938).
*/
@@ -6151,6 +6165,7 @@
analyzeFunctionBodiesPredicate = options.analyzeFunctionBodiesPredicate;
cacheSize = options.cacheSize;
dart2jsHint = options.dart2jsHint;
+ enableNullAwareOperators = options.enableNullAwareOperators;
enableStrictCallChecks = options.enableStrictCallChecks;
generateImplicitErrors = options.generateImplicitErrors;
generateSdkErrors = options.generateSdkErrors;
@@ -8954,8 +8969,8 @@
// Produce an updated token stream
CharacterReader reader = new CharSequenceReader(cache.newContents);
BooleanErrorListener errorListener = new BooleanErrorListener();
- IncrementalScanner scanner =
- new IncrementalScanner(cache.source, reader, errorListener);
+ IncrementalScanner scanner = new IncrementalScanner(
+ cache.source, reader, errorListener, context.analysisOptions);
scanner.rescan(cache.resolvedUnit.beginToken, cache.offset, cache.oldLength,
cache.newLength);
if (errorListener.errorReported) {
@@ -9021,6 +9036,11 @@
TypeResolverVisitorFactory get typeResolverVisitorFactory;
/**
+ * A factory to override how [LibraryResolver] is created.
+ */
+ LibraryResolverFactory get libraryResolverFactory;
+
+ /**
* Add the given [source] with the given [information] to this context.
*/
void addSourceInfo(Source source, SourceEntry information);
@@ -9402,10 +9422,14 @@
UriValidationCode code = directive.validate();
if (code == null) {
String encodedUriContent = Uri.encodeFull(uriContent);
- Source source =
- context.sourceFactory.resolveUri(librarySource, encodedUriContent);
- directive.source = source;
- return source;
+ try {
+ Source source =
+ context.sourceFactory.resolveUri(librarySource, encodedUriContent);
+ directive.source = source;
+ return source;
+ } on JavaIOException {
+ code = UriValidationCode.INVALID_URI;
+ }
}
if (code == UriValidationCode.URI_WITH_DART_EXT_SCHEME) {
return null;
@@ -9544,7 +9568,8 @@
ht.Token token = scanner.tokenize();
_lineInfo = new LineInfo(scanner.lineStarts);
RecordingErrorListener errorListener = new RecordingErrorListener();
- _unit = new ht.HtmlParser(source, errorListener).parse(token, _lineInfo);
+ _unit = new ht.HtmlParser(source, errorListener, context.analysisOptions)
+ .parse(token, _lineInfo);
_unit.accept(new RecursiveXmlVisitor_ParseHtmlTask_internalPerform(
this, errorListener));
_errors = errorListener.getErrorsForSource(source);
@@ -10439,7 +10464,10 @@
@override
void internalPerform() {
- _resolver = new LibraryResolver(context);
+ LibraryResolverFactory resolverFactory = context.libraryResolverFactory;
+ _resolver = resolverFactory == null
+ ? new LibraryResolver(context)
+ : resolverFactory(context);
_resolver.resolveLibrary(librarySource, true);
}
}
@@ -10777,6 +10805,8 @@
Scanner scanner = new Scanner(
source, new CharSequenceReader(_content), errorListener);
scanner.preserveComments = context.analysisOptions.preserveComments;
+ scanner.enableNullAwareOperators =
+ context.analysisOptions.enableNullAwareOperators;
_tokenStream = scanner.tokenize();
_lineInfo = new LineInfo(scanner.lineStarts);
_errors = errorListener.getErrorsForSource(source);
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index 6ba42dc..9a83ed4 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -704,8 +704,8 @@
* value.
*/
static const CompileTimeErrorCode CONST_EVAL_TYPE_BOOL =
- const CompileTimeErrorCode(
- 'CONST_EVAL_TYPE_BOOL', "An expression of type 'bool' was expected");
+ const CompileTimeErrorCode('CONST_EVAL_TYPE_BOOL',
+ "In constant expressions, operand(s) of this operator must be of type 'bool'");
/**
* 12.11.2 Const: An expression of one of the forms e1 == e2 or e1 != e2 where
@@ -714,7 +714,7 @@
*/
static const CompileTimeErrorCode CONST_EVAL_TYPE_BOOL_NUM_STRING =
const CompileTimeErrorCode('CONST_EVAL_TYPE_BOOL_NUM_STRING',
- "An expression of type 'bool', 'num', 'String' or 'null' was expected");
+ "In constant expressions, operands of this operator must be of type 'bool', 'num', 'String' or 'null'");
/**
* 12.11.2 Const: An expression of one of the forms ~e, e1 ^ e2, e1 & e2,
@@ -722,8 +722,8 @@
* that evaluate to an integer value or to null.
*/
static const CompileTimeErrorCode CONST_EVAL_TYPE_INT =
- const CompileTimeErrorCode(
- 'CONST_EVAL_TYPE_INT', "An expression of type 'int' was expected");
+ const CompileTimeErrorCode('CONST_EVAL_TYPE_INT',
+ "In constant expressions, operand(s) of this operator must be of type 'int'");
/**
* 12.11.2 Const: An expression of one of the forms e, e1 + e2, e1 - e2, e1 *
@@ -732,8 +732,8 @@
* value or to null.
*/
static const CompileTimeErrorCode CONST_EVAL_TYPE_NUM =
- const CompileTimeErrorCode(
- 'CONST_EVAL_TYPE_NUM', "An expression of type 'num' was expected");
+ const CompileTimeErrorCode('CONST_EVAL_TYPE_NUM',
+ "In constant expressions, operand(s) of this operator must be of type 'num'");
/**
* 12.11.2 Const: It is a compile-time error if evaluation of a constant
@@ -2474,8 +2474,16 @@
*/
void reportErrorForElement(
ErrorCode errorCode, Element element, List<Object> arguments) {
- reportErrorForOffset(
- errorCode, element.nameOffset, element.displayName.length, arguments);
+ String displayName = element.displayName;
+ int length = 0;
+ if (displayName != null) {
+ length = displayName.length;
+ } else if (element is ImportElement) {
+ length = 6; // 'import'.length
+ } else if (element is ExportElement) {
+ length = 6; // 'export'.length
+ }
+ reportErrorForOffset(errorCode, element.nameOffset, length, arguments);
}
/**
@@ -3734,6 +3742,16 @@
'ASSIGNMENT_TO_METHOD', "Methods cannot be assigned a value");
/**
+ * 12.18 Assignment: It is as static warning if an assignment of the form
+ * <i>v = e</i> occurs inside a top level or static function (be it function,
+ * method, getter, or setter) or variable initializer and there is neither a
+ * local variable declaration with name <i>v</i> nor setter declaration with
+ * name <i>v=</i> in the lexical scope enclosing the assignment.
+ */
+ static const StaticWarningCode ASSIGNMENT_TO_TYPE = const StaticWarningCode(
+ 'ASSIGNMENT_TO_TYPE', "Types cannot be assigned a value");
+
+ /**
* 13.9 Switch: It is a static warning if the last statement of the statement
* sequence <i>s<sub>k</sub></i> is not a break, continue, return or throw
* statement.
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 74c14ae..9bfb167 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -270,14 +270,7 @@
_isInStaticMethod = false;
_boolType = _typeProvider.boolType;
_intType = _typeProvider.intType;
- _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT = <InterfaceType>[
- _typeProvider.nullType,
- _typeProvider.numType,
- _intType,
- _typeProvider.doubleType,
- _boolType,
- _typeProvider.stringType
- ];
+ _DISALLOWED_TYPES_TO_EXTEND_OR_IMPLEMENT = _typeProvider.nonSubtypableTypes;
}
@override
@@ -309,7 +302,8 @@
sc.TokenType operatorType = node.operator.type;
Expression lhs = node.leftHandSide;
Expression rhs = node.rightHandSide;
- if (operatorType == sc.TokenType.EQ) {
+ if (operatorType == sc.TokenType.EQ ||
+ operatorType == sc.TokenType.QUESTION_QUESTION_EQ) {
_checkForInvalidAssignment(lhs, rhs);
} else {
_checkForInvalidCompoundAssignment(node, lhs, rhs);
@@ -863,7 +857,9 @@
Expression target = node.realTarget;
SimpleIdentifier methodName = node.methodName;
if (target != null) {
- ClassElement typeReference = ElementResolver.getTypeReference(target);
+ bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD;
+ ClassElement typeReference =
+ ElementResolver.getTypeReference(target, isConditional);
_checkForStaticAccessToInstanceMember(typeReference, methodName);
_checkForInstanceAccessToStaticMember(typeReference, methodName);
} else {
@@ -900,7 +896,7 @@
Object visitPrefixedIdentifier(PrefixedIdentifier node) {
if (node.parent is! Annotation) {
ClassElement typeReference =
- ElementResolver.getTypeReference(node.prefix);
+ ElementResolver.getTypeReference(node.prefix, false);
SimpleIdentifier name = node.identifier;
_checkForStaticAccessToInstanceMember(typeReference, name);
_checkForInstanceAccessToStaticMember(typeReference, name);
@@ -923,8 +919,9 @@
@override
Object visitPropertyAccess(PropertyAccess node) {
+ bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD;
ClassElement typeReference =
- ElementResolver.getTypeReference(node.realTarget);
+ ElementResolver.getTypeReference(node.realTarget, isConditional);
SimpleIdentifier propertyName = node.propertyName;
_checkForStaticAccessToInstanceMember(typeReference, propertyName);
_checkForInstanceAccessToStaticMember(typeReference, propertyName);
@@ -2003,6 +2000,13 @@
StaticWarningCode.ASSIGNMENT_TO_METHOD, expression);
return true;
}
+ if (element is ClassElement ||
+ element is FunctionTypeAliasElement ||
+ element is TypeParameterElement) {
+ _errorReporter.reportErrorForNode(
+ StaticWarningCode.ASSIGNMENT_TO_TYPE, expression);
+ return true;
+ }
return false;
}
diff --git a/pkg/analyzer/lib/src/generated/html.dart b/pkg/analyzer/lib/src/generated/html.dart
index c8cc1d3..c6ad0e0 100644
--- a/pkg/analyzer/lib/src/generated/html.dart
+++ b/pkg/analyzer/lib/src/generated/html.dart
@@ -11,7 +11,7 @@
import 'ast.dart';
import 'element.dart';
-import 'engine.dart' show AnalysisEngine;
+import 'engine.dart' show AnalysisOptions, AnalysisEngine;
import 'error.dart' show AnalysisErrorListener;
import 'java_core.dart';
import 'java_engine.dart';
@@ -388,13 +388,16 @@
*/
final AnalysisErrorListener _errorListener;
+ final AnalysisOptions _options;
+
/**
* Construct a parser for the specified source.
*
- * @param source the source being parsed
- * @param errorListener the error listener to which errors will be reported
+ * [source] is the source being parsed. [_errorListener] is the error
+ * listener to which errors will be reported. [_options] is the analysis
+ * options which should be used for parsing.
*/
- HtmlParser(Source source, this._errorListener) : super(source);
+ HtmlParser(Source source, this._errorListener, this._options) : super(source);
@override
XmlAttributeNode createAttributeNode(Token name, Token equals, Token value) =>
@@ -413,6 +416,7 @@
LineInfo_Location location = _lineInfo.getLocation(contentOffset);
sc.Scanner scanner = new sc.Scanner(source,
new sc.SubSequenceReader(contents, contentOffset), _errorListener);
+ scanner.enableNullAwareOperators = _options.enableNullAwareOperators;
scanner.setSourceStart(location.lineNumber, location.columnNumber);
sc.Token firstToken = scanner.tokenize();
Parser parser = new Parser(source, _errorListener);
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index ea6aac7..1e9b61d 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -7,6 +7,7 @@
import 'dart:collection';
import 'dart:math' as math;
+import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/services/lint.dart';
import 'ast.dart';
@@ -184,14 +185,9 @@
? _enclosingClass.unnamedConstructor
: _enclosingClass.getNamedConstructor(constructorName.name);
_processElement(element);
+ _assertEquals(node.constKeyword != null, element.isConst);
+ _assertEquals(node.factoryKeyword != null, element.isFactory);
_assertCompatibleParameters(node.parameters, element.parameters);
- // TODO(scheglov) debug null Location
- if (element != null) {
- if (element.context == null || element.source == null) {
- logger.log(
- 'Bad constructor element $element for $node in ${node.parent}');
- }
- }
// matches, update the existing element
ExecutableElement newElement = node.element;
node.element = element;
@@ -807,7 +803,7 @@
/**
* The element for the library containing the compilation unit being resolved.
*/
- LibraryElement _definingLibrary;
+ LibraryElementImpl _definingLibrary;
/**
* The [DartEntry] corresponding to the source being resolved.
@@ -883,12 +879,16 @@
}
// resolve
_resolveReferences(rootNode);
+ _computeConstants(rootNode);
+ _resolveErrors = errorListener.getErrorsForSource(_source);
// verify
_verify(rootNode);
_context.invalidateLibraryHints(_librarySource);
_generateLints(rootNode);
// update entry errors
_updateEntry();
+ // notify library
+ _definingLibrary.afterIncrementalResolution();
// OK
return true;
} finally {
@@ -958,6 +958,27 @@
node is TopLevelVariableDeclaration;
/**
+ * Compute a value for all of the constants in the given [node].
+ */
+ void _computeConstants(AstNode node) {
+ // compute values
+ {
+ CompilationUnit unit = node.getAncestor((n) => n is CompilationUnit);
+ ConstantValueComputer computer =
+ new ConstantValueComputer(_typeProvider, _context.declaredVariables);
+ computer.add(unit);
+ computer.computeValues();
+ }
+ // validate
+ {
+ ErrorReporter errorReporter = new ErrorReporter(errorListener, _source);
+ ConstantVerifier constantVerifier =
+ new ConstantVerifier(errorReporter, _definingLibrary, _typeProvider);
+ node.accept(constantVerifier);
+ }
+ }
+
+ /**
* Starting at [node], find the smallest AST node that can be resolved
* independently of any other nodes. Return the node that was found.
*
@@ -1041,8 +1062,6 @@
visitor.initForIncrementalResolution();
node.accept(visitor);
}
- // remember errors
- _resolveErrors = errorListener.getErrorsForSource(_source);
} finally {
timer.stop('resolve references');
}
@@ -1143,6 +1162,7 @@
final Source _unitSource;
final DartEntry _entry;
final CompilationUnit _oldUnit;
+ final AnalysisOptions _options;
CompilationUnitElement _unitElement;
int _updateOffset;
@@ -1154,7 +1174,7 @@
List<AnalysisError> _newParseErrors = <AnalysisError>[];
PoorMansIncrementalResolver(this._typeProvider, this._unitSource, this._entry,
- this._oldUnit, bool resolveApiChanges) {
+ this._oldUnit, bool resolveApiChanges, this._options) {
_resolveApiChanges = resolveApiChanges;
}
@@ -1223,9 +1243,9 @@
}
// Find nodes covering the "old" and "new" token ranges.
AstNode oldNode =
- _findNodeCovering(_oldUnit, beginOffsetOld, endOffsetOld);
+ _findNodeCovering(_oldUnit, beginOffsetOld, endOffsetOld - 1);
AstNode newNode =
- _findNodeCovering(newUnit, beginOffsetNew, endOffsetNew);
+ _findNodeCovering(newUnit, beginOffsetNew, endOffsetNew - 1);
logger.log(() => 'oldNode: $oldNode');
logger.log(() => 'newNode: $newNode');
// Try to find the smallest common node, a FunctionBody currently.
@@ -1237,6 +1257,12 @@
for (int i = 0; i < length; i++) {
AstNode oldParent = oldParents[i];
AstNode newParent = newParents[i];
+ if (oldParent is ConstructorInitializer ||
+ newParent is ConstructorInitializer) {
+ logger.log('Failure: changes in constant constructor initializers'
+ ' may cause external changes in constant objects.');
+ return false;
+ }
if (oldParent is FunctionDeclaration &&
newParent is FunctionDeclaration ||
oldParent is MethodDeclaration &&
@@ -1367,6 +1393,7 @@
RecordingErrorListener errorListener = new RecordingErrorListener();
CharSequenceReader reader = new CharSequenceReader(code);
Scanner scanner = new Scanner(_unitSource, reader, errorListener);
+ scanner.enableNullAwareOperators = _options.enableNullAwareOperators;
Token token = scanner.tokenize();
_newScanErrors = errorListener.errors;
return token;
diff --git a/pkg/analyzer/lib/src/generated/incremental_scanner.dart b/pkg/analyzer/lib/src/generated/incremental_scanner.dart
index d5a3984..eed2545 100644
--- a/pkg/analyzer/lib/src/generated/incremental_scanner.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_scanner.dart
@@ -6,6 +6,8 @@
import "dart:math" as math;
+import 'package:analyzer/src/generated/engine.dart';
+
import 'error.dart';
import 'scanner.dart';
import 'source.dart';
@@ -35,6 +37,8 @@
*/
final AnalysisErrorListener errorListener;
+ final AnalysisOptions _options;
+
/**
* A map from tokens that were copied to the copies of the tokens.
*/
@@ -62,8 +66,10 @@
* Initialize a newly created scanner to scan characters within the given
* [source]. The content of the source can be read using the given [reader].
* Any errors that are found will be reported to the given [errorListener].
+ * [_options] will determine how scanning is to be performed.
*/
- IncrementalScanner(this.source, this.reader, this.errorListener);
+ IncrementalScanner(
+ this.source, this.reader, this.errorListener, this._options);
/**
* Return a map from tokens that were copied to the copies of the tokens.
@@ -218,6 +224,7 @@
Token _scanRange(int start, int end) {
Scanner scanner = new Scanner(
source, new CharacterRangeReader(reader, start, end), errorListener);
+ scanner.enableNullAwareOperators = _options.enableNullAwareOperators;
return scanner.tokenize();
}
diff --git a/pkg/analyzer/lib/src/generated/java_core.dart b/pkg/analyzer/lib/src/generated/java_core.dart
index 4f67072..9a0185a 100644
--- a/pkg/analyzer/lib/src/generated/java_core.dart
+++ b/pkg/analyzer/lib/src/generated/java_core.dart
@@ -25,12 +25,14 @@
*/
String formatList(String pattern, List<Object> arguments) {
if (arguments == null || arguments.isEmpty) {
+ assert(!pattern.contains(new RegExp(r'\{(\d+)\}')));
return pattern;
}
return pattern.replaceAllMapped(new RegExp(r'\{(\d+)\}'), (match) {
String indexStr = match.group(1);
int index = int.parse(indexStr);
Object arg = arguments[index];
+ assert(arg != null);
return arg != null ? arg.toString() : null;
});
}
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 4a4823f..0358613 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -694,7 +694,7 @@
@override
AstNode visitConditionalExpression(ConditionalExpression node) {
if (identical(_oldNode, node.condition)) {
- return _parser.parseLogicalOrExpression();
+ return _parser.parseIfNullExpression();
} else if (identical(_oldNode, node.thenExpression)) {
return _parser.parseExpressionWithoutCascade();
} else if (identical(_oldNode, node.elseExpression)) {
@@ -2715,10 +2715,10 @@
* parsed.
*
* conditionalExpression ::=
- * logicalOrExpression ('?' expressionWithoutCascade ':' expressionWithoutCascade)?
+ * ifNullExpression ('?' expressionWithoutCascade ':' expressionWithoutCascade)?
*/
Expression parseConditionalExpression() {
- Expression condition = parseLogicalOrExpression();
+ Expression condition = parseIfNullExpression();
if (!_matches(TokenType.QUESTION)) {
return condition;
}
@@ -3045,6 +3045,22 @@
}
/**
+ * Parse an if-null expression. Return the if-null expression that was
+ * parsed.
+ *
+ * ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)*
+ */
+ Expression parseIfNullExpression() {
+ Expression expression = parseLogicalOrExpression();
+ while (_matches(TokenType.QUESTION_QUESTION)) {
+ Token operator = getAndAdvance();
+ expression = new BinaryExpression(
+ expression, operator, parseLogicalOrExpression());
+ }
+ return expression;
+ }
+
+ /**
* Parse an implements clause. Return the implements clause that was parsed.
*
* implementsClause ::=
@@ -3430,46 +3446,22 @@
/**
* Return the content of a string with the given literal representation. The
- * [lexeme] is the literal representation of the string. The flag [first] is
- * `true` if this is the first token in a string literal. The flag [last] is
+ * [lexeme] is the literal representation of the string. The flag [isFirst] is
+ * `true` if this is the first token in a string literal. The flag [isLast] is
* `true` if this is the last token in a string literal.
*/
- String _computeStringValue(String lexeme, bool first, bool last) {
- bool isRaw = false;
- int start = 0;
- if (first) {
- if (StringUtilities.startsWith4(lexeme, 0, 0x72, 0x22, 0x22, 0x22) ||
- StringUtilities.startsWith4(lexeme, 0, 0x72, 0x27, 0x27, 0x27)) {
- isRaw = true;
- start += 4;
- } else if (StringUtilities.startsWith2(lexeme, 0, 0x72, 0x22) ||
- StringUtilities.startsWith2(lexeme, 0, 0x72, 0x27)) {
- isRaw = true;
- start += 2;
- } else if (StringUtilities.startsWith3(lexeme, 0, 0x22, 0x22, 0x22) ||
- StringUtilities.startsWith3(lexeme, 0, 0x27, 0x27, 0x27)) {
- start += 3;
- } else if (StringUtilities.startsWithChar(lexeme, 0x22) ||
- StringUtilities.startsWithChar(lexeme, 0x27)) {
- start += 1;
- }
- }
- int end = lexeme.length;
- if (last) {
- if (StringUtilities.endsWith3(lexeme, 0x22, 0x22, 0x22) ||
- StringUtilities.endsWith3(lexeme, 0x27, 0x27, 0x27)) {
- end -= 3;
- } else if (StringUtilities.endsWithChar(lexeme, 0x22) ||
- StringUtilities.endsWithChar(lexeme, 0x27)) {
- end -= 1;
- }
- }
- if (end - start + 1 < 0) {
+ String _computeStringValue(String lexeme, bool isFirst, bool isLast) {
+ StringLexemeHelper helper = new StringLexemeHelper(lexeme, isFirst, isLast);
+ int start = helper.start;
+ int end = helper.end;
+ bool stringEndsAfterStart = end >= start;
+ assert(stringEndsAfterStart);
+ if (!stringEndsAfterStart) {
AnalysisEngine.instance.logger.logError(
- "Internal error: computeStringValue($lexeme, $first, $last)");
+ "Internal error: computeStringValue($lexeme, $isFirst, $isLast)");
return "";
}
- if (isRaw) {
+ if (helper.isRaw) {
return lexeme.substring(start, end);
}
StringBuffer buffer = new StringBuffer();
@@ -3599,12 +3591,16 @@
*
* assignableExpression ::=
* primary (arguments* assignableSelector)+
- * | 'super' assignableSelector
+ * | 'super' unconditionalAssignableSelector
* | identifier
*
- * assignableSelector ::=
+ * unconditionalAssignableSelector ::=
* '[' expression ']'
* | '.' identifier
+ *
+ * assignableSelector ::=
+ * unconditionalAssignableSelector
+ * | '?.' identifier
*/
void _ensureAssignable(Expression expression) {
if (expression != null && !expression.isAssignable) {
@@ -4163,13 +4159,13 @@
*
* assignableExpression ::=
* primary (arguments* assignableSelector)+
- * | 'super' assignableSelector
+ * | 'super' unconditionalAssignableSelector
* | identifier
*/
Expression _parseAssignableExpression(bool primaryAllowed) {
if (_matchesKeyword(Keyword.SUPER)) {
return _parseAssignableSelector(
- new SuperExpression(getAndAdvance()), false);
+ new SuperExpression(getAndAdvance()), false, allowConditional: false);
}
//
// A primary expression can start with an identifier. We resolve the
@@ -4219,13 +4215,19 @@
* Parse an assignable selector. The [prefix] is the expression preceding the
* selector. The [optional] is `true` if the selector is optional. Return the
* assignable selector that was parsed, or the original prefix if there was no
- * assignable selector.
+ * assignable selector. If [allowConditional] is false, then the '?.'
+ * operator will still be parsed, but a parse error will be generated.
*
- * assignableSelector ::=
+ * unconditionalAssignableSelector ::=
* '[' expression ']'
* | '.' identifier
+ *
+ * assignableSelector ::=
+ * unconditionalAssignableSelector
+ * | '?.' identifier
*/
- Expression _parseAssignableSelector(Expression prefix, bool optional) {
+ Expression _parseAssignableSelector(Expression prefix, bool optional,
+ {bool allowConditional: true}) {
if (_matches(TokenType.OPEN_SQUARE_BRACKET)) {
Token leftBracket = getAndAdvance();
bool wasInInitializer = _inInitializer;
@@ -4238,9 +4240,14 @@
} finally {
_inInitializer = wasInInitializer;
}
- } else if (_matches(TokenType.PERIOD)) {
- Token period = getAndAdvance();
- return new PropertyAccess(prefix, period, parseSimpleIdentifier());
+ } else if (_matches(TokenType.PERIOD) ||
+ _matches(TokenType.QUESTION_PERIOD)) {
+ if (_matches(TokenType.QUESTION_PERIOD) && !allowConditional) {
+ _reportErrorForCurrentToken(
+ ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [_currentToken.lexeme]);
+ }
+ Token operator = getAndAdvance();
+ return new PropertyAccess(prefix, operator, parseSimpleIdentifier());
} else {
if (!optional) {
// Report the missing selector.
@@ -5672,8 +5679,9 @@
}
Token functionDefinition = getAndAdvance();
if (_matchesKeyword(Keyword.RETURN)) {
- _reportErrorForToken(
- ParserErrorCode.UNEXPECTED_TOKEN, getAndAdvance());
+ _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
+ [_currentToken.lexeme]);
+ _advance();
}
Expression expression = parseExpression2();
Token semicolon = null;
@@ -5748,6 +5756,9 @@
} else {
_reportErrorForCurrentToken(
ParserErrorCode.MISSING_FUNCTION_PARAMETERS);
+ parameters = new FormalParameterList(
+ _createSyntheticToken(TokenType.OPEN_PAREN), null, null, null,
+ _createSyntheticToken(TokenType.CLOSE_PAREN));
}
} else if (_matches(TokenType.OPEN_PAREN)) {
_reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
@@ -5941,7 +5952,7 @@
* associated with the directive. Return the import directive that was parsed.
*
* importDirective ::=
- * metadata 'import' stringLiteral ('as' identifier)? combinator*';'
+ * metadata 'import' stringLiteral (deferred)? ('as' identifier)? combinator*';'
*/
ImportDirective _parseImportDirective(CommentAndMetadata commentAndMetadata) {
Token importKeyword = _expectKeyword(Keyword.IMPORT);
@@ -5958,6 +5969,21 @@
} else if (deferredToken != null) {
_reportErrorForCurrentToken(
ParserErrorCode.MISSING_PREFIX_IN_DEFERRED_IMPORT);
+ } else if (!_matches(TokenType.SEMICOLON) &&
+ !_matchesString(_SHOW) &&
+ !_matchesString(_HIDE)) {
+ Token nextToken = _peek();
+ if (_tokenMatchesKeyword(nextToken, Keyword.AS) ||
+ _tokenMatchesString(nextToken, _SHOW) ||
+ _tokenMatchesString(nextToken, _HIDE)) {
+ _reportErrorForCurrentToken(
+ ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken]);
+ _advance();
+ if (_matchesKeyword(Keyword.AS)) {
+ asToken = getAndAdvance();
+ prefix = parseSimpleIdentifier();
+ }
+ }
}
List<Combinator> combinators = _parseCombinators();
Token semicolon = _expectSemicolon();
@@ -6675,6 +6701,7 @@
Expression operand = _parseAssignableExpression(true);
if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
_matches(TokenType.PERIOD) ||
+ _matches(TokenType.QUESTION_PERIOD) ||
_matches(TokenType.OPEN_PAREN)) {
do {
if (_matches(TokenType.OPEN_PAREN)) {
@@ -6691,6 +6718,7 @@
}
} while (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
_matches(TokenType.PERIOD) ||
+ _matches(TokenType.QUESTION_PERIOD) ||
_matches(TokenType.OPEN_PAREN));
return operand;
}
@@ -6707,7 +6735,7 @@
*
* primary ::=
* thisExpression
- * | 'super' assignableSelector
+ * | 'super' unconditionalAssignableSelector
* | functionExpression
* | literal
* | identifier
@@ -6729,8 +6757,10 @@
if (_matchesKeyword(Keyword.THIS)) {
return new ThisExpression(getAndAdvance());
} else if (_matchesKeyword(Keyword.SUPER)) {
+ // TODO(paulberry): verify with Gilad that "super" must be followed by
+ // unconditionalAssignableSelector in this case.
return _parseAssignableSelector(
- new SuperExpression(getAndAdvance()), false);
+ new SuperExpression(getAndAdvance()), false, allowConditional: false);
} else if (_matchesKeyword(Keyword.NULL)) {
return new NullLiteral(getAndAdvance());
} else if (_matchesKeyword(Keyword.FALSE)) {
@@ -7823,7 +7853,18 @@
} else if (!_tokenMatches(token, TokenType.PERIOD)) {
return token;
}
- return _skipSimpleIdentifier(token.next);
+ token = token.next;
+ Token nextToken = _skipSimpleIdentifier(token);
+ if (nextToken != null) {
+ return nextToken;
+ } else if (_tokenMatches(token, TokenType.CLOSE_PAREN) ||
+ _tokenMatches(token, TokenType.COMMA)) {
+ // If the `id.` is followed by something that cannot produce a valid
+ // structure then assume this is a prefixed identifier but missing the
+ // trailing identifier
+ return token;
+ }
+ return null;
}
/**
@@ -9983,7 +10024,7 @@
bool visitMethodInvocation(MethodInvocation node) {
MethodInvocation toNode = this._toNode as MethodInvocation;
if (_and(_isEqualNodes(node.target, toNode.target),
- _isEqualTokens(node.period, toNode.period),
+ _isEqualTokens(node.operator, toNode.operator),
_isEqualNodes(node.methodName, toNode.methodName),
_isEqualNodes(node.argumentList, toNode.argumentList))) {
toNode.propagatedType = node.propagatedType;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 7f95837..d9cc380 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -35,6 +35,8 @@
typedef void ImplicitConstructorBuilderCallback(ClassElement classElement,
ClassElement superclassElement, void computation());
+typedef LibraryResolver LibraryResolverFactory(AnalysisContext context);
+
typedef ResolverVisitor ResolverVisitorFactory(
Library library, Source source, TypeProvider typeProvider);
@@ -2846,6 +2848,14 @@
}
@override
+ Object visitInstanceCreationExpression(InstanceCreationExpression node) {
+ if (node.isConst) {
+ node.constantHandle = new ConstantInstanceCreationHandle();
+ }
+ return super.visitInstanceCreationExpression(node);
+ }
+
+ @override
Object visitLabeledStatement(LabeledStatement node) {
bool onSwitchStatement = node.statement is SwitchStatement;
for (Label label in node.labels) {
@@ -3064,17 +3074,15 @@
SimpleIdentifier variableName = node.name;
LocalVariableElementImpl variable;
if (isConst && hasInitializer) {
- variable = new ConstLocalVariableElementImpl(variableName);
+ variable = new ConstLocalVariableElementImpl.forNode(variableName);
} else {
variable = new LocalVariableElementImpl.forNode(variableName);
}
element = variable;
Block enclosingBlock = node.getAncestor((node) => node is Block);
- int functionEnd = node.offset + node.length;
- int blockEnd = enclosingBlock.offset + enclosingBlock.length;
// TODO(brianwilkerson) This isn't right for variables declared in a for
// loop.
- variable.setVisibleRange(functionEnd, blockEnd - functionEnd - 1);
+ variable.setVisibleRange(enclosingBlock.offset, enclosingBlock.length);
_currentHolder.addLocalVariable(variable);
variableName.staticElement = element;
} else {
@@ -4344,6 +4352,256 @@
}
/**
+ * A visitor that visits ASTs and fills [UsedImportedElements].
+ */
+class GatherUsedImportedElementsVisitor extends RecursiveAstVisitor {
+ final LibraryElement library;
+ final UsedImportedElements usedElements = new UsedImportedElements();
+
+ GatherUsedImportedElementsVisitor(this.library);
+
+ @override
+ void visitExportDirective(ExportDirective node) {
+ _visitMetadata(node.metadata);
+ }
+
+ @override
+ void visitImportDirective(ImportDirective node) {
+ _visitMetadata(node.metadata);
+ }
+
+ @override
+ void visitLibraryDirective(LibraryDirective node) {
+ _visitMetadata(node.metadata);
+ }
+
+ @override
+ void visitPrefixedIdentifier(PrefixedIdentifier node) {
+ // If the prefixed identifier references some A.B, where A is a library
+ // prefix, then we can lookup the associated ImportDirective in
+ // prefixElementMap and remove it from the unusedImports list.
+ SimpleIdentifier prefixIdentifier = node.prefix;
+ Element element = prefixIdentifier.staticElement;
+ if (element is PrefixElement) {
+ usedElements.prefixes.add(element);
+ return;
+ }
+ // Otherwise, pass the prefixed identifier element and name onto
+ // visitIdentifier.
+ _visitIdentifier(element, prefixIdentifier.name);
+ }
+
+ @override
+ void visitSimpleIdentifier(SimpleIdentifier node) {
+ _visitIdentifier(node.staticElement, node.name);
+ }
+
+ void _visitIdentifier(Element element, String name) {
+ if (element == null) {
+ return;
+ }
+ // If the element is multiply defined then call this method recursively for
+ // each of the conflicting elements.
+ if (element is MultiplyDefinedElement) {
+ MultiplyDefinedElement multiplyDefinedElement = element;
+ for (Element elt in multiplyDefinedElement.conflictingElements) {
+ _visitIdentifier(elt, name);
+ }
+ return;
+ } else if (element is PrefixElement) {
+ usedElements.prefixes.add(element);
+ return;
+ } else if (element.enclosingElement is! CompilationUnitElement) {
+ // Identifiers that aren't a prefix element and whose enclosing element
+ // isn't a CompilationUnit are ignored- this covers the case the
+ // identifier is a relative-reference, a reference to an identifier not
+ // imported by this library.
+ return;
+ }
+ // Ignore if an unknown library.
+ LibraryElement containingLibrary = element.library;
+ if (containingLibrary == null) {
+ return;
+ }
+ // Ignore if a local element.
+ if (library == containingLibrary) {
+ return;
+ }
+ // Remember the element.
+ usedElements.elements.add(element);
+ }
+
+ /**
+ * Given some [NodeList] of [Annotation]s, ensure that the identifiers are visited by
+ * this visitor. Specifically, this covers the cases where AST nodes don't have their identifiers
+ * visited by this visitor, but still need their annotations visited.
+ *
+ * @param annotations the list of annotations to visit
+ */
+ void _visitMetadata(NodeList<Annotation> annotations) {
+ int count = annotations.length;
+ for (int i = 0; i < count; i++) {
+ annotations[i].accept(this);
+ }
+ }
+}
+
+/**
+ * An [AstVisitor] that fills [UsedLocalElements].
+ */
+class GatherUsedLocalElementsVisitor extends RecursiveAstVisitor {
+ final UsedLocalElements usedElements = new UsedLocalElements();
+
+ final LibraryElement _enclosingLibrary;
+ ClassElement _enclosingClass;
+ ExecutableElement _enclosingExec;
+
+ GatherUsedLocalElementsVisitor(this._enclosingLibrary);
+
+ @override
+ visitCatchClause(CatchClause node) {
+ SimpleIdentifier exceptionParameter = node.exceptionParameter;
+ SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
+ if (exceptionParameter != null) {
+ Element element = exceptionParameter.staticElement;
+ usedElements.addCatchException(element);
+ if (stackTraceParameter != null || node.onKeyword == null) {
+ usedElements.addElement(element);
+ }
+ }
+ if (stackTraceParameter != null) {
+ Element element = stackTraceParameter.staticElement;
+ usedElements.addCatchStackTrace(element);
+ }
+ super.visitCatchClause(node);
+ }
+
+ @override
+ visitClassDeclaration(ClassDeclaration node) {
+ ClassElement enclosingClassOld = _enclosingClass;
+ try {
+ _enclosingClass = node.element;
+ super.visitClassDeclaration(node);
+ } finally {
+ _enclosingClass = enclosingClassOld;
+ }
+ }
+
+ @override
+ visitFunctionDeclaration(FunctionDeclaration node) {
+ ExecutableElement enclosingExecOld = _enclosingExec;
+ try {
+ _enclosingExec = node.element;
+ super.visitFunctionDeclaration(node);
+ } finally {
+ _enclosingExec = enclosingExecOld;
+ }
+ }
+
+ @override
+ visitFunctionExpression(FunctionExpression node) {
+ if (node.parent is! FunctionDeclaration) {
+ usedElements.addElement(node.element);
+ }
+ super.visitFunctionExpression(node);
+ }
+
+ @override
+ visitMethodDeclaration(MethodDeclaration node) {
+ ExecutableElement enclosingExecOld = _enclosingExec;
+ try {
+ _enclosingExec = node.element;
+ super.visitMethodDeclaration(node);
+ } finally {
+ _enclosingExec = enclosingExecOld;
+ }
+ }
+
+ @override
+ visitSimpleIdentifier(SimpleIdentifier node) {
+ if (node.inDeclarationContext()) {
+ return;
+ }
+ Element element = node.staticElement;
+ bool isIdentifierRead = _isReadIdentifier(node);
+ if (element is LocalVariableElement) {
+ if (isIdentifierRead) {
+ usedElements.addElement(element);
+ }
+ } else {
+ _useIdentifierElement(node);
+ if (element == null ||
+ element is! LocalElement && !identical(element, _enclosingExec)) {
+ usedElements.members.add(node.name);
+ if (isIdentifierRead) {
+ usedElements.readMembers.add(node.name);
+ }
+ }
+ }
+ }
+
+ @override
+ visitTypeName(TypeName node) {
+ _useIdentifierElement(node.name);
+ }
+
+ /**
+ * Marks an [Element] of [node] as used in the library.
+ */
+ void _useIdentifierElement(Identifier node) {
+ Element element = node.staticElement;
+ if (element == null) {
+ return;
+ }
+ // check if a local element
+ if (!identical(element.library, _enclosingLibrary)) {
+ return;
+ }
+ // ignore references to an element from itself
+ if (identical(element, _enclosingClass)) {
+ return;
+ }
+ if (identical(element, _enclosingExec)) {
+ return;
+ }
+ // ignore places where the element is not actually used
+ if (node.parent is TypeName) {
+ AstNode parent2 = node.parent.parent;
+ if (parent2 is IsExpression) {
+ return;
+ }
+ // We need to instantiate/extend/implement a class to actually use it.
+ // OTOH, function type aliases are used to define closure structures.
+ if (parent2 is VariableDeclarationList && element is ClassElement) {
+ return;
+ }
+ }
+ // OK
+ usedElements.addElement(element);
+ }
+
+ static bool _isReadIdentifier(SimpleIdentifier node) {
+ // not reading at all
+ if (!node.inGetterContext()) {
+ return false;
+ }
+ // check if useless reading
+ AstNode parent = node.parent;
+ if (parent.parent is ExpressionStatement &&
+ (parent is PrefixExpression ||
+ parent is PostfixExpression ||
+ parent is AssignmentExpression && parent.leftHandSide == node)) {
+ // v++;
+ // ++v;
+ // v += 2;
+ return false;
+ }
+ // OK
+ return true;
+ }
+}
+
+/**
* Instances of the class `HintGenerator` traverse a library's worth of dart code at a time to
* generate hints over the set of sources.
*
@@ -4358,7 +4616,7 @@
LibraryElement _library;
- ImportsVerifier _importsVerifier;
+ GatherUsedImportedElementsVisitor _usedImportedElementsVisitor;
bool _enableDart2JSHints = false;
@@ -4367,47 +4625,47 @@
*/
InheritanceManager _manager;
- _GatherUsedElementsVisitor _usedElementsVisitor;
+ GatherUsedLocalElementsVisitor _usedLocalElementsVisitor;
HintGenerator(this._compilationUnits, this._context, this._errorListener) {
_library = _compilationUnits[0].element.library;
- _importsVerifier = new ImportsVerifier(_library);
+ _usedImportedElementsVisitor =
+ new GatherUsedImportedElementsVisitor(_library);
_enableDart2JSHints = _context.analysisOptions.dart2jsHint;
_manager = new InheritanceManager(_compilationUnits[0].element.library);
- _usedElementsVisitor = new _GatherUsedElementsVisitor(_library);
+ _usedLocalElementsVisitor = new GatherUsedLocalElementsVisitor(_library);
}
void generateForLibrary() {
PerformanceStatistics.hints.makeCurrentWhile(() {
- for (int i = 0; i < _compilationUnits.length; i++) {
- CompilationUnitElement element = _compilationUnits[i].element;
+ for (CompilationUnit unit in _compilationUnits) {
+ CompilationUnitElement element = unit.element;
if (element != null) {
- if (i == 0) {
- _importsVerifier.inDefiningCompilationUnit = true;
- _generateForCompilationUnit(_compilationUnits[i], element.source);
- _importsVerifier.inDefiningCompilationUnit = false;
- } else {
- _generateForCompilationUnit(_compilationUnits[i], element.source);
- }
+ _generateForCompilationUnit(unit, element.source);
}
}
- ErrorReporter definingCompilationUnitErrorReporter = new ErrorReporter(
- _errorListener, _compilationUnits[0].element.source);
- _importsVerifier
- .generateDuplicateImportHints(definingCompilationUnitErrorReporter);
- _importsVerifier
- .generateUnusedImportHints(definingCompilationUnitErrorReporter);
- _library.accept(new _UnusedElementsVerifier(
- _errorListener, _usedElementsVisitor.usedElements));
+ CompilationUnit definingUnit = _compilationUnits[0];
+ ErrorReporter definingUnitErrorReporter =
+ new ErrorReporter(_errorListener, definingUnit.element.source);
+ {
+ ImportsVerifier importsVerifier = new ImportsVerifier();
+ importsVerifier.addImports(definingUnit);
+ importsVerifier
+ .removeUsedElements(_usedImportedElementsVisitor.usedElements);
+ importsVerifier.generateDuplicateImportHints(definingUnitErrorReporter);
+ importsVerifier.generateUnusedImportHints(definingUnitErrorReporter);
+ }
+ _library.accept(new UnusedLocalElementsVerifier(
+ _errorListener, _usedLocalElementsVisitor.usedElements));
});
}
void _generateForCompilationUnit(CompilationUnit unit, Source source) {
ErrorReporter errorReporter = new ErrorReporter(_errorListener, source);
- unit.accept(_importsVerifier);
+ unit.accept(_usedImportedElementsVisitor);
// dead code analysis
unit.accept(new DeadCodeVerifier(errorReporter));
- unit.accept(_usedElementsVisitor);
+ unit.accept(_usedLocalElementsVisitor);
// dart2js analysis
if (_enableDart2JSHints) {
unit.accept(new Dart2JSVerifier(errorReporter));
@@ -4415,7 +4673,7 @@
// Dart best practices
unit.accept(
new BestPracticesVerifier(errorReporter, _context.typeProvider));
- unit.accept(new OverrideVerifier(_manager, errorReporter));
+ unit.accept(new OverrideVerifier(errorReporter, _manager));
// Find to-do comments
new ToDoFinder(errorReporter).findIn(unit);
// pub analysis
@@ -5191,19 +5449,7 @@
* While this class does not yet have support for an "Organize Imports" action, this logic built up
* in this class could be used for such an action in the future.
*/
-class ImportsVerifier extends RecursiveAstVisitor<Object> {
- /**
- * This is set to `true` if the current compilation unit which is being visited is the
- * defining compilation unit for the library, its value can be set with
- * [setInDefiningCompilationUnit].
- */
- bool _inDefiningCompilationUnit = false;
-
- /**
- * The current library.
- */
- LibraryElement _currentLibrary;
-
+class ImportsVerifier /*extends RecursiveAstVisitor<Object>*/ {
/**
* A list of [ImportDirective]s that the current library imports, as identifiers are visited
* by this visitor and an import has been identified as being used by the library, the
@@ -5212,13 +5458,13 @@
*
* See [ImportsVerifier.generateUnusedImportErrors].
*/
- List<ImportDirective> _unusedImports;
+ final List<ImportDirective> _unusedImports = <ImportDirective>[];
/**
* After the list of [unusedImports] has been computed, this list is a proper subset of the
* unused imports that are listed more than once.
*/
- List<ImportDirective> _duplicateImports;
+ final List<ImportDirective> _duplicateImports = <ImportDirective>[];
/**
* This is a map between the set of [LibraryElement]s that the current library imports, and
@@ -5231,7 +5477,8 @@
* will need to be used to compute the correct [ImportDirective] being used, see
* [namespaceMap].
*/
- HashMap<LibraryElement, List<ImportDirective>> _libraryMap;
+ final HashMap<LibraryElement, List<ImportDirective>> _libraryMap =
+ new HashMap<LibraryElement, List<ImportDirective>>();
/**
* In cases where there is more than one import directive per library element, this mapping is
@@ -5239,7 +5486,8 @@
* [Namespace] for each of the imports to do lookups in the same way that they are done from
* the [ElementResolver].
*/
- HashMap<ImportDirective, Namespace> _namespaceMap;
+ final HashMap<ImportDirective, Namespace> _namespaceMap =
+ new HashMap<ImportDirective, Namespace>();
/**
* This is a map between prefix elements and the import directives from which they are derived. In
@@ -5251,25 +5499,71 @@
* it is possible to have an unreported unused import in situations where two imports use the same
* prefix and at least one import directive is used.
*/
- HashMap<PrefixElement, List<ImportDirective>> _prefixElementMap;
+ final HashMap<PrefixElement, List<ImportDirective>> _prefixElementMap =
+ new HashMap<PrefixElement, List<ImportDirective>>();
- /**
- * Create a new instance of the [ImportsVerifier].
- *
- * @param errorReporter the error reporter
- */
- ImportsVerifier(LibraryElement library) {
- this._currentLibrary = library;
- this._unusedImports = new List<ImportDirective>();
- this._duplicateImports = new List<ImportDirective>();
- this._libraryMap = new HashMap<LibraryElement, List<ImportDirective>>();
- this._namespaceMap = new HashMap<ImportDirective, Namespace>();
- this._prefixElementMap =
- new HashMap<PrefixElement, List<ImportDirective>>();
- }
-
- void set inDefiningCompilationUnit(bool inDefiningCompilationUnit) {
- this._inDefiningCompilationUnit = inDefiningCompilationUnit;
+ void addImports(CompilationUnit node) {
+ for (Directive directive in node.directives) {
+ if (directive is ImportDirective) {
+ ImportDirective importDirective = directive;
+ LibraryElement libraryElement = importDirective.uriElement;
+ if (libraryElement != null) {
+ _unusedImports.add(importDirective);
+ //
+ // Initialize prefixElementMap
+ //
+ if (importDirective.asKeyword != null) {
+ SimpleIdentifier prefixIdentifier = importDirective.prefix;
+ if (prefixIdentifier != null) {
+ Element element = prefixIdentifier.staticElement;
+ if (element is PrefixElement) {
+ PrefixElement prefixElementKey = element;
+ List<ImportDirective> list =
+ _prefixElementMap[prefixElementKey];
+ if (list == null) {
+ list = new List<ImportDirective>();
+ _prefixElementMap[prefixElementKey] = list;
+ }
+ list.add(importDirective);
+ }
+ // TODO (jwren) Can the element ever not be a PrefixElement?
+ }
+ }
+ //
+ // Initialize libraryMap: libraryElement -> importDirective
+ //
+ _putIntoLibraryMap(libraryElement, importDirective);
+ //
+ // For this new addition to the libraryMap, also recursively add any
+ // exports from the libraryElement.
+ //
+ _addAdditionalLibrariesForExports(
+ libraryElement, importDirective, new List<LibraryElement>());
+ }
+ }
+ }
+ if (_unusedImports.length > 1) {
+ // order the list of unusedImports to find duplicates in faster than
+ // O(n^2) time
+ List<ImportDirective> importDirectiveArray =
+ new List<ImportDirective>.from(_unusedImports);
+ importDirectiveArray.sort(ImportDirective.COMPARATOR);
+ ImportDirective currentDirective = importDirectiveArray[0];
+ for (int i = 1; i < importDirectiveArray.length; i++) {
+ ImportDirective nextDirective = importDirectiveArray[i];
+ if (ImportDirective.COMPARATOR(currentDirective, nextDirective) == 0) {
+ // Add either the currentDirective or nextDirective depending on which
+ // comes second, this guarantees that the first of the duplicates
+ // won't be highlighted.
+ if (currentDirective.offset < nextDirective.offset) {
+ _duplicateImports.add(nextDirective);
+ } else {
+ _duplicateImports.add(currentDirective);
+ }
+ }
+ currentDirective = nextDirective;
+ }
+ }
}
/**
@@ -5310,128 +5604,52 @@
}
}
- @override
- Object visitCompilationUnit(CompilationUnit node) {
- if (_inDefiningCompilationUnit) {
- NodeList<Directive> directives = node.directives;
- for (Directive directive in directives) {
- if (directive is ImportDirective) {
- ImportDirective importDirective = directive;
- LibraryElement libraryElement = importDirective.uriElement;
- if (libraryElement != null) {
- _unusedImports.add(importDirective);
- //
- // Initialize prefixElementMap
- //
- if (importDirective.asKeyword != null) {
- SimpleIdentifier prefixIdentifier = importDirective.prefix;
- if (prefixIdentifier != null) {
- Element element = prefixIdentifier.staticElement;
- if (element is PrefixElement) {
- PrefixElement prefixElementKey = element;
- List<ImportDirective> list =
- _prefixElementMap[prefixElementKey];
- if (list == null) {
- list = new List<ImportDirective>();
- _prefixElementMap[prefixElementKey] = list;
- }
- list.add(importDirective);
- }
- // TODO (jwren) Can the element ever not be a PrefixElement?
- }
- }
- //
- // Initialize libraryMap: libraryElement -> importDirective
- //
- _putIntoLibraryMap(libraryElement, importDirective);
- //
- // For this new addition to the libraryMap, also recursively add any
- // exports from the libraryElement.
- //
- _addAdditionalLibrariesForExports(
- libraryElement, importDirective, new List<LibraryElement>());
- }
- }
- }
- }
- // If there are no imports in this library, don't visit the identifiers in
- // the library- there can be no unused imports.
+ /**
+ * Remove elements from [_unusedImports] using the given [usedElements].
+ */
+ void removeUsedElements(UsedImportedElements usedElements) {
+ // Stop if all the imports are known to be used.
if (_unusedImports.isEmpty) {
- return null;
+ return;
}
- if (_unusedImports.length > 1) {
- // order the list of unusedImports to find duplicates in faster than
- // O(n^2) time
- List<ImportDirective> importDirectiveArray =
- new List.from(_unusedImports);
- importDirectiveArray.sort(ImportDirective.COMPARATOR);
- ImportDirective currentDirective = importDirectiveArray[0];
- for (int i = 1; i < importDirectiveArray.length; i++) {
- ImportDirective nextDirective = importDirectiveArray[i];
- if (ImportDirective.COMPARATOR(currentDirective, nextDirective) == 0) {
- // Add either the currentDirective or nextDirective depending on which
- // comes second, this guarantees that the first of the duplicates
- // won't be highlighted.
- if (currentDirective.offset < nextDirective.offset) {
- _duplicateImports.add(nextDirective);
- } else {
- _duplicateImports.add(currentDirective);
- }
- }
- currentDirective = nextDirective;
- }
- }
- return super.visitCompilationUnit(node);
- }
-
- @override
- Object visitExportDirective(ExportDirective node) {
- _visitMetadata(node.metadata);
- return null;
- }
-
- @override
- Object visitImportDirective(ImportDirective node) {
- _visitMetadata(node.metadata);
- return null;
- }
-
- @override
- Object visitLibraryDirective(LibraryDirective node) {
- _visitMetadata(node.metadata);
- return null;
- }
-
- @override
- Object visitPrefixedIdentifier(PrefixedIdentifier node) {
- if (_unusedImports.isEmpty) {
- return null;
- }
- // If the prefixed identifier references some A.B, where A is a library
- // prefix, then we can lookup the associated ImportDirective in
- // prefixElementMap and remove it from the unusedImports list.
- SimpleIdentifier prefixIdentifier = node.prefix;
- Element element = prefixIdentifier.staticElement;
- if (element is PrefixElement) {
- List<ImportDirective> importDirectives = _prefixElementMap[element];
+ // Process import prefixes.
+ for (PrefixElement prefix in usedElements.prefixes) {
+ List<ImportDirective> importDirectives = _prefixElementMap[prefix];
if (importDirectives != null) {
for (ImportDirective importDirective in importDirectives) {
_unusedImports.remove(importDirective);
}
}
- return null;
}
- // Otherwise, pass the prefixed identifier element and name onto
- // visitIdentifier.
- return _visitIdentifier(element, prefixIdentifier.name);
- }
-
- @override
- Object visitSimpleIdentifier(SimpleIdentifier node) {
- if (_unusedImports.isEmpty) {
- return null;
+ // Process top-level elements.
+ for (Element element in usedElements.elements) {
+ // Stop if all the imports are known to be used.
+ if (_unusedImports.isEmpty) {
+ return;
+ }
+ // Prepare import directives for this library.
+ LibraryElement library = element.library;
+ List<ImportDirective> importsLibrary = _libraryMap[library];
+ if (importsLibrary == null) {
+ continue;
+ }
+ // If there is only one import directive for this library, then it must be
+ // the directive that this element is imported with, remove it from the
+ // unusedImports list.
+ if (importsLibrary.length == 1) {
+ ImportDirective usedImportDirective = importsLibrary[0];
+ _unusedImports.remove(usedImportDirective);
+ continue;
+ }
+ // Otherwise, find import directives using namespaces.
+ String name = element.displayName;
+ for (ImportDirective importDirective in importsLibrary) {
+ Namespace namespace = _computeNamespace(importDirective);
+ if (namespace != null && namespace.get(name) != null) {
+ _unusedImports.remove(importDirective);
+ }
+ }
}
- return _visitIdentifier(node.staticElement, node.name);
}
/**
@@ -5488,79 +5706,6 @@
}
importList.add(importDirective);
}
-
- Object _visitIdentifier(Element element, String name) {
- if (element == null) {
- return null;
- }
- // If the element is multiply defined then call this method recursively for
- // each of the conflicting elements.
- if (element is MultiplyDefinedElement) {
- MultiplyDefinedElement multiplyDefinedElement = element;
- for (Element elt in multiplyDefinedElement.conflictingElements) {
- _visitIdentifier(elt, name);
- }
- return null;
- } else if (element is PrefixElement) {
- List<ImportDirective> importDirectives = _prefixElementMap[element];
- if (importDirectives != null) {
- for (ImportDirective importDirective in importDirectives) {
- _unusedImports.remove(importDirective);
- }
- }
- return null;
- } else if (element.enclosingElement is! CompilationUnitElement) {
- // Identifiers that aren't a prefix element and whose enclosing element
- // isn't a CompilationUnit are ignored- this covers the case the
- // identifier is a relative-reference, a reference to an identifier not
- // imported by this library.
- return null;
- }
- LibraryElement containingLibrary = element.library;
- if (containingLibrary == null) {
- return null;
- }
- // If the element is declared in the current library, return.
- if (_currentLibrary == containingLibrary) {
- return null;
- }
- List<ImportDirective> importsFromSameLibrary =
- _libraryMap[containingLibrary];
- if (importsFromSameLibrary == null) {
- return null;
- }
- if (importsFromSameLibrary.length == 1) {
- // If there is only one import directive for this library, then it must be
- // the directive that this element is imported with, remove it from the
- // unusedImports list.
- ImportDirective usedImportDirective = importsFromSameLibrary[0];
- _unusedImports.remove(usedImportDirective);
- } else {
- // Otherwise, for each of the imported directives, use the namespaceMap to
- for (ImportDirective importDirective in importsFromSameLibrary) {
- // Get the namespace for this import
- Namespace namespace = _computeNamespace(importDirective);
- if (namespace != null && namespace.get(name) != null) {
- _unusedImports.remove(importDirective);
- }
- }
- }
- return null;
- }
-
- /**
- * Given some [NodeList] of [Annotation]s, ensure that the identifiers are visited by
- * this visitor. Specifically, this covers the cases where AST nodes don't have their identifiers
- * visited by this visitor, but still need their annotations visited.
- *
- * @param annotations the list of annotations to visit
- */
- void _visitMetadata(NodeList<Annotation> annotations) {
- int count = annotations.length;
- for (int i = 0; i < count; i++) {
- annotations[i].accept(this);
- }
- }
}
/**
@@ -7542,6 +7687,11 @@
TypeProvider _typeProvider;
/**
+ * The object used to access the types from the core library.
+ */
+ TypeProvider get typeProvider => _typeProvider;
+
+ /**
* A table mapping library sources to the information being maintained for those libraries.
*/
HashMap<Source, Library> _libraryMap = new HashMap<Source, Library>();
@@ -7677,7 +7827,7 @@
// method and punt the decision to the clients.
//
//if (analyzeAll) {
- _resolveReferencesAndTypes();
+ resolveReferencesAndTypes();
//} else {
// resolveReferencesAndTypes(targetLibrary);
//}
@@ -7758,7 +7908,7 @@
// method and punt the decision to the clients.
//
//if (analyzeAll) {
- _resolveReferencesAndTypes();
+ resolveReferencesAndTypes();
//} else {
// resolveReferencesAndTypes(targetLibrary);
//}
@@ -8326,7 +8476,7 @@
* @throws AnalysisException if any of the identifiers could not be resolved or if any of the
* libraries could not have their types analyzed
*/
- void _resolveReferencesAndTypes() {
+ void resolveReferencesAndTypes() {
for (Library library in _librariesInCycles) {
_resolveReferencesAndTypesInLibrary(library);
}
@@ -9494,22 +9644,22 @@
*/
class OverrideVerifier extends RecursiveAstVisitor<Object> {
/**
- * The inheritance manager used to find overridden methods.
- */
- final InheritanceManager _manager;
-
- /**
* The error reporter used to report errors.
*/
final ErrorReporter _errorReporter;
/**
+ * The inheritance manager used to find overridden methods.
+ */
+ final InheritanceManager _manager;
+
+ /**
* Initialize a newly created verifier to look for inappropriate uses of the override annotation.
*
- * @param manager the inheritance manager used to find overridden methods
* @param errorReporter the error reporter used to report errors
+ * @param manager the inheritance manager used to find overridden methods
*/
- OverrideVerifier(this._manager, this._errorReporter);
+ OverrideVerifier(this._errorReporter, this._manager);
@override
Object visitMethodDeclaration(MethodDeclaration node) {
@@ -10087,12 +10237,12 @@
/**
* The object used to resolve the element associated with the current node.
*/
- ElementResolver _elementResolver;
+ ElementResolver elementResolver;
/**
* The object used to compute the type associated with the current node.
*/
- StaticTypeAnalyzer _typeAnalyzer;
+ StaticTypeAnalyzer typeAnalyzer;
/**
* The class element representing the class containing the current node,
@@ -10157,8 +10307,8 @@
StaticTypeAnalyzerFactory typeAnalyzerFactory})
: super.con1(library, source, typeProvider) {
this._inheritanceManager = library.inheritanceManager;
- this._elementResolver = new ElementResolver(this);
- this._typeAnalyzer = typeAnalyzer != null
+ this.elementResolver = new ElementResolver(this);
+ this.typeAnalyzer = typeAnalyzer != null
? typeAnalyzer
: (typeAnalyzerFactory != null
? typeAnalyzerFactory(this)
@@ -10180,8 +10330,8 @@
AnalysisErrorListener errorListener)
: super.con2(definingLibrary, source, typeProvider, errorListener) {
this._inheritanceManager = inheritanceManager;
- this._elementResolver = new ElementResolver(this);
- this._typeAnalyzer = new StaticTypeAnalyzer(this);
+ this.elementResolver = new ElementResolver(this);
+ this.typeAnalyzer = new StaticTypeAnalyzer(this);
}
/**
@@ -10200,8 +10350,8 @@
: super.con3(
definingLibrary, source, typeProvider, nameScope, errorListener) {
this._inheritanceManager = new InheritanceManager(definingLibrary);
- this._elementResolver = new ElementResolver(this);
- this._typeAnalyzer = new StaticTypeAnalyzer(this);
+ this.elementResolver = new ElementResolver(this);
+ this.typeAnalyzer = new StaticTypeAnalyzer(this);
}
/**
@@ -10215,14 +10365,10 @@
ResolvableLibrary library, Source source, TypeProvider typeProvider)
: super.con4(library, source, typeProvider) {
this._inheritanceManager = library.inheritanceManager;
- this._elementResolver = new ElementResolver(this);
- this._typeAnalyzer = new StaticTypeAnalyzer(this);
+ this.elementResolver = new ElementResolver(this);
+ this.typeAnalyzer = new StaticTypeAnalyzer(this);
}
- get elementResolver_J2DAccessor => _elementResolver;
-
- set elementResolver_J2DAccessor(__v) => _elementResolver = __v;
-
/**
* Return the element representing the function containing the current node, or `null` if
* the current node is not contained in a function.
@@ -10231,14 +10377,6 @@
*/
ExecutableElement get enclosingFunction => _enclosingFunction;
- get labelScope_J2DAccessor => _labelScope;
-
- set labelScope_J2DAccessor(__v) => _labelScope = __v;
-
- get nameScope_J2DAccessor => _nameScope;
-
- set nameScope_J2DAccessor(__v) => _nameScope = __v;
-
/**
* Return the object keeping track of which elements have had their types overridden.
*
@@ -10253,10 +10391,6 @@
*/
TypePromotionManager get promoteManager => _promoteManager;
- get typeAnalyzer_J2DAccessor => _typeAnalyzer;
-
- set typeAnalyzer_J2DAccessor(__v) => _typeAnalyzer = __v;
-
/**
* Return the propagated element associated with the given expression whose type can be
* overridden, or `null` if there is no element whose type can be overridden.
@@ -10351,7 +10485,9 @@
Expression expression, DartType potentialType, bool allowPrecisionLoss) {
VariableElement element = getOverridableStaticElement(expression);
if (element != null) {
- overrideVariable(element, potentialType, allowPrecisionLoss);
+ DartType newBestType =
+ overrideVariable(element, potentialType, allowPrecisionLoss);
+ recordPropagatedTypeIfBetter(expression, newBestType);
}
element = getOverridablePropagatedElement(expression);
if (element != null) {
@@ -10367,16 +10503,19 @@
* @param potentialType the potential type of the element
* @param allowPrecisionLoss true if `potentialType` is allowed to be less precise than the
* current best type
+ *
+ * Return a new better [DartType], or `null` if [potentialType] is not better
+ * than the current [element] type.
*/
- void overrideVariable(VariableElement element, DartType potentialType,
+ DartType overrideVariable(VariableElement element, DartType potentialType,
bool allowPrecisionLoss) {
if (potentialType == null || potentialType.isBottom) {
- return;
+ return null;
}
DartType currentType = _overrideManager.getBestType(element);
if (potentialType == currentType) {
- return;
+ return null;
}
// If we aren't allowing precision loss then the third and fourth conditions
@@ -10415,7 +10554,44 @@
// potentialType;
// }
_overrideManager.setType(element, potentialType);
+ return potentialType;
}
+ return null;
+ }
+
+ /**
+ * If the given [type] is valid, strongly more specific than the
+ * existing static type of the given [expression], record it as a propagated
+ * type of the given [expression]. Otherwise, reset it to `null`.
+ *
+ * If [hasOldPropagatedType] is `true` then the existing propagated type
+ * should also is checked.
+ */
+ void recordPropagatedTypeIfBetter(Expression expression, DartType type,
+ [bool hasOldPropagatedType = false]) {
+ // Ensure that propagated type invalid.
+ if (type == null || type.isDynamic || type.isBottom) {
+ if (!hasOldPropagatedType) {
+ expression.propagatedType = null;
+ }
+ return;
+ }
+ // Ensure that propagated type is more specific than the static type.
+ DartType staticType = expression.staticType;
+ if (type == staticType || !type.isMoreSpecificThan(staticType)) {
+ expression.propagatedType = null;
+ return;
+ }
+ // Ensure that the new propagated type is more specific than the old one.
+ if (hasOldPropagatedType) {
+ DartType oldPropagatedType = expression.propagatedType;
+ if (oldPropagatedType != null &&
+ !type.isMoreSpecificThan(oldPropagatedType)) {
+ return;
+ }
+ }
+ // OK
+ expression.propagatedType = type;
}
@override
@@ -10488,8 +10664,8 @@
safelyVisit(leftOperand);
safelyVisit(rightOperand);
}
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -10511,8 +10687,8 @@
// We do not visit the label because it needs to be visited in the context
// of the statement.
//
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -10531,13 +10707,13 @@
ClassElement outerType = enclosingClass;
try {
enclosingClass = node.element;
- _typeAnalyzer.thisType =
+ typeAnalyzer.thisType =
enclosingClass == null ? null : enclosingClass.type;
super.visitClassDeclaration(node);
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
} finally {
- _typeAnalyzer.thisType = outerType == null ? null : outerType.type;
+ typeAnalyzer.thisType = outerType == null ? null : outerType.type;
enclosingClass = outerType;
_enclosingClassDeclaration = null;
}
@@ -10560,10 +10736,9 @@
// Continue the class resolution.
//
enclosingClass = node.element;
- _typeAnalyzer.thisType =
- enclosingClass == null ? null : enclosingClass.type;
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ typeAnalyzer.thisType = enclosingClass == null ? null : enclosingClass.type;
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
}
@override
@@ -10587,8 +10762,8 @@
// We do not visit the identifier because it needs to be visited in the
// context of the reference.
//
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -10628,8 +10803,8 @@
} finally {
_overrideManager.exitScope();
}
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -10668,8 +10843,8 @@
_overrideManager.exitScope();
}
}
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
bool thenIsAbrupt = _isAbruptTerminationExpression(thenExpression);
bool elseIsAbrupt = _isAbruptTerminationExpression(elseExpression);
if (elseIsAbrupt && !thenIsAbrupt) {
@@ -10691,6 +10866,9 @@
} finally {
_enclosingFunction = outerFunction;
}
+ ConstructorElementImpl constructor = node.element;
+ constructor.constantInitializers =
+ new ConstantAstCloner().cloneNodeList(node.initializers);
return null;
}
@@ -10701,8 +10879,8 @@
// to be visited in the context of the constructor field initializer node.
//
safelyVisit(node.expression);
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -10713,8 +10891,8 @@
// or the name, because it needs to be visited in the context of the
// constructor name.
//
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -10724,8 +10902,8 @@
// We do not visit the label because it needs to be visited in the context
// of the statement.
//
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -10842,8 +11020,8 @@
_overrideManager.exitScope();
}
}
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
}
@override
@@ -10907,10 +11085,10 @@
@override
Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
safelyVisit(node.function);
- node.accept(_elementResolver);
+ node.accept(elementResolver);
_inferFunctionExpressionsParametersTypes(node.argumentList);
safelyVisit(node.argumentList);
- node.accept(_typeAnalyzer);
+ node.accept(typeAnalyzer);
return null;
}
@@ -10974,8 +11152,8 @@
_overrideManager.exitScope();
}
}
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
// Join overrides.
bool thenIsAbrupt = _isAbruptTerminationStatement(thenStatement);
bool elseIsAbrupt = _isAbruptTerminationStatement(elseStatement);
@@ -10986,13 +11164,11 @@
_propagateFalseState(condition);
_overrideManager.applyOverrides(elseOverrides);
} else if (!thenIsAbrupt && !elseIsAbrupt) {
- if (AnalysisEngine.instance.enableUnionTypes) {
- List<Map<VariableElement, DartType>> perBranchOverrides =
- new List<Map<VariableElement, DartType>>();
- perBranchOverrides.add(thenOverrides);
- perBranchOverrides.add(elseOverrides);
- _overrideManager.joinOverrides(perBranchOverrides);
- }
+ List<Map<VariableElement, DartType>> perBranchOverrides =
+ new List<Map<VariableElement, DartType>>();
+ perBranchOverrides.add(thenOverrides);
+ perBranchOverrides.add(elseOverrides);
+ _overrideManager.mergeOverrides(perBranchOverrides);
}
return null;
}
@@ -11022,18 +11198,18 @@
// because it needs to be visited in the context of the invocation.
//
safelyVisit(node.target);
- node.accept(_elementResolver);
+ node.accept(elementResolver);
_inferFunctionExpressionsParametersTypes(node.argumentList);
safelyVisit(node.argumentList);
- node.accept(_typeAnalyzer);
+ node.accept(typeAnalyzer);
return null;
}
@override
Object visitNode(AstNode node) {
node.visitChildren(this);
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -11044,8 +11220,8 @@
// be visited in the context of the prefix.
//
safelyVisit(node.prefix);
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -11056,8 +11232,8 @@
// to be visited in the context of the property access node.
//
safelyVisit(node.target);
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -11070,8 +11246,8 @@
// invocation.
//
safelyVisit(node.argumentList);
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -11086,8 +11262,8 @@
// invocation.
//
safelyVisit(node.argumentList);
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -11131,6 +11307,16 @@
Object visitTypeName(TypeName node) => null;
@override
+ Object visitVariableDeclaration(VariableDeclaration node) {
+ super.visitVariableDeclaration(node);
+ if (node.element.isConst && node.initializer != null) {
+ (node.element as ConstVariableElement).constantInitializer =
+ new ConstantAstCloner().cloneNode(node.initializer);
+ }
+ return null;
+ }
+
+ @override
Object visitWhileStatement(WhileStatement node) {
// Note: since we don't call the base class, we have to maintain
// _implicitLabelScope ourselves.
@@ -11154,8 +11340,8 @@
}
// TODO(brianwilkerson) If the loop can only be exited because the condition
// is false, then propagateFalseState(condition);
- node.accept(_elementResolver);
- node.accept(_typeAnalyzer);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
return null;
}
@@ -11397,7 +11583,7 @@
VariableElement element = getPromotionStaticElement(expression);
if (element != null) {
// may be mutated somewhere in closure
- if ((element as VariableElementImpl).isPotentiallyMutatedInClosure) {
+ if (element.isPotentiallyMutatedInClosure) {
return;
}
// prepare current variable type
@@ -11748,7 +11934,7 @@
/**
* The scope used to resolve identifiers.
*/
- Scope _nameScope;
+ Scope nameScope;
/**
* The object used to access the types from the core library.
@@ -11764,7 +11950,7 @@
* The scope used to resolve labels for `break` and `continue` statements, or
* `null` if no labels have been defined in the current context.
*/
- LabelScope _labelScope;
+ LabelScope labelScope;
/**
* The class containing the AST nodes being visited,
@@ -11783,7 +11969,7 @@
this._definingLibrary = library.libraryElement;
LibraryScope libraryScope = library.libraryScope;
this._errorListener = libraryScope.errorListener;
- this._nameScope = libraryScope;
+ this.nameScope = libraryScope;
}
/**
@@ -11800,7 +11986,7 @@
this.typeProvider, AnalysisErrorListener errorListener) {
this._definingLibrary = definingLibrary;
this._errorListener = errorListener;
- this._nameScope = new LibraryScope(definingLibrary, errorListener);
+ this.nameScope = new LibraryScope(definingLibrary, errorListener);
}
/**
@@ -11818,7 +12004,7 @@
this.typeProvider, Scope nameScope, AnalysisErrorListener errorListener) {
this._definingLibrary = definingLibrary;
this._errorListener = errorListener;
- this._nameScope = nameScope;
+ this.nameScope = nameScope;
}
/**
@@ -11833,7 +12019,7 @@
this._definingLibrary = library.libraryElement;
LibraryScope libraryScope = library.libraryScope;
this._errorListener = libraryScope.errorListener;
- this._nameScope = libraryScope;
+ this.nameScope = libraryScope;
}
/**
@@ -11850,27 +12036,13 @@
ImplicitLabelScope get implicitLabelScope => _implicitLabelScope;
/**
- * Return the label scope in which the current node is being resolved.
- *
- * @return the label scope in which the current node is being resolved
- */
- LabelScope get labelScope => _labelScope;
-
- /**
- * Return the name scope in which the current node is being resolved.
- *
- * @return the name scope in which the current node is being resolved
- */
- Scope get nameScope => _nameScope;
-
- /**
* Replaces the current [Scope] with the enclosing [Scope].
*
* @return the enclosing [Scope].
*/
Scope popNameScope() {
- _nameScope = _nameScope.enclosingScope;
- return _nameScope;
+ nameScope = nameScope.enclosingScope;
+ return nameScope;
}
/**
@@ -11879,9 +12051,9 @@
* @return the new [Scope].
*/
Scope pushNameScope() {
- Scope newScope = new EnclosedScope(_nameScope);
- _nameScope = newScope;
- return _nameScope;
+ Scope newScope = new EnclosedScope(nameScope);
+ nameScope = newScope;
+ return nameScope;
}
/**
@@ -11937,14 +12109,14 @@
@override
Object visitBlock(Block node) {
- Scope outerScope = _nameScope;
+ Scope outerScope = nameScope;
try {
- EnclosedScope enclosedScope = new EnclosedScope(_nameScope);
+ EnclosedScope enclosedScope = new EnclosedScope(nameScope);
_hideNamesDefinedInBlock(enclosedScope, node);
- _nameScope = enclosedScope;
+ nameScope = enclosedScope;
super.visitBlock(node);
} finally {
- _nameScope = outerScope;
+ nameScope = outerScope;
}
return null;
}
@@ -11965,17 +12137,17 @@
Object visitCatchClause(CatchClause node) {
SimpleIdentifier exception = node.exceptionParameter;
if (exception != null) {
- Scope outerScope = _nameScope;
+ Scope outerScope = nameScope;
try {
- _nameScope = new EnclosedScope(_nameScope);
- _nameScope.define(exception.staticElement);
+ nameScope = new EnclosedScope(nameScope);
+ nameScope.define(exception.staticElement);
SimpleIdentifier stackTrace = node.stackTraceParameter;
if (stackTrace != null) {
- _nameScope.define(stackTrace.staticElement);
+ nameScope.define(stackTrace.staticElement);
}
super.visitCatchClause(node);
} finally {
- _nameScope = outerScope;
+ nameScope = outerScope;
}
} else {
super.visitCatchClause(node);
@@ -11986,7 +12158,7 @@
@override
Object visitClassDeclaration(ClassDeclaration node) {
ClassElement classElement = node.element;
- Scope outerScope = _nameScope;
+ Scope outerScope = nameScope;
try {
if (classElement == null) {
AnalysisEngine.instance.logger.logInformation(
@@ -11997,16 +12169,16 @@
ClassElement outerClass = enclosingClass;
try {
enclosingClass = node.element;
- _nameScope = new TypeParameterScope(_nameScope, classElement);
+ nameScope = new TypeParameterScope(nameScope, classElement);
visitClassDeclarationInScope(node);
- _nameScope = new ClassScope(_nameScope, classElement);
+ nameScope = new ClassScope(nameScope, classElement);
visitClassMembersInScope(node);
} finally {
enclosingClass = outerClass;
}
}
} finally {
- _nameScope = outerScope;
+ nameScope = outerScope;
}
return null;
}
@@ -12028,14 +12200,14 @@
@override
Object visitClassTypeAlias(ClassTypeAlias node) {
- Scope outerScope = _nameScope;
+ Scope outerScope = nameScope;
try {
ClassElement element = node.element;
- _nameScope =
- new ClassScope(new TypeParameterScope(_nameScope, element), element);
+ nameScope =
+ new ClassScope(new TypeParameterScope(nameScope, element), element);
super.visitClassTypeAlias(node);
} finally {
- _nameScope = outerScope;
+ nameScope = outerScope;
}
return null;
}
@@ -12043,7 +12215,7 @@
@override
Object visitConstructorDeclaration(ConstructorDeclaration node) {
ConstructorElement constructorElement = node.element;
- Scope outerScope = _nameScope;
+ Scope outerScope = nameScope;
try {
if (constructorElement == null) {
StringBuffer buffer = new StringBuffer();
@@ -12058,11 +12230,11 @@
AnalysisEngine.instance.logger.logInformation(buffer.toString(),
new CaughtException(new AnalysisException(), null));
} else {
- _nameScope = new FunctionScope(_nameScope, constructorElement);
+ nameScope = new FunctionScope(nameScope, constructorElement);
}
super.visitConstructorDeclaration(node);
} finally {
- _nameScope = outerScope;
+ nameScope = outerScope;
}
return null;
}
@@ -12071,7 +12243,7 @@
Object visitDeclaredIdentifier(DeclaredIdentifier node) {
VariableElement element = node.element;
if (element != null) {
- _nameScope.define(element);
+ nameScope.define(element);
}
super.visitDeclaredIdentifier(node);
return null;
@@ -12092,14 +12264,14 @@
@override
Object visitForEachStatement(ForEachStatement node) {
- Scope outerNameScope = _nameScope;
+ Scope outerNameScope = nameScope;
ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
try {
- _nameScope = new EnclosedScope(_nameScope);
+ nameScope = new EnclosedScope(nameScope);
_implicitLabelScope = _implicitLabelScope.nest(node);
visitForEachStatementInScope(node);
} finally {
- _nameScope = outerNameScope;
+ nameScope = outerNameScope;
_implicitLabelScope = outerImplicitScope;
}
return null;
@@ -12130,26 +12302,26 @@
// scope. Note: we must not do this if the parent is a
// FunctionTypedFormalParameter, because in that case we aren't finished
// resolving the full function signature, just a part of it.
- if (_nameScope is FunctionScope &&
+ if (nameScope is FunctionScope &&
node.parent is! FunctionTypedFormalParameter) {
- (_nameScope as FunctionScope).defineParameters();
+ (nameScope as FunctionScope).defineParameters();
}
- if (_nameScope is FunctionTypeScope) {
- (_nameScope as FunctionTypeScope).defineParameters();
+ if (nameScope is FunctionTypeScope) {
+ (nameScope as FunctionTypeScope).defineParameters();
}
return null;
}
@override
Object visitForStatement(ForStatement node) {
- Scope outerNameScope = _nameScope;
+ Scope outerNameScope = nameScope;
ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
try {
- _nameScope = new EnclosedScope(_nameScope);
+ nameScope = new EnclosedScope(nameScope);
_implicitLabelScope = _implicitLabelScope.nest(node);
visitForStatementInScope(node);
} finally {
- _nameScope = outerNameScope;
+ nameScope = outerNameScope;
_implicitLabelScope = outerImplicitScope;
}
return null;
@@ -12175,20 +12347,20 @@
ExecutableElement functionElement = node.element;
if (functionElement != null &&
functionElement.enclosingElement is! CompilationUnitElement) {
- _nameScope.define(functionElement);
+ nameScope.define(functionElement);
}
- Scope outerScope = _nameScope;
+ Scope outerScope = nameScope;
try {
if (functionElement == null) {
AnalysisEngine.instance.logger.logInformation(
"Missing element for top-level function ${node.name.name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
} else {
- _nameScope = new FunctionScope(_nameScope, functionElement);
+ nameScope = new FunctionScope(nameScope, functionElement);
}
super.visitFunctionDeclaration(node);
} finally {
- _nameScope = outerScope;
+ nameScope = outerScope;
}
return null;
}
@@ -12199,7 +12371,7 @@
// We have already created a function scope and don't need to do so again.
super.visitFunctionExpression(node);
} else {
- Scope outerScope = _nameScope;
+ Scope outerScope = nameScope;
try {
ExecutableElement functionElement = node.element;
if (functionElement == null) {
@@ -12220,11 +12392,11 @@
AnalysisEngine.instance.logger.logInformation(buffer.toString(),
new CaughtException(new AnalysisException(), null));
} else {
- _nameScope = new FunctionScope(_nameScope, functionElement);
+ nameScope = new FunctionScope(nameScope, functionElement);
}
super.visitFunctionExpression(node);
} finally {
- _nameScope = outerScope;
+ nameScope = outerScope;
}
}
return null;
@@ -12232,12 +12404,12 @@
@override
Object visitFunctionTypeAlias(FunctionTypeAlias node) {
- Scope outerScope = _nameScope;
+ Scope outerScope = nameScope;
try {
- _nameScope = new FunctionTypeScope(_nameScope, node.element);
+ nameScope = new FunctionTypeScope(nameScope, node.element);
super.visitFunctionTypeAlias(node);
} finally {
- _nameScope = outerScope;
+ nameScope = outerScope;
}
return null;
}
@@ -12256,14 +12428,14 @@
try {
super.visitLabeledStatement(node);
} finally {
- _labelScope = outerScope;
+ labelScope = outerScope;
}
return null;
}
@override
Object visitMethodDeclaration(MethodDeclaration node) {
- Scope outerScope = _nameScope;
+ Scope outerScope = nameScope;
try {
ExecutableElement methodElement = node.element;
if (methodElement == null) {
@@ -12271,11 +12443,11 @@
"Missing element for method ${node.name.name} in ${definingLibrary.source.fullName}",
new CaughtException(new AnalysisException(), null));
} else {
- _nameScope = new FunctionScope(_nameScope, methodElement);
+ nameScope = new FunctionScope(nameScope, methodElement);
}
super.visitMethodDeclaration(node);
} finally {
- _nameScope = outerScope;
+ nameScope = outerScope;
}
return null;
}
@@ -12292,12 +12464,12 @@
// own scope.
visitBlock(node);
} else if (node != null) {
- Scope outerNameScope = _nameScope;
+ Scope outerNameScope = nameScope;
try {
- _nameScope = new EnclosedScope(_nameScope);
+ nameScope = new EnclosedScope(nameScope);
node.accept(this);
} finally {
- _nameScope = outerNameScope;
+ nameScope = outerNameScope;
}
}
}
@@ -12305,31 +12477,31 @@
@override
Object visitSwitchCase(SwitchCase node) {
node.expression.accept(this);
- Scope outerNameScope = _nameScope;
+ Scope outerNameScope = nameScope;
try {
- _nameScope = new EnclosedScope(_nameScope);
+ nameScope = new EnclosedScope(nameScope);
node.statements.accept(this);
} finally {
- _nameScope = outerNameScope;
+ nameScope = outerNameScope;
}
return null;
}
@override
Object visitSwitchDefault(SwitchDefault node) {
- Scope outerNameScope = _nameScope;
+ Scope outerNameScope = nameScope;
try {
- _nameScope = new EnclosedScope(_nameScope);
+ nameScope = new EnclosedScope(nameScope);
node.statements.accept(this);
} finally {
- _nameScope = outerNameScope;
+ nameScope = outerNameScope;
}
return null;
}
@override
Object visitSwitchStatement(SwitchStatement node) {
- LabelScope outerScope = _labelScope;
+ LabelScope outerScope = labelScope;
ImplicitLabelScope outerImplicitScope = _implicitLabelScope;
try {
_implicitLabelScope = _implicitLabelScope.nest(node);
@@ -12337,13 +12509,13 @@
for (Label label in member.labels) {
SimpleIdentifier labelName = label.label;
LabelElement labelElement = labelName.staticElement as LabelElement;
- _labelScope =
- new LabelScope(_labelScope, labelName.name, member, labelElement);
+ labelScope =
+ new LabelScope(labelScope, labelName.name, member, labelElement);
}
}
super.visitSwitchStatement(node);
} finally {
- _labelScope = outerScope;
+ labelScope = outerScope;
_implicitLabelScope = outerImplicitScope;
}
return null;
@@ -12356,7 +12528,7 @@
node.parent.parent is! FieldDeclaration) {
VariableElement element = node.element;
if (element != null) {
- _nameScope.define(element);
+ nameScope.define(element);
}
}
return null;
@@ -12382,12 +12554,12 @@
* @return the scope that was in effect before the new scopes were added
*/
LabelScope _addScopesFor(NodeList<Label> labels, AstNode node) {
- LabelScope outerScope = _labelScope;
+ LabelScope outerScope = labelScope;
for (Label label in labels) {
SimpleIdentifier labelNameNode = label.label;
String labelName = labelNameNode.name;
LabelElement labelElement = labelNameNode.staticElement as LabelElement;
- _labelScope = new LabelScope(_labelScope, labelName, node, labelElement);
+ labelScope = new LabelScope(labelScope, labelName, node, labelElement);
}
return outerScope;
}
@@ -12646,7 +12818,7 @@
/**
* The current override scope, or `null` if no scope has been entered.
*/
- TypeOverrideManager_TypeOverrideScope _currentScope;
+ TypeOverrideManager_TypeOverrideScope currentScope;
/**
* Apply a set of overrides that were previously captured.
@@ -12654,10 +12826,10 @@
* @param overrides the overrides to be applied
*/
void applyOverrides(Map<VariableElement, DartType> overrides) {
- if (_currentScope == null) {
+ if (currentScope == null) {
throw new IllegalStateException("Cannot apply overrides without a scope");
}
- _currentScope.applyOverrides(overrides);
+ currentScope.applyOverrides(overrides);
}
/**
@@ -12667,11 +12839,11 @@
* @return the overrides in the current scope
*/
Map<VariableElement, DartType> captureLocalOverrides() {
- if (_currentScope == null) {
+ if (currentScope == null) {
throw new IllegalStateException(
"Cannot capture local overrides without a scope");
}
- return _currentScope.captureLocalOverrides();
+ return currentScope.captureLocalOverrides();
}
/**
@@ -12683,28 +12855,28 @@
*/
Map<VariableElement, DartType> captureOverrides(
VariableDeclarationList variableList) {
- if (_currentScope == null) {
+ if (currentScope == null) {
throw new IllegalStateException(
"Cannot capture overrides without a scope");
}
- return _currentScope.captureOverrides(variableList);
+ return currentScope.captureOverrides(variableList);
}
/**
* Enter a new override scope.
*/
void enterScope() {
- _currentScope = new TypeOverrideManager_TypeOverrideScope(_currentScope);
+ currentScope = new TypeOverrideManager_TypeOverrideScope(currentScope);
}
/**
* Exit the current override scope.
*/
void exitScope() {
- if (_currentScope == null) {
+ if (currentScope == null) {
throw new IllegalStateException("No scope to exit");
}
- _currentScope = _currentScope._outerScope;
+ currentScope = currentScope._outerScope;
}
/**
@@ -12727,83 +12899,28 @@
* @return the overridden type of the given element
*/
DartType getType(Element element) {
- if (_currentScope == null) {
+ if (currentScope == null) {
return null;
}
- return _currentScope.getType(element);
+ return currentScope.getType(element);
}
/**
- * Update overrides assuming `perBranchOverrides` is the collection of per-branch overrides
- * for *all* branches flowing into a join point. If a variable is updated in each per-branch
- * override, then its type before the branching is ignored. Otherwise, its type before the
- * branching is merged with all updates in the branches.
+ * Update overrides assuming [perBranchOverrides] is the collection of
+ * per-branch overrides for *all* branches flowing into a join point.
*
- * Although this method would do the right thing for a single set of overrides, we require there
- * to be at least two override sets. Instead use `applyOverrides` for to apply a single set.
- *
- * For example, for the code
- *
- * <pre>
- * if (c) {
- * ...
- * } else {
- * ...
- * }
- * </pre>
- * the `perBranchOverrides` would include overrides for the then and else branches, and for
- * the code
- *
- * <pre>
- * ...
- * while(c) {
- * ...
- * }
- * </pre>
- * the `perBranchOverrides` would include overrides for before the loop and for the loop
- * body.
- *
- * @param perBranchOverrides one set of overrides for each (at least two) branch flowing into the
- * join point
+ * If a variable type in any of branches is not the same as its type before
+ * the branching, then its propagated type is reset to `null`.
*/
- void joinOverrides(List<Map<VariableElement, DartType>> perBranchOverrides) {
- if (perBranchOverrides.length < 2) {
- throw new IllegalArgumentException(
- "There is no point in joining zero or one override sets.");
- }
- Set<VariableElement> allElements = new HashSet<VariableElement>();
- Set<VariableElement> commonElements =
- new HashSet<VariableElement>.from(perBranchOverrides[0].keys.toSet());
- for (Map<VariableElement, DartType> os in perBranchOverrides) {
- // Union: elements updated in some branch.
- allElements.addAll(os.keys.toSet());
- // Intersection: elements updated in all branches.
- commonElements.retainAll(os.keys.toSet());
- }
- Set<VariableElement> uncommonElements = allElements;
- // Difference: elements updated in some but not all branches.
- uncommonElements.removeAll(commonElements);
- Map<VariableElement, DartType> joinOverrides =
- new HashMap<VariableElement, DartType>();
- // The common elements were updated in all branches, so their type
- // before branching can be ignored.
- for (VariableElement e in commonElements) {
- joinOverrides[e] = perBranchOverrides[0][e];
- for (Map<VariableElement, DartType> os in perBranchOverrides) {
- joinOverrides[e] = UnionTypeImpl.union([joinOverrides[e], os[e]]);
- }
- }
- // The uncommon elements were updated in some but not all branches,
- // so they may still have the type they had before branching.
- for (VariableElement e in uncommonElements) {
- joinOverrides[e] = getBestType(e);
- for (Map<VariableElement, DartType> os in perBranchOverrides) {
- if (os.containsKey(e)) {
- joinOverrides[e] = UnionTypeImpl.union([joinOverrides[e], os[e]]);
+ void mergeOverrides(List<Map<VariableElement, DartType>> perBranchOverrides) {
+ for (Map<VariableElement, DartType> branch in perBranchOverrides) {
+ branch.forEach((VariableElement variable, DartType branchType) {
+ DartType currentType = currentScope.getType(variable);
+ if (currentType != branchType) {
+ currentScope.resetType(variable);
}
- }
+ });
}
- applyOverrides(joinOverrides);
}
/**
@@ -12813,10 +12930,10 @@
* @param type the overridden type of the given element
*/
void setType(VariableElement element, DartType type) {
- if (_currentScope == null) {
+ if (currentScope == null) {
throw new IllegalStateException("Cannot override without a scope");
}
- _currentScope.setType(element, type);
+ currentScope.setType(element, type);
}
}
@@ -12893,9 +13010,12 @@
* @return the overridden type of the given element
*/
DartType getType(Element element) {
+ if (element is PropertyAccessorElement) {
+ element = (element as PropertyAccessorElement).variable;
+ }
DartType type = _overridenTypes[element];
- if (type == null && element is PropertyAccessorElement) {
- type = _overridenTypes[element.variable];
+ if (_overridenTypes.containsKey(element)) {
+ return type;
}
if (type != null) {
return type;
@@ -12906,6 +13026,13 @@
}
/**
+ * Clears the overridden type of the given [element].
+ */
+ void resetType(VariableElement element) {
+ _overridenTypes[element] = null;
+ }
+
+ /**
* Set the overridden type of the given element to the given type
*
* @param element the element whose type might have been overridden
@@ -12955,28 +13082,28 @@
/**
* The current promotion scope, or `null` if no scope has been entered.
*/
- TypePromotionManager_TypePromoteScope _currentScope;
+ TypePromotionManager_TypePromoteScope currentScope;
/**
* Returns the elements with promoted types.
*/
- Iterable<Element> get promotedElements => _currentScope.promotedElements;
+ Iterable<Element> get promotedElements => currentScope.promotedElements;
/**
* Enter a new promotions scope.
*/
void enterScope() {
- _currentScope = new TypePromotionManager_TypePromoteScope(_currentScope);
+ currentScope = new TypePromotionManager_TypePromoteScope(currentScope);
}
/**
* Exit the current promotion scope.
*/
void exitScope() {
- if (_currentScope == null) {
+ if (currentScope == null) {
throw new IllegalStateException("No scope to exit");
}
- _currentScope = _currentScope._outerScope;
+ currentScope = currentScope._outerScope;
}
/**
@@ -13000,10 +13127,10 @@
* @return the promoted type of the given element
*/
DartType getType(Element element) {
- if (_currentScope == null) {
+ if (currentScope == null) {
return null;
}
- return _currentScope.getType(element);
+ return currentScope.getType(element);
}
/**
@@ -13013,10 +13140,10 @@
* @param type the promoted type of the given element
*/
void setType(Element element, DartType type) {
- if (_currentScope == null) {
+ if (currentScope == null) {
throw new IllegalStateException("Cannot promote without a scope");
}
- _currentScope.setType(element, type);
+ currentScope.setType(element, type);
}
}
@@ -13085,43 +13212,31 @@
abstract class TypeProvider {
/**
* Return the type representing the built-in type 'bool'.
- *
- * @return the type representing the built-in type 'bool'
*/
InterfaceType get boolType;
/**
* Return the type representing the type 'bottom'.
- *
- * @return the type representing the type 'bottom'
*/
DartType get bottomType;
/**
* Return the type representing the built-in type 'Deprecated'.
- *
- * @return the type representing the built-in type 'Deprecated'
*/
InterfaceType get deprecatedType;
/**
* Return the type representing the built-in type 'double'.
- *
- * @return the type representing the built-in type 'double'
*/
InterfaceType get doubleType;
/**
* Return the type representing the built-in type 'dynamic'.
- *
- * @return the type representing the built-in type 'dynamic'
*/
DartType get dynamicType;
/**
* Return the type representing the built-in type 'Function'.
- *
- * @return the type representing the built-in type 'Function'
*/
InterfaceType get functionType;
@@ -13142,8 +13257,6 @@
/**
* Return the type representing the built-in type 'int'.
- *
- * @return the type representing the built-in type 'int'
*/
InterfaceType get intType;
@@ -13159,15 +13272,17 @@
/**
* Return the type representing the built-in type 'List'.
- *
- * @return the type representing the built-in type 'List'
*/
InterfaceType get listType;
/**
+ * Return a list containing all of the types that cannot be either extended or
+ * implemented.
+ */
+ List<InterfaceType> get nonSubtypableTypes;
+
+ /**
* Return the type representing the built-in type 'Map'.
- *
- * @return the type representing the built-in type 'Map'
*/
InterfaceType get mapType;
@@ -13178,29 +13293,21 @@
/**
* Return the type representing the built-in type 'Null'.
- *
- * @return the type representing the built-in type 'null'
*/
InterfaceType get nullType;
/**
* Return the type representing the built-in type 'num'.
- *
- * @return the type representing the built-in type 'num'
*/
InterfaceType get numType;
/**
* Return the type representing the built-in type 'Object'.
- *
- * @return the type representing the built-in type 'Object'
*/
InterfaceType get objectType;
/**
* Return the type representing the built-in type 'StackTrace'.
- *
- * @return the type representing the built-in type 'StackTrace'
*/
InterfaceType get stackTraceType;
@@ -13216,22 +13323,16 @@
/**
* Return the type representing the built-in type 'String'.
- *
- * @return the type representing the built-in type 'String'
*/
InterfaceType get stringType;
/**
* Return the type representing the built-in type 'Symbol'.
- *
- * @return the type representing the built-in type 'Symbol'
*/
InterfaceType get symbolType;
/**
* Return the type representing the built-in type 'Type'.
- *
- * @return the type representing the built-in type 'Type'
*/
InterfaceType get typeType;
@@ -13435,6 +13536,16 @@
InterfaceType get mapType => _mapType;
@override
+ List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[
+ nullType,
+ numType,
+ intType,
+ doubleType,
+ boolType,
+ stringType
+ ];
+
+ @override
DartObjectImpl get nullObject {
if (_nullObject == null) {
_nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
@@ -14737,6 +14848,260 @@
}
/**
+ * Instances of the class [UnusedLocalElementsVerifier] traverse an element
+ * structure looking for cases of [HintCode.UNUSED_ELEMENT],
+ * [HintCode.UNUSED_FIELD], [HintCode.UNUSED_LOCAL_VARIABLE], etc.
+ */
+class UnusedLocalElementsVerifier extends RecursiveElementVisitor {
+ /**
+ * The error listener to which errors will be reported.
+ */
+ final AnalysisErrorListener _errorListener;
+
+ /**
+ * The elements know to be used.
+ */
+ final UsedLocalElements _usedElements;
+
+ /**
+ * Create a new instance of the [UnusedLocalElementsVerifier].
+ */
+ UnusedLocalElementsVerifier(this._errorListener, this._usedElements);
+
+ @override
+ visitClassElement(ClassElement element) {
+ if (!_isUsedElement(element)) {
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
+ element.kind.displayName,
+ element.displayName
+ ]);
+ }
+ super.visitClassElement(element);
+ }
+
+ @override
+ visitFieldElement(FieldElement element) {
+ if (!_isReadMember(element)) {
+ _reportErrorForElement(
+ HintCode.UNUSED_FIELD, element, [element.displayName]);
+ }
+ super.visitFieldElement(element);
+ }
+
+ @override
+ visitFunctionElement(FunctionElement element) {
+ if (!_isUsedElement(element)) {
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
+ element.kind.displayName,
+ element.displayName
+ ]);
+ }
+ super.visitFunctionElement(element);
+ }
+
+ @override
+ visitFunctionTypeAliasElement(FunctionTypeAliasElement element) {
+ if (!_isUsedElement(element)) {
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
+ element.kind.displayName,
+ element.displayName
+ ]);
+ }
+ super.visitFunctionTypeAliasElement(element);
+ }
+
+ @override
+ visitLocalVariableElement(LocalVariableElement element) {
+ if (!_isUsedElement(element) && !_isNamedUnderscore(element)) {
+ HintCode errorCode;
+ if (_usedElements.isCatchException(element)) {
+ errorCode = HintCode.UNUSED_CATCH_CLAUSE;
+ } else if (_usedElements.isCatchStackTrace(element)) {
+ errorCode = HintCode.UNUSED_CATCH_STACK;
+ } else {
+ errorCode = HintCode.UNUSED_LOCAL_VARIABLE;
+ }
+ _reportErrorForElement(errorCode, element, [element.displayName]);
+ }
+ }
+
+ @override
+ visitMethodElement(MethodElement element) {
+ if (!_isUsedMember(element)) {
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
+ element.kind.displayName,
+ element.displayName
+ ]);
+ }
+ super.visitMethodElement(element);
+ }
+
+ @override
+ visitPropertyAccessorElement(PropertyAccessorElement element) {
+ if (!_isUsedMember(element)) {
+ _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
+ element.kind.displayName,
+ element.displayName
+ ]);
+ }
+ super.visitPropertyAccessorElement(element);
+ }
+
+ bool _isNamedUnderscore(LocalVariableElement element) {
+ String name = element.name;
+ if (name != null) {
+ for (int index = name.length - 1; index >= 0; --index) {
+ if (name.codeUnitAt(index) != 0x5F) {
+ // 0x5F => '_'
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ bool _isReadMember(Element element) {
+ if (element.isPublic) {
+ return true;
+ }
+ if (element.isSynthetic) {
+ return true;
+ }
+ return _usedElements.readMembers.contains(element.displayName);
+ }
+
+ bool _isUsedElement(Element element) {
+ if (element.isSynthetic) {
+ return true;
+ }
+ if (element is LocalVariableElement ||
+ element is FunctionElement && !element.isStatic) {
+ // local variable or function
+ } else {
+ if (element.isPublic) {
+ return true;
+ }
+ }
+ return _usedElements.elements.contains(element);
+ }
+
+ bool _isUsedMember(Element element) {
+ if (element.isPublic) {
+ return true;
+ }
+ if (element.isSynthetic) {
+ return true;
+ }
+ if (_usedElements.members.contains(element.displayName)) {
+ return true;
+ }
+ return _usedElements.elements.contains(element);
+ }
+
+ void _reportErrorForElement(
+ ErrorCode errorCode, Element element, List<Object> arguments) {
+ if (element != null) {
+ _errorListener.onError(new AnalysisError.con2(element.source,
+ element.nameOffset, element.displayName.length, errorCode,
+ arguments));
+ }
+ }
+}
+
+/**
+ * A container with information about used imports prefixes and used imported
+ * elements.
+ */
+class UsedImportedElements {
+ /**
+ * The set of referenced [PrefixElement]s.
+ */
+ final Set<PrefixElement> prefixes = new HashSet<PrefixElement>();
+
+ /**
+ * The set of referenced top-level [Element]s.
+ */
+ final Set<Element> elements = new HashSet<Element>();
+}
+
+/**
+ * A container with sets of used [Element]s.
+ * All these elements are defined in a single compilation unit or a library.
+ */
+class UsedLocalElements {
+ /**
+ * Resolved, locally defined elements that are used or potentially can be
+ * used.
+ */
+ final HashSet<Element> elements = new HashSet<Element>();
+
+ /**
+ * [LocalVariableElement]s that represent exceptions in [CatchClause]s.
+ */
+ final HashSet<LocalVariableElement> catchExceptionElements =
+ new HashSet<LocalVariableElement>();
+
+ /**
+ * [LocalVariableElement]s that represent stack traces in [CatchClause]s.
+ */
+ final HashSet<LocalVariableElement> catchStackTraceElements =
+ new HashSet<LocalVariableElement>();
+
+ /**
+ * Names of resolved or unresolved class members that are referenced in the
+ * library.
+ */
+ final HashSet<String> members = new HashSet<String>();
+
+ /**
+ * Names of resolved or unresolved class members that are read in the
+ * library.
+ */
+ final HashSet<String> readMembers = new HashSet<String>();
+
+ UsedLocalElements();
+
+ factory UsedLocalElements.merge(List<UsedLocalElements> parts) {
+ UsedLocalElements result = new UsedLocalElements();
+ for (UsedLocalElements part in parts) {
+ result.elements.addAll(part.elements);
+ result.catchExceptionElements.addAll(part.catchExceptionElements);
+ result.catchStackTraceElements.addAll(part.catchStackTraceElements);
+ result.members.addAll(part.members);
+ result.readMembers.addAll(part.readMembers);
+ }
+ return result;
+ }
+
+ void addCatchException(LocalVariableElement element) {
+ if (element != null) {
+ catchExceptionElements.add(element);
+ }
+ }
+
+ void addCatchStackTrace(LocalVariableElement element) {
+ if (element != null) {
+ catchStackTraceElements.add(element);
+ }
+ }
+
+ void addElement(Element element) {
+ if (element != null) {
+ elements.add(element);
+ }
+ }
+
+ bool isCatchException(LocalVariableElement element) {
+ return catchExceptionElements.contains(element);
+ }
+
+ bool isCatchStackTrace(LocalVariableElement element) {
+ return catchStackTraceElements.contains(element);
+ }
+}
+
+/**
* Instances of the class `VariableResolverVisitor` are used to resolve
* [SimpleIdentifier]s to local variables and formal parameters.
*/
@@ -14962,179 +15327,6 @@
Object visitNode(AstNode node) => node.accept(builder);
}
-class _GatherUsedElementsVisitor extends RecursiveAstVisitor {
- final _UsedElements usedElements = new _UsedElements();
-
- final LibraryElement _enclosingLibrary;
- ClassElement _enclosingClass;
- ExecutableElement _enclosingExec;
-
- _GatherUsedElementsVisitor(this._enclosingLibrary);
-
- @override
- visitCatchClause(CatchClause node) {
- SimpleIdentifier exceptionParameter = node.exceptionParameter;
- SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
- if (exceptionParameter != null) {
- Element element = exceptionParameter.staticElement;
- usedElements.addCatchException(element);
- if (stackTraceParameter != null || node.onKeyword == null) {
- _useElement(element);
- }
- }
- if (stackTraceParameter != null) {
- Element element = stackTraceParameter.staticElement;
- usedElements.addCatchStackTrace(element);
- }
- super.visitCatchClause(node);
- }
-
- @override
- visitClassDeclaration(ClassDeclaration node) {
- ClassElement enclosingClassOld = _enclosingClass;
- try {
- _enclosingClass = node.element;
- super.visitClassDeclaration(node);
- } finally {
- _enclosingClass = enclosingClassOld;
- }
- }
-
- @override
- visitFunctionDeclaration(FunctionDeclaration node) {
- ExecutableElement enclosingExecOld = _enclosingExec;
- try {
- _enclosingExec = node.element;
- super.visitFunctionDeclaration(node);
- } finally {
- _enclosingExec = enclosingExecOld;
- }
- }
-
- @override
- visitFunctionExpression(FunctionExpression node) {
- if (node.parent is! FunctionDeclaration) {
- _useElement(node.element);
- }
- super.visitFunctionExpression(node);
- }
-
- @override
- visitMethodDeclaration(MethodDeclaration node) {
- ExecutableElement enclosingExecOld = _enclosingExec;
- try {
- _enclosingExec = node.element;
- super.visitMethodDeclaration(node);
- } finally {
- _enclosingExec = enclosingExecOld;
- }
- }
-
- @override
- visitSimpleIdentifier(SimpleIdentifier node) {
- if (node.inDeclarationContext()) {
- return;
- }
- Element element = node.staticElement;
- bool isIdentifierRead = _isReadIdentifier(node);
- if (element is LocalVariableElement) {
- if (isIdentifierRead) {
- _useElement(element);
- }
-// } else if (element is PropertyAccessorElement &&
-// element.isSynthetic &&
-// element.isPrivate) {
-// PropertyInducingElement variable = element.variable;
-// if (node.inGetterContext()) {
-// AstNode parent = node.parent;
-// if (parent.parent is ExpressionStatement &&
-// (parent is PrefixExpression ||
-// parent is PostfixExpression ||
-// parent is AssignmentExpression && parent.leftHandSide == node)) {
-// // f++;
-// // ++f;
-// // f += 2;
-// } else {
-// _useElement(variable);
-// }
-// }
- } else {
- _useIdentifierElement(node);
- if (element == null ||
- element is! LocalElement && !identical(element, _enclosingExec)) {
- usedElements.members.add(node.name);
- if (isIdentifierRead) {
- usedElements.readMembers.add(node.name);
- }
- }
- }
- }
-
- @override
- visitTypeName(TypeName node) {
- _useIdentifierElement(node.name);
- }
-
- _useElement(Element element) {
- if (element != null) {
- usedElements.elements.add(element);
- }
- }
-
- /**
- * Marks an [Element] of [node] as used in the library.
- */
- void _useIdentifierElement(Identifier node) {
- Element element = node.staticElement;
- if (element == null) {
- return;
- }
- // check if a local element
- if (!identical(element.library, _enclosingLibrary)) {
- return;
- }
- // ignore references to an element from itself
- if (identical(element, _enclosingClass)) {
- return;
- }
- if (identical(element, _enclosingExec)) {
- return;
- }
- // ignore places where the element is not actually used
- if (node.parent is TypeName) {
- AstNode parent2 = node.parent.parent;
- if (parent2 is IsExpression) {
- return;
- }
- if (parent2 is VariableDeclarationList) {
- return;
- }
- }
- // OK
- _useElement(element);
- }
-
- static bool _isReadIdentifier(SimpleIdentifier node) {
- // not reading at all
- if (!node.inGetterContext()) {
- return false;
- }
- // check if useless reading
- AstNode parent = node.parent;
- if (parent.parent is ExpressionStatement &&
- (parent is PrefixExpression ||
- parent is PostfixExpression ||
- parent is AssignmentExpression && parent.leftHandSide == node)) {
- // v++;
- // ++v;
- // v += 2;
- return false;
- }
- // OK
- return true;
- }
-}
-
class _ResolverVisitor_isVariableAccessedInClosure
extends RecursiveAstVisitor<Object> {
final Element variable;
@@ -15224,192 +15416,3 @@
@override
Object visitWithClause(WithClause node) => null;
}
-
-/**
- * Instances of the class [_UnusedElementsVerifier] traverse an element
- * structure looking for cases of [HintCode.UNUSED_ELEMENT] and
- * [HintCode.UNUSED_LOCAL_VARIABLE].
- */
-class _UnusedElementsVerifier extends RecursiveElementVisitor {
- /**
- * The error listener to which errors will be reported.
- */
- final AnalysisErrorListener _errorListener;
-
- /**
- * The elements know to be used.
- */
- final _UsedElements _usedElements;
-
- /**
- * Create a new instance of the [_UnusedElementsVerifier].
- */
- _UnusedElementsVerifier(this._errorListener, this._usedElements);
-
- @override
- visitClassElement(ClassElement element) {
- if (!_isUsedElement(element)) {
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
- element.kind.displayName,
- element.displayName
- ]);
- }
- super.visitClassElement(element);
- }
-
- @override
- visitFieldElement(FieldElement element) {
- if (!_isReadMember(element)) {
- _reportErrorForElement(
- HintCode.UNUSED_FIELD, element, [element.displayName]);
- }
- super.visitFieldElement(element);
- }
-
- @override
- visitFunctionElement(FunctionElement element) {
- if (!_isUsedElement(element)) {
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
- element.kind.displayName,
- element.displayName
- ]);
- }
- super.visitFunctionElement(element);
- }
-
- @override
- visitLocalVariableElement(LocalVariableElement element) {
- if (!_isUsedElement(element)) {
- HintCode errorCode;
- if (_usedElements.isCatchException(element)) {
- errorCode = HintCode.UNUSED_CATCH_CLAUSE;
- } else if (_usedElements.isCatchStackTrace(element)) {
- errorCode = HintCode.UNUSED_CATCH_STACK;
- } else {
- errorCode = HintCode.UNUSED_LOCAL_VARIABLE;
- }
- _reportErrorForElement(errorCode, element, [element.displayName]);
- }
- }
-
- @override
- visitMethodElement(MethodElement element) {
- if (!_isUsedMember(element)) {
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
- element.kind.displayName,
- element.displayName
- ]);
- }
- super.visitMethodElement(element);
- }
-
- @override
- visitPropertyAccessorElement(PropertyAccessorElement element) {
- if (!_isUsedMember(element)) {
- _reportErrorForElement(HintCode.UNUSED_ELEMENT, element, [
- element.kind.displayName,
- element.displayName
- ]);
- }
- super.visitPropertyAccessorElement(element);
- }
-
- bool _isReadMember(Element element) {
- if (element.isPublic) {
- return true;
- }
- if (element.isSynthetic) {
- return true;
- }
- return _usedElements.readMembers.contains(element.displayName);
- }
-
- bool _isUsedElement(Element element) {
- if (element.isSynthetic) {
- return true;
- }
- if (element is LocalVariableElement ||
- element is FunctionElement && !element.isStatic) {
- // local variable or function
- } else {
- if (element.isPublic) {
- return true;
- }
- }
- return _usedElements.elements.contains(element);
- }
-
- bool _isUsedMember(Element element) {
- if (element.isPublic) {
- return true;
- }
- if (element.isSynthetic) {
- return true;
- }
- if (_usedElements.members.contains(element.displayName)) {
- return true;
- }
- return _usedElements.elements.contains(element);
- }
-
- void _reportErrorForElement(
- ErrorCode errorCode, Element element, List<Object> arguments) {
- if (element != null) {
- _errorListener.onError(new AnalysisError.con2(element.source,
- element.nameOffset, element.displayName.length, errorCode,
- arguments));
- }
- }
-}
-
-class _UsedElements {
- /**
- * Resolved, locally defined elements that are used or potentially can be
- * used.
- */
- final HashSet<Element> elements = new HashSet<Element>();
-
- /**
- * [LocalVariableElement]s that represent exceptions in [CatchClause]s.
- */
- final HashSet<LocalVariableElement> catchExceptionElements =
- new HashSet<LocalVariableElement>();
-
- /**
- * [LocalVariableElement]s that represent stack traces in [CatchClause]s.
- */
- final HashSet<LocalVariableElement> catchStackTraceElements =
- new HashSet<LocalVariableElement>();
-
- /**
- * Names of resolved or unresolved class members that are referenced in the
- * library.
- */
- final HashSet<String> members = new HashSet<String>();
-
- /**
- * Names of resolved or unresolved class members that are read in the
- * library.
- */
- final HashSet<String> readMembers = new HashSet<String>();
-
- void addCatchException(LocalVariableElement element) {
- if (element != null) {
- catchExceptionElements.add(element);
- }
- }
-
- void addCatchStackTrace(LocalVariableElement element) {
- if (element != null) {
- catchStackTraceElements.add(element);
- }
- }
-
- bool isCatchException(LocalVariableElement element) {
- return catchExceptionElements.contains(element);
- }
-
- bool isCatchStackTrace(LocalVariableElement element) {
- return catchStackTraceElements.contains(element);
- }
-}
diff --git a/pkg/analyzer/lib/src/generated/scanner.dart b/pkg/analyzer/lib/src/generated/scanner.dart
index 2731610..d7bc236 100644
--- a/pkg/analyzer/lib/src/generated/scanner.dart
+++ b/pkg/analyzer/lib/src/generated/scanner.dart
@@ -723,6 +723,12 @@
bool _hasUnmatchedGroups = false;
/**
+ * A flag indicating whether null-aware operators ('?.', '??', and '??=')
+ * should be tokenized.
+ */
+ bool enableNullAwareOperators = false;
+
+ /**
* Initialize a newly created scanner to scan characters from the given
* [source]. The given character [_reader] will be used to read the characters
* in the source. The given [_errorListener] will be informed of any errors
@@ -777,140 +783,179 @@
int bigSwitch(int next) {
_beginToken();
if (next == 0xD) {
+ // '\r'
next = _reader.advance();
if (next == 0xA) {
+ // '\n'
next = _reader.advance();
}
recordStartOfLine();
return next;
} else if (next == 0xA) {
+ // '\n'
next = _reader.advance();
recordStartOfLine();
return next;
} else if (next == 0x9 || next == 0x20) {
+ // '\t' || ' '
return _reader.advance();
}
if (next == 0x72) {
+ // 'r'
int peek = _reader.peek();
if (peek == 0x22 || peek == 0x27) {
+ // '"' || "'"
int start = _reader.offset;
return _tokenizeString(_reader.advance(), start, true);
}
}
if (0x61 <= next && next <= 0x7A) {
+ // 'a'-'z'
return _tokenizeKeywordOrIdentifier(next, true);
}
if ((0x41 <= next && next <= 0x5A) || next == 0x5F || next == 0x24) {
+ // 'A'-'Z' || '_' || '$'
return _tokenizeIdentifier(next, _reader.offset, true);
}
if (next == 0x3C) {
+ // '<'
return _tokenizeLessThan(next);
}
if (next == 0x3E) {
+ // '>'
return _tokenizeGreaterThan(next);
}
if (next == 0x3D) {
+ // '='
return _tokenizeEquals(next);
}
if (next == 0x21) {
+ // '!'
return _tokenizeExclamation(next);
}
if (next == 0x2B) {
+ // '+'
return _tokenizePlus(next);
}
if (next == 0x2D) {
+ // '-'
return _tokenizeMinus(next);
}
if (next == 0x2A) {
+ // '*'
return _tokenizeMultiply(next);
}
if (next == 0x25) {
+ // '%'
return _tokenizePercent(next);
}
if (next == 0x26) {
+ // '&'
return _tokenizeAmpersand(next);
}
if (next == 0x7C) {
+ // '|'
return _tokenizeBar(next);
}
if (next == 0x5E) {
+ // '^'
return _tokenizeCaret(next);
}
if (next == 0x5B) {
+ // '['
return _tokenizeOpenSquareBracket(next);
}
if (next == 0x7E) {
+ // '~'
return _tokenizeTilde(next);
}
if (next == 0x5C) {
+ // '\\'
_appendTokenOfType(TokenType.BACKSLASH);
return _reader.advance();
}
if (next == 0x23) {
+ // '#'
return _tokenizeTag(next);
}
if (next == 0x28) {
+ // '('
_appendBeginToken(TokenType.OPEN_PAREN);
return _reader.advance();
}
if (next == 0x29) {
+ // ')'
_appendEndToken(TokenType.CLOSE_PAREN, TokenType.OPEN_PAREN);
return _reader.advance();
}
if (next == 0x2C) {
+ // ','
_appendTokenOfType(TokenType.COMMA);
return _reader.advance();
}
if (next == 0x3A) {
+ // ':'
_appendTokenOfType(TokenType.COLON);
return _reader.advance();
}
if (next == 0x3B) {
+ // ';'
_appendTokenOfType(TokenType.SEMICOLON);
return _reader.advance();
}
if (next == 0x3F) {
- _appendTokenOfType(TokenType.QUESTION);
- return _reader.advance();
+ // '?'
+ return _tokenizeQuestion();
}
if (next == 0x5D) {
+ // ']'
_appendEndToken(
TokenType.CLOSE_SQUARE_BRACKET, TokenType.OPEN_SQUARE_BRACKET);
return _reader.advance();
}
if (next == 0x60) {
+ // '`'
_appendTokenOfType(TokenType.BACKPING);
return _reader.advance();
}
if (next == 0x7B) {
+ // '{'
_appendBeginToken(TokenType.OPEN_CURLY_BRACKET);
return _reader.advance();
}
if (next == 0x7D) {
+ // '}'
_appendEndToken(
TokenType.CLOSE_CURLY_BRACKET, TokenType.OPEN_CURLY_BRACKET);
return _reader.advance();
}
if (next == 0x2F) {
+ // '/'
return _tokenizeSlashOrComment(next);
}
if (next == 0x40) {
+ // '@'
_appendTokenOfType(TokenType.AT);
return _reader.advance();
}
if (next == 0x22 || next == 0x27) {
+ // '"' || "'"
return _tokenizeString(next, _reader.offset, false);
}
if (next == 0x2E) {
+ // '.'
return _tokenizeDotOrNumber(next);
}
if (next == 0x30) {
+ // '0'
return _tokenizeHexOrNumber(next);
}
if (0x31 <= next && next <= 0x39) {
+ // '1'-'9'
return _tokenizeNumber(next);
}
if (next == -1) {
+ // EOF
return -1;
}
_reportError(ScannerErrorCode.ILLEGAL_CHARACTER, [next]);
@@ -1616,6 +1661,30 @@
}
}
+ int _tokenizeQuestion() {
+ // ? ?. ?? ??=
+ int next = _reader.advance();
+ if (enableNullAwareOperators && next == 0x2E) {
+ // '.'
+ _appendTokenOfType(TokenType.QUESTION_PERIOD);
+ return _reader.advance();
+ } else if (enableNullAwareOperators && next == 0x3F) {
+ // '?'
+ next = _reader.advance();
+ if (next == 0x3D) {
+ // '='
+ _appendTokenOfType(TokenType.QUESTION_QUESTION_EQ);
+ return _reader.advance();
+ } else {
+ _appendTokenOfType(TokenType.QUESTION_QUESTION);
+ return next;
+ }
+ } else {
+ _appendTokenOfType(TokenType.QUESTION);
+ return next;
+ }
+ }
+
int _tokenizeSingleLineComment(int next) {
while (true) {
next = _reader.advance();
@@ -2120,7 +2189,7 @@
* A value used to indicate that the token type is an additive operator.
*/
static const TokenClass ADDITIVE_OPERATOR =
- const TokenClass('ADDITIVE_OPERATOR', 12);
+ const TokenClass('ADDITIVE_OPERATOR', 13);
/**
* A value used to indicate that the token type is an assignment operator.
@@ -2132,19 +2201,19 @@
* A value used to indicate that the token type is a bitwise-and operator.
*/
static const TokenClass BITWISE_AND_OPERATOR =
- const TokenClass('BITWISE_AND_OPERATOR', 10);
+ const TokenClass('BITWISE_AND_OPERATOR', 11);
/**
* A value used to indicate that the token type is a bitwise-or operator.
*/
static const TokenClass BITWISE_OR_OPERATOR =
- const TokenClass('BITWISE_OR_OPERATOR', 8);
+ const TokenClass('BITWISE_OR_OPERATOR', 9);
/**
* A value used to indicate that the token type is a bitwise-xor operator.
*/
static const TokenClass BITWISE_XOR_OPERATOR =
- const TokenClass('BITWISE_XOR_OPERATOR', 9);
+ const TokenClass('BITWISE_XOR_OPERATOR', 10);
/**
* A value used to indicate that the token type is a cascade operator.
@@ -2162,49 +2231,55 @@
* A value used to indicate that the token type is an equality operator.
*/
static const TokenClass EQUALITY_OPERATOR =
- const TokenClass('EQUALITY_OPERATOR', 6);
+ const TokenClass('EQUALITY_OPERATOR', 7);
+
+ /**
+ * A value used to indicate that the token type is an if-null operator.
+ */
+ static const TokenClass IF_NULL_OPERATOR =
+ const TokenClass('IF_NULL_OPERATOR', 4);
/**
* A value used to indicate that the token type is a logical-and operator.
*/
static const TokenClass LOGICAL_AND_OPERATOR =
- const TokenClass('LOGICAL_AND_OPERATOR', 5);
+ const TokenClass('LOGICAL_AND_OPERATOR', 6);
/**
* A value used to indicate that the token type is a logical-or operator.
*/
static const TokenClass LOGICAL_OR_OPERATOR =
- const TokenClass('LOGICAL_OR_OPERATOR', 4);
+ const TokenClass('LOGICAL_OR_OPERATOR', 5);
/**
* A value used to indicate that the token type is a multiplicative operator.
*/
static const TokenClass MULTIPLICATIVE_OPERATOR =
- const TokenClass('MULTIPLICATIVE_OPERATOR', 13);
+ const TokenClass('MULTIPLICATIVE_OPERATOR', 14);
/**
* A value used to indicate that the token type is a relational operator.
*/
static const TokenClass RELATIONAL_OPERATOR =
- const TokenClass('RELATIONAL_OPERATOR', 7);
+ const TokenClass('RELATIONAL_OPERATOR', 8);
/**
* A value used to indicate that the token type is a shift operator.
*/
static const TokenClass SHIFT_OPERATOR =
- const TokenClass('SHIFT_OPERATOR', 11);
+ const TokenClass('SHIFT_OPERATOR', 12);
/**
* A value used to indicate that the token type is a unary operator.
*/
static const TokenClass UNARY_POSTFIX_OPERATOR =
- const TokenClass('UNARY_POSTFIX_OPERATOR', 15);
+ const TokenClass('UNARY_POSTFIX_OPERATOR', 16);
/**
* A value used to indicate that the token type is a unary operator.
*/
static const TokenClass UNARY_PREFIX_OPERATOR =
- const TokenClass('UNARY_PREFIX_OPERATOR', 14);
+ const TokenClass('UNARY_PREFIX_OPERATOR', 15);
/**
* The name of the token class.
@@ -2386,6 +2461,15 @@
static const TokenType QUESTION =
const TokenType('QUESTION', TokenClass.CONDITIONAL_OPERATOR, "?");
+ static const TokenType QUESTION_PERIOD = const TokenType(
+ 'QUESTION_PERIOD', TokenClass.UNARY_POSTFIX_OPERATOR, '?.');
+
+ static const TokenType QUESTION_QUESTION =
+ const TokenType('QUESTION_QUESTION', TokenClass.IF_NULL_OPERATOR, '??');
+
+ static const TokenType QUESTION_QUESTION_EQ = const TokenType(
+ 'QUESTION_QUESTION_EQ', TokenClass.ASSIGNMENT_OPERATOR, '??=');
+
static const TokenType SEMICOLON =
const TokenType('SEMICOLON', TokenClass.NO_CLASS, ";");
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index af157bb..b853626 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -6,6 +6,8 @@
import 'dart:collection';
+import 'package:analyzer/src/generated/scanner.dart';
+
import 'ast.dart';
import 'element.dart';
import 'java_engine.dart';
@@ -151,10 +153,15 @@
DartType overrideType = staticType;
DartType propagatedType = rightHandSide.propagatedType;
if (propagatedType != null) {
- _recordPropagatedTypeIfBetter(node, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
overrideType = propagatedType;
}
_resolver.overrideExpression(node.leftHandSide, overrideType, true);
+ } else if (operator == sc.TokenType.QUESTION_QUESTION_EQ) {
+ // The static type of a compound assignment using ??= is the least upper
+ // bound of the static types of the LHS and RHS.
+ _analyzeLeastUpperBound(node, node.leftHandSide, node.rightHandSide);
+ return null;
} else {
ExecutableElement staticMethodElement = node.staticElement;
DartType staticType = _computeStaticReturnType(staticMethodElement);
@@ -163,7 +170,7 @@
if (!identical(propagatedMethodElement, staticMethodElement)) {
DartType propagatedType =
_computeStaticReturnType(propagatedMethodElement);
- _recordPropagatedTypeIfBetter(node, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
}
}
return null;
@@ -187,7 +194,7 @@
DartType propagatedExpressionType = node.expression.propagatedType;
DartType propagatedType =
flattenFutures(_typeProvider, propagatedExpressionType);
- _recordPropagatedTypeIfBetter(node, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
return null;
}
@@ -230,6 +237,14 @@
*/
@override
Object visitBinaryExpression(BinaryExpression node) {
+ if (node.operator.type == TokenType.QUESTION_QUESTION) {
+ // Evaluation of an if-null expresion e of the form e1 ?? e2 is
+ // equivalent to the evaluation of the expression
+ // ((x) => x == null ? e2 : x)(e1). The static type of e is the least
+ // upper bound of the static type of e1 and the static type of e2.
+ _analyzeLeastUpperBound(node, node.leftOperand, node.rightOperand);
+ return null;
+ }
ExecutableElement staticMethodElement = node.staticElement;
DartType staticType = _computeStaticReturnType(staticMethodElement);
staticType = _refineBinaryExpressionType(node, staticType);
@@ -238,7 +253,7 @@
if (!identical(propagatedMethodElement, staticMethodElement)) {
DartType propagatedType =
_computeStaticReturnType(propagatedMethodElement);
- _recordPropagatedTypeIfBetter(node, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
}
return null;
}
@@ -261,7 +276,7 @@
@override
Object visitCascadeExpression(CascadeExpression node) {
_recordStaticType(node, _getStaticType(node.target));
- _recordPropagatedTypeIfBetter(node, node.target.propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, node.target.propagatedType);
return null;
}
@@ -276,34 +291,7 @@
*/
@override
Object visitConditionalExpression(ConditionalExpression node) {
- DartType staticThenType = _getStaticType(node.thenExpression);
- DartType staticElseType = _getStaticType(node.elseExpression);
- if (staticThenType == null) {
- // TODO(brianwilkerson) Determine whether this can still happen.
- staticThenType = _dynamicType;
- }
- if (staticElseType == null) {
- // TODO(brianwilkerson) Determine whether this can still happen.
- staticElseType = _dynamicType;
- }
- DartType staticType = staticThenType.getLeastUpperBound(staticElseType);
- if (staticType == null) {
- staticType = _dynamicType;
- }
- _recordStaticType(node, staticType);
- DartType propagatedThenType = node.thenExpression.propagatedType;
- DartType propagatedElseType = node.elseExpression.propagatedType;
- if (propagatedThenType != null || propagatedElseType != null) {
- if (propagatedThenType == null) {
- propagatedThenType = staticThenType;
- }
- if (propagatedElseType == null) {
- propagatedElseType = staticElseType;
- }
- DartType propagatedType =
- propagatedThenType.getLeastUpperBound(propagatedElseType);
- _recordPropagatedTypeIfBetter(node, propagatedType);
- }
+ _analyzeLeastUpperBound(node, node.thenExpression, node.elseExpression);
return null;
}
@@ -400,7 +388,7 @@
DartType functionPropagatedType = node.function.propagatedType;
if (functionPropagatedType is FunctionType) {
DartType propagatedType = functionPropagatedType.returnType;
- _recordPropagatedTypeIfBetter(node, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
}
return null;
}
@@ -419,7 +407,7 @@
MethodElement propagatedMethodElement = node.propagatedElement;
if (!identical(propagatedMethodElement, staticMethodElement)) {
DartType propagatedType = _computeArgumentType(propagatedMethodElement);
- _recordPropagatedTypeIfBetter(node, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
}
} else {
ExecutableElement staticMethodElement = node.staticElement;
@@ -429,7 +417,7 @@
if (!identical(propagatedMethodElement, staticMethodElement)) {
DartType propagatedType =
_computeStaticReturnType(propagatedMethodElement);
- _recordPropagatedTypeIfBetter(node, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
}
}
return null;
@@ -455,11 +443,11 @@
if ("tag" == constructorName) {
DartType returnType = _getFirstArgumentAsTypeWithMap(
library, node.argumentList, _HTML_ELEMENT_TO_CLASS_MAP);
- _recordPropagatedTypeIfBetter(node, returnType);
+ _resolver.recordPropagatedTypeIfBetter(node, returnType);
} else {
DartType returnType = _getElementNameAsType(
library, constructorName, _HTML_ELEMENT_TO_CLASS_MAP);
- _recordPropagatedTypeIfBetter(node, returnType);
+ _resolver.recordPropagatedTypeIfBetter(node, returnType);
}
}
}
@@ -598,7 +586,7 @@
DartType staticType = variable.type;
_recordStaticType(methodNameNode, staticType);
DartType propagatedType = _overrideManager.getType(variable);
- _recordPropagatedTypeIfBetter(methodNameNode, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(methodNameNode, propagatedType);
}
// Record static return type of the static element.
DartType staticStaticType = _computeStaticReturnType(staticMethodElement);
@@ -606,7 +594,7 @@
// Record propagated return type of the static element.
DartType staticPropagatedType =
_computePropagatedReturnType(staticMethodElement);
- _recordPropagatedTypeIfBetter(node, staticPropagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, staticPropagatedType);
// Check for special cases.
bool needPropagatedType = true;
String methodName = methodNameNode.name;
@@ -760,11 +748,13 @@
// Record static return type of the propagated element.
DartType propagatedStaticType =
_computeStaticReturnType(propagatedElement);
- _recordPropagatedTypeIfBetter(node, propagatedStaticType, true);
+ _resolver.recordPropagatedTypeIfBetter(
+ node, propagatedStaticType, true);
// Record propagated return type of the propagated element.
DartType propagatedPropagatedType =
_computePropagatedReturnType(propagatedElement);
- _recordPropagatedTypeIfBetter(node, propagatedPropagatedType, true);
+ _resolver.recordPropagatedTypeIfBetter(
+ node, propagatedPropagatedType, true);
}
}
return null;
@@ -774,7 +764,7 @@
Object visitNamedExpression(NamedExpression node) {
Expression expression = node.expression;
_recordStaticType(node, _getStaticType(expression));
- _recordPropagatedTypeIfBetter(node, expression.propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, expression.propagatedType);
return null;
}
@@ -792,7 +782,7 @@
Object visitParenthesizedExpression(ParenthesizedExpression node) {
Expression expression = node.expression;
_recordStaticType(node, _getStaticType(expression));
- _recordPropagatedTypeIfBetter(node, expression.propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, expression.propagatedType);
return null;
}
@@ -835,7 +825,7 @@
}
}
_recordStaticType(node, staticType);
- _recordPropagatedTypeIfBetter(node, operand.propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, operand.propagatedType);
return null;
}
@@ -910,8 +900,8 @@
overriddenType.isMoreSpecificThan(propagatedType))) {
propagatedType = overriddenType;
}
- _recordPropagatedTypeIfBetter(prefixedIdentifier, propagatedType);
- _recordPropagatedTypeIfBetter(node, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(prefixedIdentifier, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
return null;
}
@@ -941,7 +931,7 @@
if (!identical(propagatedMethodElement, staticMethodElement)) {
DartType propagatedType =
_computeStaticReturnType(propagatedMethodElement);
- _recordPropagatedTypeIfBetter(node, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
}
}
return null;
@@ -1015,8 +1005,8 @@
} else {
// TODO(brianwilkerson) Report this internal error.
}
- _recordPropagatedTypeIfBetter(propertyName, propagatedType);
- _recordPropagatedTypeIfBetter(node, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(propertyName, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
return null;
}
@@ -1114,7 +1104,7 @@
propagatedType = overriddenType;
}
}
- _recordPropagatedTypeIfBetter(node, propagatedType);
+ _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
return null;
}
@@ -1188,7 +1178,7 @@
if (initializer != null) {
DartType rightType = initializer.bestType;
SimpleIdentifier name = node.name;
- _recordPropagatedTypeIfBetter(name, rightType);
+ _resolver.recordPropagatedTypeIfBetter(name, rightType);
VariableElement element = name.staticElement as VariableElement;
if (element != null) {
_resolver.overrideVariable(element, rightType, true);
@@ -1198,6 +1188,42 @@
}
/**
+ * Set the static (propagated) type of [node] to be the least upper bound
+ * of the static (propagated) types of subexpressions [expr1] and [expr2].
+ */
+ void _analyzeLeastUpperBound(
+ Expression node, Expression expr1, Expression expr2) {
+ DartType staticType1 = _getStaticType(expr1);
+ DartType staticType2 = _getStaticType(expr2);
+ if (staticType1 == null) {
+ // TODO(brianwilkerson) Determine whether this can still happen.
+ staticType1 = _dynamicType;
+ }
+ if (staticType2 == null) {
+ // TODO(brianwilkerson) Determine whether this can still happen.
+ staticType2 = _dynamicType;
+ }
+ DartType staticType = staticType1.getLeastUpperBound(staticType2);
+ if (staticType == null) {
+ staticType = _dynamicType;
+ }
+ _recordStaticType(node, staticType);
+ DartType propagatedType1 = expr1.propagatedType;
+ DartType propagatedType2 = expr2.propagatedType;
+ if (propagatedType1 != null || propagatedType2 != null) {
+ if (propagatedType1 == null) {
+ propagatedType1 = staticType1;
+ }
+ if (propagatedType2 == null) {
+ propagatedType2 = staticType2;
+ }
+ DartType propagatedType =
+ propagatedType1.getLeastUpperBound(propagatedType2);
+ _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
+ }
+ }
+
+ /**
* Record that the static type of the given node is the type of the second argument to the method
* represented by the given element.
*
@@ -1600,8 +1626,12 @@
return parent is TypeName ||
(parent is PrefixedIdentifier &&
(parent.parent is TypeName || identical(parent.prefix, node))) ||
- (parent is PropertyAccess && identical(parent.target, node)) ||
- (parent is MethodInvocation && identical(node, parent.target));
+ (parent is PropertyAccess &&
+ identical(parent.target, node) &&
+ parent.operator.type == TokenType.PERIOD) ||
+ (parent is MethodInvocation &&
+ identical(node, parent.target) &&
+ parent.operator.type == TokenType.PERIOD);
}
/**
@@ -1617,41 +1647,6 @@
}
/**
- * If the given [type] is valid, strongly more specific than the
- * existing static type of the given [expression], record it as a propagated
- * type of the given [expression]. Otherwise, reset it to `null`.
- *
- * If [hasOldPropagatedType] is `true` then the existing propagated type
- * should also is checked.
- */
- void _recordPropagatedTypeIfBetter(Expression expression, DartType type,
- [bool hasOldPropagatedType = false]) {
- // Ensure that propagated type invalid.
- if (type == null || type.isDynamic || type.isBottom) {
- if (!hasOldPropagatedType) {
- expression.propagatedType = null;
- }
- return;
- }
- // Ensure that propagated type is more specific than the static type.
- DartType staticType = expression.staticType;
- if (type == staticType || !type.isMoreSpecificThan(staticType)) {
- expression.propagatedType = null;
- return;
- }
- // Ensure that the new propagated type is more specific than the old one.
- if (hasOldPropagatedType) {
- DartType oldPropagatedType = expression.propagatedType;
- if (oldPropagatedType != null &&
- !type.isMoreSpecificThan(oldPropagatedType)) {
- return;
- }
- }
- // OK
- expression.propagatedType = type;
- }
-
- /**
* Given a function element and its body, compute and record the propagated return type of the
* function.
*
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
index fa46781..0be2aaa 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
@@ -622,8 +622,9 @@
parameters, body);
static MethodInvocation methodInvocation(Expression target, String methodName,
- [List<Expression> arguments]) => new MethodInvocation(target,
- target == null ? null : TokenFactory.tokenFromType(TokenType.PERIOD),
+ [List<Expression> arguments,
+ TokenType operator = TokenType.PERIOD]) => new MethodInvocation(target,
+ target == null ? null : TokenFactory.tokenFromType(operator),
identifier3(methodName), argumentList(arguments));
static MethodInvocation methodInvocation2(String methodName,
@@ -696,9 +697,9 @@
Expression target, SimpleIdentifier propertyName) => new PropertyAccess(
target, TokenFactory.tokenFromType(TokenType.PERIOD), propertyName);
- static PropertyAccess propertyAccess2(
- Expression target, String propertyName) => new PropertyAccess(target,
- TokenFactory.tokenFromType(TokenType.PERIOD), identifier3(propertyName));
+ static PropertyAccess propertyAccess2(Expression target, String propertyName,
+ [TokenType operator = TokenType.PERIOD]) => new PropertyAccess(
+ target, TokenFactory.tokenFromType(operator), identifier3(propertyName));
static RedirectingConstructorInvocation redirectingConstructorInvocation(
[List<Expression> arguments]) =>
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index 9fab12f..ebb0713 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -70,10 +70,6 @@
[List<String> parameterNames]) =>
classElement(typeName, objectType, parameterNames);
- static ClassElementImpl classTypeAlias2(String typeName,
- [List<String> parameterNames]) =>
- classTypeAlias(typeName, objectType, parameterNames);
-
static classTypeAlias(String typeName, InterfaceType superclassType,
[List<String> parameterNames]) {
ClassElementImpl element =
@@ -82,6 +78,10 @@
return element;
}
+ static ClassElementImpl classTypeAlias2(String typeName,
+ [List<String> parameterNames]) =>
+ classTypeAlias(typeName, objectType, parameterNames);
+
static CompilationUnitElementImpl compilationUnit(String fileName) {
Source source = new NonExistingSource(fileName, UriKind.FILE_URI);
CompilationUnitElementImpl unit = new CompilationUnitElementImpl(fileName);
@@ -89,6 +89,9 @@
return unit;
}
+ static ConstLocalVariableElementImpl constLocalVariableElement(String name) =>
+ new ConstLocalVariableElementImpl(name, 0);
+
static ConstructorElementImpl constructorElement(
ClassElement definingClass, String name, bool isConst,
[List<DartType> argumentTypes]) {
diff --git a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
index 6824459..fe0c24b 100644
--- a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
@@ -159,6 +159,7 @@
ElementFactory.namedParameter2("defaultValue", _boolType)
];
fromEnvironment.factory = true;
+ fromEnvironment.isCycleFree = true;
boolElement.constructors = <ConstructorElement>[fromEnvironment];
}
return _boolType;
@@ -330,6 +331,16 @@
}
@override
+ List<InterfaceType> get nonSubtypableTypes => <InterfaceType>[
+ nullType,
+ numType,
+ intType,
+ doubleType,
+ boolType,
+ stringType
+ ];
+
+ @override
DartObjectImpl get nullObject {
if (_nullObject == null) {
_nullObject = new DartObjectImpl(nullType, NullState.NULL_STATE);
@@ -421,6 +432,7 @@
ElementFactory.namedParameter2("defaultValue", _stringType)
];
fromEnvironment.factory = true;
+ fromEnvironment.isCycleFree = true;
stringElement.constructors = <ConstructorElement>[fromEnvironment];
}
return _stringType;
@@ -433,6 +445,7 @@
ConstructorElementImpl constructor = ElementFactory.constructorElement(
symbolClass, null, true, [stringType]);
constructor.factory = true;
+ constructor.isCycleFree = true;
symbolClass.constructors = <ConstructorElement>[constructor];
_symbolType = symbolClass.type;
}
@@ -532,6 +545,7 @@
ElementFactory.namedParameter2("defaultValue", _intType)
];
fromEnvironment.factory = true;
+ fromEnvironment.isCycleFree = true;
intElement.constructors = <ConstructorElement>[fromEnvironment];
List<FieldElement> fields = <FieldElement>[
ElementFactory.fieldElement("NAN", true, false, true, _doubleType),
diff --git a/pkg/analyzer/lib/src/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index d858b1a..3e63016 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -67,7 +67,7 @@
registerExtension(taskId, BuildDirectiveElementsTask.DESCRIPTOR);
registerExtension(taskId, BuildEnumMemberElementsTask.DESCRIPTOR);
registerExtension(taskId, BuildExportNamespaceTask.DESCRIPTOR);
- registerExtension(taskId, BuildExportSourceClosureTask.DESCRIPTOR);
+ registerExtension(taskId, BuildSourceClosuresTask.DESCRIPTOR);
registerExtension(taskId, BuildFunctionTypeAliasesTask.DESCRIPTOR);
registerExtension(taskId, BuildLibraryElementTask.DESCRIPTOR);
registerExtension(taskId, BuildPublicNamespaceTask.DESCRIPTOR);
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 59b9efe..93e2f08 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -11,6 +11,7 @@
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/error_verifier.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -67,6 +68,15 @@
new ListResultDescriptor<ClassElement>('CLASS_ELEMENTS', null);
/**
+ * The element model associated with a single compilation unit.
+ *
+ * The result is only available for targets representing a Dart compilation unit.
+ */
+final ResultDescriptor<CompilationUnitElement> COMPILATION_UNIT_ELEMENT =
+ new ResultDescriptor<CompilationUnitElement>(
+ 'COMPILATION_UNIT_ELEMENT', null);
+
+/**
* The [ConstructorElement]s of a [ClassElement].
*/
final ResultDescriptor<List<ConstructorElement>> CONSTRUCTORS =
@@ -85,6 +95,7 @@
/**
* The sources representing the export closure of a library.
+ * The [Source]s include only library sources, not their units.
*
* The result is only available for targets representing a Dart library.
*/
@@ -92,6 +103,26 @@
new ListResultDescriptor<Source>('EXPORT_SOURCE_CLOSURE', null);
/**
+ * The errors produced while generating hints a compilation unit.
+ *
+ * The list will be empty if there were no errors, but will not be `null`.
+ *
+ * The result is only available for targets representing a Dart compilation unit.
+ */
+final ResultDescriptor<List<AnalysisError>> HINTS =
+ new ResultDescriptor<List<AnalysisError>>(
+ 'HINT_ERRORS', AnalysisError.NO_ERRORS, contributesTo: DART_ERRORS);
+
+/**
+ * The sources representing the import closure of a library.
+ * The [Source]s include only library sources, not their units.
+ *
+ * The result is only available for targets representing a Dart library.
+ */
+final ListResultDescriptor<Source> IMPORT_SOURCE_CLOSURE =
+ new ListResultDescriptor<Source>('IMPORT_SOURCE_CLOSURE', null);
+
+/**
* The partial [LibraryElement] associated with a library.
*
* The [LibraryElement] and its [CompilationUnitElement]s are attached to each
@@ -148,14 +179,27 @@
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT5', null);
/**
- * The partial [LibraryElement] associated with a library.
+ * The errors produced while parsing a compilation unit.
*
- * Implicit constructors are built for every [ClassElement] requiring them.
+ * The list will be empty if there were no errors, but will not be `null`.
*
- * The result is only available for targets representing a Dart library.
+ * The result is only available for targets representing a Dart compilation unit.
*/
-final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT6 =
- new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT6', null);
+final ResultDescriptor<List<AnalysisError>> PARSE_ERRORS =
+ new ResultDescriptor<List<AnalysisError>>(
+ 'PARSE_ERRORS', AnalysisError.NO_ERRORS, contributesTo: DART_ERRORS);
+
+/**
+ * The errors produced while resolving references.
+ *
+ * The list will be empty if there were no errors, but will not be `null`.
+ *
+ * The result is only available for targets representing a unit.
+ */
+final ResultDescriptor<List<AnalysisError>> RESOLVE_REFERENCES_ERRORS =
+ new ResultDescriptor<List<AnalysisError>>(
+ 'RESOLVE_REFERENCES_ERRORS', AnalysisError.NO_ERRORS,
+ contributesTo: DART_ERRORS);
/**
* The errors produced while resolving type names.
@@ -210,12 +254,56 @@
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT4', null);
/**
+ * The partially resolved [CompilationUnit] associated with a unit.
+ *
+ * [RESOLVED_UNIT4] plus resolved local variables and formal parameters.
+ *
+ * The result is only available for targets representing a unit.
+ */
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT5 =
+ new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT5', null);
+
+/**
+ * The errors produced while scanning a compilation unit.
+ *
+ * The list will be empty if there were no errors, but will not be `null`.
+ *
+ * The result is only available for targets representing a Dart compilation unit.
+ */
+final ResultDescriptor<List<AnalysisError>> SCAN_ERRORS =
+ new ResultDescriptor<List<AnalysisError>>(
+ 'SCAN_ERRORS', AnalysisError.NO_ERRORS, contributesTo: DART_ERRORS);
+
+/**
* The [TypeProvider] of the context.
*/
final ResultDescriptor<TypeProvider> TYPE_PROVIDER =
new ResultDescriptor<TypeProvider>('TYPE_PROVIDER', null);
/**
+ * The [UsedImportedElements] of a [LibraryUnitTarget].
+ */
+final ResultDescriptor<UsedImportedElements> USED_IMPORTED_ELEMENTS =
+ new ResultDescriptor<UsedImportedElements>('USED_IMPORTED_ELEMENTS', null);
+
+/**
+ * The [UsedLocalElements] of a [LibraryUnitTarget].
+ */
+final ResultDescriptor<UsedLocalElements> USED_LOCAL_ELEMENTS =
+ new ResultDescriptor<UsedLocalElements>('USED_LOCAL_ELEMENTS', null);
+
+/**
+ * The errors produced while verifying a compilation unit.
+ *
+ * The list will be empty if there were no errors, but will not be `null`.
+ *
+ * The result is only available for targets representing a Dart compilation unit.
+ */
+final ResultDescriptor<List<AnalysisError>> VERIFY_ERRORS =
+ new ResultDescriptor<List<AnalysisError>>(
+ 'VERIFY_ERRORS', AnalysisError.NO_ERRORS, contributesTo: DART_ERRORS);
+
+/**
* A task that builds implicit constructors for a [ClassElement], or keeps
* the existing explicit constructors if the class has them.
*/
@@ -889,77 +977,6 @@
}
/**
- * A task that builds [EXPORT_SOURCE_CLOSURE] of a library.
- */
-class BuildExportSourceClosureTask extends SourceBasedAnalysisTask {
- /**
- * The name of the input for [LIBRARY_ELEMENT3] of a library.
- */
- static const String LIBRARY2_ELEMENT_INPUT = 'LIBRARY2_ELEMENT_INPUT';
-
- /**
- * The task descriptor describing this kind of task.
- */
- static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
- 'BuildExportSourceClosureTask', createTask, buildInputs,
- <ResultDescriptor>[EXPORT_SOURCE_CLOSURE]);
-
- BuildExportSourceClosureTask(
- InternalAnalysisContext context, AnalysisTarget target)
- : super(context, target);
-
- @override
- TaskDescriptor get descriptor => DESCRIPTOR;
-
- @override
- void internalPerform() {
- LibraryElement library = getRequiredInput(LIBRARY2_ELEMENT_INPUT);
- //
- // Compute export closure.
- //
- Set<LibraryElement> libraries = new Set<LibraryElement>();
- _buildExportClosure(libraries, library);
- List<Source> sources = libraries.map((lib) => lib.source).toList();
- //
- // Record outputs.
- //
- outputs[EXPORT_SOURCE_CLOSURE] = sources;
- }
-
- /**
- * Return a map from the names of the inputs of this kind of task to the task
- * input descriptors describing those inputs for a task with the
- * given library [libSource].
- */
- static Map<String, TaskInput> buildInputs(Source libSource) {
- return <String, TaskInput>{
- LIBRARY2_ELEMENT_INPUT: LIBRARY_ELEMENT2.of(libSource)
- };
- }
-
- /**
- * Create a [BuildExportSourceClosureTask] based on the given [target] in
- * the given [context].
- */
- static BuildExportSourceClosureTask createTask(
- AnalysisContext context, AnalysisTarget target) {
- return new BuildExportSourceClosureTask(context, target);
- }
-
- /**
- * Create a set representing the export closure of the given [library].
- */
- static void _buildExportClosure(
- Set<LibraryElement> libraries, LibraryElement library) {
- if (library != null && libraries.add(library)) {
- for (ExportElement exportElement in library.exports) {
- _buildExportClosure(libraries, exportElement.exportedLibrary);
- }
- }
- }
-}
-
-/**
* A task that builds [RESOLVED_UNIT3] for a unit.
*/
class BuildFunctionTypeAliasesTask extends SourceBasedAnalysisTask {
@@ -1045,8 +1062,8 @@
}
/**
- * An artifitial task that does nothing except to force building constructors
- * for for the defining and part units of a library.
+ * This task finishes building [LIBRARY_ELEMENT] by forcing building
+ * constructors for classes in the defining and part units of a library.
*/
class BuildLibraryConstructorsTask extends SourceBasedAnalysisTask {
/**
@@ -1059,7 +1076,7 @@
*/
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
'BuildLibraryConstructorsTask', createTask, buildInputs,
- <ResultDescriptor>[LIBRARY_ELEMENT6]);
+ <ResultDescriptor>[LIBRARY_ELEMENT]);
BuildLibraryConstructorsTask(
InternalAnalysisContext context, AnalysisTarget target)
@@ -1071,7 +1088,7 @@
@override
void internalPerform() {
LibraryElement library = getRequiredInput(LIBRARY_INPUT);
- outputs[LIBRARY_ELEMENT6] = library;
+ outputs[LIBRARY_ELEMENT] = library;
}
/**
@@ -1120,8 +1137,7 @@
BUILD_LIBRARY_ERRORS,
CLASS_ELEMENTS,
LIBRARY_ELEMENT1,
- IS_LAUNCHABLE,
- HAS_HTML_IMPORT
+ IS_LAUNCHABLE
]);
/**
@@ -1161,13 +1177,11 @@
Source partSource = partUnit.element.source;
partUnitMap[partSource] = partUnit;
}
- Source htmlSource = context.sourceFactory.forUri(DartSdk.DART_HTML);
//
// Update "part" directives.
//
LibraryIdentifier libraryNameNode = null;
String partsLibraryName = _UNKNOWN_LIBRARY_NAME;
- bool hasHtmlImport = false;
bool hasPartDirective = false;
FunctionElement entryPoint =
_findEntryPoint(definingCompilationUnitElement);
@@ -1175,9 +1189,7 @@
List<CompilationUnitElementImpl> sourcedCompilationUnits =
<CompilationUnitElementImpl>[];
for (Directive directive in definingCompilationUnit.directives) {
- if (directive is ImportDirective) {
- hasHtmlImport = hasHtmlImport || directive.source == htmlSource;
- } else if (directive is LibraryDirective) {
+ if (directive is LibraryDirective) {
if (libraryNameNode == null) {
libraryNameNode = directive.name;
directivesToResolve.add(directive);
@@ -1265,7 +1277,6 @@
outputs[CLASS_ELEMENTS] = classElements;
outputs[LIBRARY_ELEMENT1] = libraryElement;
outputs[IS_LAUNCHABLE] = entryPoint != null;
- outputs[HAS_HTML_IMPORT] = hasHtmlImport;
}
/**
@@ -1421,6 +1432,74 @@
}
/**
+ * A task that builds [IMPORT_SOURCE_CLOSURE] and [EXPORT_SOURCE_CLOSURE] of
+ * a library.
+ */
+class BuildSourceClosuresTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the import closure.
+ */
+ static const String IMPORT_CLOSURE_INPUT = 'IMPORT_CLOSURE_INPUT';
+
+ /**
+ * The name of the export closure.
+ */
+ static const String EXPORT_CLOSURE_INPUT = 'EXPORT_CLOSURE_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'BuildExportSourceClosureTask', createTask, buildInputs,
+ <ResultDescriptor>[
+ IMPORT_SOURCE_CLOSURE,
+ EXPORT_SOURCE_CLOSURE,
+ IS_CLIENT
+ ]);
+
+ BuildSourceClosuresTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ List<Source> importClosure = getRequiredInput(IMPORT_CLOSURE_INPUT);
+ List<Source> exportClosure = getRequiredInput(EXPORT_CLOSURE_INPUT);
+ Source htmlSource = context.sourceFactory.forUri(DartSdk.DART_HTML);
+ //
+ // Record outputs.
+ //
+ outputs[IMPORT_SOURCE_CLOSURE] = importClosure;
+ outputs[EXPORT_SOURCE_CLOSURE] = exportClosure;
+ outputs[IS_CLIENT] = importClosure.contains(htmlSource);
+ }
+
+ /**
+ * Return a map from the names of the inputs of this kind of task to the task
+ * input descriptors describing those inputs for a task with the
+ * given library [libSource].
+ */
+ static Map<String, TaskInput> buildInputs(Source libSource) {
+ return <String, TaskInput>{
+ IMPORT_CLOSURE_INPUT: new _ImportSourceClosureTaskInput(libSource),
+ EXPORT_CLOSURE_INPUT: new _ExportSourceClosureTaskInput(libSource)
+ };
+ }
+
+ /**
+ * Create a [BuildSourceClosuresTask] based on the given [target] in
+ * the given [context].
+ */
+ static BuildSourceClosuresTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new BuildSourceClosuresTask(context, target);
+ }
+}
+
+/**
* A task that builds [TYPE_PROVIDER] for a context.
*/
class BuildTypeProviderTask extends SourceBasedAnalysisTask {
@@ -1586,6 +1665,238 @@
}
/**
+ * A task that builds [USED_IMPORTED_ELEMENTS] for a unit.
+ */
+class GatherUsedImportedElementsTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [RESOLVED_UNIT] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'GatherUsedImportedElementsTask', createTask, buildInputs,
+ <ResultDescriptor>[USED_IMPORTED_ELEMENTS]);
+
+ GatherUsedImportedElementsTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ CompilationUnitElement unitElement = unit.element;
+ LibraryElement libraryElement = unitElement.library;
+ //
+ // Prepare used imported elements.
+ //
+ GatherUsedImportedElementsVisitor visitor =
+ new GatherUsedImportedElementsVisitor(libraryElement);
+ unit.accept(visitor);
+ //
+ // Record outputs.
+ //
+ outputs[USED_IMPORTED_ELEMENTS] = visitor.usedElements;
+ }
+
+ /**
+ * Return a map from the names of the inputs of this kind of task to the task
+ * input descriptors describing those inputs for a task with the
+ * given [target].
+ */
+ static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) {
+ return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT.of(target)};
+ }
+
+ /**
+ * Create a [GatherUsedImportedElementsTask] based on the given [target] in
+ * the given [context].
+ */
+ static GatherUsedImportedElementsTask createTask(
+ AnalysisContext context, LibraryUnitTarget target) {
+ return new GatherUsedImportedElementsTask(context, target);
+ }
+}
+
+/**
+ * A task that builds [USED_LOCAL_ELEMENTS] for a unit.
+ */
+class GatherUsedLocalElementsTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [RESOLVED_UNIT] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'GatherUsedLocalElementsTask', createTask, buildInputs,
+ <ResultDescriptor>[USED_LOCAL_ELEMENTS]);
+
+ GatherUsedLocalElementsTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ CompilationUnitElement unitElement = unit.element;
+ LibraryElement libraryElement = unitElement.library;
+ //
+ // Prepare used local elements.
+ //
+ GatherUsedLocalElementsVisitor visitor =
+ new GatherUsedLocalElementsVisitor(libraryElement);
+ unit.accept(visitor);
+ //
+ // Record outputs.
+ //
+ outputs[USED_LOCAL_ELEMENTS] = visitor.usedElements;
+ }
+
+ /**
+ * Return a map from the names of the inputs of this kind of task to the task
+ * input descriptors describing those inputs for a task with the
+ * given [target].
+ */
+ static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) {
+ return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT.of(target)};
+ }
+
+ /**
+ * Create a [GatherUsedLocalElementsTask] based on the given [target] in
+ * the given [context].
+ */
+ static GatherUsedLocalElementsTask createTask(
+ AnalysisContext context, LibraryUnitTarget target) {
+ return new GatherUsedLocalElementsTask(context, target);
+ }
+}
+
+/**
+ * A task that generates [HINTS] for a unit.
+ */
+class GenerateHintsTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [RESOLVED_UNIT] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The name of a list of [USED_LOCAL_ELEMENTS] for each library unit input.
+ */
+ static const String USED_LOCAL_ELEMENTS_INPUT = 'USED_LOCAL_ELEMENTS';
+
+ /**
+ * The name of a list of [USED_IMPORTED_ELEMENTS] for each library unit input.
+ */
+ static const String USED_IMPORTED_ELEMENTS_INPUT = 'USED_IMPORTED_ELEMENTS';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'GenerateHintsTask', createTask, buildInputs, <ResultDescriptor>[HINTS]);
+
+ GenerateHintsTask(InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ Source source = getRequiredSource();
+ ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
+ //
+ // Prepare inputs.
+ //
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ List<UsedImportedElements> usedImportedElementsList =
+ getRequiredInput(USED_IMPORTED_ELEMENTS_INPUT);
+ List<UsedLocalElements> usedLocalElementsList =
+ getRequiredInput(USED_LOCAL_ELEMENTS_INPUT);
+ CompilationUnitElement unitElement = unit.element;
+ LibraryElement libraryElement = unitElement.library;
+ //
+ // Generate errors.
+ //
+ unit.accept(new DeadCodeVerifier(errorReporter));
+ // Verify imports.
+ {
+ ImportsVerifier verifier = new ImportsVerifier();
+ verifier.addImports(unit);
+ usedImportedElementsList.forEach(verifier.removeUsedElements);
+ verifier.generateDuplicateImportHints(errorReporter);
+ verifier.generateUnusedImportHints(errorReporter);
+ }
+ // Unused local elements.
+ {
+ UsedLocalElements usedElements =
+ new UsedLocalElements.merge(usedLocalElementsList);
+ UnusedLocalElementsVerifier visitor =
+ new UnusedLocalElementsVerifier(errorListener, usedElements);
+ unitElement.accept(visitor);
+ }
+ // Dart2js analysis.
+ if (context.analysisOptions.dart2jsHint) {
+ unit.accept(new Dart2JSVerifier(errorReporter));
+ }
+ // Dart best practices.
+ InheritanceManager inheritanceManager =
+ new InheritanceManager(libraryElement);
+ TypeProvider typeProvider = context.typeProvider;
+ unit.accept(new BestPracticesVerifier(errorReporter, typeProvider));
+ unit.accept(new OverrideVerifier(errorReporter, inheritanceManager));
+ // Find to-do comments.
+ new ToDoFinder(errorReporter).findIn(unit);
+ //
+ // Record outputs.
+ //
+ outputs[HINTS] = errorListener.errors;
+ }
+
+ /**
+ * Return a map from the names of the inputs of this kind of task to the task
+ * input descriptors describing those inputs for a task with the
+ * given [target].
+ */
+ static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) {
+ Source libSource = target.library;
+ return <String, TaskInput>{
+ UNIT_INPUT: RESOLVED_UNIT.of(target),
+ USED_LOCAL_ELEMENTS_INPUT: UNITS.of(libSource).toList((unit) {
+ LibraryUnitTarget target = new LibraryUnitTarget(libSource, unit);
+ return USED_LOCAL_ELEMENTS.of(target);
+ }),
+ USED_IMPORTED_ELEMENTS_INPUT: UNITS.of(libSource).toList((unit) {
+ LibraryUnitTarget target = new LibraryUnitTarget(libSource, unit);
+ return USED_IMPORTED_ELEMENTS.of(target);
+ })
+ };
+ }
+
+ /**
+ * Create a [GenerateHintsTask] based on the given [target] in
+ * the given [context].
+ */
+ static GenerateHintsTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new GenerateHintsTask(context, target);
+ }
+}
+
+/**
* A pair of a library [Source] and a unit [Source] in this library.
*/
class LibraryUnitTarget implements AnalysisTarget {
@@ -1856,8 +2167,11 @@
static Map<String, TaskInput> buildInputs(Source libSource) {
return <String, TaskInput>{
LIBRARY_INPUT: LIBRARY_ELEMENT4.of(libSource),
- 'resolvedUnits': UNITS.of(libSource).toMap((Source source) =>
- RESOLVED_UNIT4.of(new LibraryUnitTarget(libSource, source)))
+ 'resolvedUnits': IMPORT_SOURCE_CLOSURE
+ .of(libSource)
+ .toMapOf(UNITS)
+ .toFlattenList((Source library, Source unit) =>
+ RESOLVED_UNIT4.of(new LibraryUnitTarget(library, unit)))
};
}
@@ -1872,6 +2186,80 @@
}
/**
+ * A task that builds [RESOLVED_UNIT] for a unit.
+ */
+class ResolveReferencesTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [LIBRARY_ELEMENT] input.
+ */
+ static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+ /**
+ * The name of the [RESOLVED_UNIT5] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ResolveReferencesTask', createTask, buildInputs,
+ <ResultDescriptor>[RESOLVED_UNIT]);
+
+ ResolveReferencesTask(InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ //
+ // Prepare inputs.
+ //
+ LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT);
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ CompilationUnitElement unitElement = unit.element;
+ TypeProvider typeProvider = unitElement.context.typeProvider;
+ //
+ // Resolve references.
+ //
+ InheritanceManager inheritanceManager =
+ new InheritanceManager(libraryElement);
+ AstVisitor visitor = new ResolverVisitor.con2(libraryElement,
+ unitElement.source, typeProvider, inheritanceManager, errorListener);
+ unit.accept(visitor);
+ //
+ // Record outputs.
+ //
+ outputs[RESOLVE_REFERENCES_ERRORS] = errorListener.errors;
+ outputs[RESOLVED_UNIT] = unit;
+ }
+
+ /**
+ * Return a map from the names of the inputs of this kind of task to the task
+ * input descriptors describing those inputs for a task with the
+ * given [target].
+ */
+ static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) {
+ return <String, TaskInput>{
+ LIBRARY_INPUT: LIBRARY_ELEMENT.of(target.library),
+ UNIT_INPUT: RESOLVED_UNIT5.of(target)
+ };
+ }
+
+ /**
+ * Create a [ResolveReferencesTask] based on the given [target] in
+ * the given [context].
+ */
+ static ResolveReferencesTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new ResolveReferencesTask(context, target);
+ }
+}
+
+/**
* A task that builds [RESOLVED_UNIT4] for a unit.
*/
class ResolveUnitTypeNamesTask extends SourceBasedAnalysisTask {
@@ -1938,6 +2326,79 @@
}
/**
+ * A task that builds [RESOLVED_UNIT5] for a unit.
+ */
+class ResolveVariableReferencesTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [LIBRARY_ELEMENT] input.
+ */
+ static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+ /**
+ * The name of the [RESOLVED_UNIT4] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ResolveVariableReferencesTask', createTask, buildInputs,
+ <ResultDescriptor>[RESOLVED_UNIT5]);
+
+ ResolveVariableReferencesTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ //
+ // Prepare inputs.
+ //
+ LibraryElement libraryElement = getRequiredInput(LIBRARY_INPUT);
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ CompilationUnitElement unitElement = unit.element;
+ //
+ // Resolve local variables.
+ //
+ TypeProvider typeProvider = unitElement.context.typeProvider;
+ Scope nameScope = new LibraryScope(libraryElement, errorListener);
+ AstVisitor visitor = new VariableResolverVisitor.con2(libraryElement,
+ unitElement.source, typeProvider, nameScope, errorListener);
+ unit.accept(visitor);
+ //
+ // Record outputs.
+ //
+ outputs[RESOLVED_UNIT5] = unit;
+ }
+
+ /**
+ * Return a map from the names of the inputs of this kind of task to the task
+ * input descriptors describing those inputs for a task with the
+ * given [target].
+ */
+ static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) {
+ return <String, TaskInput>{
+ LIBRARY_INPUT: LIBRARY_ELEMENT.of(target.library),
+ UNIT_INPUT: RESOLVED_UNIT4.of(target)
+ };
+ }
+
+ /**
+ * Create a [ResolveVariableReferencesTask] based on the given [target] in
+ * the given [context].
+ */
+ static ResolveVariableReferencesTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new ResolveVariableReferencesTask(context, target);
+ }
+}
+
+/**
* A task that scans the content of a file, producing a set of Dart tokens.
*/
class ScanDartTask extends SourceBasedAnalysisTask {
@@ -1975,6 +2436,8 @@
Scanner scanner =
new Scanner(source, new CharSequenceReader(content), errorListener);
scanner.preserveComments = context.analysisOptions.preserveComments;
+ scanner.enableNullAwareOperators =
+ context.analysisOptions.enableNullAwareOperators;
outputs[TOKEN_STREAM] = scanner.tokenize();
outputs[LINE_INFO] = new LineInfo(scanner.lineStarts);
outputs[SCAN_ERRORS] = errorListener.getErrorsForSource(source);
@@ -1997,3 +2460,155 @@
return new ScanDartTask(context, target);
}
}
+
+/**
+ * A task that builds [VERIFY_ERRORS] for a unit.
+ */
+class VerifyUnitTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [RESOLVED_UNIT] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('VerifyUnitTask',
+ createTask, buildInputs, <ResultDescriptor>[VERIFY_ERRORS]);
+
+ /**
+ * The [ErrorReporter] to report errors to.
+ */
+ ErrorReporter errorReporter;
+
+ VerifyUnitTask(InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ RecordingErrorListener errorListener = new RecordingErrorListener();
+ Source source = getRequiredSource();
+ errorReporter = new ErrorReporter(errorListener, source);
+ TypeProvider typeProvider = context.typeProvider;
+ //
+ // Prepare inputs.
+ //
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ CompilationUnitElement unitElement = unit.element;
+ LibraryElement libraryElement = unitElement.library;
+ //
+ // Use the ErrorVerifier to compute errors.
+ //
+ ErrorVerifier errorVerifier = new ErrorVerifier(errorReporter,
+ libraryElement, typeProvider, new InheritanceManager(libraryElement));
+ unit.accept(errorVerifier);
+ //
+ // Record outputs.
+ //
+ outputs[VERIFY_ERRORS] = errorListener.errors;
+ }
+
+ /**
+ * Return a map from the names of the inputs of this kind of task to the task
+ * input descriptors describing those inputs for a task with the
+ * given [target].
+ */
+ static Map<String, TaskInput> buildInputs(LibraryUnitTarget target) {
+ return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT.of(target)};
+ }
+
+ /**
+ * Create a [VerifyUnitTask] based on the given [target] in
+ * the given [context].
+ */
+ static VerifyUnitTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new VerifyUnitTask(context, target);
+ }
+}
+
+/**
+ * A [TaskInput] whose value is a list of library sources exported directly
+ * or indirectly by the target [Source].
+ */
+class _ExportSourceClosureTaskInput implements TaskInput<List<Source>> {
+ final Source target;
+
+ _ExportSourceClosureTaskInput(this.target);
+
+ @override
+ TaskInputBuilder<List<Source>> createBuilder() =>
+ new _SourceClosureTaskInputBuilder(target, _SourceClosureKind.EXPORT);
+}
+
+/**
+ * The kind of the source closure to build.
+ */
+enum _SourceClosureKind { IMPORT, EXPORT }
+
+/**
+ * A [TaskInput] whose value is a list of library sources imported directly
+ * or indirectly by the target [Source].
+ */
+class _ImportSourceClosureTaskInput implements TaskInput<List<Source>> {
+ final Source target;
+
+ _ImportSourceClosureTaskInput(this.target);
+
+ @override
+ TaskInputBuilder<List<Source>> createBuilder() =>
+ new _SourceClosureTaskInputBuilder(target, _SourceClosureKind.IMPORT);
+}
+
+/**
+ * A [TaskInputBuilder] to build values for [_ImportSourceClosureTaskInput].
+ */
+class _SourceClosureTaskInputBuilder implements TaskInputBuilder<List<Source>> {
+ final _SourceClosureKind kind;
+ final Set<LibraryElement> _libraries = new HashSet<LibraryElement>();
+ final Set<Source> _newSources = new HashSet<Source>();
+
+ Source currentTarget;
+
+ _SourceClosureTaskInputBuilder(Source librarySource, this.kind) {
+ _newSources.add(librarySource);
+ }
+
+ @override
+ ResultDescriptor get currentResult => LIBRARY_ELEMENT2;
+
+ @override
+ void set currentValue(LibraryElement library) {
+ if (_libraries.add(library)) {
+ if (kind == _SourceClosureKind.IMPORT) {
+ for (ImportElement importElement in library.imports) {
+ Source importedSource = importElement.importedLibrary.source;
+ _newSources.add(importedSource);
+ }
+ } else {
+ for (ExportElement exportElement in library.exports) {
+ Source importedSource = exportElement.exportedLibrary.source;
+ _newSources.add(importedSource);
+ }
+ }
+ }
+ }
+
+ @override
+ List<Source> get inputValue {
+ return _libraries.map((LibraryElement library) => library.source).toList();
+ }
+
+ @override
+ bool moveNext() {
+ if (_newSources.isEmpty) {
+ return false;
+ }
+ currentTarget = _newSources.first;
+ _newSources.remove(currentTarget);
+ return true;
+ }
+}
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
index 88df107..f077b3a 100644
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ b/pkg/analyzer/lib/src/task/driver.dart
@@ -413,8 +413,46 @@
while (childItem != null) {
pendingItems.add(currentItem);
currentItem = childItem;
+ if (_hasInfiniteTaskLoop()) {
+ currentItem = pendingItems.removeLast();
+ try {
+ throw new InfiniteTaskLoopException(childItem);
+ } on InfiniteTaskLoopException catch (exception, stackTrace) {
+ currentItem.exception = new CaughtException(exception, stackTrace);
+ }
+ return true;
+ }
childItem = currentItem.gatherInputs(taskManager);
}
return true;
}
+
+ /**
+ * Check to see whether the current work item is attempting to perform the
+ * same task on the same target as any of the pending work items. If it is,
+ * then throw an [InfiniteTaskLoopException].
+ */
+ bool _hasInfiniteTaskLoop() {
+ TaskDescriptor descriptor = currentItem.descriptor;
+ AnalysisTarget target = currentItem.target;
+ for (WorkItem item in pendingItems) {
+ if (item.descriptor == descriptor && item.target == target) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+/**
+ * An exception indicating that an attempt was made to perform a task on a
+ * target while gathering the inputs to perform the same task for the same
+ * target.
+ */
+class InfiniteTaskLoopException extends AnalysisException {
+ /**
+ * Initialize a newly created exception to represent an attempt to perform
+ * the task for the target represented by the given [item].
+ */
+ InfiniteTaskLoopException(WorkItem item) : super('Infinite loop while performing task ${item.descriptor.name} for ${item.target}');
}
diff --git a/pkg/analyzer/lib/src/task/general.dart b/pkg/analyzer/lib/src/task/general.dart
index 8e52537..8f88327 100644
--- a/pkg/analyzer/lib/src/task/general.dart
+++ b/pkg/analyzer/lib/src/task/general.dart
@@ -8,6 +8,7 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/task/general.dart';
import 'package:analyzer/task/model.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
/**
* A task that gets the contents of the source associated with an analysis
@@ -33,10 +34,14 @@
@override
internalPerform() {
Source source = getRequiredSource();
-
- TimestampedData<String> data = context.getContents(source);
- outputs[CONTENT] = data.data;
- outputs[MODIFICATION_TIME] = data.modificationTime;
+ try {
+ TimestampedData<String> data = context.getContents(source);
+ outputs[CONTENT] = data.data;
+ outputs[MODIFICATION_TIME] = data.modificationTime;
+ } catch (exception, stackTrace) {
+ throw new AnalysisException('Could not get contents of $source',
+ new CaughtException(exception, stackTrace));
+ }
}
/**
diff --git a/pkg/analyzer/lib/src/task/inputs.dart b/pkg/analyzer/lib/src/task/inputs.dart
index a7b67df..27b48c5 100644
--- a/pkg/analyzer/lib/src/task/inputs.dart
+++ b/pkg/analyzer/lib/src/task/inputs.dart
@@ -41,12 +41,12 @@
return (this as ListTaskInputImpl<AnalysisTarget>).toList(valueResult.of);
}
- TaskInput<Map<E, dynamic /*V*/ >> toMap(
+ MapTaskInput<E, dynamic /*V*/ > toMap(
UnaryFunction<E, dynamic /*<V>*/ > mapper) {
return new ListToMapTaskInput<E, dynamic /*V*/ >(this, mapper);
}
- TaskInput<Map<AnalysisTarget, dynamic /*V*/ >> toMapOf(
+ MapTaskInput<AnalysisTarget, dynamic /*V*/ > toMapOf(
ResultDescriptor /*<V>*/ valueResult) {
return (this as ListTaskInputImpl<AnalysisTarget>).toMap(valueResult.of);
}
@@ -113,7 +113,8 @@
* input to the task.
*/
class ListToMapTaskInput<B, E>
- extends _ListToCollectionTaskInput<B, E, Map<B, E>> {
+ extends _ListToCollectionTaskInput<B, E, Map<B, E>>
+ with MapTaskInputMixin<B, E> {
/**
* Initialize a result accessor to use the given [baseAccessor] to access a
* list of values that can be passed to the given [generateTaskInputs] to
@@ -157,6 +158,125 @@
}
/**
+ * A mixin-ready implementation of [MapTaskInput].
+ */
+abstract class MapTaskInputMixin<K, V> implements MapTaskInput<K, V> {
+ TaskInput<List /*<E>*/ > toFlattenList(
+ BinaryFunction<K, dynamic /*element of V*/, dynamic /*<E>*/ > mapper) {
+ return new MapToFlattenListTaskInput<K, dynamic /*element of V*/, dynamic /*E*/ >(
+ this as MapTaskInput<K, List /*<element of V>*/ >, mapper);
+ }
+}
+
+/**
+ * A [TaskInput] that is computed by the following steps.
+ *
+ * First the [base] task input is used to compute a [Map]-valued result.
+ * The values of the [Map] must be [List]s.
+ *
+ * The given [mapper] is used to transform each key / value pair of the [Map]
+ * into task inputs.
+ *
+ * Finally, each of the task inputs are used to access analysis results,
+ * and the list of the results is used as the input.
+ */
+class MapToFlattenListTaskInput<K, V, E> implements TaskInput<List<E>> {
+ final MapTaskInput<K, List<V>> base;
+ final BinaryFunction<K, V, E> mapper;
+
+ MapToFlattenListTaskInput(this.base, this.mapper);
+
+ @override
+ TaskInputBuilder<List> createBuilder() {
+ return new MapToFlattenListTaskInputBuilder<K, V, E>(base, mapper);
+ }
+}
+
+/**
+ * The [TaskInputBuilder] for [MapToFlattenListTaskInput].
+ */
+class MapToFlattenListTaskInputBuilder<K, V, E>
+ implements TaskInputBuilder<List<E>> {
+ final MapTaskInput<K, List<V>> base;
+ final BinaryFunction<K, V, E> mapper;
+
+ TaskInputBuilder currentBuilder;
+ Map<K, List<V>> baseMap;
+ Iterator<K> keyIterator;
+ Iterator<V> valueIterator;
+
+ final List<E> inputValue = <E>[];
+
+ MapToFlattenListTaskInputBuilder(this.base, this.mapper) {
+ currentBuilder = base.createBuilder();
+ }
+
+ @override
+ ResultDescriptor get currentResult {
+ if (currentBuilder == null) {
+ return null;
+ }
+ return currentBuilder.currentResult;
+ }
+
+ AnalysisTarget get currentTarget {
+ if (currentBuilder == null) {
+ return null;
+ }
+ return currentBuilder.currentTarget;
+ }
+
+ @override
+ void set currentValue(Object value) {
+ if (currentBuilder == null) {
+ throw new StateError(
+ 'Cannot set the result value when there is no current result');
+ }
+ currentBuilder.currentValue = value;
+ }
+
+ @override
+ bool moveNext() {
+ // Prepare base Map.
+ if (baseMap == null) {
+ if (currentBuilder.moveNext()) {
+ return true;
+ }
+ baseMap = currentBuilder.inputValue;
+ keyIterator = baseMap.keys.iterator;
+ // Done with this builder.
+ currentBuilder = null;
+ }
+ // Prepare the next result value.
+ if (currentBuilder != null) {
+ if (currentBuilder.moveNext()) {
+ return true;
+ }
+ // Add the result value for the current Map key/value.
+ E resultValue = currentBuilder.inputValue;
+ inputValue.add(resultValue);
+ // Done with this builder.
+ currentBuilder = null;
+ }
+ // Move to the next Map value.
+ if (valueIterator != null && valueIterator.moveNext()) {
+ K key = keyIterator.current;
+ V value = valueIterator.current;
+ currentBuilder = mapper(key, value).createBuilder();
+ return moveNext();
+ }
+ // Move to the next Map key.
+ if (keyIterator.moveNext()) {
+ K key = keyIterator.current;
+ valueIterator = baseMap[key].iterator;
+ return moveNext();
+ }
+ // No more Map values/keys to transform.
+ return false;
+ }
+}
+
+/**
* An input to an [AnalysisTask] that is computed by accessing a single result
* defined on a single target.
*/
diff --git a/pkg/analyzer/lib/task/dart.dart b/pkg/analyzer/lib/task/dart.dart
index 2918d20..8195549 100644
--- a/pkg/analyzer/lib/task/dart.dart
+++ b/pkg/analyzer/lib/task/dart.dart
@@ -12,15 +12,6 @@
import 'package:analyzer/task/model.dart';
/**
- * The element model associated with a single compilation unit.
- *
- * The result is only available for targets representing a Dart compilation unit.
- */
-final ResultDescriptor<CompilationUnitElement> COMPILATION_UNIT_ELEMENT =
- new ResultDescriptor<CompilationUnitElement>(
- 'COMPILATION_UNIT_ELEMENT', null);
-
-/**
* The analysis errors associated with a target.
*
* The value combines errors represented by multiple other results.
@@ -43,14 +34,6 @@
new ListResultDescriptor<Source>('EXPORTED_LIBRARIES', Source.EMPTY_ARRAY);
/**
- * A flag specifying whether a library imports 'dart:html'.
- *
- * The result is only available for targets representing a Dart library.
- */
-final ResultDescriptor<bool> HAS_HTML_IMPORT =
- new ResultDescriptor<bool>('HAS_HTML_IMPORT', false);
-
-/**
* The sources of the libraries that are imported into a library.
*
* Not `null`.
@@ -74,6 +57,15 @@
new ListResultDescriptor<Source>('INCLUDED_PARTS', Source.EMPTY_ARRAY);
/**
+ * A flag specifying whether a library is dependent on code that is only
+ * available in a client.
+ *
+ * The result is only available for targets representing a Dart library.
+ */
+final ResultDescriptor<bool> IS_CLIENT =
+ new ResultDescriptor<bool>('IS_CLIENT', false);
+
+/**
* A flag specifying whether a library is launchable.
*
* The result is only available for targets representing a Dart library.
@@ -82,15 +74,12 @@
new ResultDescriptor<bool>('IS_LAUNCHABLE', false);
/**
- * The errors produced while parsing a compilation unit.
+ * The fully built [LibraryElement] associated with a library.
*
- * The list will be empty if there were no errors, but will not be `null`.
- *
- * The result is only available for targets representing a Dart compilation unit.
+ * The result is only available for targets representing a Dart library.
*/
-final ResultDescriptor<List<AnalysisError>> PARSE_ERRORS =
- new ResultDescriptor<List<AnalysisError>>(
- 'PARSE_ERRORS', AnalysisError.NO_ERRORS, contributesTo: DART_ERRORS);
+final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT =
+ new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT', null);
/**
* The compilation unit AST produced while parsing a compilation unit.
@@ -103,15 +92,12 @@
new ResultDescriptor<CompilationUnit>('PARSED_UNIT', null);
/**
- * The errors produced while scanning a compilation unit.
+ * The resolved [CompilationUnit] associated with a unit.
*
- * The list will be empty if there were no errors, but will not be `null`.
- *
- * The result is only available for targets representing a Dart compilation unit.
+ * The result is only available for targets representing a unit.
*/
-final ResultDescriptor<List<AnalysisError>> SCAN_ERRORS =
- new ResultDescriptor<List<AnalysisError>>(
- 'SCAN_ERRORS', AnalysisError.NO_ERRORS, contributesTo: DART_ERRORS);
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT =
+ new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT', null);
/**
* The token stream produced while scanning a compilation unit.
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index 4da15af..973f24e 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -12,6 +12,11 @@
import 'package:analyzer/src/task/model.dart';
/**
+ * A function that converts the given [key] and [value] into a [TaskInput].
+ */
+typedef TaskInput<E> BinaryFunction<K, V, E>(K key, V value);
+
+/**
* A function that takes an analysis [context] and an analysis [target] and
* returns an analysis task. Such functions are passed to a [TaskDescriptor] to
* be used to create the described task.
@@ -292,7 +297,7 @@
* elements of this input and whose values are the result of passing the
* corresponding key to the [mapper] function.
*/
- TaskInput<Map<E, dynamic /*V*/ >> toMap(
+ MapTaskInput<E, dynamic /*V*/ > toMap(
UnaryFunction<E, dynamic /*<V>*/ > mapper);
/**
@@ -300,11 +305,27 @@
* elements of this input and whose values are the [valueResult]'s associated
* with those elements.
*/
- TaskInput<Map<AnalysisTarget, dynamic /*V*/ >> toMapOf(
+ MapTaskInput<AnalysisTarget, dynamic /*V*/ > toMapOf(
ResultDescriptor /*<V>*/ valueResult);
}
/**
+ * A description of an input with a [Map] based values.
+ *
+ * Clients are not expected to subtype this class.
+ */
+abstract class MapTaskInput<K, V> extends TaskInput<Map<K, V>> {
+ /**
+ * [V] must be a [List].
+ * Return a task input that can be used to compute a list whose elements are
+ * the result of passing keys [K] and the corresponding elements of [V] to
+ * the [mapper] function.
+ */
+ TaskInput<List /*<E>*/ > toFlattenList(
+ BinaryFunction<K, dynamic /*element of V*/, dynamic /*<E>*/ > mapper);
+}
+
+/**
* A description of an analysis result that can be computed by an [AnalysisTask].
*
* Clients are not expected to subtype this class.
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 8ac7743..b5cde46 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.25.0-dev.2
+version: 0.24.3
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: http://www.dartlang.org
@@ -7,7 +7,6 @@
sdk: '>=0.8.10+6 <2.0.0'
dependencies:
args: '>=0.12.1 <0.13.0'
- logging: '>=0.9.0 <0.10.0'
path: '>=0.9.0 <2.0.0'
watcher: '>=0.9.0 <0.10.0'
dev_dependencies:
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 23959e4..a45e012 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -126,9 +126,8 @@
}
void test_tokenize_directive_xml() {
- _tokenize("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>", <Object>[
- "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
- ]);
+ _tokenize("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>",
+ <Object>["<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"]);
}
void test_tokenize_directives_incomplete_with_newline() {
@@ -932,10 +931,11 @@
return constructorInvocations;
}
- Map<VariableElement, VariableDeclaration> _findVariableDeclarations() {
+ Map<PotentiallyConstVariableElement, VariableDeclaration> _findVariableDeclarations() {
ConstantFinder finder = new ConstantFinder();
_node.accept(finder);
- Map<VariableElement, VariableDeclaration> variableMap = finder.variableMap;
+ Map<PotentiallyConstVariableElement, VariableDeclaration> variableMap =
+ finder.variableMap;
expect(variableMap, isNotNull);
return variableMap;
}
@@ -2284,6 +2284,26 @@
errorListener.assertNoErrors();
}
+ void test_visitSimpleIdentifier_className() {
+ CompilationUnit compilationUnit = resolveSource('''
+const a = C;
+class C {}
+''');
+ DartObjectImpl result = _evaluateConstant(compilationUnit, 'a', null);
+ expect(result.type, typeProvider.typeType);
+ ClassElement element = result.value;
+ expect(element.name, 'C');
+ }
+
+ void test_visitSimpleIdentifier_dynamic() {
+ CompilationUnit compilationUnit = resolveSource('''
+const a = dynamic;
+''');
+ DartObjectImpl result = _evaluateConstant(compilationUnit, 'a', null);
+ expect(result.type, typeProvider.typeType);
+ expect(result.value, typeProvider.dynamicType.element);
+ }
+
void test_visitSimpleIdentifier_inEnvironment() {
CompilationUnit compilationUnit = resolveSource(r'''
const a = b;
@@ -5706,10 +5726,9 @@
String firstTypeParameterName = "A";
String secondTypeParameterName = "B";
TypeAlias typeAlias = AstFactory.typeAlias(null, aliasName, AstFactory
- .typeParameterList([
- firstTypeParameterName,
- secondTypeParameterName
- ]), AstFactory.formalParameterList());
+ .typeParameterList(
+ [firstTypeParameterName, secondTypeParameterName]),
+ AstFactory.formalParameterList());
typeAlias.accept(builder);
List<FunctionTypeAliasElement> aliases = holder.typeAliases;
expect(aliases, hasLength(1));
@@ -6421,6 +6440,31 @@
expect(new ErrorReporter(listener, source), isNotNull);
}
+ void test_reportErrorForElement_named() {
+ DartType type = createType("/test1.dart", "A");
+ ClassElement element = type.element;
+ GatheringErrorListener listener = new GatheringErrorListener();
+ ErrorReporter reporter = new ErrorReporter(listener, element.source);
+ reporter.reportErrorForElement(
+ StaticWarningCode.CONFLICTING_INSTANCE_GETTER_AND_SUPERCLASS_MEMBER,
+ element, ['A']);
+ AnalysisError error = listener.errors[0];
+ expect(error.offset, element.nameOffset);
+ }
+
+ void test_reportErrorForElement_unnamed() {
+ ImportElementImpl element =
+ ElementFactory.importFor(ElementFactory.library(null, ''), null);
+ GatheringErrorListener listener = new GatheringErrorListener();
+ ErrorReporter reporter = new ErrorReporter(
+ listener, new NonExistingSource("/test.dart", UriKind.FILE_URI));
+ reporter.reportErrorForElement(
+ StaticWarningCode.CONFLICTING_INSTANCE_GETTER_AND_SUPERCLASS_MEMBER,
+ element, ['A']);
+ AnalysisError error = listener.errors[0];
+ expect(error.offset, element.nameOffset);
+ }
+
void test_reportTypeErrorForNode_differentNames() {
DartType firstType = createType("/test1.dart", "A");
DartType secondType = createType("/test2.dart", "B");
@@ -7394,9 +7438,8 @@
</html>""");
_validate(htmlUnit, [
_t4("html", [
- _t4("body", [
- _t("script", _a(["type", "'application/dart'"]), scriptBody)
- ])
+ _t4("body",
+ [_t("script", _a(["type", "'application/dart'"]), scriptBody)])
])
]);
}
@@ -7408,8 +7451,9 @@
ht.Token token = scanner.tokenize();
LineInfo lineInfo = new LineInfo(scanner.lineStarts);
GatheringErrorListener errorListener = new GatheringErrorListener();
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
ht.HtmlUnit unit =
- new ht.HtmlParser(null, errorListener).parse(token, lineInfo);
+ new ht.HtmlParser(null, errorListener, options).parse(token, lineInfo);
errorListener.assertNoErrors();
return unit;
}
@@ -7464,9 +7508,8 @@
// ht.XmlTagNode.getContent() does not include whitespace
// between '<' and '>' at this time
_validate(htmlUnit, [
- _t3("html", "\n<pa=\"b\">blat \n </p>\n", [
- _t("p", _a(["a", "\"b\""]), "blat \n ")
- ])
+ _t3("html", "\n<pa=\"b\">blat \n </p>\n",
+ [_t("p", _a(["a", "\"b\""]), "blat \n ")])
]);
}
void test_parse_content_none() {
@@ -7806,7 +7849,7 @@
@reflectiveTest
class ReferenceFinderTest extends EngineTestCase {
DirectedGraph<AstNode> _referenceGraph;
- Map<VariableElement, VariableDeclaration> _variableDeclarationMap;
+ Map<PotentiallyConstVariableElement, VariableDeclaration> _variableDeclarationMap;
Map<ConstructorElement, ConstructorDeclaration> _constructorDeclarationMap;
VariableDeclaration _head;
AstNode _tail;
@@ -7814,7 +7857,7 @@
void setUp() {
_referenceGraph = new DirectedGraph<AstNode>();
_variableDeclarationMap =
- new HashMap<VariableElement, VariableDeclaration>();
+ new HashMap<PotentiallyConstVariableElement, VariableDeclaration>();
_constructorDeclarationMap =
new HashMap<ConstructorElement, ConstructorDeclaration>();
_head = AstFactory.variableDeclaration("v1");
@@ -7937,8 +7980,8 @@
VariableDeclaration variableDeclaration =
AstFactory.variableDeclaration(name);
_tail = variableDeclaration;
- VariableElementImpl variableElement =
- ElementFactory.localVariableElement2(name);
+ ConstLocalVariableElementImpl variableElement =
+ ElementFactory.constLocalVariableElement(name);
variableElement.const3 = isConst;
AstFactory.variableDeclarationList2(
isConst ? Keyword.CONST : Keyword.VAR, [variableDeclaration]);
diff --git a/pkg/analyzer/test/generated/ast_test.dart b/pkg/analyzer/test/generated/ast_test.dart
index 51ad0ca..64ead75 100644
--- a/pkg/analyzer/test/generated/ast_test.dart
+++ b/pkg/analyzer/test/generated/ast_test.dart
@@ -264,14 +264,12 @@
void test_binary_divide_double() {
Object value = _getConstantValue("3.2 / 2.3");
- EngineTestCase.assertInstanceOf((obj) => obj is double, double, value);
- expect(value as double, 3.2 / 2.3);
+ expect(value, 3.2 / 2.3);
}
void test_binary_divide_integer() {
Object value = _getConstantValue("3 / 2");
- EngineTestCase.assertInstanceOf((obj) => obj is int, int, value);
- expect(value as int, 1);
+ expect(value, 1.5);
}
void test_binary_equal_boolean() {
@@ -337,14 +335,12 @@
void test_binary_minus_double() {
Object value = _getConstantValue("3.2 - 2.3");
- EngineTestCase.assertInstanceOf((obj) => obj is double, double, value);
- expect(value as double, 3.2 - 2.3);
+ expect(value, 3.2 - 2.3);
}
void test_binary_minus_integer() {
Object value = _getConstantValue("3 - 2");
- EngineTestCase.assertInstanceOf((obj) => obj is int, int, value);
- expect(value as int, 1);
+ expect(value, 1);
}
void test_binary_notEqual_boolean() {
@@ -374,26 +370,22 @@
void test_binary_plus_double() {
Object value = _getConstantValue("2.3 + 3.2");
- EngineTestCase.assertInstanceOf((obj) => obj is double, double, value);
- expect(value as double, 2.3 + 3.2);
+ expect(value, 2.3 + 3.2);
}
void test_binary_plus_integer() {
Object value = _getConstantValue("2 + 3");
- EngineTestCase.assertInstanceOf((obj) => obj is int, int, value);
- expect(value as int, 5);
+ expect(value, 5);
}
void test_binary_remainder_double() {
Object value = _getConstantValue("3.2 % 2.3");
- EngineTestCase.assertInstanceOf((obj) => obj is double, double, value);
- expect(value as double, 3.2 % 2.3);
+ expect(value, 3.2 % 2.3);
}
void test_binary_remainder_integer() {
Object value = _getConstantValue("8 % 3");
- EngineTestCase.assertInstanceOf((obj) => obj is int, int, value);
- expect(value as int, 2);
+ expect(value, 2);
}
void test_binary_rightShift() {
@@ -404,14 +396,12 @@
void test_binary_times_double() {
Object value = _getConstantValue("2.3 * 3.2");
- EngineTestCase.assertInstanceOf((obj) => obj is double, double, value);
- expect(value as double, 2.3 * 3.2);
+ expect(value, 2.3 * 3.2);
}
void test_binary_times_integer() {
Object value = _getConstantValue("2 * 3");
- EngineTestCase.assertInstanceOf((obj) => obj is int, int, value);
- expect(value as int, 6);
+ expect(value, 6);
}
void test_binary_truncatingDivide_double() {
@@ -463,14 +453,12 @@
void test_literal_number_double() {
Object value = _getConstantValue("3.45");
- EngineTestCase.assertInstanceOf((obj) => obj is double, double, value);
- expect(value as double, 3.45);
+ expect(value, 3.45);
}
void test_literal_number_integer() {
Object value = _getConstantValue("42");
- EngineTestCase.assertInstanceOf((obj) => obj is int, int, value);
- expect(value as int, 42);
+ expect(value, 42);
}
void test_literal_string_adjacent() {
@@ -511,14 +499,12 @@
void test_unary_negated_double() {
Object value = _getConstantValue("-42.3");
- EngineTestCase.assertInstanceOf((obj) => obj is double, double, value);
- expect(value as double, -42.3);
+ expect(value, -42.3);
}
void test_unary_negated_integer() {
Object value = _getConstantValue("-42");
- EngineTestCase.assertInstanceOf((obj) => obj is int, int, value);
- expect(value as int, -42);
+ expect(value, -42);
}
Object _getConstantValue(String source) =>
@@ -1172,9 +1158,8 @@
void test_isQualified_inMethodInvocation_withTarget() {
MethodInvocation invocation = AstFactory.methodInvocation(
- AstFactory.identifier3("target"), "test", [
- AstFactory.identifier3("arg0")
- ]);
+ AstFactory.identifier3("target"), "test",
+ [AstFactory.identifier3("arg0")]);
SimpleIdentifier identifier = invocation.methodName;
expect(identifier.isQualified, isTrue);
}
@@ -1281,19 +1266,26 @@
expect(new SimpleStringLiteral(
TokenFactory.tokenFromString("'X'"), "X").contentsEnd, 2);
expect(new SimpleStringLiteral(
- TokenFactory.tokenFromString("\"X\""), "X").contentsEnd, 2);
+ TokenFactory.tokenFromString('"X"'), "X").contentsEnd, 2);
+
expect(new SimpleStringLiteral(
- TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X").contentsEnd, 4);
+ TokenFactory.tokenFromString('"""X"""'), "X").contentsEnd, 4);
expect(new SimpleStringLiteral(
TokenFactory.tokenFromString("'''X'''"), "X").contentsEnd, 4);
expect(new SimpleStringLiteral(
+ TokenFactory.tokenFromString("''' \nX'''"), "X").contentsEnd, 7);
+
+ expect(new SimpleStringLiteral(
TokenFactory.tokenFromString("r'X'"), "X").contentsEnd, 3);
expect(new SimpleStringLiteral(
- TokenFactory.tokenFromString("r\"X\""), "X").contentsEnd, 3);
+ TokenFactory.tokenFromString('r"X"'), "X").contentsEnd, 3);
+
expect(new SimpleStringLiteral(
- TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X").contentsEnd, 5);
+ TokenFactory.tokenFromString('r"""X"""'), "X").contentsEnd, 5);
expect(new SimpleStringLiteral(
TokenFactory.tokenFromString("r'''X'''"), "X").contentsEnd, 5);
+ expect(new SimpleStringLiteral(
+ TokenFactory.tokenFromString("r''' \nX'''"), "X").contentsEnd, 8);
}
void test_contentsOffset() {
@@ -1313,6 +1305,11 @@
TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X").contentsOffset, 4);
expect(new SimpleStringLiteral(
TokenFactory.tokenFromString("r'''X'''"), "X").contentsOffset, 4);
+ // leading whitespace
+ expect(new SimpleStringLiteral(
+ TokenFactory.tokenFromString("''' \ \nX''"), "X").contentsOffset, 6);
+ expect(new SimpleStringLiteral(
+ TokenFactory.tokenFromString('r""" \ \nX"""'), "X").contentsOffset, 7);
}
void test_isMultiline() {
@@ -1880,9 +1877,8 @@
}
void test_visitCompilationUnit_directive_declaration() {
- _assertSource("library l; var a;", AstFactory.compilationUnit4([
- AstFactory.libraryDirective2("l")
- ], [
+ _assertSource("library l; var a;", AstFactory.compilationUnit4(
+ [AstFactory.libraryDirective2("l")], [
AstFactory.topLevelVariableDeclaration2(
Keyword.VAR, [AstFactory.variableDeclaration("a")])
]));
@@ -1912,9 +1908,8 @@
void test_visitCompilationUnit_script_directives_declarations() {
_assertSource("!#/bin/dartvm library l; var a;", AstFactory
- .compilationUnit8("!#/bin/dartvm", [
- AstFactory.libraryDirective2("l")
- ], [
+ .compilationUnit8("!#/bin/dartvm", [AstFactory.libraryDirective2("l")],
+ [
AstFactory.topLevelVariableDeclaration2(
Keyword.VAR, [AstFactory.variableDeclaration("a")])
]));
@@ -2308,9 +2303,8 @@
void test_visitForStatement_cu() {
_assertSource("for (; c; u) {}", AstFactory.forStatement(null,
- AstFactory.identifier3("c"), [
- AstFactory.identifier3("u")
- ], AstFactory.block()));
+ AstFactory.identifier3("c"), [AstFactory.identifier3("u")],
+ AstFactory.block()));
}
void test_visitForStatement_e() {
@@ -2326,16 +2320,14 @@
void test_visitForStatement_ecu() {
_assertSource("for (e; c; u) {}", AstFactory.forStatement(
- AstFactory.identifier3("e"), AstFactory.identifier3("c"), [
- AstFactory.identifier3("u")
- ], AstFactory.block()));
+ AstFactory.identifier3("e"), AstFactory.identifier3("c"),
+ [AstFactory.identifier3("u")], AstFactory.block()));
}
void test_visitForStatement_eu() {
_assertSource("for (e;; u) {}", AstFactory.forStatement(
- AstFactory.identifier3("e"), null, [
- AstFactory.identifier3("u")
- ], AstFactory.block()));
+ AstFactory.identifier3("e"), null, [AstFactory.identifier3("u")],
+ AstFactory.block()));
}
void test_visitForStatement_i() {
@@ -2347,26 +2339,24 @@
void test_visitForStatement_ic() {
_assertSource("for (var i; c;) {}", AstFactory.forStatement2(AstFactory
- .variableDeclarationList2(Keyword.VAR, [
- AstFactory.variableDeclaration("i")
- ]), AstFactory.identifier3("c"), null, AstFactory.block()));
+ .variableDeclarationList2(
+ Keyword.VAR, [AstFactory.variableDeclaration("i")]),
+ AstFactory.identifier3("c"), null, AstFactory.block()));
}
void test_visitForStatement_icu() {
_assertSource("for (var i; c; u) {}", AstFactory.forStatement2(AstFactory
- .variableDeclarationList2(Keyword.VAR, [
- AstFactory.variableDeclaration("i")
- ]), AstFactory.identifier3("c"), [
- AstFactory.identifier3("u")
- ], AstFactory.block()));
+ .variableDeclarationList2(
+ Keyword.VAR, [AstFactory.variableDeclaration("i")]),
+ AstFactory.identifier3("c"), [AstFactory.identifier3("u")],
+ AstFactory.block()));
}
void test_visitForStatement_iu() {
_assertSource("for (var i;; u) {}", AstFactory.forStatement2(AstFactory
- .variableDeclarationList2(
- Keyword.VAR, [AstFactory.variableDeclaration("i")]), null, [
- AstFactory.identifier3("u")
- ], AstFactory.block()));
+ .variableDeclarationList2(
+ Keyword.VAR, [AstFactory.variableDeclaration("i")]), null,
+ [AstFactory.identifier3("u")], AstFactory.block()));
}
void test_visitForStatement_u() {
@@ -2489,9 +2479,8 @@
void test_visitImportDirective_combinator() {
_assertSource("import 'a.dart' show A;", AstFactory.importDirective3(
- "a.dart", null, [
- AstFactory.showCombinator([AstFactory.identifier3("A")])
- ]));
+ "a.dart", null,
+ [AstFactory.showCombinator([AstFactory.identifier3("A")])]));
}
void test_visitImportDirective_combinators() {
@@ -2519,9 +2508,8 @@
void test_visitImportDirective_prefix_combinator() {
_assertSource("import 'a.dart' as p show A;", AstFactory.importDirective3(
- "a.dart", "p", [
- AstFactory.showCombinator([AstFactory.identifier3("A")])
- ]));
+ "a.dart", "p",
+ [AstFactory.showCombinator([AstFactory.identifier3("A")])]));
}
void test_visitImportDirective_prefix_combinators() {
@@ -2779,6 +2767,11 @@
_assertSource("@deprecated m() {}", declaration);
}
+ void test_visitMethodInvocation_conditional() {
+ _assertSource("t?.m()", AstFactory.methodInvocation(
+ AstFactory.identifier3("t"), "m", null, TokenType.QUESTION_PERIOD));
+ }
+
void test_visitMethodInvocation_noTarget() {
_assertSource("m()", AstFactory.methodInvocation2("m"));
}
@@ -2865,6 +2858,11 @@
"a.b", AstFactory.propertyAccess2(AstFactory.identifier3("a"), "b"));
}
+ void test_visitPropertyAccess_conditional() {
+ _assertSource("a?.b", AstFactory.propertyAccess2(
+ AstFactory.identifier3("a"), "b", TokenType.QUESTION_PERIOD));
+ }
+
void test_visitRedirectingConstructorInvocation_named() {
_assertSource(
"this.c()", AstFactory.redirectingConstructorInvocation2("c"));
@@ -2952,9 +2950,9 @@
}
void test_visitSwitchCase_singleLabel() {
- _assertSource("l1: case a: {}", AstFactory.switchCase2([
- AstFactory.label2("l1")
- ], AstFactory.identifier3("a"), [AstFactory.block()]));
+ _assertSource("l1: case a: {}", AstFactory.switchCase2(
+ [AstFactory.label2("l1")], AstFactory.identifier3("a"),
+ [AstFactory.block()]));
}
void test_visitSwitchDefault_multipleLabels() {
@@ -3032,9 +3030,9 @@
void test_visitTryStatement_catchFinally() {
_assertSource("try {} on E {} finally {}", AstFactory.tryStatement3(
- AstFactory.block(), [
- AstFactory.catchClause3(AstFactory.typeName4("E"))
- ], AstFactory.block()));
+ AstFactory.block(),
+ [AstFactory.catchClause3(AstFactory.typeName4("E"))],
+ AstFactory.block()));
}
void test_visitTryStatement_finally() {
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 0ee4698..7b293a8 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -636,9 +636,8 @@
void test_builtInIdentifierAsTypeParameterName() {
Source source = addSource("class A<as> {}");
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_PARAMETER_NAME
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_PARAMETER_NAME]);
verify([source]);
}
@@ -984,9 +983,8 @@
}
const a = new A();''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE]);
verify([source]);
}
@@ -1012,9 +1010,8 @@
final a = const A();
const C = a.m;''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE]);
verify([source]);
}
@@ -1147,27 +1144,24 @@
const C = p;
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE]);
verify([source]);
}
void test_constInitializedWithNonConstValue_missingConstInListLiteral() {
Source source = addSource("const List L = [0];");
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE]);
verify([source]);
}
void test_constInitializedWithNonConstValue_missingConstInMapLiteral() {
Source source = addSource("const Map M = {'a' : 0};");
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE]);
verify([source]);
}
@@ -1219,9 +1213,8 @@
const {const A() : 0};
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS]);
verify([source]);
}
@@ -1241,9 +1234,8 @@
const {B.a : 0};
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS]);
verify([source]);
}
@@ -1261,9 +1253,8 @@
var m = const { const A(): 42 };
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS]);
verify([source]);
}
@@ -1280,9 +1271,8 @@
const {const B() : 0};
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS]);
verify([source]);
}
@@ -1441,9 +1431,8 @@
return const A();
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT]);
verify([source]);
}
@@ -1458,18 +1447,16 @@
void test_defaultValueInFunctionTypedParameter_named() {
Source source = addSource("f(g({p: null})) {}");
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPED_PARAMETER
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPED_PARAMETER]);
verify([source]);
}
void test_defaultValueInFunctionTypedParameter_optional() {
Source source = addSource("f(g([p = null])) {}");
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPED_PARAMETER
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPED_PARAMETER]);
verify([source]);
}
@@ -1911,9 +1898,8 @@
A() : x = 0, x = 1 {}
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS]);
verify([source]);
}
@@ -1953,9 +1939,8 @@
A(this.x) : x = 1 {}
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER]);
verify([source]);
}
@@ -2006,9 +1991,8 @@
A() : this.named(), x = 42;
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR]);
verify([source]);
}
@@ -2020,9 +2004,8 @@
A() : x = 42, this.named();
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR]);
verify([source]);
}
@@ -2034,9 +2017,8 @@
A(this.x) : this.named();
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR]);
verify([source]);
}
@@ -2047,9 +2029,8 @@
A() : x = 0, x = 0 {}
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.FIELD_INITIALIZED_BY_MULTIPLE_INITIALIZERS]);
verify([source]);
}
@@ -2068,9 +2049,8 @@
A(this.x) : x = 0 {}
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.FIELD_INITIALIZED_IN_PARAMETER_AND_INITIALIZER]);
verify([source]);
}
@@ -2603,9 +2583,8 @@
A(this.x) {}
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD]);
verify([source]);
}
@@ -2618,9 +2597,8 @@
B(this.x) {}
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD]);
verify([source]);
}
@@ -2630,9 +2608,8 @@
A([this.x]) {}
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD]);
verify([source]);
}
@@ -2643,9 +2620,8 @@
A(this.x) {}
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD]);
verify([source]);
}
@@ -3673,9 +3649,8 @@
A.b() {}
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.MULTIPLE_REDIRECTING_CONSTRUCTOR_INVOCATIONS
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.MULTIPLE_REDIRECTING_CONSTRUCTOR_INVOCATIONS]);
verify([source]);
}
@@ -3766,9 +3741,8 @@
}
''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT]);
verify([source]);
}
@@ -3785,9 +3759,8 @@
}
''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT]);
verify([source]);
}
@@ -3822,9 +3795,8 @@
}
''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT]);
verify([source]);
}
@@ -3840,9 +3812,8 @@
}
''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT]);
verify([source]);
}
@@ -4714,6 +4685,23 @@
verify([source]);
}
+ void test_recursiveFactoryRedirect_diverging() {
+ // Analysis should terminate even though the redirections don't reach a
+ // fixed point. (C<int> redirects to C<C<int>>, then to C<C<C<int>>>, and
+ // so on).
+ Source source = addSource('''
+class C<T> {
+ const factory C() = C<C<T>>;
+}
+main() {
+ const C<int>();
+}
+''');
+ resolve(source);
+ assertErrors(source, [CompileTimeErrorCode.RECURSIVE_FACTORY_REDIRECT]);
+ verify([source]);
+ }
+
void test_recursiveFactoryRedirect_generic() {
Source source = addSource(r'''
class A<T> implements B<T> {
@@ -4905,9 +4893,8 @@
void test_recursiveInterfaceInheritanceBaseCaseWith() {
Source source = addSource("class M = Object with M;");
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_WITH
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_WITH]);
verify([source]);
}
@@ -4917,9 +4904,8 @@
A() : this.noSuchConstructor();
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.REDIRECT_GENERATIVE_TO_MISSING_CONSTRUCTOR
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.REDIRECT_GENERATIVE_TO_MISSING_CONSTRUCTOR]);
}
void test_redirectGenerativeToNonGenerativeConstructor() {
@@ -5265,8 +5251,7 @@
resolve(source);
assertErrors(source, [
CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF,
- CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF,
- StaticTypeWarningCode.RETURN_OF_INVALID_TYPE
+ CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF
]);
verify([source]);
}
@@ -5405,9 +5390,8 @@
B() : super();
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT]);
verify([source]);
}
@@ -5420,9 +5404,8 @@
B();
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT]);
verify([source]);
}
@@ -5501,9 +5484,8 @@
operator -(a, b) {}
}''');
resolve(source);
- assertErrors(source, [
- CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR_MINUS
- ]);
+ assertErrors(source,
+ [CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR_MINUS]);
verify([source]);
reset();
}
diff --git a/pkg/analyzer/test/generated/element_test.dart b/pkg/analyzer/test/generated/element_test.dart
index 70509b3..7156161 100644
--- a/pkg/analyzer/test/generated/element_test.dart
+++ b/pkg/analyzer/test/generated/element_test.dart
@@ -29,7 +29,6 @@
runReflectiveTests(FunctionTypeImplTest);
runReflectiveTests(InterfaceTypeImplTest);
runReflectiveTests(TypeParameterTypeImplTest);
- runReflectiveTests(UnionTypeImplTest);
runReflectiveTests(VoidTypeImplTest);
runReflectiveTests(ClassElementImplTest);
runReflectiveTests(CompilationUnitElementImplTest);
@@ -2634,8 +2633,9 @@
}
void test_isAssignableTo_void() {
+ InterfaceTypeImpl intType = _typeProvider.intType;
expect(
- VoidTypeImpl.instance.isAssignableTo(_typeProvider.intType), isFalse);
+ VoidTypeImpl.instance.isAssignableTo(intType), isFalse);
}
void test_isDirectSupertypeOf_extends() {
@@ -3750,203 +3750,6 @@
}
@reflectiveTest
-class UnionTypeImplTest extends EngineTestCase {
- ClassElement _classA;
-
- InterfaceType _typeA;
-
- ClassElement _classB;
-
- InterfaceType _typeB;
-
- DartType _uA;
-
- DartType _uB;
-
- DartType _uAB;
-
- DartType _uBA;
-
- List<DartType> _us;
-
- @override
- void setUp() {
- super.setUp();
- _classA = ElementFactory.classElement2("A");
- _typeA = _classA.type;
- _classB = ElementFactory.classElement("B", _typeA);
- _typeB = _classB.type;
- _uA = UnionTypeImpl.union([_typeA]);
- _uB = UnionTypeImpl.union([_typeB]);
- _uAB = UnionTypeImpl.union([_typeA, _typeB]);
- _uBA = UnionTypeImpl.union([_typeB, _typeA]);
- _us = <DartType>[_uA, _uB, _uAB, _uBA];
- }
-
- void test_emptyUnionsNotAllowed() {
- try {
- UnionTypeImpl.union([]);
- } on IllegalArgumentException {
- return;
- }
- fail("Expected illegal argument exception.");
- }
-
- void test_equality_beingASubtypeOfAnElementIsNotSufficient() {
- // Non-equal if some elements are different
- expect(_uAB == _uA, isFalse);
- }
-
- void test_equality_insertionOrderDoesntMatter() {
- // Insertion order doesn't matter, only sets of elements
- expect(_uAB == _uBA, isTrue);
- expect(_uBA == _uAB, isTrue);
- }
-
- void test_equality_reflexivity() {
- for (DartType u in _us) {
- expect(u == u, isTrue);
- }
- }
-
- void test_equality_singletonsCollapse() {
- expect(_typeA == _uA, isTrue);
- expect(_uA == _typeA, isTrue);
- }
-
- void test_isMoreSpecificThan_allElementsOnLHSAreSubtypesOfSomeElementOnRHS() {
- // Unions are subtypes when all elements are subtypes
- expect(_uAB.isMoreSpecificThan(_uA), isTrue);
- expect(_uAB.isMoreSpecificThan(_typeA), isTrue);
- }
-
- void test_isMoreSpecificThan_element() {
- // Elements of union are sub types
- expect(_typeA.isMoreSpecificThan(_uAB), isTrue);
- expect(_typeB.isMoreSpecificThan(_uAB), isTrue);
- }
-
- void test_isMoreSpecificThan_notSubtypeOfAnyElement() {
- // Types that are not subtypes of elements are not subtypes
- expect(_typeA.isMoreSpecificThan(_uB), isFalse);
- }
-
- void test_isMoreSpecificThan_reflexivity() {
- for (DartType u in _us) {
- expect(u.isMoreSpecificThan(u), isTrue);
- }
- }
-
- void test_isMoreSpecificThan_someElementOnLHSIsNotASubtypeOfAnyElementOnRHS() {
- // Unions are subtypes when some element is a subtype
- expect(_uAB.isMoreSpecificThan(_uB), isTrue);
- expect(_uAB.isMoreSpecificThan(_typeB), isTrue);
- }
-
- void test_isMoreSpecificThan_subtypeOfSomeElement() {
- // Subtypes of elements are sub types
- expect(_typeB.isMoreSpecificThan(_uA), isTrue);
- }
-
- void test_isSubtypeOf_allElementsOnLHSAreSubtypesOfSomeElementOnRHS() {
- // Unions are subtypes when all elements are subtypes
- expect(_uAB.isSubtypeOf(_uA), isTrue);
- expect(_uAB.isSubtypeOf(_typeA), isTrue);
- }
-
- void test_isSubtypeOf_element() {
- // Elements of union are sub types
- expect(_typeA.isSubtypeOf(_uAB), isTrue);
- expect(_typeB.isSubtypeOf(_uAB), isTrue);
- }
-
- void test_isSubtypeOf_notSubtypeOfAnyElement() {
- // Types that are not subtypes of elements are not subtypes
- expect(_typeA.isSubtypeOf(_uB), isFalse);
- }
-
- void test_isSubtypeOf_reflexivity() {
- for (DartType u in _us) {
- expect(u.isSubtypeOf(u), isTrue);
- }
- }
-
- void test_isSubtypeOf_someElementOnLHSIsNotASubtypeOfAnyElementOnRHS() {
- // Unions are subtypes when some element is a subtype
- expect(_uAB.isSubtypeOf(_uB), isTrue);
- expect(_uAB.isSubtypeOf(_typeB), isTrue);
- }
-
- void test_isSubtypeOf_subtypeOfSomeElement() {
- // Subtypes of elements are sub types
- expect(_typeB.isSubtypeOf(_uA), isTrue);
- }
-
- void test_nestedUnionsCollapse() {
- UnionType u = UnionTypeImpl.union([_uAB, _typeA]) as UnionType;
- for (DartType t in u.elements) {
- if (t is UnionType) {
- fail("Expected only non-union types but found $t!");
- }
- }
- }
-
- void test_noLossage() {
- UnionType u = UnionTypeImpl
- .union([_typeA, _typeB, _typeB, _typeA, _typeB, _typeB]) as UnionType;
- Set<DartType> elements = u.elements;
- expect(elements.contains(_typeA), isTrue);
- expect(elements.contains(_typeB), isTrue);
- expect(elements.length == 2, isTrue);
- }
-
- void test_substitute() {
- // Based on [InterfaceTypeImplTest.test_substitute_equal].
- ClassElement classAE = ElementFactory.classElement2("A", ["E"]);
- InterfaceType typeAE = classAE.type;
- List<DartType> args = [_typeB];
- List<DartType> params = [classAE.typeParameters[0].type];
- DartType typeAESubbed = typeAE.substitute2(args, params);
- expect(typeAE == typeAESubbed, isFalse);
- expect(UnionTypeImpl.union([_typeA, typeAESubbed]),
- UnionTypeImpl.union([_typeA, typeAE]).substitute2(args, params));
- }
-
- void test_toString_pair() {
- String s = _uAB.toString();
- expect(s == "{A,B}" || s == "{B,A}", isTrue);
- expect(_uAB.displayName, s);
- }
-
- void test_toString_singleton() {
- // Singleton unions collapse to the the single type.
- expect(_uA.toString(), "A");
- }
-
- void test_unionTypeIsLessSpecificThan_function() {
- // Based on
- // [FunctionTypeImplTest.test_isAssignableTo_normalAndPositionalArgs].
- ClassElement a = ElementFactory.classElement2("A");
- FunctionType t =
- ElementFactory.functionElement6("t", null, <ClassElement>[a]).type;
- DartType uAT = UnionTypeImpl.union([_uA, t]);
- expect(t.isMoreSpecificThan(uAT), isTrue);
- expect(t.isMoreSpecificThan(_uAB), isFalse);
- }
-
- void test_unionTypeIsSuperTypeOf_function() {
- // Based on
- // [FunctionTypeImplTest.test_isAssignableTo_normalAndPositionalArgs].
- ClassElement a = ElementFactory.classElement2("A");
- FunctionType t =
- ElementFactory.functionElement6("t", null, <ClassElement>[a]).type;
- DartType uAT = UnionTypeImpl.union([_uA, t]);
- expect(t.isSubtypeOf(uAT), isTrue);
- expect(t.isSubtypeOf(_uAB), isFalse);
- }
-}
-
-@reflectiveTest
class VoidTypeImplTest extends EngineTestCase {
/**
* Reference {code VoidTypeImpl.getInstance()}.
diff --git a/pkg/analyzer/test/generated/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index 52b8c40..2ecb8d8 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -2221,6 +2221,7 @@
options.analyzeFunctionBodies = booleanValue;
options.cacheSize = i;
options.dart2jsHint = booleanValue;
+ options.enableNullAwareOperators = booleanValue;
options.enableStrictCallChecks = booleanValue;
options.generateImplicitErrors = booleanValue;
options.generateSdkErrors = booleanValue;
@@ -2231,6 +2232,7 @@
expect(copy.analyzeFunctionBodies, options.analyzeFunctionBodies);
expect(copy.cacheSize, options.cacheSize);
expect(copy.dart2jsHint, options.dart2jsHint);
+ expect(copy.enableNullAwareOperators, options.enableNullAwareOperators);
expect(copy.enableStrictCallChecks, options.enableStrictCallChecks);
expect(copy.generateImplicitErrors, options.generateImplicitErrors);
expect(copy.generateSdkErrors, options.generateSdkErrors);
@@ -2335,7 +2337,8 @@
DartEntry entry = new DartEntry();
expect(entry.allErrors, hasLength(0));
entry.setValue(SourceEntry.CONTENT_ERRORS, <AnalysisError>[
- new AnalysisError.con1(source, ScannerErrorCode.UNABLE_GET_CONTENT)
+ new AnalysisError.con1(
+ source, ScannerErrorCode.UNABLE_GET_CONTENT, ['exception details'])
]);
entry.setValue(DartEntry.SCAN_ERRORS, <AnalysisError>[
new AnalysisError.con1(
@@ -4539,6 +4542,13 @@
AstVisitor getVisitor() => null;
}
+class MockSourceFactory extends SourceFactory {
+ MockSourceFactory() : super([]);
+ Source resolveUri(Source containingSource, String containedUri) {
+ throw new JavaIOException();
+ }
+}
+
@reflectiveTest
class ParseDartTaskTest extends EngineTestCase {
void test_accept() {
@@ -4627,6 +4637,26 @@
new ParseDartTaskTestTV_perform_validateDirectives(context, source));
}
+ void test_resolveDirective_dartUri() {
+ GatheringErrorListener listener = new GatheringErrorListener();
+ ImportDirective directive = AstFactory.importDirective3('dart:core', null);
+ AnalysisContext context = AnalysisContextFactory.contextWithCore();
+ Source source =
+ ParseDartTask.resolveDirective(context, null, directive, listener);
+ expect(source, isNotNull);
+ }
+
+ void test_resolveDirective_exception() {
+ GatheringErrorListener listener = new GatheringErrorListener();
+ ImportDirective directive = AstFactory.importDirective3('dart:core', null);
+ AnalysisContext context = new AnalysisContextImpl();
+ context.sourceFactory = new MockSourceFactory();
+ Source source =
+ ParseDartTask.resolveDirective(context, null, directive, listener);
+ expect(source, isNull);
+ expect(listener.errors, hasLength(1));
+ }
+
/**
* Create and return a task that will parse the given content from the given source in the given
* context.
@@ -5464,6 +5494,11 @@
return null;
}
@override
+ LibraryResolverFactory get libraryResolverFactory {
+ fail("Unexpected invocation of getLibraryResolverFactory");
+ return null;
+ }
+ @override
ResolverVisitorFactory get resolverVisitorFactory {
fail("Unexpected invocation of getResolverVisitorFactory");
return null;
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index 8b664f9..0d4c7ee 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -305,6 +305,66 @@
''');
}
+ void test_false_constructor_keywordConst_add() {
+ _assertDoesNotMatch(r'''
+class A {
+ A();
+}
+''', r'''
+class A {
+ const A();
+}
+''');
+ }
+
+ void test_false_constructor_keywordConst_remove() {
+ _assertDoesNotMatch(r'''
+class A {
+ const A();
+}
+''', r'''
+class A {
+ A();
+}
+''');
+ }
+
+ void test_false_constructor_keywordFactory_add() {
+ _assertDoesNotMatch(r'''
+class A {
+ A();
+ A.foo() {
+ return new A();
+ }
+}
+''', r'''
+class A {
+ A();
+ factory A.foo() {
+ return new A();
+ }
+}
+''');
+ }
+
+ void test_false_constructor_keywordFactory_remove() {
+ _assertDoesNotMatch(r'''
+class A {
+ A();
+ factory A.foo() {
+ return new A();
+ }
+}
+''', r'''
+class A {
+ A();
+ A.foo() {
+ return new A();
+ }
+}
+''');
+ }
+
void test_false_constructor_parameters_list_add() {
_assertDoesNotMatch(r'''
class A {
@@ -2810,6 +2870,23 @@
_resetWithIncremental(true);
}
+ void test_computeConstants() {
+ _resolveUnit(r'''
+int f() => 0;
+main() {
+ const x = f();
+ print(x + 1);
+}
+''');
+ _updateAndValidate(r'''
+int f() => 0;
+main() {
+ const x = f();
+ print(x + 2);
+}
+''');
+ }
+
void test_dartDoc_beforeField() {
_resolveUnit(r'''
class A {
@@ -3121,6 +3198,29 @@
''');
}
+ void test_false_constConstructor_initializer() {
+ _resolveUnit(r'''
+class C {
+ final int x;
+ const C(this.x);
+ const C.foo() : x = 0;
+}
+main() {
+ const {const C(0): 0, const C.foo(): 1};
+}
+''');
+ _updateAndValidate(r'''
+class C {
+ final int x;
+ const C(this.x);
+ const C.foo() : x = 1;
+}
+main() {
+ const {const C(0): 0, const C.foo(): 1};
+}
+''', expectedSuccess: false);
+ }
+
void test_false_topLevelFunction_name() {
_resolveUnit(r'''
a() {}
diff --git a/pkg/analyzer/test/generated/incremental_scanner_test.dart b/pkg/analyzer/test/generated/incremental_scanner_test.dart
index c0b4365..7307dfb 100644
--- a/pkg/analyzer/test/generated/incremental_scanner_test.dart
+++ b/pkg/analyzer/test/generated/incremental_scanner_test.dart
@@ -4,6 +4,7 @@
library engine.incremental_scanner_test;
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/incremental_scanner.dart';
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -220,13 +221,6 @@
expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
}
- void test_insert_periodAndIdentifier() {
- // "a + b;"
- // "a + b.x;"
- _scan("a + b", "", ".x", ";");
- _assertTokens(2, 5, ["a", "+", "b", ".", "x", ";"]);
- }
-
void test_insert_period_afterIdentifier() {
// "a + b;"
// "a + b.;"
@@ -265,6 +259,13 @@
expect(_incrementalScanner.hasNonWhitespaceChange, isTrue);
}
+ void test_insert_periodAndIdentifier() {
+ // "a + b;"
+ // "a + b.x;"
+ _scan("a + b", "", ".x", ";");
+ _assertTokens(2, 5, ["a", "+", "b", ".", "x", ";"]);
+ }
+
void test_insert_splitIdentifier() {
// "cob;"
// "cow.b;"
@@ -498,8 +499,9 @@
// Incrementally scan the modified contents.
//
GatheringErrorListener incrementalListener = new GatheringErrorListener();
- _incrementalScanner = new IncrementalScanner(
- source, new CharSequenceReader(modifiedContents), incrementalListener);
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ _incrementalScanner = new IncrementalScanner(source,
+ new CharSequenceReader(modifiedContents), incrementalListener, options);
_incrementalTokens = _incrementalScanner.rescan(
_originalTokens, replaceStart, removed.length, added.length);
//
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 1120177..25ba9fa 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -6,6 +6,7 @@
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
import 'package:analyzer/src/generated/source_io.dart';
@@ -933,6 +934,15 @@
verify([source]);
}
+ void test_const_dynamic() {
+ Source source = addSource('''
+const Type d = dynamic;
+''');
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_constConstructorWithNonConstSuper_explicit() {
Source source = addSource(r'''
class A {
@@ -2298,6 +2308,36 @@
verify([source]);
}
+ void test_invalidAssignment_ifNullAssignment_compatibleType() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableNullAwareOperators = true;
+ resetWithOptions(options);
+ Source source = addSource('''
+void f(int i) {
+ num n;
+ n ??= i;
+}
+''');
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_invalidAssignment_ifNullAssignment_sameType() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableNullAwareOperators = true;
+ resetWithOptions(options);
+ Source source = addSource('''
+void f(int i) {
+ int j;
+ j ??= i;
+}
+''');
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_invalidAssignment_implicitlyImplementFunctionViaCall_1() {
// 18341
//
@@ -4893,6 +4933,21 @@
verify([source]);
}
+ void test_undefinedGetter_typeLiteral_conditionalAccess() {
+ // When applied to a type literal, the conditional access operator '?.' can
+ // be used to access instance getters of Type.
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableNullAwareOperators = true;
+ resetWithOptions(options);
+ Source source = addSource('''
+class A {}
+f() => A?.hashCode;
+''');
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_undefinedGetter_typeSubstitution() {
Source source = addSource(r'''
class A<E> {
@@ -4968,6 +5023,21 @@
// A call to verify(source) fails as '(() => null)()' isn't resolved.
}
+ void test_undefinedMethod_typeLiteral_conditionalAccess() {
+ // When applied to a type literal, the conditional access operator '?.' can
+ // be used to access instance methods of Type.
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableNullAwareOperators = true;
+ resetWithOptions(options);
+ Source source = addSource('''
+class A {}
+f() => A?.toString();
+''');
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_undefinedOperator_index() {
Source source = addSource(r'''
class A {
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 648ea6b..514c0d7 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -6,6 +6,7 @@
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/incremental_scanner.dart';
import 'package:analyzer/src/generated/parser.dart';
@@ -316,6 +317,13 @@
}
}
+ void test_conditionalExpression_precedence_ifNullExpression() {
+ _enableNullAwareOperators = true;
+ ConditionalExpression expression = parseExpression('a ?? b ? y : z');
+ EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
+ BinaryExpression, expression.condition);
+ }
+
void test_conditionalExpression_precedence_logicalOrExpression() {
ConditionalExpression expression = parseExpression("a | b ? y : z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
@@ -359,6 +367,27 @@
BinaryExpression, expression.leftOperand);
}
+ void test_ifNullExpression() {
+ _enableNullAwareOperators = true;
+ BinaryExpression expression = parseExpression('x ?? y ?? z');
+ EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
+ BinaryExpression, expression.leftOperand);
+ }
+
+ void test_ifNullExpression_precedence_logicalOr_left() {
+ _enableNullAwareOperators = true;
+ BinaryExpression expression = parseExpression('x || y ?? z');
+ EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
+ BinaryExpression, expression.leftOperand);
+ }
+
+ void test_ifNullExpression_precendce_logicalOr_right() {
+ _enableNullAwareOperators = true;
+ BinaryExpression expression = parseExpression('x ?? y || z');
+ EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
+ BinaryExpression, expression.rightOperand);
+ }
+
void test_logicalAndExpression() {
BinaryExpression expression = parseExpression("x && y && z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
@@ -1166,8 +1195,9 @@
}
void test_getterInFunction_block_noReturnType() {
- ParserTestCase.parseStatement(
+ FunctionDeclarationStatement statement = ParserTestCase.parseStatement(
"get x { return _x; }", [ParserErrorCode.GETTER_IN_FUNCTION]);
+ expect(statement.functionDeclaration.functionExpression.parameters, isNull);
}
void test_getterInFunction_block_returnType() {
@@ -1272,6 +1302,18 @@
[ParserErrorCode.INVALID_OPERATOR]);
}
+ void test_invalidOperatorAfterSuper_assignableExpression() {
+ _enableNullAwareOperators = true;
+ parse3('parseAssignableExpression', <Object>[false], 'super?.v',
+ [ParserErrorCode.INVALID_OPERATOR_FOR_SUPER]);
+ }
+
+ void test_invalidOperatorAfterSuper_primaryExpression() {
+ _enableNullAwareOperators = true;
+ parse4('parsePrimaryExpression', 'super?.v',
+ [ParserErrorCode.INVALID_OPERATOR_FOR_SUPER]);
+ }
+
void test_invalidOperatorForSuper() {
parse4("parseUnaryExpression", "++super",
[ParserErrorCode.INVALID_OPERATOR_FOR_SUPER]);
@@ -1456,13 +1498,17 @@
}
void test_missingFunctionParameters_topLevel_void_block() {
- ParserTestCase.parseCompilationUnit(
+ CompilationUnit unit = ParserTestCase.parseCompilationUnit(
"void f { return x;}", [ParserErrorCode.MISSING_FUNCTION_PARAMETERS]);
+ FunctionDeclaration funct = unit.declarations[0];
+ expect(funct.functionExpression.parameters, hasLength(0));
}
void test_missingFunctionParameters_topLevel_void_expression() {
- ParserTestCase.parseCompilationUnit(
+ CompilationUnit unit = ParserTestCase.parseCompilationUnit(
"void f => x;", [ParserErrorCode.MISSING_FUNCTION_PARAMETERS]);
+ FunctionDeclaration funct = unit.declarations[0];
+ expect(funct.functionExpression.parameters, hasLength(0));
}
void test_missingIdentifier_afterOperator() {
@@ -1525,8 +1571,9 @@
}
void test_missingMethodParameters_void_block() {
- parse3("parseClassMember", <Object>["C"], "void m {} }",
- [ParserErrorCode.MISSING_METHOD_PARAMETERS]);
+ MethodDeclaration method = parse3("parseClassMember", <Object>["C"],
+ "void m {} }", [ParserErrorCode.MISSING_METHOD_PARAMETERS]);
+ expect(method.parameters, hasLength(0));
}
void test_missingMethodParameters_void_expression() {
@@ -1828,6 +1875,12 @@
]);
}
+ void test_topLevel_getter() {
+ FunctionDeclaration funct = parse3("parseCompilationUnitMember",
+ <Object>[emptyCommentAndMetadata()], "get x => 7;");
+ expect(funct.functionExpression.parameters, isNull);
+ }
+
void test_topLevelOperator_withoutType() {
parse3("parseCompilationUnitMember", <Object>[emptyCommentAndMetadata()],
"operator +(bool x, bool y) => x | y;",
@@ -1888,6 +1941,70 @@
"int x; ; int y;", [ParserErrorCode.UNEXPECTED_TOKEN]);
}
+ void test_unterminatedString_at_eof() {
+ // Although the "unterminated string" error message is produced by the
+ // scanner, we need to verify that the parser can handle the tokens
+ // produced by the scanner when an unterminated string is encountered.
+ ParserTestCase.parseCompilationUnit(r'''
+void main() {
+ var x = "''', [
+ ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
+ ParserErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.EXPECTED_TOKEN
+ ]);
+ }
+
+ void test_unterminatedString_at_eol() {
+ // Although the "unterminated string" error message is produced by the
+ // scanner, we need to verify that the parser can handle the tokens
+ // produced by the scanner when an unterminated string is encountered.
+ ParserTestCase.parseCompilationUnit(r'''
+void main() {
+ var x = "
+;
+}
+''', [ScannerErrorCode.UNTERMINATED_STRING_LITERAL]);
+ }
+
+ void test_unterminatedString_multiline_at_eof_3_quotes() {
+ // Although the "unterminated string" error message is produced by the
+ // scanner, we need to verify that the parser can handle the tokens
+ // produced by the scanner when an unterminated string is encountered.
+ ParserTestCase.parseCompilationUnit(r'''
+void main() {
+ var x = """''', [
+ ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
+ ParserErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.EXPECTED_TOKEN
+ ]);
+ }
+
+ void test_unterminatedString_multiline_at_eof_4_quotes() {
+ // Although the "unterminated string" error message is produced by the
+ // scanner, we need to verify that the parser can handle the tokens
+ // produced by the scanner when an unterminated string is encountered.
+ ParserTestCase.parseCompilationUnit(r'''
+void main() {
+ var x = """"''', [
+ ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
+ ParserErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.EXPECTED_TOKEN
+ ]);
+ }
+
+ void test_unterminatedString_multiline_at_eof_5_quotes() {
+ // Although the "unterminated string" error message is produced by the
+ // scanner, we need to verify that the parser can handle the tokens
+ // produced by the scanner when an unterminated string is encountered.
+ ParserTestCase.parseCompilationUnit(r'''
+void main() {
+ var x = """""''', [
+ ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
+ ParserErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.EXPECTED_TOKEN
+ ]);
+ }
+
void test_useOfUnaryPlusOperator() {
SimpleIdentifier expression = parse4(
"parseUnaryExpression", "+x", [ParserErrorCode.MISSING_IDENTIFIER]);
@@ -2360,8 +2477,9 @@
// Incrementally parse the modified contents.
//
GatheringErrorListener incrementalListener = new GatheringErrorListener();
- IncrementalScanner incrementalScanner = new IncrementalScanner(
- source, new CharSequenceReader(modifiedContents), incrementalListener);
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ IncrementalScanner incrementalScanner = new IncrementalScanner(source,
+ new CharSequenceReader(modifiedContents), incrementalListener, options);
Token incrementalTokens = incrementalScanner.rescan(
originalTokens, replaceStart, removed.length, added.length);
expect(incrementalTokens, isNotNull);
@@ -2399,6 +2517,12 @@
static bool parseFunctionBodies = true;
/**
+ * If non-null, this value is used to override the default value of
+ * [Scanner.enableNullAwareOperators] before scanning.
+ */
+ bool _enableNullAwareOperators;
+
+ /**
* Return a CommentAndMetadata object with the given values that can be used for testing.
*
* @param comment the comment to be wrapped in the object
@@ -2441,6 +2565,9 @@
//
Scanner scanner =
new Scanner(null, new CharSequenceReader(source), listener);
+ if (_enableNullAwareOperators != null) {
+ scanner.enableNullAwareOperators = _enableNullAwareOperators;
+ }
Token tokenStream = scanner.tokenize();
listener.setLineInfo(new TestSource(), scanner.lineStarts);
//
@@ -2574,6 +2701,9 @@
GatheringErrorListener listener = new GatheringErrorListener();
Scanner scanner =
new Scanner(null, new CharSequenceReader(source), listener);
+ if (_enableNullAwareOperators != null) {
+ scanner.enableNullAwareOperators = _enableNullAwareOperators;
+ }
listener.setLineInfo(new TestSource(), scanner.lineStarts);
Token token = scanner.tokenize();
Parser parser = createParser(listener);
@@ -3139,6 +3269,36 @@
parseExpression("m(f() => 0);", [ParserErrorCode.EXPECTED_TOKEN]);
}
+ void test_importDirectivePartial_as() {
+ CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+ "import 'b.dart' d as b;",
+ [ParserErrorCode.UNEXPECTED_TOKEN]);
+ ImportDirective importDirective = unit.childEntities.first;
+ expect(importDirective.asKeyword, isNotNull);
+ expect(unit.directives, hasLength(1));
+ expect(unit.declarations, hasLength(0));
+ }
+
+ void test_importDirectivePartial_show() {
+ CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+ "import 'b.dart' d show foo;",
+ [ParserErrorCode.UNEXPECTED_TOKEN]);
+ ImportDirective importDirective = unit.childEntities.first;
+ expect(importDirective.combinators, hasLength(1));
+ expect(unit.directives, hasLength(1));
+ expect(unit.declarations, hasLength(0));
+ }
+
+ void test_importDirectivePartial_hide() {
+ CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+ "import 'b.dart' d hide foo;",
+ [ParserErrorCode.UNEXPECTED_TOKEN]);
+ ImportDirective importDirective = unit.childEntities.first;
+ expect(importDirective.combinators, hasLength(1));
+ expect(unit.directives, hasLength(1));
+ expect(unit.declarations, hasLength(0));
+ }
+
void test_incomplete_conditionalExpression() {
parseExpression("x ? 0", [
ParserErrorCode.EXPECTED_TOKEN,
@@ -4469,6 +4629,15 @@
ParserTestCase.parseCompilationUnit("class C { C() : a = \"\${(){}}\"; }");
}
+ void test_import_as_show() {
+ ParserTestCase.parseCompilationUnit("import 'dart:math' as M show E;");
+ }
+
+ void test_import_show_hide() {
+ ParserTestCase.parseCompilationUnit(
+ "import 'import1_lib.dart' show hide, show hide ugly;");
+ }
+
void test_isFunctionDeclaration_nameButNoReturn_block() {
expect(_isFunctionDeclaration("f() {}"), isTrue);
}
@@ -4769,7 +4938,7 @@
PropertyAccess propertyAccess =
parse("parseAssignableExpression", <Object>[false], "(x).y");
expect(propertyAccess.target, isNotNull);
- expect(propertyAccess.operator, isNotNull);
+ expect(propertyAccess.operator.type, TokenType.PERIOD);
expect(propertyAccess.propertyName, isNotNull);
}
@@ -4782,6 +4951,15 @@
expect(expression.rightBracket, isNotNull);
}
+ void test_parseAssignableExpression_expression_question_dot() {
+ _enableNullAwareOperators = true;
+ PropertyAccess propertyAccess =
+ parse("parseAssignableExpression", <Object>[false], "(x)?.y");
+ expect(propertyAccess.target, isNotNull);
+ expect(propertyAccess.operator.type, TokenType.QUESTION_PERIOD);
+ expect(propertyAccess.propertyName, isNotNull);
+ }
+
void test_parseAssignableExpression_identifier() {
SimpleIdentifier identifier =
parse("parseAssignableExpression", <Object>[false], "x");
@@ -4805,6 +4983,7 @@
parse("parseAssignableExpression", <Object>[false], "x.y");
expect(propertyAccess.target, isNotNull);
expect(propertyAccess.operator, isNotNull);
+ expect(propertyAccess.operator.type, TokenType.PERIOD);
expect(propertyAccess.propertyName, isNotNull);
}
@@ -4817,6 +4996,15 @@
expect(expression.rightBracket, isNotNull);
}
+ void test_parseAssignableExpression_identifier_question_dot() {
+ _enableNullAwareOperators = true;
+ PropertyAccess propertyAccess =
+ parse("parseAssignableExpression", <Object>[false], "x?.y");
+ expect(propertyAccess.target, isNotNull);
+ expect(propertyAccess.operator.type, TokenType.QUESTION_PERIOD);
+ expect(propertyAccess.propertyName, isNotNull);
+ }
+
void test_parseAssignableExpression_super_dot() {
PropertyAccess propertyAccess =
parse("parseAssignableExpression", <Object>[false], "super.y");
@@ -4839,7 +5027,7 @@
void test_parseAssignableSelector_dot() {
PropertyAccess selector =
parse("parseAssignableSelector", <Object>[null, true], ".x");
- expect(selector.operator, isNotNull);
+ expect(selector.operator.type, TokenType.PERIOD);
expect(selector.propertyName, isNotNull);
}
@@ -4859,6 +5047,14 @@
expect(selector, isNotNull);
}
+ void test_parseAssignableSelector_question_dot() {
+ _enableNullAwareOperators = true;
+ PropertyAccess selector =
+ parse("parseAssignableSelector", <Object>[null, true], "?.x");
+ expect(selector.operator.type, TokenType.QUESTION_PERIOD);
+ expect(selector.propertyName, isNotNull);
+ }
+
void test_parseAwaitExpression() {
AwaitExpression expression = parse4("parseAwaitExpression", "await x;");
expect(expression.awaitKeyword, isNotNull);
@@ -4996,7 +5192,7 @@
MethodInvocation section = parse4("parseCascadeSection", "..a(b).c(d)");
EngineTestCase.assertInstanceOf(
(obj) => obj is MethodInvocation, MethodInvocation, section.target);
- expect(section.period, isNotNull);
+ expect(section.operator, isNotNull);
expect(section.methodName, isNotNull);
expect(section.argumentList, isNotNull);
expect(section.argumentList.arguments, hasLength(1));
@@ -5037,7 +5233,7 @@
void test_parseCascadeSection_pa() {
MethodInvocation section = parse4("parseCascadeSection", "..a(b)");
expect(section.target, isNull);
- expect(section.period, isNotNull);
+ expect(section.operator, isNotNull);
expect(section.methodName, isNotNull);
expect(section.argumentList, isNotNull);
expect(section.argumentList.arguments, hasLength(1));
@@ -5365,6 +5561,7 @@
expect(method.name, isNotNull);
expect(method.operatorKeyword, isNull);
expect(method.body, isNotNull);
+ expect(method.parameters, isNull);
}
void test_parseClassMember_method_external() {
@@ -7154,6 +7351,46 @@
expect(parameterList.rightParenthesis, isNotNull);
}
+ void test_parseFormalParameterList_prefixedType() {
+ FormalParameterList parameterList =
+ parse4("parseFormalParameterList", "(io.File f)");
+ expect(parameterList.leftParenthesis, isNotNull);
+ expect(parameterList.leftDelimiter, isNull);
+ expect(parameterList.parameters, hasLength(1));
+ expect(parameterList.parameters[0].toSource(), 'io.File f');
+ expect(parameterList.rightDelimiter, isNull);
+ expect(parameterList.rightParenthesis, isNotNull);
+ }
+
+ void test_parseFormalParameterList_prefixedType_partial() {
+ FormalParameterList parameterList = parse4("parseFormalParameterList",
+ "(io.)", [
+ ParserErrorCode.MISSING_IDENTIFIER,
+ ParserErrorCode.MISSING_IDENTIFIER
+ ]);
+ expect(parameterList.leftParenthesis, isNotNull);
+ expect(parameterList.leftDelimiter, isNull);
+ expect(parameterList.parameters, hasLength(1));
+ expect(parameterList.parameters[0].toSource(), 'io. ');
+ expect(parameterList.rightDelimiter, isNull);
+ expect(parameterList.rightParenthesis, isNotNull);
+ }
+
+ void test_parseFormalParameterList_prefixedType_partial2() {
+ FormalParameterList parameterList = parse4("parseFormalParameterList",
+ "(io.,a)", [
+ ParserErrorCode.MISSING_IDENTIFIER,
+ ParserErrorCode.MISSING_IDENTIFIER
+ ]);
+ expect(parameterList.leftParenthesis, isNotNull);
+ expect(parameterList.leftDelimiter, isNull);
+ expect(parameterList.parameters, hasLength(2));
+ expect(parameterList.parameters[0].toSource(), 'io. ');
+ expect(parameterList.parameters[1].toSource(), 'a');
+ expect(parameterList.rightDelimiter, isNull);
+ expect(parameterList.rightParenthesis, isNotNull);
+ }
+
void test_parseForStatement_each_await() {
ForEachStatement statement =
parse4("parseForStatement", "await for (element in list) {}");
@@ -8435,6 +8672,16 @@
void test_parsePostfixExpression_none_methodInvocation() {
MethodInvocation expression = parse4("parsePostfixExpression", "a.m()");
expect(expression.target, isNotNull);
+ expect(expression.operator.type, TokenType.PERIOD);
+ expect(expression.methodName, isNotNull);
+ expect(expression.argumentList, isNotNull);
+ }
+
+ void test_parsePostfixExpression_none_methodInvocation_question_dot() {
+ _enableNullAwareOperators = true;
+ MethodInvocation expression = parse4('parsePostfixExpression', 'a?.m()');
+ expect(expression.target, isNotNull);
+ expect(expression.operator.type, TokenType.QUESTION_PERIOD);
expect(expression.methodName, isNotNull);
expect(expression.argumentList, isNotNull);
}
@@ -8822,6 +9069,23 @@
expect((secondString as SimpleStringLiteral).value, "b");
}
+ void test_parseStringLiteral_endsWithInterpolation() {
+ StringLiteral literal = parse4('parseStringLiteral', r"'x$y'");
+ expect(literal, new isInstanceOf<StringInterpolation>());
+ StringInterpolation interpolation = literal;
+ expect(interpolation.elements, hasLength(3));
+ expect(interpolation.elements[0], new isInstanceOf<InterpolationString>());
+ InterpolationString element0 = interpolation.elements[0];
+ expect(element0.value, 'x');
+ expect(
+ interpolation.elements[1], new isInstanceOf<InterpolationExpression>());
+ InterpolationExpression element1 = interpolation.elements[1];
+ expect(element1.expression, new isInstanceOf<SimpleIdentifier>());
+ expect(interpolation.elements[2], new isInstanceOf<InterpolationString>());
+ InterpolationString element2 = interpolation.elements[2];
+ expect(element2.value, '');
+ }
+
void test_parseStringLiteral_interpolated() {
StringInterpolation literal =
parse4("parseStringLiteral", "'a \${b} c \$this d'");
@@ -8834,12 +9098,173 @@
expect(elements[4] is InterpolationString, isTrue);
}
+ void test_parseStringLiteral_multiline_encodedSpace() {
+ SimpleStringLiteral literal =
+ parse4("parseStringLiteral", "'''\\x20\na'''");
+ expect(literal.literal, isNotNull);
+ expect(literal.value, " \na");
+ }
+
+ void test_parseStringLiteral_multiline_endsWithInterpolation() {
+ StringLiteral literal = parse4('parseStringLiteral', r"'''x$y'''");
+ expect(literal, new isInstanceOf<StringInterpolation>());
+ StringInterpolation interpolation = literal;
+ expect(interpolation.elements, hasLength(3));
+ expect(interpolation.elements[0], new isInstanceOf<InterpolationString>());
+ InterpolationString element0 = interpolation.elements[0];
+ expect(element0.value, 'x');
+ expect(
+ interpolation.elements[1], new isInstanceOf<InterpolationExpression>());
+ InterpolationExpression element1 = interpolation.elements[1];
+ expect(element1.expression, new isInstanceOf<SimpleIdentifier>());
+ expect(interpolation.elements[2], new isInstanceOf<InterpolationString>());
+ InterpolationString element2 = interpolation.elements[2];
+ expect(element2.value, '');
+ }
+
+ void test_parseStringLiteral_multiline_escapedBackslash() {
+ SimpleStringLiteral literal = parse4("parseStringLiteral", "'''\\\\\na'''");
+ expect(literal.literal, isNotNull);
+ expect(literal.value, "\\\na");
+ }
+
+ void test_parseStringLiteral_multiline_escapedBackslash_raw() {
+ SimpleStringLiteral literal =
+ parse4("parseStringLiteral", "r'''\\\\\na'''");
+ expect(literal.literal, isNotNull);
+ expect(literal.value, "\\\\\na");
+ }
+
+ void test_parseStringLiteral_multiline_escapedEolMarker() {
+ SimpleStringLiteral literal = parse4("parseStringLiteral", "'''\\\na'''");
+ expect(literal.literal, isNotNull);
+ expect(literal.value, "a");
+ }
+
+ void test_parseStringLiteral_multiline_escapedEolMarker_raw() {
+ SimpleStringLiteral literal = parse4("parseStringLiteral", "r'''\\\na'''");
+ expect(literal.literal, isNotNull);
+ expect(literal.value, "a");
+ }
+
+ void test_parseStringLiteral_multiline_escapedSpaceAndEolMarker() {
+ SimpleStringLiteral literal =
+ parse4("parseStringLiteral", "'''\\ \\\na'''");
+ expect(literal.literal, isNotNull);
+ expect(literal.value, "a");
+ }
+
+ void test_parseStringLiteral_multiline_escapedSpaceAndEolMarker_raw() {
+ SimpleStringLiteral literal =
+ parse4("parseStringLiteral", "r'''\\ \\\na'''");
+ expect(literal.literal, isNotNull);
+ expect(literal.value, "a");
+ }
+
+ void test_parseStringLiteral_multiline_escapedTab() {
+ SimpleStringLiteral literal = parse4("parseStringLiteral", "'''\\t\na'''");
+ expect(literal.literal, isNotNull);
+ expect(literal.value, "\t\na");
+ }
+
+ void test_parseStringLiteral_multiline_escapedTab_raw() {
+ SimpleStringLiteral literal = parse4("parseStringLiteral", "r'''\\t\na'''");
+ expect(literal.literal, isNotNull);
+ expect(literal.value, "\\t\na");
+ }
+
+ void test_parseStringLiteral_multiline_quoteAfterInterpolation() {
+ StringLiteral literal = parse4('parseStringLiteral', r"""'''$x'y'''""");
+ expect(literal, new isInstanceOf<StringInterpolation>());
+ StringInterpolation interpolation = literal;
+ expect(interpolation.elements, hasLength(3));
+ expect(interpolation.elements[0], new isInstanceOf<InterpolationString>());
+ InterpolationString element0 = interpolation.elements[0];
+ expect(element0.value, '');
+ expect(
+ interpolation.elements[1], new isInstanceOf<InterpolationExpression>());
+ InterpolationExpression element1 = interpolation.elements[1];
+ expect(element1.expression, new isInstanceOf<SimpleIdentifier>());
+ expect(interpolation.elements[2], new isInstanceOf<InterpolationString>());
+ InterpolationString element2 = interpolation.elements[2];
+ expect(element2.value, "'y");
+ }
+
+ void test_parseStringLiteral_multiline_startsWithInterpolation() {
+ StringLiteral literal = parse4('parseStringLiteral', r"'''${x}y'''");
+ expect(literal, new isInstanceOf<StringInterpolation>());
+ StringInterpolation interpolation = literal;
+ expect(interpolation.elements, hasLength(3));
+ expect(interpolation.elements[0], new isInstanceOf<InterpolationString>());
+ InterpolationString element0 = interpolation.elements[0];
+ expect(element0.value, '');
+ expect(
+ interpolation.elements[1], new isInstanceOf<InterpolationExpression>());
+ InterpolationExpression element1 = interpolation.elements[1];
+ expect(element1.expression, new isInstanceOf<SimpleIdentifier>());
+ expect(interpolation.elements[2], new isInstanceOf<InterpolationString>());
+ InterpolationString element2 = interpolation.elements[2];
+ expect(element2.value, 'y');
+ }
+
+ void test_parseStringLiteral_multiline_twoSpaces() {
+ SimpleStringLiteral literal = parse4("parseStringLiteral", "''' \na'''");
+ expect(literal.literal, isNotNull);
+ expect(literal.value, "a");
+ }
+
+ void test_parseStringLiteral_multiline_twoSpaces_raw() {
+ SimpleStringLiteral literal = parse4("parseStringLiteral", "r''' \na'''");
+ expect(literal.literal, isNotNull);
+ expect(literal.value, "a");
+ }
+
+ void test_parseStringLiteral_multiline_untrimmed() {
+ SimpleStringLiteral literal = parse4("parseStringLiteral", "''' a\nb'''");
+ expect(literal.literal, isNotNull);
+ expect(literal.value, " a\nb");
+ }
+
+ void test_parseStringLiteral_quoteAfterInterpolation() {
+ StringLiteral literal = parse4('parseStringLiteral', r"""'$x"'""");
+ expect(literal, new isInstanceOf<StringInterpolation>());
+ StringInterpolation interpolation = literal;
+ expect(interpolation.elements, hasLength(3));
+ expect(interpolation.elements[0], new isInstanceOf<InterpolationString>());
+ InterpolationString element0 = interpolation.elements[0];
+ expect(element0.value, '');
+ expect(
+ interpolation.elements[1], new isInstanceOf<InterpolationExpression>());
+ InterpolationExpression element1 = interpolation.elements[1];
+ expect(element1.expression, new isInstanceOf<SimpleIdentifier>());
+ expect(interpolation.elements[2], new isInstanceOf<InterpolationString>());
+ InterpolationString element2 = interpolation.elements[2];
+ expect(element2.value, '"');
+ }
+
void test_parseStringLiteral_single() {
SimpleStringLiteral literal = parse4("parseStringLiteral", "'a'");
expect(literal.literal, isNotNull);
expect(literal.value, "a");
}
+ void test_parseStringLiteral_startsWithInterpolation() {
+ StringLiteral literal = parse4('parseStringLiteral', r"'${x}y'");
+ expect(literal, new isInstanceOf<StringInterpolation>());
+ StringInterpolation interpolation = literal;
+ expect(interpolation.elements, hasLength(3));
+ expect(interpolation.elements[0], new isInstanceOf<InterpolationString>());
+ InterpolationString element0 = interpolation.elements[0];
+ expect(element0.value, '');
+ expect(
+ interpolation.elements[1], new isInstanceOf<InterpolationExpression>());
+ InterpolationExpression element1 = interpolation.elements[1];
+ expect(element1.expression, new isInstanceOf<SimpleIdentifier>());
+ expect(interpolation.elements[2], new isInstanceOf<InterpolationString>());
+ InterpolationString element2 = interpolation.elements[2];
+ expect(element2.value, 'y');
+ }
+
void test_parseSuperConstructorInvocation_named() {
SuperConstructorInvocation invocation =
parse4("parseSuperConstructorInvocation", "super.a()");
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 539bf0d..7b173af 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -365,6 +365,8 @@
currentOptions.dart2jsHint != options.dart2jsHint ||
(currentOptions.hint && !options.hint) ||
currentOptions.preserveComments != options.preserveComments ||
+ currentOptions.enableNullAwareOperators !=
+ options.enableNullAwareOperators ||
currentOptions.enableStrictCallChecks != options.enableStrictCallChecks;
if (needsRecompute) {
fail(
@@ -1857,7 +1859,7 @@
library.libraryElement = _definingLibrary;
_visitor = new ResolverVisitor.con1(library, source, _typeProvider);
try {
- return _visitor.elementResolver_J2DAccessor as ElementResolver;
+ return _visitor.elementResolver;
} catch (exception) {
throw new IllegalArgumentException(
"Could not create resolver", exception);
@@ -1916,16 +1918,16 @@
*/
void _resolveInClass(AstNode node, ClassElement enclosingClass) {
try {
- Scope outerScope = _visitor.nameScope_J2DAccessor as Scope;
+ Scope outerScope = _visitor.nameScope;
try {
_visitor.enclosingClass = enclosingClass;
EnclosedScope innerScope = new ClassScope(
new TypeParameterScope(outerScope, enclosingClass), enclosingClass);
- _visitor.nameScope_J2DAccessor = innerScope;
+ _visitor.nameScope = innerScope;
node.accept(_resolver);
} finally {
_visitor.enclosingClass = null;
- _visitor.nameScope_J2DAccessor = outerScope;
+ _visitor.nameScope = outerScope;
}
} catch (exception) {
throw new IllegalArgumentException("Could not resolve node", exception);
@@ -1958,7 +1960,7 @@
*/
void _resolveNode(AstNode node, [List<Element> definedElements]) {
try {
- Scope outerScope = _visitor.nameScope_J2DAccessor as Scope;
+ Scope outerScope = _visitor.nameScope;
try {
EnclosedScope innerScope = new EnclosedScope(outerScope);
if (definedElements != null) {
@@ -1966,10 +1968,10 @@
innerScope.define(element);
}
}
- _visitor.nameScope_J2DAccessor = innerScope;
+ _visitor.nameScope = innerScope;
node.accept(_resolver);
} finally {
- _visitor.nameScope_J2DAccessor = outerScope;
+ _visitor.nameScope = outerScope;
}
} catch (exception) {
throw new IllegalArgumentException("Could not resolve node", exception);
@@ -1987,7 +1989,7 @@
void _resolveStatement(
Statement statement, LabelElementImpl labelElement, AstNode labelTarget) {
try {
- LabelScope outerScope = _visitor.labelScope_J2DAccessor as LabelScope;
+ LabelScope outerScope = _visitor.labelScope;
try {
LabelScope innerScope;
if (labelElement == null) {
@@ -1996,10 +1998,10 @@
innerScope = new LabelScope(
outerScope, labelElement.name, labelTarget, labelElement);
}
- _visitor.labelScope_J2DAccessor = innerScope;
+ _visitor.labelScope = innerScope;
statement.accept(_resolver);
} finally {
- _visitor.labelScope_J2DAccessor = outerScope;
+ _visitor.labelScope = outerScope;
}
} catch (exception) {
throw new IllegalArgumentException("Could not resolve node", exception);
@@ -2207,29 +2209,6 @@
verify([source]);
}
- void test_argumentTypeNotAssignable_unionTypeMethodMerge() {
- enableUnionTypes(false);
- Source source = addSource(r'''
-class A {
- int m(int x) => 0;
-}
-class B {
- String m(String x) => '0';
-}
-f(A a, B b) {
- var ab;
- if (0 < 1) {
- ab = a;
- } else {
- ab = b;
- }
- ab.m(0.5);
-}''');
- resolve(source);
- assertErrors(source, [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]);
- verify([source]);
- }
-
void test_deadCode_deadBlock_conditionalElse() {
Source source = addSource(r'''
f() {
@@ -2658,27 +2637,6 @@
verify([source]);
}
- void test_deprecatedAnnotationUse_deprecatedMethodCalledOnUnionType() {
- enableUnionTypes(false);
- Source source = addSource(r'''
-class A {
- @deprecated f() => 0;
-}
-class B extends A {}
-main(A a, B b) {
- var x;
- if (0 < 1) {
- x = a;
- } else {
- x = b;
- }
- x.f(); // Here [x] has type [{A,B}] but we still want the deprecation warning.
-}''');
- resolve(source);
- assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
- verify([source]);
- }
-
void test_deprecatedAnnotationUse_export() {
Source source = addSource("export 'deprecated_library.dart';");
addNamedSource("/deprecated_library.dart", r'''
@@ -3137,28 +3095,6 @@
assertErrors(source, [HintCode.UNDEFINED_METHOD]);
}
- void test_undefinedMethod_unionType_noSuchMethod() {
- enableUnionTypes(false);
- Source source = addSource(r'''
-class A {
- int m(int x) => 0;
-}
-class B {
- String m() => '0';
-}
-f(A a, B b) {
- var ab;
- if (0 < 1) {
- ab = a;
- } else {
- ab = b;
- }
- ab.n();
-}''');
- resolve(source);
- assertErrors(source, [HintCode.UNDEFINED_METHOD]);
- }
-
void test_undefinedOperator_binaryExpression() {
Source source = addSource(r'''
class A {}
@@ -3325,50 +3261,6 @@
verify([source]);
}
- void test_unusedElement_class_inClassMember() {
- enableUnusedElement = true;
- Source source = addSource(r'''
-class _A {
- static staticMethod() {
- new _A();
- }
- instanceMethod() {
- new _A();
- }
-}
-''');
- resolve(source);
- assertErrors(source, [HintCode.UNUSED_ELEMENT]);
- verify([source]);
- }
-
- void test_unusedElement_class_inConstructorName() {
- enableUnusedElement = true;
- Source source = addSource(r'''
-class _A {
- _A() {}
- _A.named() {}
-}
-''');
- resolve(source);
- assertErrors(source, [HintCode.UNUSED_ELEMENT]);
- verify([source]);
- }
-
- void test_unusedElement_class_isExpression() {
- enableUnusedElement = true;
- Source source = addSource(r'''
-class _A {}
-main(p) {
- if (p is _A) {
- }
-}
-''');
- resolve(source);
- assertErrors(source, [HintCode.UNUSED_ELEMENT]);
- verify([source]);
- }
-
void test_unusedElement_class_isUsed_extends() {
enableUnusedElement = true;
Source source = addSource(r'''
@@ -3431,7 +3323,51 @@
verify([source]);
}
- void test_unusedElement_class_noReference() {
+ void test_unusedElement_class_notUsed_inClassMember() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {
+ static staticMethod() {
+ new _A();
+ }
+ instanceMethod() {
+ new _A();
+ }
+}
+''');
+ resolve(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_notUsed_inConstructorName() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {
+ _A() {}
+ _A.named() {}
+}
+''');
+ resolve(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_notUsed_isExpression() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {}
+main(p) {
+ if (p is _A) {
+ }
+}
+''');
+ resolve(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_notUsed_noReference() {
enableUnusedElement = true;
Source source = addSource(r'''
class _A {}
@@ -3442,7 +3378,7 @@
verify([source]);
}
- void test_unusedElement_class_variableDeclaration() {
+ void test_unusedElement_class_notUsed_variableDeclaration() {
enableUnusedElement = true;
Source source = addSource(r'''
class _A {}
@@ -3457,6 +3393,29 @@
verify([source]);
}
+ void test_unusedElement_enum_isUsed_fieldReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+enum _MyEnum {A, B, C}
+main() {
+ print(_MyEnum.B);
+}''');
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_enum_notUsed_noReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+enum _MyEnum {A, B, C}
+main() {
+}''');
+ resolve(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
void test_unusedElement_functionLocal_isUsed_closure() {
enableUnusedElement = true;
Source source = addSource(r'''
@@ -3570,6 +3529,40 @@
verify([source]);
}
+ void test_unusedElement_functionTypeAlias_isUsed_reference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+typedef _F(a, b);
+main(_F f) {
+}''');
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionTypeAlias_isUsed_variableDeclaration() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+typedef _F(a, b);
+class A {
+ _F f;
+}''');
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionTypeAlias_notUsed_noReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+typedef _F(a, b);
+main() {
+}''');
+ resolve(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
void test_unusedElement_getter_isUsed_invocation_implicitThis() {
enableUnusedElement = true;
Source source = addSource(r'''
@@ -4218,6 +4211,21 @@
verify([source]);
}
+ void test_unusedLocalVariable_inFor_underscore_ignored() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+main() {
+ for (var _ in [1,2,3]) {
+ for (var __ in [4,5,6]) {
+ // do something
+ }
+ }
+}''');
+ resolve(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
void test_unusedLocalVariable_inFunction() {
enableUnusedLocalVariable = true;
Source source = addSource(r'''
@@ -6532,21 +6540,6 @@
verify([source]);
}
- void test_issue20904BuggyTypePromotionAtIfJoin_2() {
- // https://code.google.com/p/dart/issues/detail?id=20904
- enableUnionTypes(false);
- Source source = addSource(r'''
-f(var message) {
- if (message is Function) {
- message = '';
- }
- int s = message;
-}''');
- resolve(source);
- assertNoErrors(source);
- verify([source]);
- }
-
void test_issue20904BuggyTypePromotionAtIfJoin_3() {
// https://code.google.com/p/dart/issues/detail?id=20904
Source source = addSource(r'''
@@ -7731,16 +7724,6 @@
return library;
}
- /**
- * Enable optionally strict union types for the current test.
- *
- * @param strictUnionTypes `true` if union types should be strict.
- */
- void enableUnionTypes(bool strictUnionTypes) {
- AnalysisEngine.instance.enableUnionTypes = true;
- AnalysisEngine.instance.strictUnionTypes = strictUnionTypes;
- }
-
Expression findTopLevelConstantExpression(
CompilationUnit compilationUnit, String name) =>
findTopLevelDeclaration(compilationUnit, name).initializer;
@@ -7766,10 +7749,6 @@
*/
void reset() {
analysisContext2 = AnalysisContextFactory.contextWithCore();
- // These defaults are duplicated for the editor in
- // editor/tools/plugins/com.google.dart.tools.core/.options .
- AnalysisEngine.instance.enableUnionTypes = false;
- AnalysisEngine.instance.strictUnionTypes = false;
}
/**
@@ -9875,6 +9854,24 @@
_listener.assertNoErrors();
}
+ void test_visitAssignmentExpression_compoundIfNull_differentTypes() {
+ // double d; d ??= 0
+ Expression node = AstFactory.assignmentExpression(
+ _resolvedVariable(_typeProvider.doubleType, 'd'),
+ TokenType.QUESTION_QUESTION_EQ, _resolvedInteger(0));
+ expect(_analyze(node), same(_typeProvider.numType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitAssignmentExpression_compoundIfNull_sameTypes() {
+ // int i; i ??= 0
+ Expression node = AstFactory.assignmentExpression(
+ _resolvedVariable(_typeProvider.intType, 'i'),
+ TokenType.QUESTION_QUESTION_EQ, _resolvedInteger(0));
+ expect(_analyze(node), same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
void test_visitAssignmentExpression_simple() {
// i = 0
InterfaceType intType = _typeProvider.intType;
@@ -9916,6 +9913,14 @@
_listener.assertNoErrors();
}
+ void test_visitBinaryExpression_ifNull() {
+ // 1 ?? 1.5
+ Expression node = AstFactory.binaryExpression(
+ _resolvedInteger(1), TokenType.QUESTION_QUESTION, _resolvedDouble(1.5));
+ expect(_analyze(node), same(_typeProvider.numType));
+ _listener.assertNoErrors();
+ }
+
void test_visitBinaryExpression_logicalAnd() {
// false && true
Expression node = AstFactory.binaryExpression(
@@ -10915,7 +10920,7 @@
_visitor = new ResolverVisitor.con1(library, source, _typeProvider);
_visitor.overrideManager.enterScope();
try {
- return _visitor.typeAnalyzer_J2DAccessor as StaticTypeAnalyzer;
+ return _visitor.typeAnalyzer;
} catch (exception) {
throw new IllegalArgumentException(
"Could not create analyzer", exception);
@@ -12592,21 +12597,6 @@
expect(variableName.propagatedType, same(typeA));
}
- void test_issue20904BuggyTypePromotionAtIfJoin_2() {
- // https://code.google.com/p/dart/issues/detail?id=20904
- enableUnionTypes(false);
- String code = r'''
-f(var message) {
- if (message is Function) {
- message = '';
- }
- message; // marker
-}''';
- DartType t = _findMarkedIdentifier(code, "; // marker").propagatedType;
- expect(typeProvider.stringType == t, isFalse);
- expect(typeProvider.functionType == t, isFalse);
- }
-
void test_issue20904BuggyTypePromotionAtIfJoin_5() {
// https://code.google.com/p/dart/issues/detail?id=20904
//
@@ -12749,6 +12739,62 @@
expect(typeArguments[1], same(typeProvider.dynamicType));
}
+ void test_mergePropagatedTypes_afterIfThen_different() {
+ String code = r'''
+main() {
+ var v = 0;
+ if (v != null) {
+ v = '';
+ }
+ return v;
+}''';
+ {
+ SimpleIdentifier identifier = _findMarkedIdentifier(code, "v;");
+ expect(identifier.propagatedType, null);
+ }
+ {
+ SimpleIdentifier identifier = _findMarkedIdentifier(code, "v = '';");
+ expect(identifier.propagatedType, typeProvider.stringType);
+ }
+ }
+
+ void test_mergePropagatedTypes_afterIfThen_same() {
+ _assertTypeOfMarkedExpression(r'''
+main() {
+ var v = 1;
+ if (v != null) {
+ v = 2;
+ }
+ return v; // marker
+}''', null, typeProvider.intType);
+ }
+
+ void test_mergePropagatedTypes_afterIfThenElse_different() {
+ _assertTypeOfMarkedExpression(r'''
+main() {
+ var v = 1;
+ if (v != null) {
+ v = 2;
+ } else {
+ v = '3';
+ }
+ return v; // marker
+}''', null, null);
+ }
+
+ void test_mergePropagatedTypes_afterIfThenElse_same() {
+ _assertTypeOfMarkedExpression(r'''
+main() {
+ var v = 1;
+ if (v != null) {
+ v = 2;
+ } else {
+ v = 3;
+ }
+ return v; // marker
+}''', null, typeProvider.intType);
+ }
+
void test_mergePropagatedTypesAtJoinPoint_4() {
// https://code.google.com/p/dart/issues/detail?id=19929
_assertTypeOfMarkedExpression(r'''
@@ -12764,34 +12810,6 @@
}''', null, typeProvider.intType);
}
- void test_mergePropagatedTypesAtJoinPoint_6() {
- // https://code.google.com/p/dart/issues/detail?id=19929
- //
- // Labeled [break]s are unsafe for the purposes of
- // [isAbruptTerminationStatement].
- //
- // This is tricky: the [break] jumps back above the [if], making
- // it into a loop of sorts. The [if] type-propagation code assumes
- // that [break] does not introduce a loop.
- enableUnionTypes(false);
- String code = r'''
-f() {
- var x = 0;
- var c = false;
- L:
- if (c) {
- } else {
- x = '';
- c = true;
- break L;
- }
- x; // marker
-}''';
- DartType t = _findMarkedIdentifier(code, "; // marker").propagatedType;
- expect(typeProvider.intType.isSubtypeOf(t), isTrue);
- expect(typeProvider.stringType.isSubtypeOf(t), isTrue);
- }
-
void test_mutatedOutsideScope() {
// https://code.google.com/p/dart/issues/detail?id=22732
Source source = addSource(r'''
@@ -13007,9 +13025,7 @@
if (expectedStaticType != null) {
expect(identifier.staticType, expectedStaticType);
}
- if (expectedPropagatedType != null) {
- expect(identifier.propagatedType, expectedPropagatedType);
- }
+ expect(identifier.propagatedType, expectedPropagatedType);
}
/**
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index b65bd51..3531847 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -170,6 +170,12 @@
@reflectiveTest
class ScannerTest {
+ /**
+ * If non-null, this value is used to override the default value of
+ * [Scanner.enableNullAwareOperators] before scanning.
+ */
+ bool _enableNullAwareOperators;
+
void fail_incomplete_string_interpolation() {
// https://code.google.com/p/dart/issues/detail?id=18073
_assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9,
@@ -720,6 +726,21 @@
_assertToken(TokenType.QUESTION, "?");
}
+ void test_question_dot() {
+ _enableNullAwareOperators = true;
+ _assertToken(TokenType.QUESTION_PERIOD, "?.");
+ }
+
+ void test_question_question() {
+ _enableNullAwareOperators = true;
+ _assertToken(TokenType.QUESTION_QUESTION, "??");
+ }
+
+ void test_question_question_eq() {
+ _enableNullAwareOperators = true;
+ _assertToken(TokenType.QUESTION_QUESTION_EQ, "??=");
+ }
+
void test_scriptTag_withArgs() {
_assertToken(TokenType.SCRIPT_TAG, "#!/bin/dart -debug");
}
@@ -1208,6 +1229,9 @@
Token _scanWithListener(String source, GatheringErrorListener listener) {
Scanner scanner =
new Scanner(null, new CharSequenceReader(source), listener);
+ if (_enableNullAwareOperators != null) {
+ scanner.enableNullAwareOperators = _enableNullAwareOperators;
+ }
Token result = scanner.tokenize();
listener.setLineInfo(new TestSource(), scanner.lineStarts);
return result;
diff --git a/pkg/analyzer/test/generated/static_type_warning_code_test.dart b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
index 019c07e..0282d99 100644
--- a/pkg/analyzer/test/generated/static_type_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
@@ -355,6 +355,21 @@
verify([source]);
}
+ void test_invalidAssignment_ifNullAssignment() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableNullAwareOperators = true;
+ resetWithOptions(options);
+ Source source = addSource('''
+void f(int i) {
+ double d;
+ d ??= i;
+}
+''');
+ resolve(source);
+ assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+ verify([source]);
+ }
+
void test_invalidAssignment_instanceVariable() {
Source source = addSource(r'''
class A {
@@ -668,29 +683,6 @@
verify([source]);
}
- void test_notEnoughRequiredArguments_mergedUnionTypeMethod() {
- enableUnionTypes(false);
- Source source = addSource(r'''
-class A {
- int m(int x) => 0;
-}
-class B {
- String m(String x) => '0';
-}
-f(A a, B b) {
- var ab;
- if (0 < 1) {
- ab = a;
- } else {
- ab = b;
- }
- ab.m();
-}''');
- resolve(source);
- assertErrors(source, [StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS]);
- verify([source]);
- }
-
void test_returnOfInvalidType_async_future_int_mismatches_future_null() {
Source source = addSource('''
import 'dart:async';
@@ -1382,6 +1374,22 @@
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_GETTER]);
}
+ void test_undefinedGetter_static_conditionalAccess() {
+ // The conditional access operator '?.' cannot be used to access static
+ // fields.
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableNullAwareOperators = true;
+ resetWithOptions(options);
+ Source source = addSource('''
+class A {
+ static var x;
+}
+var a = A?.x;
+''');
+ resolve(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_GETTER]);
+ }
+
void test_undefinedGetter_void() {
Source source = addSource(r'''
class T {
@@ -1534,6 +1542,22 @@
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_METHOD]);
}
+ void test_undefinedMethod_static_conditionalAccess() {
+ // The conditional access operator '?.' cannot be used to access static
+ // methods.
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableNullAwareOperators = true;
+ resetWithOptions(options);
+ Source source = addSource('''
+class A {
+ static void m() {}
+}
+f() { A?.m(); }
+''');
+ resolve(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_METHOD]);
+ }
+
void test_undefinedOperator_indexBoth() {
Source source = addSource(r'''
class A {}
@@ -1610,6 +1634,22 @@
assertErrors(source, [StaticTypeWarningCode.UNDEFINED_SETTER]);
}
+ void test_undefinedSetter_static_conditionalAccess() {
+ // The conditional access operator '?.' cannot be used to access static
+ // fields.
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.enableNullAwareOperators = true;
+ resetWithOptions(options);
+ Source source = addSource('''
+class A {
+ static var x;
+}
+f() { A?.x = 1; }
+''');
+ resolve(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_SETTER]);
+ }
+
void test_undefinedSetter_void() {
Source source = addSource(r'''
class T {
diff --git a/pkg/analyzer/test/generated/static_warning_code_test.dart b/pkg/analyzer/test/generated/static_warning_code_test.dart
index 0ad381f..6df4785 100644
--- a/pkg/analyzer/test/generated/static_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_warning_code_test.dart
@@ -598,6 +598,17 @@
verify([source]);
}
+ void test_assignmentToClass() {
+ Source source = addSource('''
+class C {}
+main() {
+ C = null;
+}
+''');
+ resolve(source);
+ assertErrors(source, [StaticWarningCode.ASSIGNMENT_TO_TYPE]);
+ }
+
void test_assignmentToConst_instanceVariable() {
Source source = addSource(r'''
class A {
@@ -646,6 +657,17 @@
verify([source]);
}
+ void test_assignmentToEnumType() {
+ Source source = addSource('''
+enum E { e }
+main() {
+ E = null;
+}
+''');
+ resolve(source);
+ assertErrors(source, [StaticWarningCode.ASSIGNMENT_TO_TYPE]);
+ }
+
void test_assignmentToFinal_instanceVariable() {
Source source = addSource(r'''
class A {
@@ -825,6 +847,29 @@
verify([source]);
}
+ void test_assignmentToTypedef() {
+ Source source = addSource('''
+typedef void F();
+main() {
+ F = null;
+}
+''');
+ resolve(source);
+ assertErrors(source, [StaticWarningCode.ASSIGNMENT_TO_TYPE]);
+ }
+
+ void test_assignmentToTypeParameter() {
+ Source source = addSource('''
+class C<T> {
+ f() {
+ T = null;
+ }
+}
+''');
+ resolve(source);
+ assertErrors(source, [StaticWarningCode.ASSIGNMENT_TO_TYPE]);
+ }
+
void test_caseBlockNotTerminated() {
Source source = addSource(r'''
f(int p) {
diff --git a/pkg/analyzer/test/src/mock_sdk.dart b/pkg/analyzer/test/src/mock_sdk.dart
index 6716801..7cadfcc 100644
--- a/pkg/analyzer/test/src/mock_sdk.dart
+++ b/pkg/analyzer/test/src/mock_sdk.dart
@@ -98,6 +98,11 @@
external bool identical(Object a, Object b);
void print(Object object) {}
+
+class _Override {
+ const _Override();
+}
+const Object override = const _Override();
''');
static const _MockSdkLibrary LIB_ASYNC = const _MockSdkLibrary('dart:async',
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index c03b51d..6ddf3d9 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -35,17 +35,23 @@
runReflectiveTests(BuildCompilationUnitElementTaskTest);
runReflectiveTests(BuildDirectiveElementsTaskTest);
runReflectiveTests(BuildEnumMemberElementsTaskTest);
- runReflectiveTests(BuildExportSourceClosureTaskTest);
+ runReflectiveTests(BuildSourceClosuresTaskTest);
runReflectiveTests(BuildExportNamespaceTaskTest);
runReflectiveTests(BuildFunctionTypeAliasesTaskTest);
runReflectiveTests(BuildLibraryConstructorsTaskTest);
runReflectiveTests(BuildLibraryElementTaskTest);
runReflectiveTests(BuildPublicNamespaceTaskTest);
runReflectiveTests(BuildTypeProviderTaskTest);
+ runReflectiveTests(GatherUsedImportedElementsTaskTest);
+ runReflectiveTests(GatherUsedLocalElementsTaskTest);
+ runReflectiveTests(GenerateHintsTaskTest);
runReflectiveTests(ParseDartTaskTest);
runReflectiveTests(ResolveUnitTypeNamesTaskTest);
runReflectiveTests(ResolveLibraryTypeNamesTaskTest);
+ runReflectiveTests(ResolveReferencesTaskTest);
+ runReflectiveTests(ResolveVariableReferencesTaskTest);
runReflectiveTests(ScanDartTaskTest);
+ runReflectiveTests(VerifyUnitTaskTest);
}
@reflectiveTest
@@ -614,48 +620,6 @@
}
@reflectiveTest
-class BuildExportSourceClosureTaskTest extends _AbstractDartTaskTest {
- test_perform() {
- Source sourceA = _newSource('/a.dart', '''
-library lib_a;
-export 'b.dart';
-''');
- Source sourceB = _newSource('/b.dart', '''
-library lib_b;
-export 'b.dart';
-''');
- Source sourceC = _newSource('/c.dart', '''
-library lib_c;
-export 'a.dart';
-''');
- Source sourceD = _newSource('/d.dart', '''
-library lib_d;
-''');
- // a.dart
- {
- _computeResult(sourceA, EXPORT_SOURCE_CLOSURE);
- expect(task, new isInstanceOf<BuildExportSourceClosureTask>());
- List<Source> closure = outputs[EXPORT_SOURCE_CLOSURE];
- expect(closure, unorderedEquals([sourceA, sourceB]));
- }
- // c.dart
- {
- _computeResult(sourceC, EXPORT_SOURCE_CLOSURE);
- expect(task, new isInstanceOf<BuildExportSourceClosureTask>());
- List<Source> closure = outputs[EXPORT_SOURCE_CLOSURE];
- expect(closure, unorderedEquals([sourceA, sourceB, sourceC]));
- }
- // d.dart
- {
- _computeResult(sourceD, EXPORT_SOURCE_CLOSURE);
- expect(task, new isInstanceOf<BuildExportSourceClosureTask>());
- List<Source> closure = outputs[EXPORT_SOURCE_CLOSURE];
- expect(closure, unorderedEquals([sourceD]));
- }
- }
-}
-
-@reflectiveTest
class BuildFunctionTypeAliasesTaskTest extends _AbstractDartTaskTest {
test_perform() {
Source source = _newSource('/test.dart', '''
@@ -712,9 +676,9 @@
class C1 = B with M1;
class C3 = B with M2;
''');
- _computeResult(source, LIBRARY_ELEMENT6);
+ _computeResult(source, LIBRARY_ELEMENT);
expect(task, new isInstanceOf<BuildLibraryConstructorsTask>());
- LibraryElement libraryElement = outputs[LIBRARY_ELEMENT6];
+ LibraryElement libraryElement = outputs[LIBRARY_ELEMENT];
// C1
{
ClassElement classElement = libraryElement.getType('C2');
@@ -782,11 +746,10 @@
part of lib;
'''
});
- expect(outputs, hasLength(5));
+ expect(outputs, hasLength(4));
// simple outputs
expect(outputs[BUILD_LIBRARY_ERRORS], isEmpty);
expect(outputs[IS_LAUNCHABLE], isFalse);
- expect(outputs[HAS_HTML_IMPORT], isFalse);
// LibraryElement output
expect(libraryElement, isNotNull);
expect(libraryElement.entryPoint, isNull);
@@ -910,15 +873,6 @@
_assertErrorsWithCodes([CompileTimeErrorCode.PART_OF_NON_PART]);
}
- test_perform_hasHtmlImport() {
- _performBuildTask({
- '/lib.dart': '''
-import 'dart:html';
-'''
- });
- expect(outputs[HAS_HTML_IMPORT], isTrue);
- }
-
test_perform_isLaunchable_inDefiningUnit() {
_performBuildTask({
'/lib.dart': '''
@@ -1057,6 +1011,132 @@
}
@reflectiveTest
+class BuildSourceClosuresTaskTest extends _AbstractDartTaskTest {
+ test_perform_exportClosure() {
+ Source sourceA = _newSource('/a.dart', '''
+library lib_a;
+export 'b.dart';
+''');
+ Source sourceB = _newSource('/b.dart', '''
+library lib_b;
+export 'c.dart';
+''');
+ Source sourceC = _newSource('/c.dart', '''
+library lib_c;
+export 'a.dart';
+''');
+ Source sourceD = _newSource('/d.dart', '''
+library lib_d;
+''');
+ // a.dart
+ {
+ _computeResult(sourceA, EXPORT_SOURCE_CLOSURE);
+ expect(task, new isInstanceOf<BuildSourceClosuresTask>());
+ List<Source> closure = outputs[EXPORT_SOURCE_CLOSURE];
+ expect(closure, unorderedEquals([sourceA, sourceB, sourceC]));
+ }
+ // c.dart
+ {
+ _computeResult(sourceC, EXPORT_SOURCE_CLOSURE);
+ expect(task, new isInstanceOf<BuildSourceClosuresTask>());
+ List<Source> closure = outputs[EXPORT_SOURCE_CLOSURE];
+ expect(closure, unorderedEquals([sourceA, sourceB, sourceC]));
+ }
+ // d.dart
+ {
+ _computeResult(sourceD, EXPORT_SOURCE_CLOSURE);
+ expect(task, new isInstanceOf<BuildSourceClosuresTask>());
+ List<Source> closure = outputs[EXPORT_SOURCE_CLOSURE];
+ expect(closure, unorderedEquals([sourceD]));
+ }
+ }
+
+ test_perform_importClosure() {
+ Source sourceA = _newSource('/a.dart', '''
+library lib_a;
+import 'b.dart';
+''');
+ Source sourceB = _newSource('/b.dart', '''
+library lib_b;
+import 'c.dart';
+''');
+ Source sourceC = _newSource('/c.dart', '''
+library lib_c;
+import 'a.dart';
+''');
+ Source sourceD = _newSource('/d.dart', '''
+library lib_d;
+''');
+ Source coreSource = context.sourceFactory.resolveUri(null, 'dart:core');
+ // a.dart
+ {
+ _computeResult(sourceA, IMPORT_SOURCE_CLOSURE);
+ expect(task, new isInstanceOf<BuildSourceClosuresTask>());
+ List<Source> closure = outputs[IMPORT_SOURCE_CLOSURE];
+ expect(closure, contains(sourceA));
+ expect(closure, contains(sourceB));
+ expect(closure, contains(sourceC));
+ expect(closure, contains(coreSource));
+ }
+ // c.dart
+ {
+ _computeResult(sourceC, IMPORT_SOURCE_CLOSURE);
+ expect(task, new isInstanceOf<BuildSourceClosuresTask>());
+ List<Source> closure = outputs[IMPORT_SOURCE_CLOSURE];
+ expect(closure, contains(sourceA));
+ expect(closure, contains(sourceB));
+ expect(closure, contains(sourceC));
+ expect(closure, contains(coreSource));
+ }
+ // d.dart
+ {
+ _computeResult(sourceD, IMPORT_SOURCE_CLOSURE);
+ expect(task, new isInstanceOf<BuildSourceClosuresTask>());
+ List<Source> closure = outputs[IMPORT_SOURCE_CLOSURE];
+ expect(closure, contains(sourceD));
+ expect(closure, contains(coreSource));
+ }
+ }
+
+ test_perform_isClient_false() {
+ Source sourceA = _newSource('/a.dart', '''
+library lib_a;
+import 'b.dart';
+''');
+ _newSource('/b.dart', '''
+library lib_b;
+''');
+ _computeResult(sourceA, IS_CLIENT);
+ expect(task, new isInstanceOf<BuildSourceClosuresTask>());
+ expect(outputs[IS_CLIENT], isFalse);
+ }
+
+ test_perform_isClient_true_direct() {
+ Source sourceA = _newSource('/a.dart', '''
+library lib_a;
+import 'dart:html';
+''');
+ _computeResult(sourceA, IS_CLIENT);
+ expect(task, new isInstanceOf<BuildSourceClosuresTask>());
+ expect(outputs[IS_CLIENT], isTrue);
+ }
+
+ test_perform_isClient_true_indirect() {
+ Source sourceA = _newSource('/a.dart', '''
+library lib_a;
+import 'b.dart';
+''');
+ _newSource('/b.dart', '''
+library lib_b;
+import 'dart:html';
+''');
+ _computeResult(sourceA, IS_CLIENT);
+ expect(task, new isInstanceOf<BuildSourceClosuresTask>());
+ expect(outputs[IS_CLIENT], isTrue);
+ }
+}
+
+@reflectiveTest
class BuildTypeProviderTaskTest extends _AbstractDartTaskTest {
test_perform() {
_computeResult(AnalysisContextTarget.request, TYPE_PROVIDER);
@@ -1071,6 +1151,281 @@
}
@reflectiveTest
+class GatherUsedImportedElementsTaskTest extends _AbstractDartTaskTest {
+ UsedImportedElements usedElements;
+ Set<String> usedElementNames;
+
+ test_perform() {
+ _newSource('/a.dart', r'''
+library lib_a;
+class A {}
+''');
+ _newSource('/b.dart', r'''
+library lib_b;
+class B {}
+''');
+ Source source = _newSource('/test.dart', r'''
+import 'a.dart';
+import 'b.dart';
+main() {
+ new A();
+}''');
+ _computeUsedElements(source);
+ // validate
+ expect(usedElementNames, unorderedEquals(['A']));
+ }
+
+ void _computeUsedElements(Source source) {
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, USED_IMPORTED_ELEMENTS);
+ expect(task, new isInstanceOf<GatherUsedImportedElementsTask>());
+ usedElements = outputs[USED_IMPORTED_ELEMENTS];
+ usedElementNames = usedElements.elements.map((e) => e.name).toSet();
+ }
+}
+
+@reflectiveTest
+class GatherUsedLocalElementsTaskTest extends _AbstractDartTaskTest {
+ UsedLocalElements usedElements;
+ Set<String> usedElementNames;
+
+ test_perform_localVariable() {
+ Source source = _newSource('/test.dart', r'''
+main() {
+ var v1 = 1;
+ var v2 = 2;
+ print(v2);
+}''');
+ _computeUsedElements(source);
+ // validate
+ expect(usedElementNames, unorderedEquals(['v2']));
+ }
+
+ test_perform_method() {
+ Source source = _newSource('/test.dart', r'''
+class A {
+ _m1() {}
+ _m2() {}
+}
+
+main(A a, p) {
+ a._m2();
+ p._m3();
+}
+''');
+ _computeUsedElements(source);
+ // validate
+ expect(usedElementNames, unorderedEquals(['A', 'a', 'p', '_m2']));
+ expect(usedElements.members, unorderedEquals(['_m2', '_m3']));
+ }
+
+ void _computeUsedElements(Source source) {
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, USED_LOCAL_ELEMENTS);
+ expect(task, new isInstanceOf<GatherUsedLocalElementsTask>());
+ usedElements = outputs[USED_LOCAL_ELEMENTS];
+ usedElementNames = usedElements.elements.map((e) => e.name).toSet();
+ }
+}
+
+@reflectiveTest
+class GenerateHintsTaskTest extends _AbstractDartTaskTest {
+ test_perform_bestPractices_missingReturn() {
+ Source source = _newSource('/test.dart', '''
+int main() {
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, HINTS);
+ expect(task, new isInstanceOf<GenerateHintsTask>());
+ // validate
+ _fillErrorListener(HINTS);
+ errorListener.assertErrorsWithCodes(<ErrorCode>[HintCode.MISSING_RETURN]);
+ }
+
+ test_perform_dart2js() {
+ Source source = _newSource('/test.dart', '''
+main(p) {
+ if (p is double) {
+ print('double');
+ }
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, HINTS);
+ expect(task, new isInstanceOf<GenerateHintsTask>());
+ // validate
+ _fillErrorListener(HINTS);
+ errorListener.assertErrorsWithCodes(<ErrorCode>[HintCode.IS_DOUBLE]);
+ }
+
+ test_perform_deadCode() {
+ Source source = _newSource('/test.dart', '''
+main() {
+ if (false) {
+ print('how?');
+ }
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, HINTS);
+ expect(task, new isInstanceOf<GenerateHintsTask>());
+ // validate
+ _fillErrorListener(HINTS);
+ errorListener.assertErrorsWithCodes(<ErrorCode>[HintCode.DEAD_CODE]);
+ }
+
+ test_perform_imports_duplicateImport() {
+ _newSource('/a.dart', r'''
+library lib_a;
+class A {}
+''');
+ Source source = _newSource('/test.dart', r'''
+import 'a.dart';
+import 'a.dart';
+main() {
+ new A();
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, HINTS);
+ expect(task, new isInstanceOf<GenerateHintsTask>());
+ // validate
+ _fillErrorListener(HINTS);
+ errorListener.assertErrorsWithCodes(<ErrorCode>[HintCode.DUPLICATE_IMPORT]);
+ }
+
+ test_perform_imports_unusedImport_one() {
+ _newSource('/a.dart', r'''
+library lib_a;
+class A {}
+''');
+ _newSource('/b.dart', r'''
+library lib_b;
+class B {}
+''');
+ Source source = _newSource('/test.dart', r'''
+import 'a.dart';
+import 'b.dart';
+main() {
+ new A();
+}''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, HINTS);
+ expect(task, new isInstanceOf<GenerateHintsTask>());
+ // validate
+ _fillErrorListener(HINTS);
+ errorListener.assertErrorsWithCodes(<ErrorCode>[HintCode.UNUSED_IMPORT]);
+ }
+
+ test_perform_imports_unusedImport_zero() {
+ _newSource('/a.dart', r'''
+library lib_a;
+class A {}
+''');
+ Source source = _newSource('/test.dart', r'''
+import 'a.dart';
+main() {
+ new A();
+}''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, HINTS);
+ expect(task, new isInstanceOf<GenerateHintsTask>());
+ // validate
+ _fillErrorListener(HINTS);
+ errorListener.assertNoErrors();
+ }
+
+ test_perform_overrideVerifier() {
+ Source source = _newSource('/test.dart', '''
+class A {}
+class B {
+ @override
+ m() {}
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, HINTS);
+ expect(task, new isInstanceOf<GenerateHintsTask>());
+ // validate
+ _fillErrorListener(HINTS);
+ errorListener.assertErrorsWithCodes(
+ <ErrorCode>[HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD]);
+ }
+
+ test_perform_todo() {
+ Source source = _newSource('/test.dart', '''
+main() {
+ // TODO(developer) foo bar
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, HINTS);
+ expect(task, new isInstanceOf<GenerateHintsTask>());
+ // validate
+ _fillErrorListener(HINTS);
+ errorListener.assertErrorsWithCodes(<ErrorCode>[TodoCode.TODO]);
+ }
+
+ test_perform_unusedLocalElements_class() {
+ Source source = _newSource('/test.dart', '''
+class _A {}
+class _B {}
+main() {
+ new _A();
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, HINTS);
+ expect(task, new isInstanceOf<GenerateHintsTask>());
+ // validate
+ _fillErrorListener(HINTS);
+ errorListener.assertErrorsWithCodes(<ErrorCode>[HintCode.UNUSED_ELEMENT]);
+ }
+
+ test_perform_unusedLocalElements_localVariable() {
+ Source source = _newSource('/test.dart', '''
+main() {
+ var v = 42;
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, HINTS);
+ expect(task, new isInstanceOf<GenerateHintsTask>());
+ // validate
+ _fillErrorListener(HINTS);
+ errorListener
+ .assertErrorsWithCodes(<ErrorCode>[HintCode.UNUSED_LOCAL_VARIABLE]);
+ }
+
+ test_perform_unusedLocalElements_method() {
+ Source source = _newSource('/my_lib.dart', '''
+library my_lib;
+part 'my_part.dart';
+class A {
+ _ma() {}
+ _mb() {}
+ _mc() {}
+}
+''');
+ _newSource('/my_part.dart', '''
+part of my_lib;
+
+f(A a) {
+ a._mb();
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, HINTS);
+ expect(task, new isInstanceOf<GenerateHintsTask>());
+ // validate
+ _fillErrorListener(HINTS);
+ errorListener.assertErrorsWithCodes(
+ <ErrorCode>[HintCode.UNUSED_ELEMENT, HintCode.UNUSED_ELEMENT]);
+ }
+}
+
+@reflectiveTest
class ParseDartTaskTest extends _AbstractDartTaskTest {
test_buildInputs() {
Map<String, TaskInput> inputs = ParseDartTask.buildInputs(emptySource);
@@ -1194,6 +1549,99 @@
expect(classC.supertype.displayName, 'A');
}
}
+
+ test_perform_deep() {
+ Source sourceA = _newSource('/a.dart', '''
+library a;
+import 'b.dart';
+class A extends B {}
+''');
+ _newSource('/b.dart', '''
+library b;
+import 'c.dart';
+part 'b2.dart';
+class B extends B2 {}
+''');
+ _newSource('/b2.dart', '''
+part of b;
+class B2 extends C {}
+''');
+ _newSource('/c.dart', '''
+library c;
+class C {}
+''');
+ _computeResult(sourceA, LIBRARY_ELEMENT5);
+ expect(task, new isInstanceOf<ResolveLibraryTypeNamesTask>());
+ // validate
+ LibraryElement library = outputs[LIBRARY_ELEMENT5];
+ {
+ ClassElement clazz = library.getType('A');
+ expect(clazz.displayName, 'A');
+ clazz = clazz.supertype.element;
+ expect(clazz.displayName, 'B');
+ clazz = clazz.supertype.element;
+ expect(clazz.displayName, 'B2');
+ clazz = clazz.supertype.element;
+ expect(clazz.displayName, 'C');
+ clazz = clazz.supertype.element;
+ expect(clazz.displayName, 'Object');
+ expect(clazz.supertype, isNull);
+ }
+ }
+}
+
+@reflectiveTest
+class ResolveReferencesTaskTest extends _AbstractDartTaskTest {
+ test_perform() {
+ Source source = _newSource('/test.dart', '''
+class A {
+ m() {}
+}
+main(A a) {
+ a.m();
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ // prepare unit and "a.m()" invocation
+ CompilationUnit unit;
+ MethodInvocation invocation;
+ {
+ _computeResult(target, RESOLVED_UNIT1);
+ unit = outputs[RESOLVED_UNIT1];
+ // walk the AST
+ FunctionDeclaration function = unit.declarations[1];
+ BlockFunctionBody body = function.functionExpression.body;
+ ExpressionStatement statement = body.block.statements[0];
+ invocation = statement.expression;
+ // not resolved yet
+ expect(invocation.methodName.staticElement, isNull);
+ }
+ // fully resolve
+ {
+ _computeResult(target, RESOLVED_UNIT);
+ expect(task, new isInstanceOf<ResolveReferencesTask>());
+ expect(outputs[RESOLVED_UNIT], same(outputs[RESOLVED_UNIT]));
+ // a.m() is resolved now
+ expect(invocation.methodName.staticElement, isNotNull);
+ }
+ }
+
+ test_perform_errors() {
+ Source source = _newSource('/test.dart', '''
+class A {
+}
+main(A a) {
+ a.unknownMethod();
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, RESOLVED_UNIT);
+ expect(task, new isInstanceOf<ResolveReferencesTask>());
+ // validate
+ _fillErrorListener(RESOLVE_REFERENCES_ERRORS);
+ errorListener.assertErrorsWithCodes(
+ <ErrorCode>[StaticTypeWarningCode.UNDEFINED_METHOD]);
+ }
}
@reflectiveTest
@@ -1240,6 +1688,69 @@
}
@reflectiveTest
+class ResolveVariableReferencesTaskTest extends _AbstractDartTaskTest {
+ /**
+ * Verify that the mutated states of the given [variable] correspond to the
+ * [mutatedInClosure] and [mutatedInScope] matchers.
+ */
+ void expectMutated(VariableElement variable, Matcher mutatedInClosure,
+ Matcher mutatedInScope) {
+ expect(variable.isPotentiallyMutatedInClosure, mutatedInClosure);
+ expect(variable.isPotentiallyMutatedInScope, mutatedInScope);
+ }
+
+ test_perform_local() {
+ Source source = _newSource('/test.dart', '''
+main() {
+ var v1 = 1;
+ var v2 = 1;
+ var v3 = 1;
+ var v4 = 1;
+ v2 = 2;
+ v4 = 2;
+ localFunction() {
+ v3 = 3;
+ v4 = 3;
+ }
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, RESOLVED_UNIT5);
+ expect(task, new isInstanceOf<ResolveVariableReferencesTask>());
+ // validate
+ CompilationUnit unit = outputs[RESOLVED_UNIT5];
+ FunctionElement main = unit.element.functions[0];
+ expectMutated(main.localVariables[0], isFalse, isFalse);
+ expectMutated(main.localVariables[1], isFalse, isTrue);
+ expectMutated(main.localVariables[2], isTrue, isTrue);
+ expectMutated(main.localVariables[3], isTrue, isTrue);
+ }
+
+ test_perform_parameter() {
+ Source source = _newSource('/test.dart', '''
+main(p1, p2, p3, p4) {
+ p2 = 2;
+ p4 = 2;
+ localFunction() {
+ p3 = 3;
+ p4 = 3;
+ }
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, RESOLVED_UNIT5);
+ expect(task, new isInstanceOf<ResolveVariableReferencesTask>());
+ // validate
+ CompilationUnit unit = outputs[RESOLVED_UNIT5];
+ FunctionElement main = unit.element.functions[0];
+ expectMutated(main.parameters[0], isFalse, isFalse);
+ expectMutated(main.parameters[1], isFalse, isTrue);
+ expectMutated(main.parameters[2], isTrue, isTrue);
+ expectMutated(main.parameters[3], isTrue, isTrue);
+ }
+}
+
+@reflectiveTest
class ScanDartTaskTest extends _AbstractDartTaskTest {
test_buildInputs() {
Map<String, TaskInput> inputs = ScanDartTask.buildInputs(emptySource);
@@ -1294,6 +1805,26 @@
}
}
+@reflectiveTest
+class VerifyUnitTaskTest extends _AbstractDartTaskTest {
+ test_perform_verifyError() {
+ Source source = _newSource('/test.dart', '''
+main() {
+ if (42) {
+ print('Not bool!');
+ }
+}
+''');
+ LibraryUnitTarget target = new LibraryUnitTarget(source, source);
+ _computeResult(target, VERIFY_ERRORS);
+ expect(task, new isInstanceOf<VerifyUnitTask>());
+ // validate
+ _fillErrorListener(VERIFY_ERRORS);
+ errorListener.assertErrorsWithCodes(
+ <ErrorCode>[StaticTypeWarningCode.NON_BOOL_CONDITION]);
+ }
+}
+
class _AbstractDartTaskTest extends EngineTestCase {
MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
Source emptySource;
@@ -1330,13 +1861,19 @@
taskManager.addTaskDescriptor(BuildLibraryElementTask.DESCRIPTOR);
taskManager.addTaskDescriptor(BuildPublicNamespaceTask.DESCRIPTOR);
taskManager.addTaskDescriptor(BuildDirectiveElementsTask.DESCRIPTOR);
- taskManager.addTaskDescriptor(BuildExportSourceClosureTask.DESCRIPTOR);
+ taskManager.addTaskDescriptor(BuildSourceClosuresTask.DESCRIPTOR);
taskManager.addTaskDescriptor(BuildExportNamespaceTask.DESCRIPTOR);
- taskManager.addTaskDescriptor(BuildTypeProviderTask.DESCRIPTOR);
taskManager.addTaskDescriptor(BuildEnumMemberElementsTask.DESCRIPTOR);
taskManager.addTaskDescriptor(BuildFunctionTypeAliasesTask.DESCRIPTOR);
+ taskManager.addTaskDescriptor(BuildTypeProviderTask.DESCRIPTOR);
+ taskManager.addTaskDescriptor(GatherUsedImportedElementsTask.DESCRIPTOR);
+ taskManager.addTaskDescriptor(GatherUsedLocalElementsTask.DESCRIPTOR);
+ taskManager.addTaskDescriptor(GenerateHintsTask.DESCRIPTOR);
taskManager.addTaskDescriptor(ResolveUnitTypeNamesTask.DESCRIPTOR);
taskManager.addTaskDescriptor(ResolveLibraryTypeNamesTask.DESCRIPTOR);
+ taskManager.addTaskDescriptor(ResolveReferencesTask.DESCRIPTOR);
+ taskManager.addTaskDescriptor(ResolveVariableReferencesTask.DESCRIPTOR);
+ taskManager.addTaskDescriptor(VerifyUnitTask.DESCRIPTOR);
// prepare AnalysisDriver
analysisDriver = new AnalysisDriver(taskManager, context);
}
diff --git a/pkg/analyzer/test/src/task/driver_test.dart b/pkg/analyzer/test/src/task/driver_test.dart
index 17e55db..093a91f 100644
--- a/pkg/analyzer/test/src/task/driver_test.dart
+++ b/pkg/analyzer/test/src/task/driver_test.dart
@@ -260,6 +260,35 @@
expect(driver.performAnalysisTask(), false);
}
+ test_performAnalysisTask_infiniteLoop() {
+ AnalysisTarget target = new TestSource();
+ ResultDescriptor resultA = new ResultDescriptor('resultA', -1);
+ ResultDescriptor resultB = new ResultDescriptor('resultB', -2);
+ // configure tasks
+ TestAnalysisTask task1;
+ TestAnalysisTask task2;
+ TaskDescriptor descriptor1 = new TaskDescriptor(
+ 'task1', (context, target) => task1, (target) => {
+ 'inputB': new SimpleTaskInput<int>(target, resultB)
+ }, [resultA]);
+ TaskDescriptor descriptor2 = new TaskDescriptor('task2',
+ (context, target) => task2, (target) => {
+ 'inputA': new SimpleTaskInput<int>(target, resultA)
+ }, [resultB]);
+ task1 = new TestAnalysisTask(context, target, descriptor: descriptor1);
+ task2 = new TestAnalysisTask(context, target, descriptor: descriptor2);
+ manager.addTaskDescriptor(descriptor1);
+ manager.addTaskDescriptor(descriptor2);
+ context.explicitTargets.add(target);
+ manager.addGeneralResult(resultB);
+ // prepare work order
+ expect(driver.performAnalysisTask(), true);
+ expect(driver.performAnalysisTask(), true);
+ CaughtException exception = context.getCacheEntry(target).exception;
+ expect(exception, isNotNull);
+ expect(exception.exception, new isInstanceOf<InfiniteTaskLoopException>());
+ }
+
test_performWorkItem_exceptionInTask() {
AnalysisTarget target = new TestSource();
ResultDescriptor result = new ResultDescriptor('result', null);
@@ -545,6 +574,10 @@
baseContext.refactoringUnsafeSources;
@override
+ LibraryResolverFactory get libraryResolverFactory =>
+ baseContext.libraryResolverFactory;
+
+ @override
ResolverVisitorFactory get resolverVisitorFactory =>
baseContext.resolverVisitorFactory;
diff --git a/pkg/analyzer/test/src/task/general_test.dart b/pkg/analyzer/test/src/task/general_test.dart
index 664a2d6..a043c84 100644
--- a/pkg/analyzer/test/src/task/general_test.dart
+++ b/pkg/analyzer/test/src/task/general_test.dart
@@ -66,6 +66,16 @@
expect(task.outputs[CONTENT], 'foo');
expect(task.outputs[MODIFICATION_TIME], 42);
}
+
+ void test_perform_exception() {
+ AnalysisContext context = new _MockContext();
+ Source target = new TestSource();
+ GetContentTask task = new GetContentTask(context, target);
+ when(context.getContents(target)).thenThrow('My exception!');
+ task.perform();
+ expect(task.caughtException, isNotNull);
+ expect(task.outputs, isEmpty);
+ }
}
class _MockContext extends TypedMock implements AnalysisContext {
diff --git a/pkg/analyzer2dart/lib/src/cps_generator.dart b/pkg/analyzer2dart/lib/src/cps_generator.dart
index fbb0ee0..2360c16 100644
--- a/pkg/analyzer2dart/lib/src/cps_generator.dart
+++ b/pkg/analyzer2dart/lib/src/cps_generator.dart
@@ -55,8 +55,7 @@
}
@override
- ir.ExecutableDefinition visitConstructorElement(
- analyzer.ConstructorElement element) {
+ ir.RootNode visitConstructorElement(analyzer.ConstructorElement element) {
CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element);
if (!element.isFactory) {
ConstructorDeclaration constructorDeclaration = node;
@@ -96,8 +95,8 @@
return withBuilder(
new DartIrBuilder(DART_CONSTANT_SYSTEM,
element,
- // TODO(johnniwinther): Supported closure variables.
- new NullCapturedVariables()),
+ // TODO(johnniwinther): Support closure variables.
+ new Set<dart2js.Local>()),
() {
irBuilder.buildFunctionHeader(
constructor.parameters.map(converter.convertElement));
@@ -115,8 +114,8 @@
return withBuilder(
new DartIrBuilder(DART_CONSTANT_SYSTEM,
element,
- // TODO(johnniwinther): Supported closure variables.
- new NullCapturedVariables()),
+ // TODO(johnniwinther): Support closure variables.
+ new Set<dart2js.Local>()),
() {
irBuilder.buildFieldInitializerHeader();
ir.Primitive initializer = build(node.initializer);
@@ -130,8 +129,8 @@
return withBuilder(
new DartIrBuilder(DART_CONSTANT_SYSTEM,
element,
- // TODO(johnniwinther): Supported closure variables.
- new NullCapturedVariables()),
+ // TODO(johnniwinther): Support closure variables.
+ new Set<dart2js.Local>()),
() {
irBuilder.buildFunctionHeader(
function.parameters.map(converter.convertElement));
@@ -586,7 +585,3 @@
catchClauseInfos: catchClauseInfos);
}
}
-
-class NullCapturedVariables extends DartCapturedVariables {
- NullCapturedVariables() : super(null);
-}
diff --git a/pkg/analyzer2dart/lib/src/modely.dart b/pkg/analyzer2dart/lib/src/modely.dart
index 493b58d..e69d5f0 100644
--- a/pkg/analyzer2dart/lib/src/modely.dart
+++ b/pkg/analyzer2dart/lib/src/modely.dart
@@ -169,9 +169,6 @@
}
@override
- void setFixedBackendName(String name) => unsupported('setFixedBackendName');
-
- @override
void setNative(String name) => unsupported('setNative');
String toString() => '$kind($name)';
@@ -723,7 +720,8 @@
with AnalyzableElementY,
AstElementY,
TopLevelElementMixin,
- VariableElementMixin
+ VariableElementMixin,
+ MemberElementMixin
implements dart2js.FieldElement {
analyzer.TopLevelVariableElement get element => super.element;
@@ -813,7 +811,8 @@
with AnalyzableElementY,
AstElementY,
FunctionElementMixin,
- ClassMemberMixin
+ ClassMemberMixin,
+ MemberElementMixin
implements dart2js.ConstructorElement {
analyzer.ConstructorElement get element => super.element;
@@ -830,6 +829,10 @@
@override
bool get isRedirectingFactory => false;
+ // TODO(johnniwinther): Support redirecting generative constructors.
+ @override
+ bool get isRedirectingGenerative => false;
+
@override
bool get isStatic => false;
@@ -860,7 +863,8 @@
with AnalyzableElementY,
AstElementY,
FunctionElementMixin,
- ClassMemberMixin
+ ClassMemberMixin,
+ MemberElementMixin
implements dart2js.MethodElement {
analyzer.MethodElement get element => super.element;
@@ -887,3 +891,7 @@
@override
get nestedClosures => unsupported('nestedClosures');
}
+
+abstract class MemberElementMixin implements dart2js.MemberElement {
+ dart2js.Name get memberName => new dart2js.Name(name, library);
+}
\ No newline at end of file
diff --git a/pkg/analyzer2dart/test/end2end_data.dart b/pkg/analyzer2dart/test/end2end_data.dart
index b1cb1db..2ad4598 100644
--- a/pkg/analyzer2dart/test/end2end_data.dart
+++ b/pkg/analyzer2dart/test/end2end_data.dart
@@ -256,6 +256,14 @@
print(a);
return a;
}
+''', '''
+main() {
+ var a;
+ print(0);
+ a = "";
+ print(a);
+ return a;
+}
'''),
const TestSpec('''
@@ -275,6 +283,12 @@
print(a);
return a;
}
+''', '''
+main(a) {
+ a = a ? "" : a;
+ print(a);
+ return a;
+}
'''),
]),
@@ -741,12 +755,10 @@
}
''', '''
main(a) {
- var v0 = a.iterator, i;
+ var v0 = a.iterator;
while (v0.moveNext()) {
- i = v0.current;
- print(i);
- i = 0;
- print(i);
+ print(v0.current);
+ print(0);
}
}
'''),
diff --git a/pkg/analyzer2dart/test/sexpr_test.dart b/pkg/analyzer2dart/test/sexpr_test.dart
index 9450ced..2c8da58 100644
--- a/pkg/analyzer2dart/test/sexpr_test.dart
+++ b/pkg/analyzer2dart/test/sexpr_test.dart
@@ -42,7 +42,7 @@
void checkOutput(String elementName,
dart2js.Element element,
String expectedOutput) {
- ExecutableDefinition ir = convertedWorld.getIr(element);
+ RootNode ir = convertedWorld.getIr(element);
if (expectedOutput == null) {
expect(ir, isNull,
reason: "\nInput:\n${result.input}\n"
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index 175ca25..4aaa293 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -93,7 +93,7 @@
// TODO(ahe): These classes continuously cause problems. We need to
// find a more general solution.
class ClosureFieldElement extends ElementX
- implements VariableElement, CapturedVariable {
+ implements FieldElement, CapturedVariable {
/// The [BoxLocal] or [LocalElement] being accessed through the field.
final Local local;
@@ -146,6 +146,9 @@
accept(ElementVisitor visitor) => visitor.visitClosureFieldElement(this);
Element get analyzableElement => closureClass.methodElement.analyzableElement;
+
+ @override
+ List<FunctionElement> get nestedClosures => const <FunctionElement>[];
}
// TODO(ahe): These classes continuously cause problems. We need to find
@@ -226,7 +229,7 @@
// TODO(ngeoffray, ahe): These classes continuously cause problems. We need to
// find a more general solution.
class BoxFieldElement extends ElementX
- implements TypedElement, CapturedVariable {
+ implements TypedElement, CapturedVariable, FieldElement {
final BoxLocal box;
BoxFieldElement(String name, this.variableElement, BoxLocal box)
@@ -240,6 +243,33 @@
final VariableElement variableElement;
accept(ElementVisitor visitor) => visitor.visitBoxFieldElement(this);
+
+ @override
+ bool get hasNode => false;
+
+ @override
+ bool get hasResolvedAst => false;
+
+ @override
+ Expression get initializer {
+ throw new UnsupportedError("BoxFieldElement.initializer");
+ }
+
+ @override
+ MemberElement get memberContext => box.executableContext.memberContext;
+
+ @override
+ List<FunctionElement> get nestedClosures => const <FunctionElement>[];
+
+ @override
+ Node get node {
+ throw new UnsupportedError("BoxFieldElement.node");
+ }
+
+ @override
+ ResolvedAst get resolvedAst {
+ throw new UnsupportedError("BoxFieldElement.resolvedAst");
+ }
}
/// A local variable used encode the direct (uncaptured) references to [this].
@@ -254,7 +284,8 @@
}
/// Call method of a closure class.
-class SynthesizedCallMethodElementX extends BaseFunctionElementX {
+class SynthesizedCallMethodElementX extends BaseFunctionElementX
+ implements MethodElement {
final LocalFunctionElement expression;
SynthesizedCallMethodElementX(String name,
diff --git a/pkg/compiler/lib/src/common.dart b/pkg/compiler/lib/src/common.dart
index ff58374..65debcd 100644
--- a/pkg/compiler/lib/src/common.dart
+++ b/pkg/compiler/lib/src/common.dart
@@ -11,6 +11,7 @@
TypeConstantValue;
export 'dart2jslib.dart' show
+ CallStructure,
CompilerTask,
Compiler,
ConstantEnvironment,
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
index 13d5d63..c6f1af4 100644
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ b/pkg/compiler/lib/src/compile_time_constants.dart
@@ -444,7 +444,7 @@
new DartString.literal(text))))];
AstConstant constant = makeConstructedConstant(
compiler, handler, context, node, type, compiler.symbolConstructor,
- new Selector.callConstructor('', null, 1),
+ CallStructure.ONE_ARG,
arguments, arguments);
return new AstConstant(
context, node, new SymbolConstantExpression(constant.value, text));
@@ -652,7 +652,7 @@
*/
List<AstConstant> evaluateArgumentsToConstructor(
Node node,
- Selector selector,
+ CallStructure callStructure,
Link<Node> arguments,
FunctionElement target,
{AstConstant compileArgument(Node node)}) {
@@ -664,7 +664,7 @@
}
target.computeSignature(compiler);
- if (!selector.applies(target, compiler.world)) {
+ if (!callStructure.signatureApplies(target)) {
String name = Elements.constructorNameForDiagnostics(
target.enclosingClass.name, target.name);
compiler.reportError(
@@ -676,10 +676,11 @@
target.functionSignature.parameterCount,
new ErroneousAstConstant(context, node));
}
- return selector.makeArgumentsList(arguments,
- target,
- compileArgument,
- compileDefaultValue);
+ return callStructure.makeArgumentsList(
+ arguments,
+ target,
+ compileArgument,
+ compileDefaultValue);
}
AstConstant visitNewExpression(NewExpression node) {
@@ -706,7 +707,7 @@
compiler.analyzeElement(constructor.declaration);
InterfaceType type = elements.getType(node);
- Selector selector = elements.getSelector(send);
+ CallStructure callStructure = elements.getSelector(send).callStructure;
Map<Node, AstConstant> concreteArgumentMap =
<Node, AstConstant>{};
@@ -721,7 +722,7 @@
List<AstConstant> normalizedArguments =
evaluateArgumentsToConstructor(
- node, selector, send.arguments, constructor.implementation,
+ node, callStructure, send.arguments, constructor.implementation,
compileArgument: (node) => concreteArgumentMap[node]);
List<AstConstant> concreteArguments =
concreteArgumentMap.values.toList();
@@ -732,11 +733,11 @@
AstConstant createEvaluatedConstant(ConstantValue value) {
return new AstConstant(
- context, node, new ConstructedConstantExpresssion(
+ context, node, new ConstructedConstantExpression(
value,
type,
constructor,
- elements.getSelector(send),
+ elements.getSelector(send).callStructure,
concreteArguments.map((e) => e.expression).toList()));
}
@@ -811,7 +812,7 @@
} else {
return makeConstructedConstant(
compiler, handler, context,
- node, type, constructor, selector,
+ node, type, constructor, callStructure,
concreteArguments, normalizedArguments);
}
}
@@ -823,12 +824,12 @@
Node node,
InterfaceType type,
ConstructorElement constructor,
- Selector selector,
+ CallStructure callStructure,
List<AstConstant> concreteArguments,
List<AstConstant> normalizedArguments) {
- assert(invariant(node, selector.applies(constructor, compiler.world) ||
+ assert(invariant(node, callStructure.signatureApplies(constructor) ||
compiler.compilationFailed,
- message: "Selector $selector does not apply to constructor "
+ message: "Call structure $callStructure does not apply to constructor "
"$constructor."));
// The redirection chain of this element may not have been resolved through
@@ -850,13 +851,13 @@
evaluator.buildFieldConstants(classElement);
return new AstConstant(
- context, node, new ConstructedConstantExpresssion(
+ context, node, new ConstructedConstantExpression(
new ConstructedConstantValue(
constructedType,
fieldConstants.map((e) => e.value).toList()),
type,
constructor,
- selector,
+ callStructure,
concreteArguments.map((e) => e.expression).toList()));
}
@@ -994,12 +995,12 @@
Function compileArgument = (element) => definitions[element];
Function compileConstant = handler.compileConstant;
FunctionElement target = constructor.definingConstructor.implementation;
- Selector.addForwardingElementArgumentsToList(constructor,
- compiledArguments,
- target,
- compileArgument,
- compileConstant,
- compiler.world);
+ CallStructure.addForwardingElementArgumentsToList(
+ constructor,
+ compiledArguments,
+ target,
+ compileArgument,
+ compileConstant);
evaluateSuperOrRedirectSend(compiledArguments, target);
return;
}
@@ -1019,7 +1020,8 @@
FunctionElement target = elements[call];
List<AstConstant> compiledArguments =
evaluateArgumentsToConstructor(
- call, elements.getSelector(call), call.arguments, target,
+ call, elements.getSelector(call).callStructure,
+ call.arguments, target,
compileArgument: evaluateConstant);
evaluateSuperOrRedirectSend(compiledArguments, target);
foundSuperOrRedirect = true;
@@ -1048,9 +1050,9 @@
// If we do not find a default constructor, an error was reported
// already and compilation will fail anyway. So just ignore that case.
if (targetConstructor != null) {
- Selector selector = new Selector.callDefaultConstructor();
List<AstConstant> compiledArguments = evaluateArgumentsToConstructor(
- functionNode, selector, const Link<Node>(), targetConstructor);
+ functionNode, CallStructure.NO_ARGS,
+ const Link<Node>(), targetConstructor);
evaluateSuperOrRedirectSend(compiledArguments, targetConstructor);
}
}
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index dcaea59..5bd9aee 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -291,6 +291,7 @@
bool get canHandleCompilationFailed;
void onResolutionComplete() {}
+ void onTypeInferenceComplete() {}
ItemCompilationContext createItemCompilationContext() {
return new ItemCompilationContext();
@@ -362,7 +363,7 @@
void registerRuntimeType(Enqueuer enqueuer, Registry registry) {}
/// Call this to register a `noSuchMethod` implementation.
- void registerNoSuchMethod(Element noSuchMethodElement) {}
+ void registerNoSuchMethod(FunctionElement noSuchMethodElement) {}
/// Call this method to enable support for `noSuchMethod`.
void enableNoSuchMethod(Enqueuer enqueuer) {}
@@ -1611,6 +1612,8 @@
if (stopAfterTypeInference) return;
+ backend.onTypeInferenceComplete();
+
log('Compiling...');
phase = PHASE_COMPILING;
// TODO(johnniwinther): Move these to [CodegenEnqueuer].
diff --git a/pkg/compiler/lib/src/constants/expressions.dart b/pkg/compiler/lib/src/constants/expressions.dart
index ef416fa..c24b66d 100644
--- a/pkg/compiler/lib/src/constants/expressions.dart
+++ b/pkg/compiler/lib/src/constants/expressions.dart
@@ -10,7 +10,7 @@
Element,
FunctionElement,
VariableElement;
-import '../universe/universe.dart' show Selector;
+import '../universe/universe.dart' show CallStructure;
import 'values.dart';
/// An expression that is a compile-time constant.
@@ -97,18 +97,19 @@
}
/// Invocation of a const constructor.
-class ConstructedConstantExpresssion extends ConstantExpression {
+class ConstructedConstantExpression extends ConstantExpression {
final ConstantValue value;
final InterfaceType type;
final FunctionElement target;
- final Selector selector;
+ final CallStructure callStructure;
final List<ConstantExpression> arguments;
- ConstructedConstantExpresssion(this.value,
- this.type,
- this.target,
- this.selector,
- this.arguments) {
+ ConstructedConstantExpression(
+ this.value,
+ this.type,
+ this.target,
+ this.callStructure,
+ this.arguments) {
assert(type.element == target.enclosingClass);
}
@@ -274,7 +275,7 @@
R visitPrimitive(PrimitiveConstantExpression exp, C context);
R visitList(ListConstantExpression exp, C context);
R visitMap(MapConstantExpression exp, C context);
- R visitConstructed(ConstructedConstantExpresssion exp, C context);
+ R visitConstructed(ConstructedConstantExpression exp, C context);
R visitConcatenate(ConcatenateConstantExpression exp, C context);
R visitSymbol(SymbolConstantExpression exp, C context);
R visitType(TypeConstantExpression exp, C context);
@@ -367,7 +368,7 @@
}
@override
- void visitConstructed(ConstructedConstantExpresssion exp, [_]) {
+ void visitConstructed(ConstructedConstantExpression exp, [_]) {
sb.write('const ');
sb.write(exp.target.enclosingClass.name);
if (exp.target.name != '') {
@@ -378,7 +379,7 @@
sb.write('(');
bool needsComma = false;
- int namedOffset = exp.selector.positionalArgumentCount;
+ int namedOffset = exp.callStructure.positionalArgumentCount;
for (int index = 0; index < namedOffset; index++) {
if (needsComma) {
sb.write(', ');
@@ -386,11 +387,11 @@
visit(exp.arguments[index]);
needsComma = true;
}
- for (int index = 0; index < exp.selector.namedArgumentCount; index++) {
+ for (int index = 0; index < exp.callStructure.namedArgumentCount; index++) {
if (needsComma) {
sb.write(', ');
}
- sb.write(exp.selector.namedArguments[index]);
+ sb.write(exp.callStructure.namedArguments[index]);
sb.write(': ');
visit(exp.arguments[namedOffset + index]);
needsComma = true;
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
index deffab4..5f35a3f 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -13,7 +13,8 @@
import '../tree/tree.dart' as ast;
import '../closure.dart' hide ClosureScope;
import 'cps_ir_nodes.dart' as ir;
-import 'cps_ir_builder_task.dart' show DartCapturedVariables;
+import 'cps_ir_builder_task.dart' show DartCapturedVariables,
+ GlobalProgramInformation;
/// A mapping from variable elements to their compile-time values.
///
@@ -43,6 +44,17 @@
index2variable = new List<Local>.from(other.index2variable),
index2value = new List<ir.Primitive>.from(other.index2value);
+ /// Construct an environment that is shaped like another one but with a
+ /// fresh parameter for each variable.
+ ///
+ /// The mapping from elements to indexes is shared, not copied.
+ Environment.fresh(Environment other)
+ : variable2index = other.variable2index,
+ index2variable = new List<Local>.from(other.index2variable),
+ index2value = other.index2variable.map((Local local) {
+ return new ir.Parameter(local);
+ }).toList();
+
get length => index2variable.length;
ir.Primitive operator [](int index) => index2value[index];
@@ -61,6 +73,14 @@
index2value.add(value);
}
+ void discard(int count) {
+ assert(count <= index2variable.length);
+ // The map from variables to their index are shared, so we cannot remove
+ // the mapping in `variable2index`.
+ index2variable.length -= count;
+ index2value.length -= count;
+ }
+
ir.Primitive lookup(Local element) {
assert(invariant(element, variable2index.containsKey(element),
message: "Unknown variable: $element."));
@@ -91,57 +111,41 @@
}
}
-/// A class to collect breaks or continues.
-///
-/// When visiting a potential target of breaks or continues, any breaks or
-/// continues are collected by a JumpCollector and processed later, on demand.
-/// The site of the break or continue is represented by a continuation
-/// invocation that will have its target and arguments filled in later.
-///
-/// The environment of the builder at that point is captured and should not
-/// be subsequently mutated until the jump is resolved.
-class JumpCollector {
+/// The abstract base class of objects that emit jumps to a continuation and
+/// give a handle to the continuation and its environment.
+abstract class JumpCollector {
final JumpTarget target;
- final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[];
- final List<Environment> _environments = <Environment>[];
- final List<Iterable<LocalVariableElement>> boxedTryVariables =
+
+ ir.Continuation _continuation = null;
+ final Environment _continuationEnvironment;
+
+ final List<Iterable<LocalVariableElement>> _boxedTryVariables =
<Iterable<LocalVariableElement>>[];
- JumpCollector(this.target);
+ JumpCollector(this._continuationEnvironment, this.target);
- bool get isEmpty => _invocations.isEmpty;
- int get length => _invocations.length;
- List<ir.InvokeContinuation> get invocations => _invocations;
- List<Environment> get environments => _environments;
+ /// True if the collector has not recorded any jumps to its continuation.
+ bool get isEmpty;
- void addJump(IrBuilder builder) {
- // Unbox all variables that were boxed on entry to try blocks between the
- // jump and the target.
- for (Iterable<LocalVariableElement> boxedOnEntry in boxedTryVariables) {
- for (LocalVariableElement variable in boxedOnEntry) {
- assert(builder.isInMutableVariable(variable));
- ir.Primitive value = builder.buildLocalGet(variable);
- builder.environment.update(variable, value);
- }
- }
- ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized();
- builder.add(invoke);
- _invocations.add(invoke);
- _environments.add(builder.environment);
- builder._current = null;
- // TODO(kmillikin): Can we set builder.environment to null to make it
- // less likely to mutate it?
- }
+ /// The continuation encapsulated by this collector.
+ ir.Continuation get continuation;
+
+ /// The compile-time environment to be used for translating code in the body
+ /// of the continuation.
+ Environment get environment;
+
+ /// Emit a jump to the continuation for a given [IrBuilder].
+ void addJump(IrBuilder builder);
/// Add a set of variables that were boxed on entry to a try block.
///
- /// Jumps from a try block to targets outside have to unbox the variables
- /// that were boxed on entry before invoking the target continuation. Call
- /// this function before translating a try block and call [leaveTry] after
- /// translating it.
+ /// All jumps from a try block to targets outside have to unbox the
+ /// variables that were boxed on entry before invoking the target
+ /// continuation. Call this function before translating a try block and
+ /// call [leaveTry] after translating it.
void enterTry(Iterable<LocalVariableElement> boxedOnEntry) {
// The boxed variables are maintained as a stack to make leaving easy.
- boxedTryVariables.add(boxedOnEntry);
+ _boxedTryVariables.add(boxedOnEntry);
}
/// Remove the most recently added set of variables boxed on entry to a try
@@ -150,7 +154,172 @@
/// Call [enterTry] before translating a try block and call this function
/// after translating it.
void leaveTry() {
- boxedTryVariables.removeLast();
+ _boxedTryVariables.removeLast();
+ }
+
+ void _buildTryExit(IrBuilder builder) {
+ for (Iterable<LocalVariableElement> boxedOnEntry in _boxedTryVariables) {
+ for (LocalVariableElement variable in boxedOnEntry) {
+ assert(builder.isInMutableVariable(variable));
+ ir.Primitive value = builder.buildLocalGet(variable);
+ builder.environment.update(variable, value);
+ }
+ }
+ }
+}
+
+/// A class to collect 'forward' jumps.
+///
+/// A forward jump to a continuation in the sense of the CPS translation is
+/// a jump where the jump is emitted before any code in the body of the
+/// continuation is translated. They have the property that continuation
+/// parameters and the environment for the translation of the body can be
+/// determined based on the invocations, before translating the body. A
+/// [ForwardJumpCollector] can encapsulate a continuation where all the
+/// jumps are forward ones.
+///
+/// Examples of forward jumps in the translation are join points of
+/// if-then-else and breaks from loops.
+///
+/// The implementation strategy is that the collector collects invocation
+/// sites and the environments at those sites. Then it constructs a
+/// continuation 'on demand' after all the jumps are seen. It determines
+/// continuation parameters, the environment for the translation of code in
+/// the continuation body, and the arguments at the invocation site only
+/// after all the jumps to the continuation are seen.
+class ForwardJumpCollector extends JumpCollector {
+ final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[];
+ final List<Environment> _invocationEnvironments = <Environment>[];
+
+ /// Construct a collector with a given base environment.
+ ///
+ /// The base environment is the one in scope at the site that the
+ /// continuation represented by this collector will be bound. The
+ /// environment is copied by the collector. Subsequent mutation of the
+ /// original environment will not affect the collector.
+ ForwardJumpCollector(Environment environment, {JumpTarget target: null})
+ : super(new Environment.from(environment), target);
+
+ bool get isEmpty => _invocations.isEmpty;
+
+ ir.Continuation get continuation {
+ if (_continuation == null) _setContinuation();
+ return _continuation;
+ }
+
+ Environment get environment {
+ if (_continuation == null) _setContinuation();
+ return _continuationEnvironment;
+ }
+
+ void addJump(IrBuilder builder) {
+ assert(_continuation == null);
+ _buildTryExit(builder);
+ ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized();
+ builder.add(invoke);
+ _invocations.add(invoke);
+ _invocationEnvironments.add(builder.environment);
+ builder._current = null;
+ // TODO(kmillikin): Can we set builder.environment to null to make it
+ // less likely to mutate it?
+ }
+
+ void _setContinuation() {
+ assert(_continuation == null);
+ // We have seen all invocations of this continuation, and recorded the
+ // environment in effect at each invocation site.
+
+ // Compute the union of the assigned variables reaching the continuation.
+ //
+ // There is a continuation parameter for each environment variable
+ // that has a different value (from the environment in scope at the
+ // continuation binding) on some path. `_environment` is initially a copy
+ // of the environment in scope at the continuation binding. Compute the
+ // continuation parameters and add them to `_environment` so it will become
+ // the one in scope for the continuation body.
+ List<ir.Parameter> parameters = <ir.Parameter>[];
+ if (_invocationEnvironments.isNotEmpty) {
+ int length = _continuationEnvironment.length;
+ for (int varIndex = 0; varIndex < length; ++varIndex) {
+ for (Environment invocationEnvironment in _invocationEnvironments) {
+ assert(invocationEnvironment.sameDomain(length,
+ _continuationEnvironment));
+ if (invocationEnvironment[varIndex] !=
+ _continuationEnvironment[varIndex]) {
+ ir.Parameter parameter = new ir.Parameter(
+ _continuationEnvironment.index2variable[varIndex]);
+ _continuationEnvironment.index2value[varIndex] = parameter;
+ parameters.add(parameter);
+ break;
+ }
+ }
+ }
+ }
+ _continuation = new ir.Continuation(parameters);
+
+ // Compute the intersection of the parameters with the environments at
+ // each continuation invocation. Initialize the invocations.
+ for (int jumpIndex = 0; jumpIndex < _invocations.length; ++jumpIndex) {
+ Environment invocationEnvironment = _invocationEnvironments[jumpIndex];
+ List<ir.Reference> arguments = <ir.Reference>[];
+ int varIndex = 0;
+ for (ir.Parameter parameter in parameters) {
+ varIndex =
+ _continuationEnvironment.index2value.indexOf(parameter, varIndex);
+ arguments.add(new ir.Reference(invocationEnvironment[varIndex]));
+ }
+ ir.InvokeContinuation invocation = _invocations[jumpIndex];
+ invocation.continuation = new ir.Reference(_continuation);
+ invocation.arguments = arguments;
+ }
+ }
+}
+
+/// A class to collect 'backward' jumps.
+///
+/// A backward jump to a continuation in the sense of the CPS translation is
+/// a jump where some code in the body of the continuation is translated
+/// before the jump is emitted. They have the property that the
+/// continuation parameters and the environment for the translation of the
+/// body must be determined before emitting all the invocations. A
+/// [BackwardJumpCollector] can ecapsulate a continuation where some jumps
+/// are backward ones.
+///
+/// Examples of backward jumps in the translation are the recursive
+/// invocations of loop continuations.
+///
+/// The implementation strategy is that the collector inserts a continuation
+/// parameter for each variable in scope at the entry to the continuation,
+/// before emitting any jump to the continuation. When a jump is added, it
+/// is given an argument for each continuation parameter.
+class BackwardJumpCollector extends JumpCollector {
+ /// Construct a collector with a given base environment.
+ ///
+ /// The base environment is the one in scope at the site that the
+ /// continuation represented by this collector will be bound. The
+ /// translation of the continuation body will use an environment with the
+ /// same shape, but with fresh continuation parameters for each variable.
+ BackwardJumpCollector(Environment environment, {JumpTarget target: null})
+ : super(new Environment.fresh(environment), target) {
+ List<ir.Parameter> parameters =
+ new List<ir.Parameter>.from(_continuationEnvironment.index2value);
+ _continuation = new ir.Continuation(parameters, isRecursive: true);
+ }
+
+ bool isEmpty = true;
+
+ ir.Continuation get continuation => _continuation;
+ Environment get environment => _continuationEnvironment;
+
+ void addJump(IrBuilder builder) {
+ assert(_continuation.parameters.length <= builder.environment.length);
+ isEmpty = false;
+ _buildTryExit(builder);
+ builder.add(new ir.InvokeContinuation(_continuation,
+ builder.environment.index2value.take(_continuation.parameters.length)
+ .toList(),
+ isRecursive: true));
+ builder._current = null;
}
}
@@ -247,17 +416,6 @@
abstract class IrBuilder {
IrBuilder _makeInstance();
- // TODO(johnniwinther): Remove this from the [IrBuilder].
- /// A map from TryStatements in the AST to their analysis information.
- ///
- /// This includes which variables should be copied into [ir.MutableVariable]s
- /// on entry to the try and copied out on exit.
- Map<ast.TryStatement, TryStatementInfo> get tryStatements;
-
- /// The set of local variables that will spend their lifetime as
- /// [ir.MutableVariable]s due to being captured by a nested function.
- Set<Local> get mutableCapturedVariables;
-
/// True if [local] should currently be accessed from a [ir.MutableVariable].
bool isInMutableVariable(Local local);
@@ -308,7 +466,7 @@
/// Add the given function parameter to the IR, and bind it in the environment
/// or put it in its box, if necessary.
- void _createFunctionParameter(ParameterElement parameterElement);
+ void _createFunctionParameter(Local parameterElement);
void _createThisParameter();
/// Creates an access to the receiver from the current (or enclosing) method.
@@ -365,14 +523,17 @@
/// Construct a delimited visitor for visiting a subtree.
///
- /// The delimited visitor has its own compile-time environment mapping
- /// local variables to their values, which is initially a copy of the parent
- /// environment. It has its own context for building an IR expression, so
- /// the built expression is not plugged into the parent's context.
- IrBuilder makeDelimitedBuilder() {
+ /// Build a subterm that is not (yet) connected to the CPS term. The
+ /// delimited visitor has its own has its own context for building an IR
+ /// expression, so the built expression is not plugged into the parent's
+ /// context. It has its own compile-time environment mapping local
+ /// variables to their values. If an optional environment argument is
+ /// supplied, it is used as the builder's initial environment. Otherwise
+ /// the environment is initially a copy of the parent builder's environment.
+ IrBuilder makeDelimitedBuilder([Environment env = null]) {
return _makeInstance()
..state = state
- ..environment = new Environment.from(environment);
+ ..environment = env != null ? env : new Environment.from(environment);
}
/// Construct a builder for making constructor field initializers.
@@ -383,22 +544,6 @@
..environment = new Environment.from(environment);
}
- /// Construct a visitor for a recursive continuation.
- ///
- /// The recursive continuation builder has fresh parameters (i.e. SSA phis)
- /// for all the local variables in the parent, because the invocation sites
- /// of the continuation are not all known when the builder is created. The
- /// recursive invocations will be passed values for all the local variables,
- /// which may be eliminated later if they are redundant---if they take on
- /// the same value at all invocation sites.
- IrBuilder makeRecursiveBuilder() {
- IrBuilder inner = _makeInstance()
- ..state = state
- ..environment = new Environment.empty();
- environment.index2variable.forEach(inner.createLocalParameter);
- return inner;
- }
-
/// Construct a builder for an inner function.
IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) {
IrBuilderDelimitedState innerState =
@@ -416,7 +561,7 @@
_enterScope(closureScope);
}
- List<ir.Primitive> buildFunctionHeader(Iterable<ParameterElement> parameters,
+ List<ir.Primitive> buildFunctionHeader(Iterable<Local> parameters,
{ClosureScope closureScope,
ClosureEnvironment env}) {
_createThisParameter();
@@ -500,11 +645,9 @@
}
ir.Primitive _buildInvokeCall(ir.Primitive target,
- Selector selector,
- List<ir.Definition> arguments) {
- Selector callSelector = new Selector.callClosure(
- selector.argumentCount,
- selector.namedArguments);
+ Selector selector,
+ List<ir.Definition> arguments) {
+ Selector callSelector = new Selector.callClosureFrom(selector);
return _buildInvokeDynamic(target, callSelector, arguments);
}
@@ -551,7 +694,7 @@
ir.Primitive buildListLiteral(InterfaceType type,
Iterable<ir.Primitive> values) {
assert(isOpen);
- return addPrimitive(new ir.LiteralList(type, values));
+ return addPrimitive(new ir.LiteralList(type, values.toList()));
}
/// Creates a non-constant map literal of the provided [type] and with the
@@ -573,13 +716,12 @@
}
/// Creates a conditional expression with the provided [condition] where the
- /// then and else expression are created through the [buildThenExpression] and
- /// [buildElseExpression] functions, respectively.
+ /// then and else expression are created through the [buildThenExpression]
+ /// and [buildElseExpression] functions, respectively.
ir.Primitive buildConditional(
ir.Primitive condition,
ir.Primitive buildThenExpression(IrBuilder builder),
ir.Primitive buildElseExpression(IrBuilder builder)) {
-
assert(isOpen);
// The then and else expressions are delimited.
@@ -590,16 +732,24 @@
// Treat the values of the subexpressions as named values in the
// environment, so they will be treated as arguments to the join-point
- // continuation.
+ // continuation. We know the environments are the right size because
+ // expressions cannot introduce variable bindings.
assert(environment.length == thenBuilder.environment.length);
assert(environment.length == elseBuilder.environment.length);
+ // Extend the join-point environment with a placeholder for the value of
+ // the expression. Optimistically assume that the value is the value of
+ // the first subexpression. This value might noe even be in scope at the
+ // join-point because it's bound in the first subexpression. However, if
+ // that is the case, it will necessarily differ from the value of the
+ // other subexpression and cause the introduction of a join-point
+ // continuation parameter. If the two values do happen to be the same,
+ // this will avoid inserting a useless continuation parameter.
+ environment.extend(null, thenValue);
thenBuilder.environment.extend(null, thenValue);
elseBuilder.environment.extend(null, elseValue);
- JumpCollector jumps = new JumpCollector(null);
- jumps.addJump(thenBuilder);
- jumps.addJump(elseBuilder);
- ir.Continuation joinContinuation =
- createJoin(environment.length + 1, jumps);
+ JumpCollector join = new ForwardJumpCollector(environment);
+ thenBuilder.jumpTo(join);
+ elseBuilder.jumpTo(join);
// Build the term
// let cont join(x, ..., result) = [] in
@@ -611,15 +761,17 @@
ir.Continuation elseContinuation = new ir.Continuation([]);
thenContinuation.body = thenBuilder._root;
elseContinuation.body = elseBuilder._root;
- add(new ir.LetCont(joinContinuation,
+ add(new ir.LetCont(join.continuation,
new ir.LetCont.many(<ir.Continuation>[thenContinuation,
elseContinuation],
new ir.Branch(new ir.IsTrue(condition),
thenContinuation,
elseContinuation))));
+ environment = join.environment;
+ environment.discard(1);
return (thenValue == elseValue)
? thenValue
- : joinContinuation.parameters.last;
+ : join.continuation.parameters.last;
}
/**
@@ -635,13 +787,13 @@
}
ir.SuperInitializer makeSuperInitializer(ConstructorElement target,
- List<ir.RunnableBody> arguments,
+ List<ir.Body> arguments,
Selector selector) {
return new ir.SuperInitializer(target, arguments, selector);
}
ir.FieldInitializer makeFieldInitializer(FieldElement element,
- ir.RunnableBody body) {
+ ir.Body body) {
return new ir.FieldInitializer(element, body);
}
@@ -651,18 +803,18 @@
if (initializer == null) {
return new ir.FieldDefinition.withoutInitializer(state.currentElement);
} else {
- ir.RunnableBody body = makeRunnableBody(initializer);
+ ir.Body body = makeBody(initializer);
return new ir.FieldDefinition(state.currentElement, body);
}
}
- ir.RunnableBody makeRunnableBody([ir.Primitive value]) {
+ ir.Body makeBody([ir.Primitive value]) {
if (value == null) {
_ensureReturn();
} else {
buildReturn(value);
}
- return new ir.RunnableBody(_root, state.returnContinuation);
+ return new ir.Body(_root, state.returnContinuation);
}
/// Create a [ir.FunctionDefinition] for [element] using [_root] as the body.
@@ -679,9 +831,9 @@
message: "Local constants for abstract method $element: "
"${state.localConstants}"));
return new ir.FunctionDefinition.abstract(
- element, state.thisParameter, state.functionParameters, defaults);
+ element, state.functionParameters, defaults);
} else {
- ir.RunnableBody body = makeRunnableBody();
+ ir.Body body = makeBody();
return new ir.FunctionDefinition(
element, state.thisParameter, state.functionParameters, body,
state.localConstants, defaults);
@@ -705,7 +857,7 @@
ir.ConstructorDefinition makeConstructorDefinition(
List<ConstantExpression> defaults, List<ir.Initializer> initializers) {
FunctionElement element = state.currentElement;
- ir.RunnableBody body = makeRunnableBody();
+ ir.Body body = makeBody();
return new ir.ConstructorDefinition(
element, state.thisParameter, state.functionParameters, body, initializers,
state.localConstants, defaults);
@@ -829,11 +981,7 @@
ir.Primitive buildConstructorInvocation(FunctionElement element,
Selector selector,
DartType type,
- List<ir.Primitive> arguments) {
- assert(isOpen);
- return _continueWithExpression(
- (k) => new ir.InvokeConstructor(type, element, selector, k, arguments));
- }
+ List<ir.Primitive> arguments);
/// Create a string concatenation of the [arguments].
ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments) {
@@ -890,16 +1038,15 @@
thenContinuation,
elseContinuation));
- ir.Continuation joinContinuation; // Null if there is no join.
+ JumpCollector join; // Null if there is no join.
if (thenBuilder.isOpen && elseBuilder.isOpen) {
// There is a join-point continuation. Build the term
// 'let cont join(x, ...) = [] in Result' and plug invocations of the
// join-point continuation into the then and else continuations.
- JumpCollector jumps = new JumpCollector(null);
- jumps.addJump(thenBuilder);
- jumps.addJump(elseBuilder);
- joinContinuation = createJoin(environment.length, jumps);
- result = new ir.LetCont(joinContinuation, result);
+ join = new ForwardJumpCollector(environment);
+ thenBuilder.jumpTo(join);
+ elseBuilder.jumpTo(join);
+ result = new ir.LetCont(join.continuation, result);
}
// The then or else term root could be null, but not both. If there is
@@ -913,7 +1060,7 @@
elseContinuation.body = elseBuilder._root;
add(result);
- if (joinContinuation == null) {
+ if (join == null) {
// At least one subexpression is closed.
if (thenBuilder.isOpen) {
if (thenBuilder._root != null) _current = thenBuilder._current;
@@ -924,43 +1071,21 @@
} else {
_current = null;
}
+ } else {
+ environment = join.environment;
}
}
- void jumpTo(ir.Continuation continuation) {
- assert(isOpen);
- assert(environment.length >= continuation.parameters.length);
- ir.InvokeContinuation jump = new ir.InvokeContinuation.uninitialized();
- jump.continuation = new ir.Reference(continuation);
- jump.arguments = new List<ir.Reference>.generate(
- continuation.parameters.length, (i) {
- return new ir.Reference(environment[i]);
- });
- add(jump);
- _current = null;
+ void jumpTo(JumpCollector collector) {
+ collector.addJump(this);
}
- /// Invoke a join-point continuation that contains arguments for all local
- /// variables.
- ///
- /// Given the continuation and a list of uninitialized invocations, fill
- /// in each invocation with the continuation and appropriate arguments.
- void invokeFullJoin(ir.Continuation join,
- JumpCollector jumps,
- {recursive: false}) {
- // TODO(kmillikin): If the JumpCollector collected open IrBuilders instead
- // of pairs of invocations and environments, we could use IrBuilder.jumpTo
- // here --- the code is almost the same.
- join.isRecursive = recursive;
- for (int i = 0; i < jumps.length; ++i) {
- Environment currentEnvironment = jumps.environments[i];
- ir.InvokeContinuation invoke = jumps.invocations[i];
- invoke.continuation = new ir.Reference(join);
- invoke.arguments = new List<ir.Reference>.generate(
- join.parameters.length,
- (i) => new ir.Reference(currentEnvironment[i]));
- invoke.isRecursive = recursive;
- }
+ void addRecursiveContinuation(BackwardJumpCollector collector) {
+ assert(environment.length == collector.environment.length);
+ add(new ir.LetCont(collector.continuation,
+ new ir.InvokeContinuation(collector.continuation,
+ environment.index2value)));
+ environment = collector.environment;
}
/// Creates a for loop in which the initializer, condition, body, update are
@@ -994,7 +1119,7 @@
// [[initializer]];
// let cont loop(x, ...) =
// let prim cond = [[condition]] in
- // let cont break() = [[successor]] in
+ // let cont break(x, ...) = [[successor]] in
// let cont exit() = break(v, ...) in
// let cont body() =
// _enterForLoopBody();
@@ -1012,28 +1137,33 @@
// statement occurs in the exit continuation). If there is only one
// invocation of the continue continuation (i.e., no continues in the
// body), the continue continuation is inlined in the body.
-
_enterForLoopInitializer(closureScope, loopVariables);
-
buildInitializer(this);
- IrBuilder condBuilder = makeRecursiveBuilder();
- ir.Primitive condition = buildCondition(condBuilder);
+ JumpCollector loop = new BackwardJumpCollector(environment);
+ addRecursiveContinuation(loop);
+
+ ir.Primitive condition = buildCondition(this);
if (condition == null) {
// If the condition is empty then the body is entered unconditionally.
- condition = condBuilder.buildBooleanLiteral(true);
+ condition = buildBooleanLiteral(true);
}
+ JumpCollector breakCollector =
+ new ForwardJumpCollector(environment, target: target);
- JumpCollector breakCollector = new JumpCollector(target);
- JumpCollector continueCollector = new JumpCollector(target);
- state.breakCollectors.add(breakCollector);
- state.continueCollectors.add(continueCollector);
-
- IrBuilder outerBodyBuilder = condBuilder.makeDelimitedBuilder();
+ // Use a pair of builders for the body, one for the entry code if any
+ // and one for the body itself. We only decide whether to insert a
+ // continue continuation until after translating the body and there is no
+ // way to insert such a continuation between the entry code and the body
+ // if they are translated together.
+ IrBuilder outerBodyBuilder = makeDelimitedBuilder();
outerBodyBuilder._enterForLoopBody(closureScope, loopVariables);
+ JumpCollector continueCollector =
+ new ForwardJumpCollector(outerBodyBuilder.environment, target: target);
IrBuilder innerBodyBuilder = outerBodyBuilder.makeDelimitedBuilder();
-
+ state.breakCollectors.add(breakCollector);
+ state.continueCollectors.add(continueCollector);
buildBody(innerBodyBuilder);
assert(state.breakCollectors.last == breakCollector);
assert(state.continueCollectors.last == continueCollector);
@@ -1043,17 +1173,34 @@
// The binding of the continue continuation should occur as late as
// possible, that is, at the nearest common ancestor of all the continue
// sites in the body. However, that is difficult to compute here, so it
- // is instead placed just outside the body of the body continuation.
+ // is instead placed just outside the translation of the loop body. In
+ // the case where there are no continues in the body, the updates are
+ // translated immediately after the body.
bool hasContinues = !continueCollector.isEmpty;
- IrBuilder updateBuilder = hasContinues
- ? outerBodyBuilder.makeRecursiveBuilder()
- : innerBodyBuilder;
+ IrBuilder updateBuilder;
+ if (hasContinues) {
+ if (innerBodyBuilder.isOpen) innerBodyBuilder.jumpTo(continueCollector);
+ updateBuilder = makeDelimitedBuilder(continueCollector.environment);
+ } else {
+ updateBuilder = innerBodyBuilder;
+ }
updateBuilder._enterForLoopUpdate(closureScope, loopVariables);
buildUpdate(updateBuilder);
+ if (updateBuilder.isOpen) updateBuilder.jumpTo(loop);
+ // Connect the inner and outer body builders. This is done only after
+ // it is guaranteed that the updateBuilder has a non-empty term.
+ if (hasContinues) {
+ outerBodyBuilder.add(new ir.LetCont(continueCollector.continuation,
+ innerBodyBuilder._root));
+ continueCollector.continuation.body = updateBuilder._root;
+ } else {
+ outerBodyBuilder.add(innerBodyBuilder._root);
+ }
- // Create body entry and loop exit continuations and a branch to them.
- ir.Continuation bodyContinuation = new ir.Continuation([]);
+ // Create loop exit and body entry continuations and a branch to them.
ir.Continuation exitContinuation = new ir.Continuation([]);
+ ir.Continuation bodyContinuation = new ir.Continuation([]);
+ bodyContinuation.body = outerBodyBuilder._root;
// Note the order of continuations: the first one is the one that will
// be filled by LetCont.plug.
ir.LetCont branch =
@@ -1063,57 +1210,19 @@
bodyContinuation,
exitContinuation));
// If there are breaks in the body, then there must be a join-point
- // continuation for the normal exit and the breaks.
+ // continuation for the normal exit and the breaks. Otherwise, the
+ // successor is translated in the hole in the exit continuation.
bool hasBreaks = !breakCollector.isEmpty;
- ir.LetCont letJoin;
+ ir.LetCont letBreak;
if (hasBreaks) {
- letJoin = new ir.LetCont(null, branch);
- condBuilder.add(letJoin);
- condBuilder._current = branch;
+ IrBuilder exitBuilder = makeDelimitedBuilder();
+ exitBuilder.jumpTo(breakCollector);
+ exitContinuation.body = exitBuilder._root;
+ letBreak = new ir.LetCont(breakCollector.continuation, branch);
+ add(letBreak);
+ environment = breakCollector.environment;
} else {
- condBuilder.add(branch);
- }
- ir.Continuation continueContinuation;
- if (hasContinues) {
- // If there are continues in the body, we need a named continue
- // continuation as a join point.
- continueContinuation = new ir.Continuation(updateBuilder._parameters);
- if (innerBodyBuilder.isOpen) continueCollector.addJump(innerBodyBuilder);
- invokeFullJoin(continueContinuation, continueCollector);
- }
- ir.Continuation loopContinuation =
- new ir.Continuation(condBuilder._parameters);
- if (updateBuilder.isOpen) {
- JumpCollector backEdges = new JumpCollector(null);
- backEdges.addJump(updateBuilder);
- invokeFullJoin(loopContinuation, backEdges, recursive: true);
- }
-
- // Fill in the body and possible continue continuation bodies. Do this
- // only after it is guaranteed that they are not empty.
- if (hasContinues) {
- continueContinuation.body = updateBuilder._root;
- outerBodyBuilder.add(new ir.LetCont(continueContinuation,
- innerBodyBuilder._root));
- } else {
- outerBodyBuilder.add(innerBodyBuilder._root);
- }
- bodyContinuation.body = outerBodyBuilder._root;
-
- loopContinuation.body = condBuilder._root;
- add(new ir.LetCont(loopContinuation,
- new ir.InvokeContinuation(loopContinuation,
- environment.index2value)));
- if (hasBreaks) {
- _current = branch;
- environment = condBuilder.environment;
- breakCollector.addJump(this);
- letJoin.continuations =
- <ir.Continuation>[createJoin(environment.length, breakCollector)];
- _current = letJoin;
- } else {
- _current = condBuilder._current;
- environment = condBuilder.environment;
+ add(branch);
}
}
@@ -1152,37 +1261,50 @@
// s;
// }
- // The condition and body are delimited.
- IrBuilder condBuilder = makeRecursiveBuilder();
-
+ // Fill the current hole with:
+ // let prim expressionReceiver = [[e]] in
+ // let cont iteratorInvoked(iterator) =
+ // [ ]
+ // in expressionReceiver.iterator () iteratorInvoked
ir.Primitive expressionReceiver = buildExpression(this);
- List<ir.Primitive> emptyArguments = new List<ir.Primitive>();
-
+ List<ir.Primitive> emptyArguments = <ir.Primitive>[];
ir.Parameter iterator = new ir.Parameter(null);
ir.Continuation iteratorInvoked = new ir.Continuation([iterator]);
add(new ir.LetCont(iteratorInvoked,
new ir.InvokeMethod(expressionReceiver,
- new Selector.getter("iterator", null), iteratorInvoked,
+ new Selector.getter("iterator", null),
+ iteratorInvoked,
emptyArguments)));
+ // Fill with:
+ // let cont loop(x, ...) =
+ // let cont moveNextInvoked(condition) =
+ // [ ]
+ // in iterator.moveNext () moveNextInvoked
+ // in loop(v, ...)
+ JumpCollector loop = new BackwardJumpCollector(environment, target: target);
+ addRecursiveContinuation(loop);
ir.Parameter condition = new ir.Parameter(null);
ir.Continuation moveNextInvoked = new ir.Continuation([condition]);
- condBuilder.add(new ir.LetCont(moveNextInvoked,
+ add(new ir.LetCont(moveNextInvoked,
new ir.InvokeMethod(iterator,
new Selector.call("moveNext", null, 0),
- moveNextInvoked, emptyArguments)));
+ moveNextInvoked,
+ emptyArguments)));
- JumpCollector breakCollector = new JumpCollector(target);
- JumpCollector continueCollector = new JumpCollector(target);
- state.breakCollectors.add(breakCollector);
- state.continueCollectors.add(continueCollector);
-
- IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
+ // As a delimited term, build:
+ // <<BODY>> =
+ // _enterScope();
+ // [[variableDeclaration]]
+ // let cont currentInvoked(currentValue) =
+ // [[a = currentValue]];
+ // [ ]
+ // in iterator.current () currentInvoked
+ IrBuilder bodyBuilder = makeDelimitedBuilder();
bodyBuilder._enterScope(closureScope);
if (buildVariableDeclaration != null) {
buildVariableDeclaration(bodyBuilder);
}
-
ir.Parameter currentValue = new ir.Parameter(null);
ir.Continuation currentInvoked = new ir.Continuation([currentValue]);
bodyBuilder.add(new ir.LetCont(currentInvoked,
@@ -1201,15 +1323,27 @@
bodyBuilder.buildDynamicSet(receiver, variableSelector, currentValue);
}
+ // Translate the body in the hole in the delimited term above, and add
+ // a jump to the loop if control flow is live after the body.
+ JumpCollector breakCollector =
+ new ForwardJumpCollector(environment, target: target);
+ state.breakCollectors.add(breakCollector);
+ state.continueCollectors.add(loop);
buildBody(bodyBuilder);
assert(state.breakCollectors.last == breakCollector);
- assert(state.continueCollectors.last == continueCollector);
+ assert(state.continueCollectors.last == loop);
state.breakCollectors.removeLast();
state.continueCollectors.removeLast();
+ if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop);
// Create body entry and loop exit continuations and a branch to them.
- ir.Continuation bodyContinuation = new ir.Continuation([]);
+ //
+ // let cont exit() = [ ]
+ // and body() = <<BODY>>
+ // in branch condition (body, exit)
ir.Continuation exitContinuation = new ir.Continuation([]);
+ ir.Continuation bodyContinuation = new ir.Continuation([]);
+ bodyContinuation.body = bodyBuilder._root;
// Note the order of continuations: the first one is the one that will
// be filled by LetCont.plug.
ir.LetCont branch =
@@ -1219,37 +1353,19 @@
bodyContinuation,
exitContinuation));
// If there are breaks in the body, then there must be a join-point
- // continuation for the normal exit and the breaks.
+ // continuation for the normal exit and the breaks. Otherwise, the
+ // successor is translated in the hole in the exit continuation.
bool hasBreaks = !breakCollector.isEmpty;
- ir.LetCont letJoin;
+ ir.LetCont letBreak;
if (hasBreaks) {
- letJoin = new ir.LetCont(null, branch);
- condBuilder.add(letJoin);
- condBuilder._current = branch;
+ IrBuilder exitBuilder = makeDelimitedBuilder();
+ exitBuilder.jumpTo(breakCollector);
+ exitContinuation.body = exitBuilder._root;
+ letBreak = new ir.LetCont(breakCollector.continuation, branch);
+ add(letBreak);
+ environment = breakCollector.environment;
} else {
- condBuilder.add(branch);
- }
- ir.Continuation loopContinuation =
- new ir.Continuation(condBuilder._parameters);
- if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder);
- invokeFullJoin(
- loopContinuation, continueCollector, recursive: true);
- bodyContinuation.body = bodyBuilder._root;
-
- loopContinuation.body = condBuilder._root;
- add(new ir.LetCont(loopContinuation,
- new ir.InvokeContinuation(loopContinuation,
- environment.index2value)));
- if (hasBreaks) {
- _current = branch;
- environment = condBuilder.environment;
- breakCollector.addJump(this);
- letJoin.continuations =
- <ir.Continuation>[createJoin(environment.length, breakCollector)];
- _current = letJoin;
- } else {
- _current = condBuilder._current;
- environment = condBuilder.environment;
+ add(branch);
}
}
@@ -1271,34 +1387,39 @@
// let prim cond = [[condition]] in
// let cont break(x, ...) = [[successor]] in
// let cont exit() = break(v, ...)
- // and body() = [[body]]; continue(v, ...)
+ // and body() =
+ // _enterScope();
+ // [[body]];
+ // continue(v, ...)
// in branch cond (body, exit)
// in continue(v, ...)
//
// If there are no breaks in the body, the break continuation is inlined
// in the exit continuation (i.e., the translation of the successor
// statement occurs in the exit continuation).
+ JumpCollector loop = new BackwardJumpCollector(environment, target: target);
+ addRecursiveContinuation(loop);
- // The condition and body are delimited.
- IrBuilder condBuilder = makeRecursiveBuilder();
- ir.Primitive condition = buildCondition(condBuilder);
+ ir.Primitive condition = buildCondition(this);
- JumpCollector breakCollector = new JumpCollector(target);
- JumpCollector continueCollector = new JumpCollector(target);
- state.breakCollectors.add(breakCollector);
- state.continueCollectors.add(continueCollector);
+ JumpCollector breakCollector =
+ new ForwardJumpCollector(environment, target: target);
- IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
+ IrBuilder bodyBuilder = makeDelimitedBuilder();
bodyBuilder._enterScope(closureScope);
+ state.breakCollectors.add(breakCollector);
+ state.continueCollectors.add(loop);
buildBody(bodyBuilder);
assert(state.breakCollectors.last == breakCollector);
- assert(state.continueCollectors.last == continueCollector);
+ assert(state.continueCollectors.last == loop);
state.breakCollectors.removeLast();
state.continueCollectors.removeLast();
+ if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop);
// Create body entry and loop exit continuations and a branch to them.
- ir.Continuation bodyContinuation = new ir.Continuation([]);
ir.Continuation exitContinuation = new ir.Continuation([]);
+ ir.Continuation bodyContinuation = new ir.Continuation([]);
+ bodyContinuation.body = bodyBuilder._root;
// Note the order of continuations: the first one is the one that will
// be filled by LetCont.plug.
ir.LetCont branch =
@@ -1308,36 +1429,19 @@
bodyContinuation,
exitContinuation));
// If there are breaks in the body, then there must be a join-point
- // continuation for the normal exit and the breaks.
+ // continuation for the normal exit and the breaks. Otherwise, the
+ // successor is translated in the hole in the exit continuation.
bool hasBreaks = !breakCollector.isEmpty;
- ir.LetCont letJoin;
+ ir.LetCont letBreak;
if (hasBreaks) {
- letJoin = new ir.LetCont(null, branch);
- condBuilder.add(letJoin);
- condBuilder._current = branch;
+ IrBuilder exitBuilder = makeDelimitedBuilder();
+ exitBuilder.jumpTo(breakCollector);
+ exitContinuation.body = exitBuilder._root;
+ letBreak = new ir.LetCont(breakCollector.continuation, branch);
+ add(letBreak);
+ environment = breakCollector.environment;
} else {
- condBuilder.add(branch);
- }
- ir.Continuation loopContinuation =
- new ir.Continuation(condBuilder._parameters);
- if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder);
- invokeFullJoin(loopContinuation, continueCollector, recursive: true);
- bodyContinuation.body = bodyBuilder._root;
-
- loopContinuation.body = condBuilder._root;
- add(new ir.LetCont(loopContinuation,
- new ir.InvokeContinuation(loopContinuation,
- environment.index2value)));
- if (hasBreaks) {
- _current = branch;
- environment = condBuilder.environment;
- breakCollector.addJump(this);
- letJoin.continuations =
- <ir.Continuation>[createJoin(environment.length, breakCollector)];
- _current = letJoin;
- } else {
- _current = condBuilder._current;
- environment = condBuilder.environment;
+ add(branch);
}
}
@@ -1365,99 +1469,66 @@
// in branch cond (repeat, exit)
// in [[body]]; continue(v, ...)
// in loop(v, ...)
- IrBuilder bodyBuilder = makeRecursiveBuilder();
- IrBuilder continueBuilder = bodyBuilder.makeRecursiveBuilder();
+ IrBuilder loopBuilder = makeDelimitedBuilder();
+ JumpCollector loop =
+ new BackwardJumpCollector(loopBuilder.environment, target: target);
+ loopBuilder.addRecursiveContinuation(loop);
- // Construct the continue continuation (i.e., the condition).
+ // Translate the body.
+ JumpCollector breakCollector =
+ new ForwardJumpCollector(environment, target: target);
+ JumpCollector continueCollector =
+ new ForwardJumpCollector(loopBuilder.environment, target: target);
+ IrBuilder bodyBuilder = loopBuilder.makeDelimitedBuilder();
+ bodyBuilder._enterScope(closureScope);
+ state.breakCollectors.add(breakCollector);
+ state.continueCollectors.add(continueCollector);
+ buildBody(bodyBuilder);
+ assert(state.breakCollectors.last == breakCollector);
+ assert(state.continueCollectors.last == continueCollector);
+ state.breakCollectors.removeLast();
+ state.continueCollectors.removeLast();
+ if (bodyBuilder.isOpen) bodyBuilder.jumpTo(continueCollector);
+
+ // Construct the body of the continue continuation (i.e., the condition).
// <Continue> =
// let prim cond = [[condition]] in
// let cont exit() = break(v, ...)
// and repeat() = loop(v, ...)
// in branch cond (repeat, exit)
+ IrBuilder continueBuilder = loopBuilder.makeDelimitedBuilder();
+ continueBuilder.environment = continueCollector.environment;
ir.Primitive condition = buildCondition(continueBuilder);
- // Use a delimited IrBuilder for the exit continuation's body so that
- // we can capture the break with the body's break collector.
+
ir.Continuation exitContinuation = new ir.Continuation([]);
IrBuilder exitBuilder = continueBuilder.makeDelimitedBuilder();
+ exitBuilder.jumpTo(breakCollector);
+ exitContinuation.body = exitBuilder._root;
ir.Continuation repeatContinuation = new ir.Continuation([]);
- ir.InvokeContinuation invokeLoop =
- new ir.InvokeContinuation.uninitialized(recursive: true);
- invokeLoop.arguments =
- continueBuilder.environment.index2value.map(
- (ir.Primitive value) => new ir.Reference(value)).toList();
- repeatContinuation.body = invokeLoop;
+ IrBuilder repeatBuilder = continueBuilder.makeDelimitedBuilder();
+ repeatBuilder.jumpTo(loop);
+ repeatContinuation.body = repeatBuilder._root;
+
continueBuilder.add(
new ir.LetCont.many(<ir.Continuation>[exitContinuation,
repeatContinuation],
new ir.Branch(new ir.IsTrue(condition),
repeatContinuation,
exitContinuation)));
- ir.Continuation continueContinuation =
- new ir.Continuation(continueBuilder._parameters);
- continueContinuation.body = continueBuilder._root;
+ continueCollector.continuation.body = continueBuilder._root;
// Construct the loop continuation (i.e., the body and condition).
// <Loop> =
// let cont continue(x, ...) =
// <Continue>
// in [[body]]; continue(v, ...)
- JumpCollector breakCollector = new JumpCollector(target);
- JumpCollector continueCollector = new JumpCollector(target);
- state.breakCollectors.add(breakCollector);
- state.continueCollectors.add(continueCollector);
- bodyBuilder._enterScope(closureScope);
- buildBody(bodyBuilder);
- assert(state.breakCollectors.last == breakCollector);
- assert(state.continueCollectors.last == continueCollector);
- state.breakCollectors.removeLast();
- state.continueCollectors.removeLast();
- // Add the jump from the loop's exit to the break condition. It is only
- // here where the exitBuilder's root is non-null and we can set the
- // exitContinuation's body.
- breakCollector.addJump(exitBuilder);
- exitContinuation.body = exitBuilder._root;
- if (bodyBuilder.isOpen) {
- continueCollector.addJump(bodyBuilder);
- }
- invokeFullJoin(continueContinuation, continueCollector, recursive: false);
- ir.Continuation loopContinuation =
- new ir.Continuation(bodyBuilder._parameters);
- loopContinuation.isRecursive = true;
- loopContinuation.body =
- new ir.LetCont(continueContinuation, bodyBuilder._root);
- invokeLoop.continuation =
- new ir.Reference<ir.Continuation>(loopContinuation);
- ir.LetCont letLoop =
- new ir.LetCont(loopContinuation,
- new ir.InvokeContinuation(loopContinuation,
- environment.index2value));
+ loopBuilder.add(
+ new ir.LetCont(continueCollector.continuation,
+ bodyBuilder._root));
- // Add the break condition.
- ir.Continuation breakContinuation;
- if (breakCollector.length == 1) {
- // createJoin only works when there is more than one jump to a join-point
- // continuation. This is to potentially catch errors in the case that
- // a join was intended and at least one jump is missing. Unfortunately
- // we have the explicit code below for the (common?) case that the
- // only break from the do-while is the implicit one when the condition
- // is false.
- List<ir.Parameter> parameters = <ir.Parameter>[];
- List<ir.Reference> arguments = <ir.Reference>[];
- for (int i = 0; i < environment.length; ++i) {
- ir.Parameter parameter =
- new ir.Parameter(environment.index2variable[i]);
- parameters.add(parameter);
- environment.index2value[i] = parameter;
- arguments.add(new ir.Reference(breakCollector.environments.first[i]));
- }
- breakContinuation = new ir.Continuation(parameters);
- breakCollector.invocations.first.arguments = arguments;
- breakCollector.invocations.first.continuation =
- new ir.Reference(breakContinuation);
- } else {
- breakContinuation = createJoin(environment.length, breakCollector);
- }
- add(new ir.LetCont(breakContinuation, letLoop));
+ // And tie it all together.
+ add(new ir.LetCont(breakCollector.continuation, loopBuilder._root));
+ environment = breakCollector.environment;
}
/// Creates a try-statement.
@@ -1502,35 +1573,26 @@
// scope of the handler. The mutable bindings are dereferenced at the end
// of the try block and at the beginning of the catch block, so the
// variables are unboxed in the catch block and at the join point.
-
+ JumpCollector join = new ForwardJumpCollector(environment);
IrBuilder tryCatchBuilder = makeDelimitedBuilder();
+
// Variables that are boxed due to being captured in a closure are boxed
// for their entire lifetime, and so they do not need to be boxed on
- // entry to any try block. We check for them here because we can not
- // identify all of them in the same pass where we identify the variables
- // assigned in the try (the may be captured by a closure after the try
- // statement).
- Iterable<LocalVariableElement> boxedOnEntry =
- tryStatementInfo.boxedOnEntry.where((LocalVariableElement variable) {
- return !tryCatchBuilder.mutableCapturedVariables.contains(variable);
- });
- for (LocalVariableElement variable in boxedOnEntry) {
+ // entry to any try block. They are not filtered out before this because
+ // we can not identify all of them in the same pass where we identify the
+ // variables assigned in the try (they may be captured by a closure after
+ // the try statement).
+ for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) {
assert(!tryCatchBuilder.isInMutableVariable(variable));
ir.Primitive value = tryCatchBuilder.buildLocalGet(variable);
tryCatchBuilder.makeMutableVariable(variable);
tryCatchBuilder.declareLocalVariable(variable, initialValue: value);
}
- IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder();
- List<ir.Parameter> joinParameters =
- new List<ir.Parameter>.generate(environment.length, (i) {
- return new ir.Parameter(environment.index2variable[i]);
- });
- ir.Continuation joinContinuation = new ir.Continuation(joinParameters);
void interceptJumps(JumpCollector collector) {
- collector.enterTry(boxedOnEntry);
+ collector.enterTry(tryStatementInfo.boxedOnEntry);
}
void restoreJumps(JumpCollector collector) {
collector.leaveTry();
@@ -1538,18 +1600,16 @@
tryBuilder.state.breakCollectors.forEach(interceptJumps);
tryBuilder.state.continueCollectors.forEach(interceptJumps);
buildTryBlock(tryBuilder);
+ if (tryBuilder.isOpen) {
+ interceptJumps(join);
+ tryBuilder.jumpTo(join);
+ restoreJumps(join);
+ }
tryBuilder.state.breakCollectors.forEach(restoreJumps);
tryBuilder.state.continueCollectors.forEach(restoreJumps);
- if (tryBuilder.isOpen) {
- for (LocalVariableElement variable in boxedOnEntry) {
- assert(tryBuilder.isInMutableVariable(variable));
- ir.Primitive value = tryBuilder.buildLocalGet(variable);
- tryBuilder.environment.update(variable, value);
- }
- tryBuilder.jumpTo(joinContinuation);
- }
- for (LocalVariableElement variable in boxedOnEntry) {
+ IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
+ for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) {
assert(catchBuilder.isInMutableVariable(variable));
ir.Primitive value = catchBuilder.buildLocalGet(variable);
// Note that we remove the variable from the set of mutable variables
@@ -1580,9 +1640,7 @@
traceParameter = new ir.Parameter(null);
}
catchClauseInfo.buildCatchBlock(catchBuilder);
- if (catchBuilder.isOpen) {
- catchBuilder.jumpTo(joinContinuation);
- }
+ if (catchBuilder.isOpen) catchBuilder.jumpTo(join);
List<ir.Parameter> catchParameters =
<ir.Parameter>[exceptionParameter, traceParameter];
ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
@@ -1593,10 +1651,8 @@
tryCatchBuilder._current = null;
}
- add(new ir.LetCont(joinContinuation, tryCatchBuilder._root));
- for (int i = 0; i < environment.length; ++i) {
- environment.index2value[i] = joinParameters[i];
- }
+ add(new ir.LetCont(join.continuation, tryCatchBuilder._root));
+ environment = join.environment;
}
/// Create a return statement `return value;` or `return;` if [value] is
@@ -1637,48 +1693,28 @@
}
}
-
/// Creates a labeled statement
void buildLabeledStatement({SubbuildFunction buildBody,
JumpTarget target}) {
- JumpCollector jumps = new JumpCollector(target);
- state.breakCollectors.add(jumps);
+ JumpCollector join = new ForwardJumpCollector(environment, target: target);
IrBuilder innerBuilder = makeDelimitedBuilder();
+ innerBuilder.state.breakCollectors.add(join);
buildBody(innerBuilder);
- state.breakCollectors.removeLast();
- bool hasBreaks = !jumps.isEmpty;
- ir.Continuation joinContinuation;
+ innerBuilder.state.breakCollectors.removeLast();
+ bool hasBreaks = !join.isEmpty;
if (hasBreaks) {
- if (innerBuilder.isOpen) {
- jumps.addJump(innerBuilder);
- }
-
- // All jumps to the break continuation must be in the scope of the
- // continuation's binding. The continuation is bound just outside the
- // body to satisfy this property without extra analysis.
- // As a consequence, the break continuation needs parameters for all
- // local variables in scope at the exit from the body.
- List<ir.Parameter> parameters =
- new List<ir.Parameter>.generate(environment.length, (i) {
- return new ir.Parameter(environment.index2variable[i]);
- });
- joinContinuation = new ir.Continuation(parameters);
- invokeFullJoin(joinContinuation, jumps, recursive: false);
- add(new ir.LetCont(joinContinuation, innerBuilder._root));
- for (int i = 0; i < environment.length; ++i) {
- environment.index2value[i] = parameters[i];
- }
+ if (innerBuilder.isOpen) innerBuilder.jumpTo(join);
+ add(new ir.LetCont(join.continuation, innerBuilder._root));
+ environment = join.environment;
+ } else if (innerBuilder._root != null) {
+ add(innerBuilder._root);
+ _current = innerBuilder._current;
+ environment = innerBuilder.environment;
} else {
- if (innerBuilder._root != null) {
- add(innerBuilder._root);
- _current = innerBuilder._current;
- environment = innerBuilder.environment;
- }
+ // The translation of the body did not emit any CPS term.
}
- return null;
}
-
// Build(BreakStatement L, C) = C[InvokeContinuation(...)]
//
// The continuation and arguments are filled in later after translating
@@ -1700,7 +1736,7 @@
assert(isOpen);
for (JumpCollector collector in collectors) {
if (target == collector.target) {
- collector.addJump(this);
+ jumpTo(collector);
return true;
}
}
@@ -1768,7 +1804,6 @@
// e0 || e1 is translated as if e0 ? true : (e1 == true).
// The translation must convert both e0 and e1 to booleans and handle
// local variable assignments in e1.
-
IrBuilder rightBuilder = makeDelimitedBuilder();
ir.Primitive rightValue = buildRightValue(rightBuilder);
// A dummy empty target for the branch on the left subexpression branch.
@@ -1795,18 +1830,19 @@
assert(environment.length == emptyBuilder.environment.length);
assert(environment.length == rightTrueBuilder.environment.length);
assert(environment.length == rightFalseBuilder.environment.length);
+ // Treat the value of the expression as a local variable so it will get
+ // a continuation parameter.
+ environment.extend(null, null);
emptyBuilder.environment.extend(null, leftBool);
rightTrueBuilder.environment.extend(null, rightTrue);
rightFalseBuilder.environment.extend(null, rightFalse);
// Wire up two continuations for the left subexpression, two continuations
// for the right subexpression, and a three-way join continuation.
- JumpCollector jumps = new JumpCollector(null);
- jumps.addJump(emptyBuilder);
- jumps.addJump(rightTrueBuilder);
- jumps.addJump(rightFalseBuilder);
- ir.Continuation joinContinuation =
- createJoin(environment.length + 1, jumps);
+ JumpCollector join = new ForwardJumpCollector(environment);
+ emptyBuilder.jumpTo(join);
+ rightTrueBuilder.jumpTo(join);
+ rightFalseBuilder.jumpTo(join);
ir.Continuation leftTrueContinuation = new ir.Continuation([]);
ir.Continuation leftFalseContinuation = new ir.Continuation([]);
ir.Continuation rightTrueContinuation = new ir.Continuation([]);
@@ -1831,120 +1867,17 @@
leftFalseContinuation.body = emptyBuilder._root;
}
- add(new ir.LetCont(joinContinuation,
+ add(new ir.LetCont(join.continuation,
new ir.LetCont.many(<ir.Continuation>[leftTrueContinuation,
leftFalseContinuation],
new ir.Branch(new ir.IsTrue(leftValue),
leftTrueContinuation,
leftFalseContinuation))));
+ environment = join.environment;
+ environment.discard(1);
// There is always a join parameter for the result value, because it
// is different on at least two paths.
- return joinContinuation.parameters.last;
- }
-
- /// Create a non-recursive join-point continuation.
- ///
- /// Given the environment length at the join point and a list of
- /// jumps that should reach the join point, create a join-point
- /// continuation. The join-point continuation has a parameter for each
- /// variable that has different values reaching on different paths.
- ///
- /// The jumps are uninitialized [ir.InvokeContinuation] expressions.
- /// They are filled in with the target continuation and appropriate
- /// arguments.
- ///
- /// As a side effect, the environment of this builder is updated to include
- /// the join-point continuation parameters.
- ir.Continuation createJoin(int environmentLength, JumpCollector jumps) {
- assert(jumps.length >= 2);
-
- // Compute which values are identical on all paths reaching the join.
- // Handle the common case of a pair of contexts efficiently.
- Environment first = jumps.environments[0];
- Environment second = jumps.environments[1];
- assert(environmentLength <= first.length);
- assert(environmentLength <= second.length);
- assert(first.sameDomain(environmentLength, second));
- // A running count of the join-point parameters.
- int parameterCount = 0;
- // The null elements of common correspond to required parameters of the
- // join-point continuation.
- List<ir.Primitive> common =
- new List<ir.Primitive>.generate(environmentLength,
- (i) {
- ir.Primitive candidate = first[i];
- if (second[i] == candidate) {
- return candidate;
- } else {
- ++parameterCount;
- return null;
- }
- });
- // If there is already a parameter for each variable, the other
- // environments do not need to be considered.
- if (parameterCount < environmentLength) {
- for (int i = 0; i < environmentLength; ++i) {
- ir.Primitive candidate = common[i];
- if (candidate == null) continue;
- for (Environment current in jumps.environments.skip(2)) {
- assert(environmentLength <= current.length);
- assert(first.sameDomain(environmentLength, current));
- if (candidate != current[i]) {
- common[i] = null;
- ++parameterCount;
- break;
- }
- }
- if (parameterCount >= environmentLength) break;
- }
- }
-
- // Create the join point continuation.
- List<ir.Parameter> parameters = <ir.Parameter>[];
- parameters.length = parameterCount;
- int index = 0;
- for (int i = 0; i < environmentLength; ++i) {
- if (common[i] == null) {
- parameters[index++] = new ir.Parameter(first.index2variable[i]);
- }
- }
- assert(index == parameterCount);
- ir.Continuation join = new ir.Continuation(parameters);
-
- // Fill in all the continuation invocations.
- for (int i = 0; i < jumps.length; ++i) {
- Environment currentEnvironment = jumps.environments[i];
- ir.InvokeContinuation invoke = jumps.invocations[i];
- // Sharing this.environment with one of the invocations will not do
- // the right thing (this.environment has already been mutated).
- List<ir.Reference> arguments = <ir.Reference>[];
- arguments.length = parameterCount;
- int index = 0;
- for (int i = 0; i < environmentLength; ++i) {
- if (common[i] == null) {
- arguments[index++] = new ir.Reference(currentEnvironment[i]);
- }
- }
- invoke.continuation = new ir.Reference(join);
- invoke.arguments = arguments;
- }
-
- // Mutate this.environment to be the environment at the join point. Do
- // this after adding the continuation invocations, because this.environment
- // might be collected by the jump collector and so the old environment
- // values are needed for the continuation invocation.
- //
- // Iterate to environment.length because environmentLength includes values
- // outside the environment which are 'phantom' variables used for the
- // values of expressions like &&, ||, and ?:.
- index = 0;
- for (int i = 0; i < environment.length; ++i) {
- if (common[i] == null) {
- environment.index2value[i] = parameters[index++];
- }
- }
-
- return join;
+ return join.continuation.parameters.last;
}
}
@@ -1954,9 +1887,6 @@
final Map<Local, ir.MutableVariable> local2mutable =
<Local, ir.MutableVariable>{};
- // Move this to the IrBuilderVisitor.
- final DartCapturedVariables capturedVariables;
-
/// Creates a [MutableVariable] for the given local.
void makeMutableVariable(Local local) {
ir.MutableVariable variable =
@@ -1967,8 +1897,8 @@
/// [MutableVariable]s that should temporarily be treated as registers.
final Set<Local> registerizedMutableVariables = new Set<Local>();
- DartIrBuilderSharedState(this.capturedVariables) {
- capturedVariables.capturedVariables.forEach(makeMutableVariable);
+ DartIrBuilderSharedState(Set<Local> capturedVariables) {
+ capturedVariables.forEach(makeMutableVariable);
}
}
@@ -1987,19 +1917,11 @@
DartIrBuilder(ConstantSystem constantSystem,
ExecutableElement currentElement,
- DartCapturedVariables capturedVariables)
+ Set<Local> capturedVariables)
: dartState = new DartIrBuilderSharedState(capturedVariables) {
_init(constantSystem, currentElement);
}
- Map<ast.TryStatement, TryStatementInfo> get tryStatements {
- return dartState.capturedVariables.tryStatements;
- }
-
- Set<Local> get mutableCapturedVariables {
- return dartState.capturedVariables.capturedVariables;
- }
-
bool isInMutableVariable(Local local) {
return dartState.local2mutable.containsKey(local) &&
!dartState.registerizedMutableVariables.contains(local);
@@ -2070,7 +1992,7 @@
}
}
- void _createFunctionParameter(ParameterElement parameterElement) {
+ void _createFunctionParameter(Local parameterElement) {
ir.Parameter parameter = new ir.Parameter(parameterElement);
_parameters.add(parameter);
if (isInMutableVariable(parameterElement)) {
@@ -2169,6 +2091,16 @@
return _buildInvokeSuper(target, selector, arguments);
}
+ @override
+ ir.Primitive buildConstructorInvocation(FunctionElement element,
+ Selector selector,
+ DartType type,
+ List<ir.Primitive> arguments) {
+ assert(isOpen);
+ return _continueWithExpression(
+ (k) => new ir.InvokeConstructor(type, element, selector, k,
+ arguments));
+ }
}
/// State shared between JsIrBuilders within the same function.
@@ -2181,6 +2113,10 @@
/// If non-null, this refers to the receiver (`this`) in the enclosing method.
ir.Primitive receiver;
+
+ /// `true` when we are currently building expressions inside the initializer
+ /// list of a constructor.
+ bool inInitializers = false;
}
/// JS-specific subclass of [IrBuilder].
@@ -2189,11 +2125,13 @@
/// variables are boxed as necessary using [CreateBox], [GetField], [SetField].
class JsIrBuilder extends IrBuilder {
final JsIrBuilderSharedState jsState;
+ final GlobalProgramInformation program;
- IrBuilder _makeInstance() => new JsIrBuilder._blank(jsState);
- JsIrBuilder._blank(this.jsState);
+ IrBuilder _makeInstance() => new JsIrBuilder._blank(program, jsState);
+ JsIrBuilder._blank(this.program, this.jsState);
- JsIrBuilder(ConstantSystem constantSystem, ExecutableElement currentElement)
+ JsIrBuilder(this.program, ConstantSystem constantSystem,
+ ExecutableElement currentElement)
: jsState = new JsIrBuilderSharedState() {
_init(constantSystem, currentElement);
}
@@ -2204,6 +2142,16 @@
void makeMutableVariable(Local local) {}
void removeMutableVariable(Local local) {}
+ void enterInitializers() {
+ assert(jsState.inInitializers == false);
+ jsState.inInitializers = true;
+ }
+
+ void leaveInitializers() {
+ assert(jsState.inInitializers == true);
+ jsState.inInitializers = false;
+ }
+
void _enterClosureEnvironment(ClosureEnvironment env) {
if (env == null) return;
@@ -2255,7 +2203,7 @@
});
}
- void _createFunctionParameter(ParameterElement parameterElement) {
+ void _createFunctionParameter(Local parameterElement) {
ir.Parameter parameter = new ir.Parameter(parameterElement);
_parameters.add(parameter);
state.functionParameters.add(parameter);
@@ -2310,7 +2258,8 @@
: environment.lookup(field.local);
arguments.add(value);
}
- return addPrimitive(new ir.CreateInstance(classElement, arguments));
+ return addPrimitive(
+ new ir.CreateInstance(classElement, arguments, const <ir.Primitive>[]));
}
/// Create a read access of [local].
@@ -2430,6 +2379,64 @@
jsState.boxedVariables.addAll(closureScope.capturedVariables);
}
}
+
+ @override
+ ir.Primitive buildConstructorInvocation(ConstructorElement element,
+ Selector selector,
+ DartType type,
+ List<ir.Primitive> arguments) {
+ assert(isOpen);
+
+ ClassElement cls = element.enclosingClass;
+ if (program.requiresRuntimeTypesFor(cls)) {
+ InterfaceType interface = type;
+ Iterable<ir.Primitive> typeArguments =
+ interface.typeArguments.map((DartType argument) {
+ return type.treatAsRaw
+ ? buildNullLiteral()
+ : buildTypeExpression(argument);
+ });
+ arguments = new List<ir.Primitive>.from(arguments)
+ ..addAll(typeArguments);
+ }
+ return _continueWithExpression(
+ (k) => new ir.InvokeConstructor(type, element, selector, k,
+ arguments));
+ }
+
+ ir.Primitive buildTypeExpression(DartType type) {
+ if (type is TypeVariableType) {
+ return buildTypeVariableAccess(buildThis(), type);
+ } else {
+ assert(type is InterfaceType);
+ List<ir.Primitive> arguments = <ir.Primitive>[];
+ type.forEachTypeVariable((TypeVariableType variable) {
+ ir.Primitive value = buildTypeVariableAccess(buildThis(), variable);
+ arguments.add(value);
+ });
+ return addPrimitive(new ir.TypeExpression(type, arguments));
+ }
+ }
+
+ ir.Primitive buildTypeVariableAccess(ir.Primitive target,
+ TypeVariableType variable) {
+ ir.Parameter accessTypeArgumentParameter() {
+ for (int i = 0; i < environment.length; i++) {
+ Local local = environment.index2variable[i];
+ if (local is TypeInformationParameter &&
+ local.variable == variable.element) {
+ return environment.index2value[i];
+ }
+ }
+ throw 'unable to find constructor parameter for type variable $variable.';
+ }
+
+ if (jsState.inInitializers) {
+ return accessTypeArgumentParameter();
+ } else {
+ return addPrimitive(new ir.ReadTypeVariable(variable, target));
+ }
+ }
}
@@ -2501,3 +2508,12 @@
this.stackTraceVariable,
this.buildCatchBlock});
}
+
+/// Synthetic parameter to a JavaScript factory method that takes the type
+/// argument given for the type variable [variable].
+class TypeInformationParameter implements Local {
+ final TypeVariableElement variable;
+ final ExecutableElement executableContext;
+ TypeInformationParameter(this.variable, this.executableContext);
+ String get name => variable.name;
+}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
index f375244..289b230 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
@@ -19,7 +19,7 @@
import '../resolution/operators.dart' as op;
import '../scanner/scannerlib.dart' show Token, isUserDefinableOperator;
import '../tree/tree.dart' as ast;
-import '../universe/universe.dart' show SelectorKind;
+import '../universe/universe.dart' show SelectorKind, CallStructure;
import 'cps_ir_nodes.dart' as ir;
import 'cps_ir_builder.dart';
@@ -41,10 +41,11 @@
* re-implemented to work directly on the IR.
*/
class IrBuilderTask extends CompilerTask {
- final Map<Element, ir.ExecutableDefinition> nodes =
- <Element, ir.ExecutableDefinition>{};
+ final Map<Element, ir.RootNode> nodes = <Element, ir.RootNode>{};
final bool generateSourceMap;
+ String bailoutMessage = null;
+
IrBuilderTask(Compiler compiler, {this.generateSourceMap: true})
: super(compiler);
@@ -52,12 +53,16 @@
bool hasIr(Element element) => nodes.containsKey(element.implementation);
- ir.ExecutableDefinition getIr(ExecutableElement element) {
+ ir.RootNode getIr(ExecutableElement element) {
return nodes[element.implementation];
}
- ir.ExecutableDefinition buildNode(AstElement element) {
- if (!canBuild(element)) return null;
+ ir.RootNode buildNode(AstElement element) {
+ bailoutMessage = null;
+ if (!canBuild(element)) {
+ bailoutMessage = 'unsupported element ${element.name}:${element.kind}';
+ return null;
+ }
TreeElements elementsMapping = element.resolvedAst.elements;
element = element.implementation;
@@ -72,12 +77,13 @@
elementsMapping, compiler, sourceInformationBuilder)
: new DartIrBuilderVisitor(
elementsMapping, compiler, sourceInformationBuilder);
- ir.ExecutableDefinition definition =
- builder.buildExecutable(element);
- if (definition != null) {
- nodes[element] = definition;
+ ir.RootNode irNode = builder.buildExecutable(element);
+ if (irNode == null) {
+ bailoutMessage = builder.bailoutMessage;
+ } else {
+ nodes[element] = irNode;
}
- return definition;
+ return irNode;
});
}
@@ -130,11 +136,20 @@
BaseImplementationOfDynamicsMixin<ir.Primitive, dynamic>,
BaseImplementationOfConstantsMixin<ir.Primitive, dynamic>,
BaseImplementationOfSuperIncDecsMixin<ir.Primitive, dynamic>,
+ BaseImplementationOfNewMixin<ir.Primitive, dynamic>,
ErrorBulkMixin<ir.Primitive, dynamic>
implements SemanticSendVisitor<ir.Primitive, dynamic> {
final Compiler compiler;
final SourceInformationBuilder sourceInformationBuilder;
+ /// A map from try statements in the source to analysis information about
+ /// them.
+ ///
+ /// The analysis information includes the set of variables that must be
+ /// copied into [ir.MutableVariable]s on entry to the try and copied out on
+ /// exit.
+ Map<ast.TryStatement, TryStatementInfo> tryStatements = null;
+
// In SSA terms, join-point continuation parameters are the phis and the
// continuation invocation arguments are the corresponding phi inputs. To
// support name introduction and renaming for source level variables, we use
@@ -160,7 +175,9 @@
: super(elements);
@override
- bulkHandleNode(ast.Node node, String message) => giveup(node, message);
+ bulkHandleNode(ast.Node node, String message, _) => giveup(node, message);
+
+ String bailoutMessage = null;
@override
ir.Primitive apply(ast.Node node, _) => node.accept(this);
@@ -169,11 +186,11 @@
SemanticSendVisitor get sendVisitor => this;
/**
- * Builds the [ir.ExecutableDefinition] for an executable element. In case the
+ * Builds the [ir.RootNode] for an executable element. In case the
* function uses features that cannot be expressed in the IR, this element
* returns `null`.
*/
- ir.ExecutableDefinition buildExecutable(ExecutableElement element);
+ ir.RootNode buildExecutable(ExecutableElement element);
ClosureScope getClosureScopeForNode(ast.Node node);
ClosureEnvironment getClosureEnvironment();
@@ -186,7 +203,7 @@
///
/// For the Dart backend, returns [arguments].
List<ir.Primitive> normalizeStaticArguments(
- Selector selector,
+ CallStructure callStructure,
FunctionElement target,
List<ir.Primitive> arguments);
@@ -200,8 +217,8 @@
Selector selector,
List<ir.Primitive> arguments);
- ir.FunctionDefinition _makeFunctionBody(FunctionElement element,
- ast.FunctionExpression node) {
+ ir.RootNode _makeFunctionBody(FunctionElement element,
+ ast.FunctionExpression node) {
FunctionSignature signature = element.functionSignature;
List<ParameterElement> parameters = [];
signature.orderedForEachParameter(parameters.add);
@@ -246,7 +263,7 @@
ir.Primitive value = irBuilder.buildLocalGet(parameterElement);
result.add(irBuilder.makeFieldInitializer(
initializingFormal.fieldElement,
- irBuilder.makeRunnableBody(value)));
+ irBuilder.makeBody(value)));
});
}
}
@@ -262,7 +279,7 @@
FieldElement field = elements[initializer];
withBuilder(irBuilder.makeInitializerBuilder(), () {
ir.Primitive value = visit(initializer.arguments.head);
- ir.RunnableBody body = irBuilder.makeRunnableBody(value);
+ ir.Body body = irBuilder.makeBody(value);
result.add(irBuilder.makeFieldInitializer(field, body));
});
} else if (initializer is ast.Send) {
@@ -272,11 +289,11 @@
}
ConstructorElement constructor = elements[initializer].implementation;
Selector selector = elements.getSelector(initializer);
- List<ir.RunnableBody> arguments =
+ List<ir.Body> arguments =
initializer.arguments.mapToList((ast.Node argument) {
return withBuilder(irBuilder.makeInitializerBuilder(), () {
ir.Primitive value = visit(argument);
- return irBuilder.makeRunnableBody(value);
+ return irBuilder.makeBody(value);
});
});
result.add(irBuilder.makeSuperInitializer(constructor,
@@ -302,7 +319,7 @@
}
Selector selector = new Selector.callDefaultConstructor();
result.add(irBuilder.makeSuperInitializer(target,
- <ir.RunnableBody>[],
+ <ir.Body>[],
selector));
}
}
@@ -462,7 +479,7 @@
visitTryStatement(ast.TryStatement node) {
// Try/catch is not yet implemented in the JS backend.
- if (this.irBuilder.tryStatements == null) {
+ if (tryStatements == null) {
return giveup(node, 'try/catch in the JS backend');
}
// Multiple catch blocks are not yet implemented.
@@ -494,7 +511,7 @@
}
irBuilder.buildTry(
- tryStatementInfo: irBuilder.tryStatements[node],
+ tryStatementInfo: tryStatements[node],
buildTryBlock: subbuild(node.tryBlock),
catchClauseInfos: catchClauseInfos);
}
@@ -641,8 +658,9 @@
}
@override
- ir.Primitive handleConstantGet(ast.Send node,
- ConstantExpression constant, _) {
+ ir.Primitive handleConstantGet(
+ ast.Node node,
+ ConstantExpression constant, _) {
return irBuilder.buildConstantLiteral(constant);
}
@@ -922,8 +940,10 @@
ir.Primitive visitUnary(ast.Send node,
op.UnaryOperator operator, ast.Node expression, _) {
// TODO(johnniwinther): Clean up the creation of selectors.
- Selector selector =
- new Selector(SelectorKind.OPERATOR, operator.selectorName, null, 0);
+ Selector selector = new Selector(
+ SelectorKind.OPERATOR,
+ new PublicName(operator.selectorName),
+ CallStructure.NO_ARGS);
ir.Primitive receiver = translateReceiver(expression);
return irBuilder.buildDynamicInvocation(receiver, selector, const []);
}
@@ -935,8 +955,10 @@
FunctionElement function,
_) {
// TODO(johnniwinther): Clean up the creation of selectors.
- Selector selector =
- new Selector(SelectorKind.OPERATOR, operator.selectorName, null, 0);
+ Selector selector = new Selector(
+ SelectorKind.OPERATOR,
+ new PublicName(operator.selectorName),
+ CallStructure.NO_ARGS);
return irBuilder.buildSuperInvocation(function, selector, const []);
}
@@ -952,9 +974,9 @@
// semantic correlation between arguments and invocation.
List<ir.Primitive> translateStaticArguments(ast.NodeList nodeList,
Element element,
- Selector selector) {
+ CallStructure callStructure) {
List<ir.Primitive> arguments = nodeList.nodes.mapToList(visit);
- return normalizeStaticArguments(selector, element, arguments);
+ return normalizeStaticArguments(callStructure, element, arguments);
}
ir.Primitive translateCallInvoke(ir.Primitive target,
@@ -1030,7 +1052,7 @@
return giveup(node, 'handleStaticFunctionInvoke: foreign: $function');
}
return irBuilder.buildStaticInvocation(function, selector,
- translateStaticArguments(arguments, function, selector),
+ translateStaticArguments(arguments, function, selector.callStructure),
sourceInformation: sourceInformationBuilder.buildCall(node));
}
@@ -1703,19 +1725,19 @@
});
}
- ir.Primitive visitNewExpression(ast.NewExpression node) {
- if (node.isConst) {
- return translateConstant(node);
- }
- FunctionElement element = elements[node.send];
- Selector selector = elements.getSelector(node.send);
- DartType type = elements.getType(node);
- ast.Node selectorNode = node.send.selector;
+ @override
+ ir.Primitive handleConstructorInvoke(
+ ast.NewExpression node,
+ ConstructorElement constructor,
+ DartType type,
+ ast.NodeList arguments,
+ Selector selector, _) {
List<ir.Primitive> arguments =
node.send.arguments.mapToList(visit, growable:false);
- arguments = normalizeStaticArguments(selector, element, arguments);
+ arguments = normalizeStaticArguments(
+ selector.callStructure, constructor, arguments);
return irBuilder.buildConstructorInvocation(
- element, selector, type, arguments);
+ constructor, selector, type, arguments);
}
ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) {
@@ -1743,7 +1765,7 @@
return irBuilder.buildConstantLiteral(getConstantForNode(node));
}
- ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) {
+ ir.RootNode nullIfGiveup(ir.RootNode action()) {
try {
return action();
} catch(e, tr) {
@@ -1755,21 +1777,22 @@
}
void internalError(ast.Node node, String message) {
- giveup(node);
+ giveup(node, message);
}
@override
visitNode(ast.Node node) {
internalError(node, "Unhandled node");
}
+
+ dynamic giveup(ast.Node node, [String reason]) {
+ bailoutMessage = '($node): $reason';
+ throw ABORT_IRNODE_BUILDER;
+ }
}
final String ABORT_IRNODE_BUILDER = "IrNode builder aborted";
-dynamic giveup(ast.Node node, [String reason]) {
- throw ABORT_IRNODE_BUILDER;
-}
-
/// Classifies local variables and local functions as captured, if they
/// are accessed from within a nested function.
///
@@ -1791,10 +1814,29 @@
List<TryStatementInfo> tryNestingStack = <TryStatementInfo>[];
bool get inTryStatement => tryNestingStack.isNotEmpty;
+ String bailoutMessage = null;
+
+ giveup(ast.Node node, [String reason]) {
+ bailoutMessage = '($node): $reason';
+ throw ABORT_IRNODE_BUILDER;
+ }
+
void markAsCaptured(Local local) {
capturedVariables.add(local);
}
+ analyze(ast.Node node) {
+ visit(node);
+ // Variables that are captured by a closure are boxed for their entire
+ // lifetime, so they never need to be boxed on entry to a try block.
+ // They are not filtered out before this because we cannot identify all
+ // of them in the same pass (they may be captured by a closure after the
+ // try statement).
+ for (TryStatementInfo info in tryStatements.values) {
+ info.boxedOnEntry.removeAll(capturedVariables);
+ }
+ }
+
visit(ast.Node node) => node.accept(this);
visitNode(ast.Node node) {
@@ -1920,14 +1962,25 @@
SourceInformationBuilder sourceInformationBuilder)
: super(elements, compiler, sourceInformationBuilder);
- DartIrBuilder makeIRBuilder(ast.Node node, ExecutableElement element) {
- DartCapturedVariables closures = new DartCapturedVariables(elements);
- if (!element.isSynthesized) {
- closures.visit(node);
- }
+ DartIrBuilder makeIRBuilder(ExecutableElement element,
+ Set<Local> capturedVariables) {
return new DartIrBuilder(compiler.backend.constantSystem,
element,
- closures);
+ capturedVariables);
+ }
+
+ DartCapturedVariables _analyzeCapturedVariables(ExecutableElement element,
+ ast.Node node) {
+ DartCapturedVariables variables = new DartCapturedVariables(elements);
+ if (!element.isSynthesized) {
+ try {
+ variables.analyze(node);
+ } catch (e) {
+ bailoutMessage = variables.bailoutMessage;
+ rethrow;
+ }
+ }
+ return variables;
}
/// Recursively builds the IR for the given nested function.
@@ -1953,11 +2006,11 @@
ClosureScope getClosureScopeForNode(ast.Node node) => null;
ClosureEnvironment getClosureEnvironment() => null;
- ir.ExecutableDefinition buildExecutable(ExecutableElement element) {
+ ir.RootNode buildExecutable(ExecutableElement element) {
return nullIfGiveup(() {
if (element is FieldElement) {
return buildField(element);
- } else if (element is FunctionElement) {
+ } else if (element is FunctionElement || element is ConstructorElement) {
return buildFunction(element);
} else {
compiler.internalError(element, "Unexpected element type $element");
@@ -1976,7 +2029,10 @@
assert(fieldDefinition != null);
assert(elements[fieldDefinition] != null);
- IrBuilder builder = makeIRBuilder(fieldDefinition, element);
+ DartCapturedVariables variables =
+ _analyzeCapturedVariables(element, fieldDefinition);
+ tryStatements = variables.tryStatements;
+ IrBuilder builder = makeIRBuilder(element, variables.capturedVariables);
return withBuilder(builder, () {
builder.buildFieldInitializerHeader(
@@ -1990,7 +2046,7 @@
});
}
- ir.FunctionDefinition buildFunction(FunctionElement element) {
+ ir.RootNode buildFunction(FunctionElement element) {
assert(invariant(element, element.isImplementation));
ast.FunctionExpression node = element.node;
if (element.asyncMarker != AsyncMarker.SYNC) {
@@ -2007,13 +2063,16 @@
}
}
- IrBuilder builder = makeIRBuilder(node, element);
+ DartCapturedVariables variables =
+ _analyzeCapturedVariables(element, node);
+ tryStatements = variables.tryStatements;
+ IrBuilder builder = makeIRBuilder(element, variables.capturedVariables);
return withBuilder(builder, () => _makeFunctionBody(element, node));
}
List<ir.Primitive> normalizeStaticArguments(
- Selector selector,
+ CallStructure callStructure,
FunctionElement target,
List<ir.Primitive> arguments) {
return arguments;
@@ -2035,6 +2094,21 @@
}
}
+/// The [IrBuilder]s view on the information about the program that has been
+/// computed in resolution and and type interence.
+class GlobalProgramInformation {
+ final Compiler _compiler;
+ JavaScriptBackend get _backend => _compiler.backend;
+
+ GlobalProgramInformation(this._compiler);
+
+ /// Returns [true], if the analysis could not determine that the type
+ /// arguments for the class [cls] are never used in the program.
+ bool requiresRuntimeTypesFor(ClassElement cls) {
+ return cls.typeVariables.isNotEmpty && _backend.classNeedsRti(cls);
+ }
+}
+
/// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder].
class JsIrBuilderVisitor extends IrBuilderVisitor {
/// Promote the type of [irBuilder] to [JsIrBuilder].
@@ -2136,7 +2210,7 @@
scope.boxedLoopVariables);
}
- ir.ExecutableDefinition buildExecutable(ExecutableElement element) {
+ ir.RootNode buildExecutable(ExecutableElement element) {
return nullIfGiveup(() {
switch (element.kind) {
case ElementKind.GENERATIVE_CONSTRUCTOR:
@@ -2180,6 +2254,13 @@
return visitor.withBuilder(irBuilder, () => visitor.translateConstant(exp));
}
+ JsIrBuilder getBuilderFor(Element element) {
+ return new JsIrBuilder(
+ new GlobalProgramInformation(compiler),
+ compiler.backend.constantSystem,
+ element);
+ }
+
/// Builds the IR for a given constructor.
///
/// 1. Evaluates all own or inherited field initializers.
@@ -2190,20 +2271,47 @@
constructor = constructor.implementation;
ClassElement classElement = constructor.enclosingClass.implementation;
- JsIrBuilder builder =
- new JsIrBuilder(compiler.backend.constantSystem, constructor);
+ JsIrBuilder builder = getBuilderFor(constructor);
+
+ final bool requiresTypeInformation =
+ builder.program.requiresRuntimeTypesFor(classElement);
return withBuilder(builder, () {
// Setup parameters and create a box if anything is captured.
- List<ParameterElement> parameters = [];
- constructor.functionSignature.orderedForEachParameter(parameters.add);
- builder.buildFunctionHeader(parameters,
+ List<Local> parameters = <Local>[];
+ constructor.functionSignature.orderedForEachParameter(
+ (ParameterElement p) => parameters.add(p));
+
+ int firstTypeArgumentParameterIndex;
+
+ // If instances of the class may need runtime type information, we add a
+ // synthetic parameter for each type parameter.
+ if (requiresTypeInformation) {
+ firstTypeArgumentParameterIndex = parameters.length;
+ classElement.typeVariables.forEach((TypeVariableType variable) {
+ parameters.add(
+ new TypeInformationParameter(variable.element, constructor));
+ });
+ }
+
+ // Create IR parameters and setup the environment.
+ List<ir.Parameter> irParameters = builder.buildFunctionHeader(parameters,
closureScope: getClosureScopeForFunction(constructor));
+ // Create a list of the values of all type argument parameters, if any.
+ List<ir.Primitive> typeInformation;
+ if (requiresTypeInformation) {
+ typeInformation = irParameters.sublist(firstTypeArgumentParameterIndex);
+ } else {
+ typeInformation = const <ir.Primitive>[];
+ }
+
// -- Step 1: evaluate field initializers ---
// Evaluate field initializers in constructor and super constructors.
+ irBuilder.enterInitializers();
List<ConstructorElement> constructorList = <ConstructorElement>[];
evaluateConstructorFieldInitializers(constructor, constructorList);
+ irBuilder.leaveInitializers();
// All parameters in all constructors are now bound in the environment.
// BoxLocals for captured parameters are also in the environment.
@@ -2221,8 +2329,10 @@
// Native fields are initialized elsewhere.
}
}, includeSuperAndInjectedMembers: true);
- ir.Primitive instance =
- new ir.CreateInstance(classElement, instanceArguments);
+ ir.Primitive instance = new ir.CreateInstance(
+ classElement,
+ instanceArguments,
+ typeInformation);
irBuilder.add(new ir.LetPrim(instance));
// --- Step 3: call constructor bodies ---
@@ -2456,8 +2566,7 @@
node,
elements);
- JsIrBuilder builder =
- new JsIrBuilder(compiler.backend.constantSystem, body);
+ JsIrBuilder builder = getBuilderFor(body);
return withBuilder(builder, () {
irBuilder.buildConstructorBodyHeader(getConstructorBodyParameters(body),
@@ -2479,8 +2588,7 @@
element,
node,
elements);
- IrBuilder builder =
- new JsIrBuilder(compiler.backend.constantSystem, element);
+ IrBuilder builder = getBuilderFor(element);
return withBuilder(builder, () => _makeFunctionBody(element, node));
}
@@ -2495,7 +2603,7 @@
/// Inserts default arguments and normalizes order of named arguments.
List<ir.Primitive> normalizeStaticArguments(
- Selector selector,
+ CallStructure callStructure,
FunctionElement target,
List<ir.Primitive> arguments) {
target = target.implementation;
@@ -2528,7 +2636,7 @@
// find them in [compiledNamedArguments]. If found, we use the
// value in the temporary list, otherwise the default value.
signature.orderedOptionalParameters.forEach((ParameterElement element) {
- int nameIndex = selector.namedArguments.indexOf(element.name);
+ int nameIndex = callStructure.namedArguments.indexOf(element.name);
if (nameIndex != -1) {
int translatedIndex = offset + nameIndex;
result.add(arguments[translatedIndex]);
@@ -2544,16 +2652,17 @@
List<ir.Primitive> normalizeDynamicArguments(
Selector selector,
List<ir.Primitive> arguments) {
- assert(arguments.length == selector.argumentCount);
+ CallStructure callStructure = selector.callStructure;
+ assert(arguments.length == callStructure.argumentCount);
// Optimization: don't copy the argument list for trivial cases.
- if (selector.namedArguments.isEmpty) return arguments;
+ if (callStructure.namedArguments.isEmpty) return arguments;
List<ir.Primitive> result = <ir.Primitive>[];
- for (int i=0; i < selector.positionalArgumentCount; i++) {
+ for (int i=0; i < callStructure.positionalArgumentCount; i++) {
result.add(arguments[i]);
}
- for (String argName in selector.getOrderedNamedArguments()) {
- int nameIndex = selector.namedArguments.indexOf(argName);
- int translatedIndex = selector.positionalArgumentCount + nameIndex;
+ for (String argName in callStructure.getOrderedNamedArguments()) {
+ int nameIndex = callStructure.namedArguments.indexOf(argName);
+ int translatedIndex = callStructure.positionalArgumentCount + nameIndex;
result.add(arguments[translatedIndex]);
}
return result;
@@ -2562,8 +2671,9 @@
@override
ir.Primitive buildReifyTypeVariable(ir.Primitive target,
TypeVariableType variable) {
- ir.Primitive typeArgument = new ir.ReadTypeVariable(variable, target);
- irBuilder.add(new ir.LetPrim(typeArgument));
+ ir.Primitive typeArgument =
+ irBuilder.buildTypeVariableAccess(target, variable);
+
ir.Primitive type = new ir.ReifyRuntimeType(typeArgument);
irBuilder.add(new ir.LetPrim(type));
return type;
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
index 0b115cb..e7a7d14 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
@@ -26,7 +26,7 @@
///
class CheckCpsIntegrity extends RecursiveVisitor {
- ExecutableDefinition topLevelNode;
+ RootNode topLevelNode;
Set<Definition> seenDefinitions = new Set<Definition>();
Map<Definition, Set<Reference>> seenReferences =
@@ -78,7 +78,7 @@
}
@override
- visitRunnableBody(RunnableBody node) {
+ visitBody(Body node) {
markAsSeen(node.returnContinuation);
if (!node.returnContinuation.isReturnContinuation) {
error('Return continuation with a body', node);
@@ -209,7 +209,7 @@
'$sexpr\n';
}
- void check(ExecutableDefinition node) {
+ void check(RootNode node) {
topLevelNode = node;
visit(node);
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
index d16fd8c..b0a305d 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -65,11 +65,6 @@
/// binding originated.
Entity hint;
- /// Register in which the variable binding this primitive can be allocated.
- /// Separate register spaces are used for primitives with different [element].
- /// Assigned by [RegisterAllocator], is null before that phase.
- int registerIndex;
-
/// Use the given element as a hint for naming this primitive.
///
/// Has no effect if this primitive already has a non-null [element].
@@ -214,7 +209,8 @@
/// child.parent = parent;
/// parent.body = child;
abstract class InteriorNode extends Node {
- Expression body;
+ Expression get body;
+ void set body(Expression body);
}
/// Invoke a static function or static field getter/setter.
@@ -382,15 +378,11 @@
: continuation = new Reference<Continuation>(cont),
arguments = _referenceList(args) {
assert(dart2js.invariant(target,
- target.isErroneous || target.isConstructor,
- message: "Constructor invocation target is not a constructor: "
- "$target."));
- assert(dart2js.invariant(target,
target.isErroneous ||
type.isDynamic ||
type.element == target.enclosingClass.declaration,
- message: "Constructor invocation type ${type} does not match enclosing "
- "class of target ${target}."));
+ message: "Constructor invocation target is not a constructor: "
+ "$target."));
}
accept(Visitor visitor) => visitor.visitInvokeConstructor(this);
@@ -506,13 +498,11 @@
bool isRecursive;
InvokeContinuation(Continuation cont, List<Primitive> args,
- {recursive: false})
+ {this.isRecursive: false})
: continuation = new Reference<Continuation>(cont),
- arguments = _referenceList(args),
- isRecursive = recursive {
- assert(cont.parameters == null ||
- cont.parameters.length == args.length);
- if (recursive) cont.isRecursive = true;
+ arguments = _referenceList(args) {
+ assert(cont.parameters == null || cont.parameters.length == args.length);
+ if (isRecursive) cont.isRecursive = true;
}
/// A continuation invocation whose target and arguments will be filled
@@ -520,10 +510,9 @@
///
/// Used as a placeholder for a jump whose target is not yet created
/// (e.g., in the translation of break and continue).
- InvokeContinuation.uninitialized({recursive: false})
+ InvokeContinuation.uninitialized({this.isRecursive: false})
: continuation = null,
- arguments = null,
- isRecursive = recursive;
+ arguments = null;
accept(Visitor visitor) => visitor.visitInvokeContinuation(this);
}
@@ -597,7 +586,8 @@
accept(Visitor visitor) => visitor.visitCreateBox(this);
}
-/// Creates an instance of a class and initializes its fields.
+/// Creates an instance of a class and initializes its fields and runtime type
+/// information.
class CreateInstance extends Primitive implements JsSpecificNode {
final ClassElement classElement;
@@ -605,8 +595,17 @@
/// The order corresponds to the order of fields on the class.
final List<Reference<Primitive>> arguments;
- CreateInstance(this.classElement, List<Primitive> arguments)
- : this.arguments = _referenceList(arguments);
+ /// The runtime type information structure which contains the type arguments.
+ ///
+ /// May be `null` to indicate that no type information is needed because the
+ /// compiler determined that the type information for instances of this class
+ /// is not needed at runtime.
+ final List<Reference<Primitive>> typeInformation;
+
+ CreateInstance(this.classElement, List<Primitive> arguments,
+ List<Primitive> typeInformation)
+ : this.arguments = _referenceList(arguments),
+ this.typeInformation = _referenceList(typeInformation);
accept(Visitor visitor) => visitor.visitCreateInstance(this);
}
@@ -655,7 +654,7 @@
final GenericType type;
final List<Reference<Primitive>> values;
- LiteralList(this.type, Iterable<Primitive> values)
+ LiteralList(this.type, List<Primitive> values)
: this.values = _referenceList(values);
accept(Visitor visitor) => visitor.visitLiteralList(this);
@@ -717,30 +716,39 @@
int parent_index;
// A continuation is recursive if it has any recursive invocations.
- bool isRecursive = false;
+ bool isRecursive;
bool get isReturnContinuation => body == null;
- Continuation(this.parameters);
+ Continuation(this.parameters, {this.isRecursive: false});
Continuation.retrn() : parameters = <Parameter>[new Parameter(null)];
accept(Visitor visitor) => visitor.visitContinuation(this);
}
-abstract class ExecutableDefinition implements Node {
- RunnableBody get body;
+abstract class RootNode extends Node {
Element get element;
- applyPass(Pass pass);
+ /// True if there is no body for this root node.
+ ///
+ /// In some parts of the compiler, empty root nodes are used as placeholders
+ /// for abstract methods, external constructors, fields without initializers,
+ /// etc.
+ bool get isEmpty;
+
+ /// List of parameters, or an empty list if this is a field.
+ /// For fields, this list is immutable.
+ List<Definition> get parameters;
}
// This is basically a function definition with an empty parameter list and a
// field element instead of a function element and no const declarations, and
// never a getter or setter, though that's less important.
-class FieldDefinition extends Node implements ExecutableDefinition {
+class FieldDefinition extends RootNode implements DartSpecificNode {
final FieldElement element;
- RunnableBody body;
+ List<Definition> get parameters => const <Definition>[];
+ final Body body;
FieldDefinition(this.element, this.body);
@@ -748,26 +756,8 @@
: this.body = null;
accept(Visitor visitor) => visitor.visitFieldDefinition(this);
- applyPass(Pass pass) => pass.rewriteFieldDefinition(this);
- /// `true` if this field has no initializer.
- ///
- /// If `true` [body] is `null`.
- ///
- /// This is different from a initializer that is `null`. Consider this class:
- ///
- /// class Class {
- /// final field;
- /// Class.a(this.field);
- /// Class.b() : this.field = null;
- /// Class.c();
- /// }
- ///
- /// If `field` had an initializer, possibly `null`, constructors `Class.a` and
- /// `Class.b` would be invalid, and since `field` has no initializer
- /// constructor `Class.c` is invalid. We therefore need to distinguish the two
- /// cases.
- bool get hasInitializer => body != null;
+ bool get isEmpty => body == null;
}
/// Identifies a mutable variable.
@@ -781,22 +771,21 @@
accept(Visitor v) => v.visitMutableVariable(this);
}
-class RunnableBody extends InteriorNode {
+class Body extends InteriorNode {
Expression body;
final Continuation returnContinuation;
- RunnableBody(this.body, this.returnContinuation);
- accept(Visitor visitor) => visitor.visitRunnableBody(this);
+ Body(this.body, this.returnContinuation);
+ accept(Visitor visitor) => visitor.visitBody(this);
}
/// A function definition, consisting of parameters and a body. The parameters
/// include a distinguished continuation parameter (held by the body).
-class FunctionDefinition extends Node
- implements ExecutableDefinition {
+class FunctionDefinition extends RootNode {
final FunctionElement element;
final Parameter thisParameter;
/// Mixed list of [Parameter]s and [MutableVariable]s.
final List<Definition> parameters;
- final RunnableBody body;
+ final Body body;
final List<ConstDeclaration> localConstants;
/// Values for optional parameters.
@@ -810,26 +799,22 @@
this.defaultParameterValues);
FunctionDefinition.abstract(this.element,
- this.thisParameter,
this.parameters,
this.defaultParameterValues)
: body = null,
+ thisParameter = null,
localConstants = const <ConstDeclaration>[];
accept(Visitor visitor) => visitor.visitFunctionDefinition(this);
- applyPass(Pass pass) => pass.rewriteFunctionDefinition(this);
- /// Returns `true` if this function is abstract or external.
- ///
- /// If `true`, [body] is `null` and [localConstants] is empty.
- bool get isAbstract => body == null;
+ bool get isEmpty => body == null;
}
abstract class Initializer extends Node implements DartSpecificNode {}
class FieldInitializer extends Initializer {
final FieldElement element;
- final RunnableBody body;
+ final Body body;
FieldInitializer(this.element, this.body);
accept(Visitor visitor) => visitor.visitFieldInitializer(this);
@@ -837,36 +822,46 @@
class SuperInitializer extends Initializer {
final ConstructorElement target;
- final List<RunnableBody> arguments;
+ final List<Body> arguments;
final Selector selector;
SuperInitializer(this.target, this.arguments, this.selector);
accept(Visitor visitor) => visitor.visitSuperInitializer(this);
}
-class ConstructorDefinition extends FunctionDefinition {
+class ConstructorDefinition extends RootNode implements DartSpecificNode {
+ final ConstructorElement element;
+ final Parameter thisParameter;
+ /// Mixed list of [Parameter]s and [MutableVariable]s.
+ final List<Definition> parameters;
+ final Body body;
+ final List<ConstDeclaration> localConstants;
final List<Initializer> initializers;
- ConstructorDefinition(ConstructorElement element,
- Definition thisParameter, // only Dart
- List<Definition> parameters,
- RunnableBody body,
+ /// Values for optional parameters.
+ final List<ConstantExpression> defaultParameterValues;
+
+ ConstructorDefinition(this.element,
+ this.thisParameter,
+ this.parameters,
+ this.body,
this.initializers,
- List<ConstDeclaration> localConstants,
- List<ConstantExpression> defaultParameterValues)
- : super(element, thisParameter, parameters, body, localConstants,
- defaultParameterValues);
+ this.localConstants,
+ this.defaultParameterValues);
// 'Abstract' here means "has no body" and is used to represent external
// constructors.
ConstructorDefinition.abstract(
- ConstructorElement element,
- List<Definition> parameters,
- List<ConstantExpression> defaultParameterValues)
- : initializers = null,
- super.abstract(element, null, parameters, defaultParameterValues);
+ this.element,
+ this.parameters,
+ this.defaultParameterValues)
+ : body = null,
+ initializers = null,
+ thisParameter = null,
+ localConstants = const <ConstDeclaration>[];
accept(Visitor visitor) => visitor.visitConstructorDefinition(this);
- applyPass(Pass pass) => pass.rewriteConstructorDefinition(this);
+
+ bool get isEmpty => body == null;
}
/// Converts the internal representation of a type to a Dart object of type
@@ -898,6 +893,28 @@
accept(Visitor visitor) => visitor.visitReadTypeVariable(this);
}
+/// Representation of a closed type (that is, a type without type variables).
+///
+/// The resulting value is constructed from [dartType] by replacing the type
+/// variables with consecutive values from [arguments], in the order generated
+/// by [DartType.forEachTypeVariable]. The type variables in [dartType] are
+/// treated as 'holes' in the term, which means that it must be ensured at
+/// construction, that duplicate occurences of a type variable in [dartType]
+/// are assigned the same value.
+class TypeExpression extends Primitive implements JsSpecificNode {
+ final DartType dartType;
+ final List<Reference<Primitive>> arguments;
+
+ TypeExpression(this.dartType,
+ [List<Primitive> arguments = const <Primitive>[]])
+ : this.arguments = _referenceList(arguments);
+
+ @override
+ accept(Visitor visitor) {
+ return visitor.visitTypeExpression(this);
+ }
+}
+
List<Reference<Primitive>> _referenceList(Iterable<Primitive> definitions) {
return definitions.map((e) => new Reference<Primitive>(e)).toList();
}
@@ -911,7 +928,7 @@
T visitFieldDefinition(FieldDefinition node);
T visitFunctionDefinition(FunctionDefinition node);
T visitConstructorDefinition(ConstructorDefinition node);
- T visitRunnableBody(RunnableBody node);
+ T visitBody(Body node);
// Initializers
T visitFieldInitializer(FieldInitializer node);
@@ -960,6 +977,7 @@
T visitCreateBox(CreateBox node);
T visitReifyRuntimeType(ReifyRuntimeType node);
T visitReadTypeVariable(ReadTypeVariable node);
+ T visitTypeExpression(TypeExpression node);
}
/// Recursively visits the entire CPS term, and calls abstract `process*`
@@ -971,9 +989,9 @@
processReference(Reference ref) {}
- processRunnableBody(RunnableBody node) {}
- visitRunnableBody(RunnableBody node) {
- processRunnableBody(node);
+ processBody(Body node) {}
+ visitBody(Body node) {
+ processBody(node);
visit(node.returnContinuation);
visit(node.body);
}
@@ -981,7 +999,7 @@
processFieldDefinition(FieldDefinition node) {}
visitFieldDefinition(FieldDefinition node) {
processFieldDefinition(node);
- if (node.hasInitializer) {
+ if (node.body != null) {
visit(node.body);
}
}
@@ -991,7 +1009,7 @@
processFunctionDefinition(node);
if (node.thisParameter != null) visit(node.thisParameter);
node.parameters.forEach(visit);
- if (!node.isAbstract) {
+ if (node.body != null) {
visit(node.body);
}
}
@@ -1001,8 +1019,12 @@
processConstructorDefinition(node);
if (node.thisParameter != null) visit(node.thisParameter);
node.parameters.forEach(visit);
- node.initializers.forEach(visit);
- visit(node.body);
+ if (node.initializers != null) {
+ node.initializers.forEach(visit);
+ }
+ if (node.body != null) {
+ visit(node.body);
+ }
}
processFieldInitializer(FieldInitializer node) {}
@@ -1199,6 +1221,7 @@
visitCreateInstance(CreateInstance node) {
processCreateInstance(node);
node.arguments.forEach(processReference);
+ node.typeInformation.forEach(processReference);
}
processSetField(SetField node) {}
@@ -1231,273 +1254,11 @@
processReadTypeVariable(node);
processReference(node.target);
}
-}
-/// Keeps track of currently unused register indices.
-class RegisterArray {
- int nextIndex = 0;
- final List<int> freeStack = <int>[];
-
- /// Returns an index that is currently unused.
- int makeIndex() {
- if (freeStack.isEmpty) {
- return nextIndex++;
- } else {
- return freeStack.removeLast();
- }
- }
-
- void releaseIndex(int index) {
- freeStack.add(index);
- }
-}
-
-/// Assigns indices to each primitive in the IR such that primitives that are
-/// live simultaneously never get assigned the same index.
-/// This information is used by the dart tree builder to generate fewer
-/// redundant variables.
-/// Currently, the liveness analysis is very simple and is often inadequate
-/// for removing all of the redundant variables.
-class RegisterAllocator implements Visitor {
- final dart2js.InternalErrorFunction internalError;
-
- /// Separate register spaces for each source-level variable/parameter.
- /// Note that null is used as key for primitives without hints.
- final Map<Local, RegisterArray> elementRegisters = <Local, RegisterArray>{};
-
- RegisterAllocator(this.internalError);
-
- RegisterArray getRegisterArray(Local local) {
- RegisterArray registers = elementRegisters[local];
- if (registers == null) {
- registers = new RegisterArray();
- elementRegisters[local] = registers;
- }
- return registers;
- }
-
- void allocate(Primitive primitive) {
- if (primitive.registerIndex == null) {
- primitive.registerIndex = getRegisterArray(primitive.hint).makeIndex();
- }
- }
-
- void release(Primitive primitive) {
- // Do not share indices for temporaries as this may obstruct inlining.
- if (primitive.hint == null) return;
- if (primitive.registerIndex != null) {
- getRegisterArray(primitive.hint).releaseIndex(primitive.registerIndex);
- }
- }
-
- void visit(Node node) => node.accept(this);
-
- void visitReference(Reference reference) {
- allocate(reference.definition);
- }
-
- void visitFieldDefinition(FieldDefinition node) {
- if (node.hasInitializer) {
- visit(node.body);
- }
- }
-
- void visitRunnableBody(RunnableBody node) {
- visit(node.body);
- }
-
- void visitFunctionDefinition(FunctionDefinition node) {
- if (!node.isAbstract) {
- visit(node.body);
- }
- // Assign indices to unused parameters.
- for (Definition param in node.parameters) {
- if (param is Primitive) {
- allocate(param);
- }
- }
- }
-
- void visitConstructorDefinition(ConstructorDefinition node) {
- if (!node.isAbstract) {
- node.initializers.forEach(visit);
- visit(node.body);
- }
- // Assign indices to unused parameters.
- for (Definition param in node.parameters) {
- if (param is Primitive) {
- allocate(param);
- }
- }
- }
-
- void visitFieldInitializer(FieldInitializer node) {
- visit(node.body.body);
- }
-
- void visitSuperInitializer(SuperInitializer node) {
- node.arguments.forEach(visit);
- }
-
- void visitLetPrim(LetPrim node) {
- visit(node.body);
- release(node.primitive);
- visit(node.primitive);
- }
-
- void visitLetCont(LetCont node) {
- node.continuations.forEach(visit);
- visit(node.body);
- }
-
- void visitLetHandler(LetHandler node) {
- visit(node.handler);
- // Handler parameters that were not used in the handler body will not have
- // had register indexes assigned. Assign them here, otherwise they will
- // be eliminated later and they should not be (i.e., a catch clause that
- // does not use the exception parameter should not have the exception
- // parameter eliminated, because it would not be well-formed anymore).
- // In any case release the parameter indexes because the parameters are
- // not live in the try block.
- node.handler.parameters.forEach((Parameter parameter) {
- allocate(parameter);
- release(parameter);
- });
- visit(node.body);
- }
-
- void visitLetMutable(LetMutable node) {
- visit(node.body);
- visitReference(node.value);
- }
-
- void visitInvokeStatic(InvokeStatic node) {
- node.arguments.forEach(visitReference);
- }
-
- void visitInvokeContinuation(InvokeContinuation node) {
- node.arguments.forEach(visitReference);
- }
-
- void visitInvokeMethod(InvokeMethod node) {
- visitReference(node.receiver);
- node.arguments.forEach(visitReference);
- }
-
- void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- visitReference(node.receiver);
- node.arguments.forEach(visitReference);
- }
-
- void visitInvokeConstructor(InvokeConstructor node) {
- node.arguments.forEach(visitReference);
- }
-
- void visitConcatenateStrings(ConcatenateStrings node) {
- node.arguments.forEach(visitReference);
- }
-
- void visitBranch(Branch node) {
- visit(node.condition);
- }
-
- void visitLiteralList(LiteralList node) {
- node.values.forEach(visitReference);
- }
-
- void visitLiteralMap(LiteralMap node) {
- for (LiteralMapEntry entry in node.entries) {
- visitReference(entry.key);
- visitReference(entry.value);
- }
- }
-
- void visitTypeOperator(TypeOperator node) {
- visitReference(node.receiver);
- }
-
- void visitConstant(Constant node) {
- }
-
- void visitReifyTypeVar(ReifyTypeVar node) {
- }
-
- void visitCreateFunction(CreateFunction node) {
- new RegisterAllocator(internalError).visit(node.definition);
- }
-
- void visitGetMutableVariable(GetMutableVariable node) {
- }
-
- void visitSetMutableVariable(SetMutableVariable node) {
- visit(node.body);
- visitReference(node.value);
- }
-
- void visitDeclareFunction(DeclareFunction node) {
- new RegisterAllocator(internalError).visit(node.definition);
- visit(node.body);
- }
-
- void visitParameter(Parameter node) {
- // Parameters are handled differently depending on whether they are
- // function parameters, continuation parameters, exception handler
- // parameters, etc. Thus we do not call visitParameter directly and
- // handle them explicitly in their parent IR node.
- internalError(dart2js.CURRENT_ELEMENT_SPANNABLE,
- 'tried to allocate a parameter');
- }
-
- void visitMutableVariable(MutableVariable node) {}
-
- void visitContinuation(Continuation node) {
- visit(node.body);
-
- // Arguments get allocated left-to-right, so we release parameters
- // right-to-left. This increases the likelihood that arguments can be
- // transferred without intermediate assignments.
- for (int i = node.parameters.length - 1; i >= 0; --i) {
- release(node.parameters[i]);
- }
- }
-
- void visitIsTrue(IsTrue node) {
- visitReference(node.value);
- }
-
- // JavaScript specific nodes.
-
- void visitSetField(SetField node) {
- visit(node.body);
- visitReference(node.value);
- visitReference(node.object);
- }
-
- void visitGetField(GetField node) {
- visitReference(node.object);
- }
-
- void visitCreateBox(CreateBox node) {
- }
-
- void visitCreateInstance(CreateInstance node) {
- node.arguments.forEach(visitReference);
- }
-
- void visitIdentical(Identical node) {
- visitReference(node.left);
- visitReference(node.right);
- }
-
- void visitInterceptor(Interceptor node) {
- visitReference(node.input);
- }
-
- void visitReifyRuntimeType(ReifyRuntimeType node) {
- visitReference(node.value);
- }
-
- void visitReadTypeVariable(ReadTypeVariable node) {
- visitReference(node.target);
+ processTypeExpression(TypeExpression node) {}
+ @override
+ visitTypeExpression(TypeExpression node) {
+ processTypeExpression(node);
+ node.arguments.forEach(processReference);
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
index 3b71d9a..a645fb9 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
@@ -62,7 +62,7 @@
String visitFieldDefinition(FieldDefinition node) {
String name = node.element.name;
- if (node.hasInitializer) {
+ if (node.body != null) {
String body = visit(node.body);
return '$indentation(FieldDefinition $name () return\n'
'$body)';
@@ -111,7 +111,7 @@
return '$indentation(SuperInitializer $target $selector (\n$arguments)';
}
- String visitRunnableBody(RunnableBody node) {
+ String visitBody(Body node) {
namer.setReturnContinuation(node.returnContinuation);
return indentBlock(() => visit(node.body));
}
@@ -207,11 +207,21 @@
}
String visitInvokeConstructor(InvokeConstructor node) {
+ String className;
+ // TODO(karlklose): for illegal nodes constructed for tests or unresolved
+ // constructor calls in the DartBackend, we get an element with no enclosing
+ // class. Clean this up by introducing a name field to the node and
+ // removing [ErroneousElement]s from the IR.
+ if (node.type != null) {
+ className = node.type.toString();
+ } else {
+ className = node.target.enclosingClass.name;
+ }
String callName;
if (node.target.name.isEmpty) {
- callName = '${node.type}';
+ callName = '${className}';
} else {
- callName = '${node.type}.${node.target.name}';
+ callName = '${className}.${node.target.name}';
}
String cont = access(node.continuation);
String args = formatArguments(node);
@@ -323,7 +333,8 @@
String visitCreateInstance(CreateInstance node) {
String className = node.classElement.name;
String arguments = node.arguments.map(access).join(' ');
- return '(CreateInstance $className ($arguments))';
+ String typeInformation = node.typeInformation.map(access).join(' ');
+ return '(CreateInstance $className ($arguments)$typeInformation)';
}
String visitIdentical(Identical node) {
@@ -343,6 +354,12 @@
String visitReadTypeVariable(ReadTypeVariable node) {
return '(ReadTypeVariable ${access(node.target)}.${node.variable})';
}
+
+ @override
+ String visitTypeExpression(TypeExpression node) {
+ String args = node.arguments.map(access).join(', ');
+ return '(TypeExpression ${node.dartType.toString()} $args)';
+ }
}
class ConstantStringifier extends ConstantValueVisitor<String, Null> {
@@ -427,7 +444,9 @@
String nameParameter(Parameter parameter) {
assert(!_names.containsKey(parameter));
- return _names[parameter] = parameter.hint.name;
+ String name =
+ parameter.hint != null ? parameter.hint.name : nameValue(parameter);
+ return _names[parameter] = name;
}
String nameMutableVariable(MutableVariable variable) {
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
index 74c4b1c..92b81e2 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
@@ -21,44 +21,50 @@
visit(cps_ir.Node node) => node.accept(this);
- void traceGraph(String name, cps_ir.ExecutableDefinition graph) {
+ void traceGraph(String name, cps_ir.RootNode node) {
+ if (node.isEmpty) return; // Don't bother printing an empty trace.
tag("cfg", () {
printProperty("name", name);
- visit(graph);
+
+ names = new Names();
+ BlockCollector builder = new BlockCollector(names);
+ builder.visit(node);
+
+ for (Block block in builder.entries) {
+ printBlock(block, entryPointParameters: node.parameters);
+ }
+ for (Block block in builder.cont2block.values) {
+ printBlock(block);
+ }
+ names = null;
});
}
// Temporary field used during tree walk
Names names;
- printDefinition(cps_ir.ExecutableDefinition node) {
- names = new Names();
- BlockCollector builder = new BlockCollector(names);
- builder.visit(node);
-
- for (Block block in builder.entries) {
- printBlock(block);
- }
- for (Block block in builder.cont2block.values) {
- printBlock(block);
- }
- names = null;
- }
-
visitFieldDefinition(cps_ir.FieldDefinition node) {
- if (node.hasInitializer) {
- printDefinition(node);
- }
+ unexpectedNode(node);
}
visitFunctionDefinition(cps_ir.FunctionDefinition node) {
- if (node.isAbstract) return;
- printDefinition(node);
+ unexpectedNode(node);
}
visitConstructorDefinition(cps_ir.ConstructorDefinition node) {
- if (node.isAbstract) return;
- printDefinition(node);
+ unexpectedNode(node);
+ }
+
+ visitFieldInitializer(cps_ir.FieldInitializer node) {
+ unexpectedNode(node);
+ }
+
+ visitSuperInitializer(cps_ir.SuperInitializer node) {
+ unexpectedNode(node);
+ }
+
+ visitBody(cps_ir.Body node) {
+ unexpectedNode(node);
}
// Bodies and initializers are not visited. They contain continuations which
@@ -68,15 +74,6 @@
throw 'The IR tracer reached an unexpected IR instruction: $node';
}
- visitRunnableBody(cps_ir.RunnableBody node) {
- unexpectedNode(node);
- }
- visitFieldInitializer(cps_ir.FieldInitializer node) {
- unexpectedNode(node);
- }
- visitSuperInitializer(cps_ir.SuperInitializer node) {
- unexpectedNode(node);
- }
int countUses(cps_ir.Definition definition) {
int count = 0;
@@ -88,7 +85,9 @@
return count;
}
- printBlock(Block block) {
+ /// If [entryPointParameters] is given, this block is an entry point
+ /// and [entryPointParameters] is the list of function parameters.
+ printBlock(Block block, {List<cps_ir.Definition> entryPointParameters}) {
tag("block", () {
printProperty("name", block.name);
printProperty("from_bci", -1);
@@ -104,6 +103,10 @@
});
});
tag("HIR", () {
+ if (entryPointParameters != null) {
+ String params = entryPointParameters.map(names.name).join(', ');
+ printStmt('x0', 'Entry ($params)');
+ }
for (cps_ir.Parameter param in block.parameters) {
String name = names.name(param);
printStmt(name, "Parameter $name [useCount=${countUses(param)}]");
@@ -182,11 +185,12 @@
visitInvokeConstructor(cps_ir.InvokeConstructor node) {
String dummy = names.name(node);
+ String className = node.target.enclosingClass.name;
String callName;
if (node.target.name.isEmpty) {
- callName = '${node.type}';
+ callName = '${className}';
} else {
- callName = '${node.type}.${node.target.name}';
+ callName = '${className}.${node.target.name}';
}
String args = node.arguments.map(formatReference).join(', ');
String kont = formatReference(node.continuation);
@@ -308,7 +312,9 @@
visitCreateInstance(cps_ir.CreateInstance node) {
String className = node.classElement.name;
String arguments = node.arguments.map(formatReference).join(', ');
- return 'CreateInstance $className ($arguments)';
+ String typeInformation =
+ node.typeInformation.map(formatReference).join(', ');
+ return 'CreateInstance $className ($arguments) <$typeInformation>';
}
visitIdentical(cps_ir.Identical node) {
@@ -344,6 +350,12 @@
visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
return "ReifyRuntimeType ${formatReference(node.value)}";
}
+
+ @override
+ visitTypeExpression(cps_ir.TypeExpression node) {
+ return "TypeExpression ${node.dartType} "
+ "${node.arguments.map(formatReference).join(', ')}";
+ }
}
/**
@@ -403,7 +415,7 @@
final Map<cps_ir.Continuation, Block> cont2block =
<cps_ir.Continuation, Block>{};
final Set<Block> entries = new Set<Block>();
- Block current_block;
+ Block currentBlock;
Names names;
BlockCollector(this.names);
@@ -420,9 +432,7 @@
visit(cps_ir.Node node) => node.accept(this);
visitFieldDefinition(cps_ir.FieldDefinition node) {
- if (node.hasInitializer) {
- visit(node.body);
- }
+ visit(node.body);
}
visitFunctionDefinition(cps_ir.FunctionDefinition node) {
@@ -430,12 +440,13 @@
}
visitConstructorDefinition(cps_ir.ConstructorDefinition node) {
+ node.initializers.forEach(visit);
visit(node.body);
}
- visitRunnableBody(cps_ir.RunnableBody node) {
- current_block = new Block(names.name(node), [], node.body);
- entries.add(current_block);
+ visitBody(cps_ir.Body node) {
+ currentBlock = new Block(names.name(node), [], node.body);
+ entries.add(currentBlock);
visit(node.body);
}
@@ -468,7 +479,7 @@
void addEdgeToContinuation(cps_ir.Reference continuation) {
cps_ir.Definition target = continuation.definition;
if (target is cps_ir.Continuation && !target.isReturnContinuation) {
- current_block.addEdgeTo(getBlock(target));
+ currentBlock.addEdgeTo(getBlock(target));
}
}
@@ -511,11 +522,11 @@
visitBranch(cps_ir.Branch exp) {
cps_ir.Continuation trueTarget = exp.trueContinuation.definition;
if (!trueTarget.isReturnContinuation) {
- current_block.addEdgeTo(getBlock(trueTarget));
+ currentBlock.addEdgeTo(getBlock(trueTarget));
}
cps_ir.Continuation falseTarget = exp.falseContinuation.definition;
if (!falseTarget.isReturnContinuation) {
- current_block.addEdgeTo(getBlock(falseTarget));
+ currentBlock.addEdgeTo(getBlock(falseTarget));
}
}
@@ -524,10 +535,10 @@
}
visitContinuation(cps_ir.Continuation c) {
- var old_node = current_block;
- current_block = getBlock(c);
+ var old_node = currentBlock;
+ currentBlock = getBlock(c);
visit(c.body);
- current_block = old_node;
+ currentBlock = old_node;
}
// Primitives and conditions are not visited when searching for blocks.
@@ -588,4 +599,9 @@
visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
unexpectedNode(node);
}
+
+ @override
+ visitTypeExpression(cps_ir.TypeExpression node) {
+ unexpectedNode(node);
+ }
}
diff --git a/pkg/compiler/lib/src/cps_ir/optimizers.dart b/pkg/compiler/lib/src/cps_ir/optimizers.dart
index 5fba01c..4db77c8 100644
--- a/pkg/compiler/lib/src/cps_ir/optimizers.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimizers.dart
@@ -27,31 +27,7 @@
/// An optimization pass over the CPS IR.
abstract class Pass {
/// Applies optimizations to root, rewriting it in the process.
- void rewrite(ExecutableDefinition root) => root.applyPass(this);
-
- void rewriteConstructorDefinition(ConstructorDefinition root);
- void rewriteFunctionDefinition(FunctionDefinition root);
- void rewriteFieldDefinition(FieldDefinition root);
+ void rewrite(RootNode root);
String get passName;
}
-
-abstract class PassMixin implements Pass {
- void rewrite(ExecutableDefinition root) => root.applyPass(this);
-
- void rewriteExecutableDefinition(ExecutableDefinition root);
-
- void rewriteFunctionDefinition(FunctionDefinition root) {
- if (root.isAbstract) return;
- rewriteExecutableDefinition(root);
- }
-
- void rewriteConstructorDefinition(ConstructorDefinition root) {
- if (root.isAbstract) return;
- rewriteExecutableDefinition(root);
- }
- void rewriteFieldDefinition(FieldDefinition root) {
- if (!root.hasInitializer) return;
- rewriteExecutableDefinition(root);
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
index b61e785..0fe59ba 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
@@ -12,13 +12,14 @@
/// (except for feedback). Redundant parameters are removed from the
/// continuation signature, all invocations, and replaced within the
/// continuation body.
-class RedundantPhiEliminator extends RecursiveVisitor with PassMixin {
+class RedundantPhiEliminator extends RecursiveVisitor implements Pass {
String get passName => 'Redundant phi elimination';
final Set<Continuation> workSet = new Set<Continuation>();
@override
- void rewriteExecutableDefinition(final ExecutableDefinition root) {
+ void rewrite(RootNode root) {
+ if (root.isEmpty) return;
// Set all parent pointers.
new ParentVisitor().visit(root);
diff --git a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
index c3823ec..445838e 100644
--- a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
+++ b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
@@ -8,7 +8,7 @@
* [ShrinkingReducer] applies shrinking reductions to CPS terms as described
* in 'Compiling with Continuations, Continued' by Andrew Kennedy.
*/
-class ShrinkingReducer extends PassMixin {
+class ShrinkingReducer extends Pass {
String get passName => 'Shrinking reductions';
Set<_ReductionTask> _worklist;
@@ -17,7 +17,9 @@
/// Applies shrinking reductions to root, mutating root in the process.
@override
- void rewriteExecutableDefinition(ExecutableDefinition root) {
+ void rewrite(RootNode root) {
+ if (root.isEmpty) return;
+
_worklist = new Set<_ReductionTask>();
_RedexVisitor redexVisitor = new _RedexVisitor(_worklist);
@@ -464,7 +466,7 @@
Continuation cont = reference.definition;
Node parent = cont.parent;
// The parent might be the deleted sentinel, or it might be a
- // RunnableBody if the continuation is the return continuation.
+ // Body if the continuation is the return continuation.
if (parent is LetCont) {
if (cont.isRecursive && cont.hasAtMostOneUse) {
// Convert recursive to nonrecursive continuations. If the
@@ -494,7 +496,7 @@
});
}
- processRunnableBody(RunnableBody node) {
+ processBody(Body node) {
node.returnContinuation.parent = node;
node.body.parent = node;
}
@@ -516,7 +518,7 @@
}
processSuperInitializer(SuperInitializer node) {
- node.arguments.forEach((RunnableBody argument) => argument.parent = node);
+ node.arguments.forEach((Body argument) => argument.parent = node);
}
processLetPrim(LetPrim node) {
@@ -658,6 +660,7 @@
processCreateInstance(CreateInstance node) {
node.arguments.forEach((Reference ref) => ref.parent = node);
+ node.typeInformation.forEach((Reference ref) => ref.parent = node);
}
processCreateBox(CreateBox node) {
@@ -670,6 +673,10 @@
processReadTypeVariable(ReadTypeVariable node) {
node.target.parent = node;
}
+
+ processTypeExpression(TypeExpression node) {
+ node.arguments.forEach((Reference ref) => ref.parent = node);
+ }
}
class _ReductionKind {
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index bd723fc..234df38 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -67,6 +67,7 @@
}
@override
+ // TODO(karlklose): Do not base this on containsMask.
bool areAssignable(TypeMask a, TypeMask b) {
return a.containsMask(b, classWorld) || b.containsMask(a, classWorld);
}
@@ -92,7 +93,7 @@
* Implemented according to 'Constant Propagation with Conditional Branches'
* by Wegman, Zadeck.
*/
-class TypePropagator<T> extends PassMixin {
+class TypePropagator<T> extends Pass {
String get passName => 'Sparse constant propagation';
final types.DartTypes _dartTypes;
@@ -111,7 +112,9 @@
: _types = <Node, _AbstractValue>{};
@override
- void rewriteExecutableDefinition(ExecutableDefinition root) {
+ void rewrite(RootNode root) {
+ if (root.isEmpty) return;
+
// Set all parent pointers.
new ParentVisitor().visit(root);
@@ -149,7 +152,7 @@
_TransformingVisitor(this.reachable, this.values, this.internalError);
- void transform(ExecutableDefinition root) {
+ void transform(RootNode root) {
visit(root);
}
@@ -346,7 +349,7 @@
new _AbstractValue<T>.unknown(typeSystem.dynamicType),
this.typeSystem = typeSystem;
- void analyze(ExecutableDefinition root) {
+ void analyze(RootNode root) {
reachableNodes.clear();
defWorkset.clear();
nodeWorklist.clear();
@@ -416,9 +419,7 @@
void visit(Node node) { node.accept(this); }
void visitFieldDefinition(FieldDefinition node) {
- if (node.hasInitializer) {
- setReachable(node.body);
- }
+ setReachable(node.body);
}
void visitFunctionDefinition(FunctionDefinition node) {
@@ -435,7 +436,7 @@
setReachable(node.body);
}
- void visitRunnableBody(RunnableBody node) {
+ void visitBody(Body node) {
setReachable(node.body);
}
@@ -746,7 +747,7 @@
void visitMutableVariable(MutableVariable node) {
// [MutableVariable]s are bound either as parameters to
// [FunctionDefinition]s, by [LetMutable], or by [DeclareFunction].
- if (node.parent is FunctionDefinition) {
+ if (node.parent is RootNode) {
// Just like immutable parameters, the values of mutable parameters are
// never constant.
// TODO(karlklose): remove reference to the element model.
@@ -768,14 +769,14 @@
// TODO(karlklose): remove reference to the element model.
T type = (source is ParameterElement) ? typeSystem.getParameterType(source)
: typeSystem.dynamicType;
- if (node.parent is FunctionDefinition) {
+ if (node.parent is RootNode) {
// Functions may escape and thus their parameters must be non-constant.
setValue(node, nonConst(type));
} else if (node.parent is Continuation) {
// Continuations on the other hand are local, and parameters can have
// some other abstract value than non-constant.
} else {
- internalError(node.hint, "Unexpected parent of Parameter");
+ internalError(node.hint, "Unexpected parent of Parameter: ${node.parent}");
}
}
@@ -852,6 +853,13 @@
// real constants of type [Type].
setValue(node, nonConst());
}
+
+ @override
+ visitTypeExpression(TypeExpression node) {
+ // TODO(karlklose): come up with a type marker for JS entities or switch to
+ // real constants of type [Type].
+ setValue(node, nonConst());
+ }
}
/// Represents the abstract value of a primitive value at some point in the
diff --git a/pkg/compiler/lib/src/dart2jslib.dart b/pkg/compiler/lib/src/dart2jslib.dart
index d52396c..2491ebc 100644
--- a/pkg/compiler/lib/src/dart2jslib.dart
+++ b/pkg/compiler/lib/src/dart2jslib.dart
@@ -46,6 +46,9 @@
import 'patch_parser.dart';
import 'resolution/class_members.dart' show MembersCreator;
import 'resolution/resolution.dart';
+import 'resolution/semantic_visitor.dart';
+import 'resolution/send_structure.dart';
+import 'resolution/operators.dart' as op;
import 'scanner/scannerlib.dart';
import 'ssa/ssa.dart';
import 'io/source_file.dart' show SourceFile;
@@ -65,7 +68,7 @@
isBinaryOperator,
isTernaryOperator,
isMinusOperator;
-export 'universe/universe.dart' show Selector, TypedSelector;
+export 'universe/universe.dart' show CallStructure, Selector, TypedSelector;
export 'util/util.dart'
show Spannable,
CURRENT_ELEMENT_SPANNABLE,
diff --git a/pkg/compiler/lib/src/dart_backend/backend.dart b/pkg/compiler/lib/src/dart_backend/backend.dart
index f2c6c71..409b61f 100644
--- a/pkg/compiler/lib/src/dart_backend/backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend.dart
@@ -131,12 +131,12 @@
void codegen(CodegenWorkItem work) { }
- static bool checkTreeIntegrity(tree_ir.ExecutableDefinition node) {
+ static bool checkTreeIntegrity(tree_ir.RootNode node) {
new CheckTreeIntegrity().check(node);
return true; // So this can be used from assert().
}
- static bool checkCpsIntegrity(cps_ir.ExecutableDefinition node) {
+ static bool checkCpsIntegrity(cps_ir.RootNode node) {
new CheckCpsIntegrity().check(node);
return true; // So this can be used from assert().
}
@@ -145,16 +145,16 @@
static ElementAst createElementAst(
ElementAstCreationContext context,
Element element,
- cps_ir.ExecutableDefinition cpsDefinition) {
+ cps_ir.RootNode cpsRoot) {
context.traceCompilation(element.name);
- context.traceGraph('CPS builder', cpsDefinition);
- assert(checkCpsIntegrity(cpsDefinition));
+ context.traceGraph('CPS builder', cpsRoot);
+ assert(checkCpsIntegrity(cpsRoot));
// Transformations on the CPS IR.
void applyCpsPass(cps_opt.Pass pass) {
- pass.rewrite(cpsDefinition);
- context.traceGraph(pass.passName, cpsDefinition);
- assert(checkCpsIntegrity(cpsDefinition));
+ pass.rewrite(cpsRoot);
+ context.traceGraph(pass.passName, cpsRoot);
+ assert(checkCpsIntegrity(cpsRoot));
}
// TODO(karlklose): enable type propagation for dart2dart when constant
@@ -168,37 +168,32 @@
applyCpsPass(new RedundantPhiEliminator());
applyCpsPass(new ShrinkingReducer());
- // Do not rewrite the IR after variable allocation. Allocation
- // makes decisions based on an approximation of IR variable live
- // ranges that can be invalidated by transforming the IR.
- new cps_ir.RegisterAllocator(context.internalError).visit(cpsDefinition);
-
tree_builder.Builder builder =
new tree_builder.Builder(context.internalError);
- tree_ir.ExecutableDefinition treeDefinition = builder.build(cpsDefinition);
- assert(treeDefinition != null);
- context.traceGraph('Tree builder', treeDefinition);
- assert(checkTreeIntegrity(treeDefinition));
+ tree_ir.RootNode treeRoot = builder.build(cpsRoot);
+ assert(treeRoot != null);
+ context.traceGraph('Tree builder', treeRoot);
+ assert(checkTreeIntegrity(treeRoot));
// Transformations on the Tree IR.
void applyTreePass(tree_opt.Pass pass) {
- pass.rewrite(treeDefinition);
- context.traceGraph(pass.passName, treeDefinition);
- assert(checkTreeIntegrity(treeDefinition));
+ pass.rewrite(treeRoot);
+ context.traceGraph(pass.passName, treeRoot);
+ assert(checkTreeIntegrity(treeRoot));
}
applyTreePass(new StatementRewriter());
- applyTreePass(new CopyPropagator());
+ applyTreePass(new VariableMerger());
applyTreePass(new LoopRewriter());
applyTreePass(new LogicalRewriter());
// Backend-specific transformations.
- new backend_ast_emitter.UnshadowParameters().unshadow(treeDefinition);
- context.traceGraph('Unshadow parameters', treeDefinition);
+ new backend_ast_emitter.UnshadowParameters().unshadow(treeRoot);
+ context.traceGraph('Unshadow parameters', treeRoot);
TreeElementMapping treeElements = new TreeElementMapping(element);
- backend_ast.ExecutableDefinition backendAst =
- backend_ast_emitter.emit(treeDefinition);
+ backend_ast.RootNode backendAst =
+ backend_ast_emitter.emit(treeRoot);
Node frontend_ast = backend2frontend.emit(treeElements, backendAst);
return new ElementAst(frontend_ast, treeElements);
@@ -225,9 +220,8 @@
return new ElementAst(element.resolvedAst.node,
element.resolvedAst.elements);
} else {
- cps_ir.ExecutableDefinition definition =
- compiler.irBuilder.getIr(element);
- return createElementAst(context, element, definition);
+ cps_ir.RootNode irNode = compiler.irBuilder.getIr(element);
+ return createElementAst(context, element, irNode);
}
}
diff --git a/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart b/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
index 1508259..4131146 100644
--- a/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
@@ -15,8 +15,8 @@
import '../tree/tree.dart' as tree show Modifiers;
/// Translates the dart_tree IR to Dart backend AST.
-ExecutableDefinition emit(tree.ExecutableDefinition definition) {
- return new ASTEmitter().emit(definition, new BuilderContext<Statement>());
+RootNode emit(tree.RootNode root) {
+ return new ASTEmitter().emit(root);
}
// TODO(johnniwinther): Split into function/block state.
@@ -203,29 +203,25 @@
Iterable<T> get statements => _statementBuffer;
}
-
/// Translates the dart_tree IR to Dart backend AST.
/// An instance of this class should only be used once; a fresh emitter
/// must be created for each function to be emitted.
class ASTEmitter
- extends tree.Visitor1<dynamic, Expression, BuilderContext<Statement>> {
+ extends tree.StatementVisitor1<dynamic, BuilderContext<Statement>>
+ with tree.ExpressionVisitor1<Expression, BuilderContext<Statement>>,
+ tree.RootVisitor1<RootNode, BuilderContext<Statement>>,
+ tree.InitializerVisitor1<Initializer, BuilderContext<Statement>> {
- ExecutableDefinition emit(tree.ExecutableDefinition definition,
- BuilderContext<Statement> context) {
- if (definition is tree.FieldDefinition) {
- return emitField(definition, context);
- } else if (definition is tree.ConstructorDefinition) {
- return emitConstructor(definition, context);
- }
- assert(definition is tree.FunctionDefinition);
- return emitFunction(definition, context);
+ RootNode emit(tree.RootNode node) {
+ return visitRootNode(node, new BuilderContext<Statement>());
}
- FieldDefinition emitField(tree.FieldDefinition definition,
- BuilderContext<Statement> context) {
+ @override
+ FieldDefinition visitFieldDefinition(tree.FieldDefinition definition,
+ BuilderContext<Statement> context) {
context.currentElement = definition.element;
Expression initializer;
- if (definition.hasInitializer) {
+ if (!definition.isEmpty) {
visitStatement(definition.body, context);
List<Statement> bodyParts;
for (tree.Variable variable in context.variableNames.keys) {
@@ -273,11 +269,14 @@
return false;
}
- FunctionExpression emitConstructor(tree.ConstructorDefinition definition,
- BuilderContext<Statement> context) {
+ @override
+ FunctionExpression visitConstructorDefinition(
+ tree.ConstructorDefinition definition,
+ BuilderContext<Statement> context) {
context.currentElement = definition.element;
- Parameters parameters = emitRootParameters(definition, context);
+ Parameters parameters = emitRootParameters(
+ definition, definition.defaultParameterValues, context);
// Declare parameters.
for (tree.Variable param in definition.parameters) {
@@ -286,13 +285,13 @@
context.declaredVariables.add(param);
}
- List<Expression> initializers;
+ List<Initializer> initializers;
Statement body;
- if (!definition.isAbstract) {
+ if (!definition.isEmpty) {
initializers =
definition.initializers.map((tree.Initializer initializer) {
- return visitExpression(initializer, context);
+ return visitInitializer(initializer, context);
}).toList();
context.firstStatement = definition.body;
@@ -344,11 +343,14 @@
..element = context.currentElement;
}
- FunctionExpression emitFunction(tree.FunctionDefinition definition,
- BuilderContext<Statement> context) {
+ @override
+ FunctionExpression visitFunctionDefinition(
+ tree.FunctionDefinition definition,
+ BuilderContext<Statement> context) {
context.currentElement = definition.element;
- Parameters parameters = emitRootParameters(definition, context);
+ Parameters parameters = emitRootParameters(
+ definition, definition.defaultParameterValues, context);
// Declare parameters.
for (tree.Variable param in definition.parameters) {
@@ -358,7 +360,7 @@
}
Statement body;
- if (definition.isAbstract) {
+ if (definition.isEmpty) {
body = new EmptyStatement();
} else {
context.firstStatement = definition.body;
@@ -414,7 +416,8 @@
/// Emits parameters that are not nested inside other parameters.
/// Root parameters can have default values, while inner parameters cannot.
- Parameters emitRootParameters(tree.FunctionDefinition function,
+ Parameters emitRootParameters(tree.RootNode function,
+ List<ConstantExpression> defaults,
BuilderContext<Statement> context) {
FunctionType functionType = function.element.type;
List<Parameter> required = TypeGenerator.createParameters(
@@ -427,7 +430,7 @@
? functionType.namedParameterTypes
: functionType.optionalParameterTypes,
context: context,
- defaultValues: function.defaultParameterValues,
+ defaultValues: defaults,
elements: function.parameters.skip(required.length)
.map((p) => p.element));
return new Parameters(required, optional, optionalParametersAreNamed);
@@ -519,7 +522,8 @@
// that may occur in expression context, but could not be inlined anywhere.
if (stmt.variable.element is FunctionElement &&
stmt.value is tree.FunctionExpression &&
- !context.declaredVariables.contains(stmt.variable)) {
+ !context.declaredVariables.contains(stmt.variable) &&
+ stmt.variable.writeCount == 1) {
tree.FunctionExpression functionExp = stmt.value;
FunctionExpression function =
makeSubFunction(functionExp.definition, context);
@@ -876,7 +880,8 @@
FunctionExpression makeSubFunction(tree.FunctionDefinition function,
BuilderContext<Statement> context) {
- return emit(function, new BuilderContext<Statement>.inner(context));
+ return visitFunctionDefinition(function,
+ new BuilderContext<Statement>.inner(context));
}
@override
@@ -920,14 +925,14 @@
}
@override
- Expression visitFieldInitializer(tree.FieldInitializer node,
+ Initializer visitFieldInitializer(tree.FieldInitializer node,
BuilderContext<Statement> context) {
return new FieldInitializer(node.element,
ensureExpression(buildInInitializerContext(node.body, context)));
}
@override
- Expression visitSuperInitializer(tree.SuperInitializer node,
+ Initializer visitSuperInitializer(tree.SuperInitializer node,
BuilderContext<Statement> context) {
List<Argument> arguments = node.arguments.map((tree.Statement argument) {
return ensureExpression(buildInInitializerContext(argument, context));
@@ -937,6 +942,11 @@
}
@override
+ Expression visitTypeExpression(tree.TypeExpression node, arg) {
+ throw '$node not supported by dart backend';
+ }
+
+ @override
visitGetField(tree.GetField node, arg) => errorUnsupportedNode(node);
@override
@@ -963,6 +973,7 @@
errorUnsupportedNode(tree.JsSpecificNode node) {
throw '$node not supported by dart backend';
}
+
}
class TypeGenerator {
@@ -1153,14 +1164,14 @@
}
@override
- Expression visitConstructed(ConstructedConstantExpresssion exp,
+ Expression visitConstructed(ConstructedConstantExpression exp,
BuilderContext<Statement> context) {
- int positionalArgumentCount = exp.selector.positionalArgumentCount;
+ int positionalArgumentCount = exp.callStructure.positionalArgumentCount;
List<Argument> args = new List<Argument>.generate(
positionalArgumentCount,
(i) => visit(exp.arguments[i], context));
- for (int i = 0; i < exp.selector.namedArgumentCount; ++i) {
- args.add(new NamedArgument(exp.selector.namedArguments[i],
+ for (int i = 0; i < exp.callStructure.namedArgumentCount; ++i) {
+ args.add(new NamedArgument(exp.callStructure.namedArguments[i],
visit(exp.arguments[positionalArgumentCount + i], context)));
}
@@ -1251,14 +1262,12 @@
/// Parameters that are used in a context where it is shadowed.
Set<tree.Variable> hasShadowedUse = new Set<tree.Variable>();
- void unshadow(tree.ExecutableDefinition definition) {
- // Fields have no parameters.
- if (definition is tree.FieldDefinition) return;
- visitFunctionDefinition(definition);
+ void unshadow(tree.RootNode definition) {
+ if (definition.isEmpty) return;
+ unshadowFunction(definition);
}
- visitFunctionDefinition(tree.FunctionDefinition definition) {
- if (definition.isAbstract) return;
+ void unshadowFunction(tree.RootNode definition) {
var oldShadow = shadowedParameters;
var oldEnvironment = environment;
environment = new Map<String, tree.Variable>.from(environment);
@@ -1270,7 +1279,7 @@
}
environment[param.element.name] = param;
}
- visitStatement(definition.body);
+ definition.forEachBody(visitStatement);
environment = oldEnvironment;
shadowedParameters = oldShadow;
@@ -1280,8 +1289,9 @@
tree.Variable newParam = new tree.Variable(definition.element,
param.element);
definition.parameters[i] = newParam;
- definition.body = new tree.Assign(param, new tree.VariableUse(newParam),
- definition.body);
+ definition.replaceEachBody((tree.Statement body) {
+ return new tree.Assign(param, new tree.VariableUse(newParam), body);
+ });
newParam.writeCount = 1; // Being a parameter counts as a write.
param.writeCount--; // Not a parameter anymore.
}
@@ -1289,6 +1299,11 @@
}
@override
+ void visitInnerFunction(tree.FunctionDefinition definition) {
+ unshadowFunction(definition);
+ }
+
+ @override
visitVariable(tree.Variable variable) {
if (shadowedParameters.contains(variable)) {
hasShadowedUse.add(variable);
diff --git a/pkg/compiler/lib/src/dart_backend/backend_ast_nodes.dart b/pkg/compiler/lib/src/dart_backend/backend_ast_nodes.dart
index ba21ccb..bc4867d 100644
--- a/pkg/compiler/lib/src/dart_backend/backend_ast_nodes.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend_ast_nodes.dart
@@ -26,11 +26,11 @@
bool get assignable => false;
}
-abstract class ExecutableDefinition extends Node {
+abstract class RootNode extends Node {
elements.Element get element;
}
-class FieldDefinition extends ExecutableDefinition {
+class FieldDefinition extends RootNode {
final elements.Element element;
final Expression initializer;
FieldDefinition(this.element, this.initializer);
@@ -322,7 +322,7 @@
SuperInitializer(this.target, this.arguments);
}
-class FunctionExpression extends Expression implements ExecutableDefinition {
+class FunctionExpression extends Expression implements RootNode {
final TypeAnnotation returnType;
String name;
final Parameters parameters;
diff --git a/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart b/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart
index 9bf9121..8e29ca0 100644
--- a/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart
@@ -16,8 +16,8 @@
/// Translates the backend AST to Dart frontend AST.
tree.Node emit(dart2js.TreeElementMapping treeElements,
- ExecutableDefinition definition) {
- return new TreePrinter(treeElements).makeDefinition(definition);
+ RootNode root) {
+ return new TreePrinter(treeElements).makeDefinition(root);
}
/// If true, the unparser will insert a coment in front of every function
@@ -32,7 +32,7 @@
TreePrinter([this.treeElements]);
- tree.Node makeDefinition(ExecutableDefinition node) {
+ tree.Node makeDefinition(RootNode node) {
if (node is FieldDefinition) {
tree.Node definition;
if (node.initializer == null) {
diff --git a/pkg/compiler/lib/src/dart_backend/dart_backend.dart b/pkg/compiler/lib/src/dart_backend/dart_backend.dart
index 2d73044..fbc3437 100644
--- a/pkg/compiler/lib/src/dart_backend/dart_backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/dart_backend.dart
@@ -20,8 +20,7 @@
import '../tree_ir/tree_ir_nodes.dart' as tree_ir;
import '../util/util.dart';
import '../mirror_renamer/mirror_renamer.dart';
-import '../tree_ir/optimization/optimization.dart'
- show LogicalRewriter, LoopRewriter, CopyPropagator, StatementRewriter;
+import '../tree_ir/optimization/optimization.dart';
import '../tree_ir/optimization/optimization.dart' as tree_opt;
import '../tree_ir/tree_ir_integrity.dart';
import '../cps_ir/cps_ir_integrity.dart';
diff --git a/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart b/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
index 9f9a2b8..4d47c14 100644
--- a/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
+++ b/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
@@ -37,7 +37,7 @@
DeclarationTypePlaceholder(this.typeNode, this.requiresVar);
}
-class SendVisitor extends ResolvedVisitor {
+class SendVisitor extends OldResolvedVisitor {
final PlaceholderCollector collector;
SendVisitor(this.collector, TreeElements elements)
@@ -100,7 +100,7 @@
}
}
- visitAssert(node) {
+ visitAssertSend(node) {
visitStaticSend(node);
}
@@ -134,7 +134,7 @@
}
}
- internalError(String reason, {Node node}) {
+ internalError(Spannable node, String reason) {
collector.internalError(reason, node: node);
}
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index 4a8af6e..b845ffc 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -980,6 +980,9 @@
abstract class MemberElement extends Element implements ExecutableElement {
/// The local functions defined within this member.
List<FunctionElement> get nestedClosures;
+
+ /// The name of this member taking privacy into account.
+ Name get memberName;
}
/// A function, variable or parameter defined in an executable context.
@@ -1223,6 +1226,9 @@
/// constructor so its immediate redirection target is `null`.
ConstructorElement get immediateRedirectionTarget;
+ /// Is `true` if this constructor is a redirecting generative constructor.
+ bool get isRedirectingGenerative;
+
/// Is `true` if this constructor is a redirecting factory constructor.
bool get isRedirectingFactory;
@@ -1250,8 +1256,8 @@
}
/// JavaScript backend specific element for the body of constructor.
-// TODO(johnniwinther): Remove this class for the element model.
-abstract class ConstructorBodyElement extends FunctionElement {
+// TODO(johnniwinther): Remove this class from the element model.
+abstract class ConstructorBodyElement extends MethodElement {
FunctionElement get constructor;
}
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index 68ee1a4..a8cea0a 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -168,6 +168,8 @@
LibraryElement get library => enclosingElement.library;
+ Name get memberName => new Name(name, library);
+
LibraryElement get implementationLibrary {
Element element = this;
while (!identical(element.kind, ElementKind.LIBRARY)) {
@@ -305,6 +307,7 @@
get executableContext => unsupported();
get isExternal => unsupported();
+ bool get isRedirectingGenerative => unsupported();
bool get isRedirectingFactory => unsupported();
computeSignature(compiler) => unsupported();
@@ -341,6 +344,12 @@
Element enclosing)
: super(messageKind, messageArguments, name, enclosing);
+ bool get isRedirectingGenerative => false;
+
+ void set isRedirectingGenerative(_) {
+ throw new UnsupportedError("isRedirectingGenerative");
+ }
+
bool get isRedirectingFactory => false;
get definingElement {
@@ -1912,6 +1921,7 @@
abstract class ConstructorElementX extends FunctionElementX
implements ConstructorElement {
+ bool isRedirectingGenerative = false;
ConstructorElementX(String name,
ElementKind kind,
diff --git a/pkg/compiler/lib/src/elements/names.dart b/pkg/compiler/lib/src/elements/names.dart
index 56f3bf1..38e0945 100644
--- a/pkg/compiler/lib/src/elements/names.dart
+++ b/pkg/compiler/lib/src/elements/names.dart
@@ -46,6 +46,8 @@
/// privacy into account.
bool isSimilarTo(Name other);
int get similarHashCode;
+
+ LibraryElement get library;
}
class PublicName implements Name {
@@ -72,6 +74,8 @@
bool isSimilarTo(Name other) =>
text == other.text && isSetter == other.isSetter;
int get similarHashCode => text.hashCode + 11 * isSetter.hashCode;
+
+ LibraryElement get library => null;
String toString() => isSetter ? '$text=' : text;
}
diff --git a/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart
index 46cd386..5247fe3 100644
--- a/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart
@@ -6,6 +6,7 @@
import 'dart:collection' show Queue, IterableBase;
import '../native/native.dart' as native;
+import '../closure.dart' show BoxFieldElement;
import '../dart2jslib.dart' hide Selector, TypedSelector;
import '../dart_types.dart' show DartType, TypeKind;
import '../elements/elements.dart';
@@ -1773,7 +1774,7 @@
*/
void ensureFieldInitialized(Element field) {
// This is test is needed for fitering out BoxFieldElements.
- if (field is FieldElement && inferredFieldTypes[field] == null) {
+ if (field is! BoxFieldElement && inferredFieldTypes[field] == null) {
analyzeFieldInitialization(field);
}
}
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
index 6743561..a969baa 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
@@ -655,7 +655,7 @@
}
abstract class InferrerVisitor
- <T, E extends MinimalInferrerEngine<T>> extends ResolvedVisitor<T> {
+ <T, E extends MinimalInferrerEngine<T>> extends NewResolvedVisitor<T> {
final Compiler compiler;
final AstElement analyzedElement;
final TypeSystem<T> types;
@@ -719,7 +719,7 @@
T visitFunctionExpression(FunctionExpression node);
- T visitAssert(Send node) {
+ T visitAssertSend(Send node) {
if (!compiler.enableUserAssertions) {
return types.nullType;
}
@@ -1229,7 +1229,7 @@
return null;
}
- void internalError(String reason, {Node node}) {
+ void internalError(Spannable node, String reason) {
compiler.internalError(node, reason);
}
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index e23b1cf..9ea66a2 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -880,9 +880,9 @@
@override
js.Expression visitConditional(js.Conditional node) {
if (!shouldTransform(node.then) && !shouldTransform(node.otherwise)) {
- return withExpression(node.condition, (js.Expression condition) {
- return js.js('# ? # : #', [condition, node.then, node.otherwise]);
- }, store: false);
+ return js.js('# ? # : #', [visitExpression(node.condition),
+ visitExpression(node.then),
+ visitExpression(node.otherwise)]);
}
int thenLabel = newLabel("then");
int joinLabel = newLabel("join");
@@ -969,10 +969,9 @@
if (!shouldTransform(node)) {
bool oldInsideUntranslatedBreakable = insideUntranslatedBreakable;
insideUntranslatedBreakable = true;
- withExpression(node.condition, (js.Expression condition) {
- addStatement(js.js.statement('do {#} while (#)',
- [node.body, condition]));
- }, store: false);
+ addStatement(js.js.statement('do {#} while (#)',
+ [translateInBlock(node.body),
+ visitExpression(node.condition)]));
insideUntranslatedBreakable = oldInsideUntranslatedBreakable;
return;
}
@@ -1348,7 +1347,8 @@
for (js.SwitchClause clause in node.cases) {
if (clause is js.Case) {
labels[i] = newLabel("case");
- clauses.add(new js.Case(clause.expression, gotoAndBreak(labels[i])));
+ clauses.add(new js.Case(visitExpression(clause.expression),
+ gotoAndBreak(labels[i])));
} else if (clause is js.Default) {
labels[i] = newLabel("default");
clauses.add(new js.Default(gotoAndBreak(labels[i])));
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 3559724..6d1ead5 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -1115,6 +1115,11 @@
rti.computeClassesNeedingRti();
}
+ onTypeInferenceComplete() {
+ super.onTypeInferenceComplete();
+ noSuchMethodRegistry.onTypeInferenceComplete();
+ }
+
void registerGetRuntimeTypeArgument(Registry registry) {
enqueueInResolution(getGetRuntimeTypeArgument(), registry);
enqueueInResolution(getGetTypeArgumentByIndex(), registry);
@@ -1216,7 +1221,7 @@
enqueueClass(compiler.enqueuer.resolution, compiler.stringClass, registry);
}
- void registerNoSuchMethod(Element noSuchMethod) {
+ void registerNoSuchMethod(FunctionElement noSuchMethod) {
noSuchMethodRegistry.registerNoSuchMethod(noSuchMethod);
}
@@ -1399,6 +1404,7 @@
int assembleProgram() {
int programSize = emitter.assembleProgram();
+ noSuchMethodRegistry.emitDiagnostic();
int totalMethodCount = generatedCode.length;
if (totalMethodCount != preMirrorsMethodCount) {
int mirrorCount = totalMethodCount - preMirrorsMethodCount;
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index f6c7e21..2fa219b 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -23,7 +23,8 @@
}
}
-class CodeGenerator extends tree_ir.Visitor<dynamic, js.Expression> {
+class CodeGenerator extends tree_ir.StatementVisitor
+ with tree_ir.ExpressionVisitor<js.Expression> {
final CodegenRegistry registry;
final Glue glue;
@@ -206,9 +207,10 @@
@override
js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) {
checkStaticTargetIsValid(node, node.target);
-
if (node.constant != null) return giveup(node);
- registry.registerInstantiatedClass(node.target.enclosingClass);
+
+ ClassElement instantiatedClass = node.target.enclosingClass;
+ registry.registerInstantiatedClass(instantiatedClass);
Selector selector = node.selector;
FunctionElement target = node.target;
List<js.Expression> arguments = visitArguments(node.arguments);
@@ -500,9 +502,24 @@
@override
js.Expression visitCreateInstance(tree_ir.CreateInstance node) {
- registry.registerInstantiatedClass(node.classElement);
- return new js.New(glue.constructorAccess(node.classElement),
- node.arguments.map(visitExpression).toList());
+ ClassElement cls = node.classElement;
+ registry.registerInstantiatedClass(cls);
+ js.Expression instance = new js.New(
+ glue.constructorAccess(cls),
+ node.arguments.map(visitExpression).toList());
+
+ List<tree_ir.Expression> typeInformation = node.typeInformation;
+ assert(typeInformation.isEmpty ||
+ typeInformation.length == cls.typeVariables.length);
+ if (typeInformation.isNotEmpty) {
+ FunctionElement helper = glue.getAddRuntimeTypeInformation();
+ js.Expression typeArguments = new js.ArrayInitializer(
+ typeInformation.map(visitExpression).toList());
+ return buildStaticHelperInvocation(helper,
+ <js.Expression>[instance, typeArguments]);
+ } else {
+ return instance;
+ }
}
@override
@@ -555,6 +572,12 @@
}
}
+ @override
+ js.Expression visitTypeExpression(tree_ir.TypeExpression node) {
+ List<js.Expression> arguments =
+ node.arguments.map(visitExpression).toList(growable: false);
+ return glue.generateTypeRepresentation(node.dartType, arguments);
+ }
// Dart-specific IR nodes
@@ -573,16 +596,6 @@
return errorUnsupportedNode(node);
}
- @override
- visitFieldInitializer(tree_ir.FieldInitializer node) {
- return errorUnsupportedNode(node);
- }
-
- @override
- visitSuperInitializer(tree_ir.SuperInitializer node) {
- return errorUnsupportedNode(node);
- }
-
errorUnsupportedNode(tree_ir.DartSpecificNode node) {
throw "Unsupported node in JS backend: $node";
}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/glue.dart b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
index 5dfd8de..642e136 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/glue.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
@@ -11,7 +11,7 @@
import '../../constants/values.dart';
import '../../elements/elements.dart';
import '../../constants/expressions.dart';
-import '../../dart_types.dart' show TypeVariableType;
+import '../../dart_types.dart' show DartType, TypeVariableType;
/// Encapsulates the dependencies of the function-compiler to the compiler,
/// backend and emitter.
@@ -154,4 +154,18 @@
return !_backend.rti.isTrivialSubstitution(subclass, cls);
});
}
+
+ FunctionElement getAddRuntimeTypeInformation() {
+ return _backend.getSetRuntimeTypeInfo();
+ }
+
+ js.Expression generateTypeRepresentation(DartType dartType,
+ List<js.Expression> arguments) {
+ int variableIndex = 0;
+ js.Expression representation = _backend.rti.getTypeRepresentation(
+ dartType,
+ (_) => arguments[variableIndex++]);
+ assert(variableIndex == arguments.length);
+ return representation;
+ }
}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/js_tree_builder.dart b/pkg/compiler/lib/src/js_backend/codegen/js_tree_builder.dart
index fcc772c..ecd3f59 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/js_tree_builder.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/js_tree_builder.dart
@@ -69,6 +69,7 @@
Expression visitCreateInstance(cps_ir.CreateInstance node) {
return new CreateInstance(
node.classElement,
- node.arguments.map(getVariableUse).toList());
+ node.arguments.map(getVariableUse).toList(growable: false),
+ node.typeInformation.map(getVariableUse).toList(growable: false));
}
}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index db85809..a4ef0d9 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -108,7 +108,11 @@
cps.FunctionDefinition cpsNode = irBuilderTask.buildNode(element);
if (cpsNode == null) {
- giveUp('unable to build cps definition of $element');
+ if (irBuilderTask.bailoutMessage == null) {
+ giveUp('unable to build cps definition of $element');
+ } else {
+ giveUp(irBuilderTask.bailoutMessage);
+ }
}
if (element.isInstanceMember && !element.isGenerativeConstructorBody) {
Selector selector = new Selector.fromElement(cpsNode.element);
@@ -156,7 +160,7 @@
}
}
- static bool checkCpsIntegrity(cps.ExecutableDefinition node) {
+ static bool checkCpsIntegrity(cps.RootNode node) {
new CheckCpsIntegrity().check(node);
return true; // So this can be used from assert().
}
@@ -179,10 +183,6 @@
applyCpsPass(new RedundantPhiEliminator());
applyCpsPass(new ShrinkingReducer());
- // Do not rewrite the IR after variable allocation. Allocation
- // makes decisions based on an approximation of IR variable live
- // ranges that can be invalidated by transforming the IR.
- new cps.RegisterAllocator(compiler.internalError).visit(cpsNode);
return cpsNode;
}
@@ -196,7 +196,7 @@
return treeNode;
}
- static bool checkTreeIntegrity(tree_ir.ExecutableDefinition node) {
+ static bool checkTreeIntegrity(tree_ir.RootNode node) {
new CheckTreeIntegrity().check(node);
return true; // So this can be used from assert().
}
@@ -209,7 +209,7 @@
}
applyTreePass(new StatementRewriter());
- applyTreePass(new CopyPropagator());
+ applyTreePass(new VariableMerger());
applyTreePass(new LoopRewriter());
applyTreePass(new LogicalRewriter());
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 1dd4fc1..af5ac3b 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -496,23 +496,27 @@
*
* The resulting name is a *proposed name* and is never minified.
*/
- String privateName(LibraryElement library, String originalName) {
+ String privateName(Name originalName) {
+ String text = originalName.text;
+
// Public names are easy.
- if (!isPrivateName(originalName)) return originalName;
+ if (!originalName.isPrivate) return text;
+
+ LibraryElement library = originalName.library;
// The first library asking for a short private name wins.
LibraryElement owner =
- shortPrivateNameOwners.putIfAbsent(originalName, () => library);
+ shortPrivateNameOwners.putIfAbsent(text, () => library);
if (owner == library) {
- return originalName;
+ return text;
} else {
// Make sure to return a private name that starts with _ so it
// cannot clash with any public names.
// The name is still not guaranteed to be unique, since both the library
// name and originalName could contain $ symbols.
String libraryName = _disambiguateGlobal(library);
- return '_$libraryName\$${originalName}';
+ return '_$libraryName\$${text}';
}
}
@@ -558,9 +562,9 @@
///
/// This is used for the annotated names of `call`, and for the proposed name
/// for other instance methods.
- List<String> callSuffixForSelector(Selector selector) {
- List<String> suffixes = ['${selector.argumentCount}'];
- suffixes.addAll(selector.getOrderedNamedArguments());
+ List<String> callSuffixForStructure(CallStructure callStructure) {
+ List<String> suffixes = ['${callStructure.argumentCount}'];
+ suffixes.addAll(callStructure.getOrderedNamedArguments());
return suffixes;
}
@@ -582,14 +586,13 @@
/// Annotated name for the member being invoked by [selector].
String invocationName(Selector selector) {
- LibraryElement library = selector.library;
switch (selector.kind) {
case SelectorKind.GETTER:
- String disambiguatedName = _disambiguateMember(library, selector.name);
+ String disambiguatedName = _disambiguateMember(selector.memberName);
return deriveGetterName(disambiguatedName);
case SelectorKind.SETTER:
- String disambiguatedName = _disambiguateMember(library, selector.name);
+ String disambiguatedName = _disambiguateMember(selector.memberName);
return deriveSetterName(disambiguatedName);
case SelectorKind.OPERATOR:
@@ -599,13 +602,13 @@
return disambiguatedName; // Operators are not annotated.
case SelectorKind.CALL:
- List<String> suffix = callSuffixForSelector(selector);
+ List<String> suffix = callSuffixForStructure(selector.callStructure);
if (selector.name == Compiler.CALL_OPERATOR_NAME) {
// Derive the annotated name for this variant of 'call'.
return deriveCallMethodName(suffix);
}
String disambiguatedName =
- _disambiguateMember(library, selector.name, suffix);
+ _disambiguateMember(selector.memberName, suffix);
return disambiguatedName; // Methods other than call are not annotated.
default:
@@ -625,9 +628,9 @@
* Returns the disambiguated name for the given field, used for constructing
* the getter and setter names.
*/
- String fieldAccessorName(Element element) {
+ String fieldAccessorName(FieldElement element) {
return element.isInstanceMember
- ? _disambiguateMember(element.library, element.name)
+ ? _disambiguateMember(element.memberName)
: _disambiguateGlobal(element);
}
@@ -635,7 +638,7 @@
* Returns name of the JavaScript property used to store a static or instance
* field.
*/
- String fieldPropertyName(Element element) {
+ String fieldPropertyName(FieldElement element) {
return element.isInstanceMember
? instanceFieldPropertyName(element)
: _disambiguateGlobal(element);
@@ -663,7 +666,7 @@
/**
* Returns the JavaScript property name used to store an instance field.
*/
- String instanceFieldPropertyName(Element element) {
+ String instanceFieldPropertyName(FieldElement element) {
ClassElement enclosingClass = element.enclosingClass;
if (element.hasFixedBackendName) {
@@ -703,7 +706,7 @@
// No superclass uses the disambiguated name as a property name, so we can
// use it for this field. This generates nicer field names since otherwise
// the field name would have to be mangled.
- return _disambiguateMember(element.library, element.name);
+ return _disambiguateMember(element.memberName);
}
bool _isShadowingSuperField(Element element) {
@@ -717,10 +720,10 @@
}
/// Annotated name for the setter of [element].
- String setterForElement(Element element) {
+ String setterForElement(MemberElement element) {
// We dynamically create setters from the field-name. The setter name must
// therefore be derived from the instance field-name.
- String name = _disambiguateMember(element.library, element.name);
+ String name = _disambiguateMember(element.memberName);
return deriveSetterName(name);
}
@@ -739,28 +742,19 @@
}
/// Annotated name for the getter of [element].
- String getterForElement(Element element) {
+ String getterForElement(MemberElement element) {
// We dynamically create getters from the field-name. The getter name must
// therefore be derived from the instance field-name.
- String name = _disambiguateMember(element.library, element.name);
+ String name = _disambiguateMember(element.memberName);
return deriveGetterName(name);
}
- /// Property name for the getter of an instance member with [originalName]
- /// in [library].
- ///
- /// [library] may be `null` if [originalName] is known to be public.
- String getterForMember(LibraryElement library, String originalName) {
- String disambiguatedName = _disambiguateMember(library, originalName);
+ /// Property name for the getter of an instance member with [originalName].
+ String getterForMember(Name originalName) {
+ String disambiguatedName = _disambiguateMember(originalName);
return deriveGetterName(disambiguatedName);
}
- /// Property name for the getter or a public instance member with
- /// [originalName].
- String getterForPublicMember(String originalName) {
- return getterForMember(null, originalName);
- }
-
/// Disambiguated name for a compiler-owned global variable.
///
/// The resulting name is unique within the global-member namespace.
@@ -822,23 +816,19 @@
/// The resulting name, and its associated annotated names, are unique
/// to the ([originalName], [suffixes]) pair within the instance-member
/// namespace.
- String _disambiguateMember(LibraryElement library,
- String originalName,
+ String _disambiguateMember(Name originalName,
[List<String> suffixes = const []]) {
- // For private names, a library must be given.
- assert(isPublicName(originalName) || library != null);
-
// Build a string encoding the library name, if the name is private.
- String libraryKey = isPrivateName(originalName)
- ? _disambiguateGlobal(library)
+ String libraryKey = originalName.isPrivate
+ ? _disambiguateGlobal(originalName.library)
: '';
// In the unique key, separate the name parts by '@'.
// This avoids clashes since the original names cannot contain that symbol.
- String key = '$libraryKey@$originalName@${suffixes.join('@')}';
+ String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}';
String newName = userInstanceMembers[key];
if (newName == null) {
- String proposedName = privateName(library, originalName);
+ String proposedName = privateName(originalName);
if (!suffixes.isEmpty) {
// In the proposed name, separate the name parts by '$', because the
// proposed name must be a valid identifier, but not necessarily unique.
diff --git a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
index 70a7936..547905d 100644
--- a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
+++ b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
@@ -42,10 +42,15 @@
/// The implementations that fall into category B, described above.
final Set<FunctionElement> throwingImpls = new Set<FunctionElement>();
/// The implementations that fall into category C, described above.
- final Set<Element> otherImpls = new Set<Element>();
+ final Set<FunctionElement> otherImpls = new Set<FunctionElement>();
+
+ /// The implementations that fall into category C1
+ final Set<FunctionElement> complexNoReturnImpls = new Set<FunctionElement>();
+ /// The implementations that fall into category C2
+ final Set<FunctionElement> complexReturningImpls = new Set<FunctionElement>();
/// The implementations that have not yet been categorized.
- final Set<Element> _uncategorizedImpls = new Set<Element>();
+ final Set<FunctionElement> _uncategorizedImpls = new Set<FunctionElement>();
final JavaScriptBackend _backend;
final Compiler _compiler;
@@ -57,7 +62,7 @@
bool get hasThrowingNoSuchMethod => throwingImpls.isNotEmpty;
bool get hasComplexNoSuchMethod => otherImpls.isNotEmpty;
- void registerNoSuchMethod(Element noSuchMethodElement) {
+ void registerNoSuchMethod(FunctionElement noSuchMethodElement) {
_uncategorizedImpls.add(noSuchMethodElement);
}
@@ -66,6 +71,35 @@
_uncategorizedImpls.clear();
}
+ /// Now that type inference is complete, split category C into two
+ /// subcategories: C1, those that have no return type, and C2, those
+ /// that have a return type.
+ void onTypeInferenceComplete() {
+ otherImpls.forEach(_subcategorizeOther);
+ }
+
+ /// Emits a diagnostic
+ void emitDiagnostic() {
+ throwingImpls.forEach((e) {
+ if (!_hasForwardingSyntax(e)) {
+ _compiler.reportHint(e,
+ MessageKind.DIRECTLY_THROWING_NSM);
+ }
+ });
+ complexNoReturnImpls.forEach((e) {
+ if (!_hasForwardingSyntax(e)) {
+ _compiler.reportHint(e,
+ MessageKind.COMPLEX_THROWING_NSM);
+ }
+ });
+ complexReturningImpls.forEach((e) {
+ if (!_hasForwardingSyntax(e)) {
+ _compiler.reportHint(e,
+ MessageKind.COMPLEX_RETURNING_NSM);
+ }
+ });
+ }
+
/// Returns [true] if the given element is a complex [noSuchMethod]
/// implementation. An implementation is complex if it falls into
/// category C, as described above.
@@ -74,54 +108,62 @@
return otherImpls.contains(element);
}
- NsmCategory _categorizeImpl(Element noSuchMethodElement) {
- assert(noSuchMethodElement.name == Compiler.NO_SUCH_METHOD);
- if (defaultImpls.contains(noSuchMethodElement)) {
+ _subcategorizeOther(FunctionElement element) {
+ TypeMask returnType =
+ _compiler.typesTask.getGuaranteedReturnTypeOfElement(element);
+ if (returnType == const TypeMask.nonNullEmpty()) {
+ complexNoReturnImpls.add(element);
+ } else {
+ complexReturningImpls.add(element);
+ }
+ }
+
+ NsmCategory _categorizeImpl(FunctionElement element) {
+ assert(element.name == Compiler.NO_SUCH_METHOD);
+ if (defaultImpls.contains(element)) {
return NsmCategory.DEFAULT;
}
- if (throwingImpls.contains(noSuchMethodElement)) {
+ if (throwingImpls.contains(element)) {
return NsmCategory.THROWING;
}
- if (otherImpls.contains(noSuchMethodElement)) {
+ if (otherImpls.contains(element)) {
return NsmCategory.OTHER;
}
- if (noSuchMethodElement is! FunctionElement ||
- !_compiler.noSuchMethodSelector.signatureApplies(noSuchMethodElement)) {
- otherImpls.add(noSuchMethodElement);
+ if (!_compiler.noSuchMethodSelector.signatureApplies(element)) {
+ otherImpls.add(element);
return NsmCategory.OTHER;
}
- FunctionElement noSuchMethodFunc = noSuchMethodElement as FunctionElement;
- if (_isDefaultNoSuchMethodImplementation(noSuchMethodFunc)) {
- defaultImpls.add(noSuchMethodFunc);
+ if (_isDefaultNoSuchMethodImplementation(element)) {
+ defaultImpls.add(element);
return NsmCategory.DEFAULT;
- } else if (_hasForwardingSyntax(noSuchMethodFunc)) {
+ } else if (_hasForwardingSyntax(element)) {
// If the implementation is 'noSuchMethod(x) => super.noSuchMethod(x);'
// then it is in the same category as the super call.
- Element superCall = noSuchMethodFunc.enclosingClass
+ Element superCall = element.enclosingClass
.lookupSuperSelector(_compiler.noSuchMethodSelector);
NsmCategory category = _categorizeImpl(superCall);
switch(category) {
case NsmCategory.DEFAULT:
- defaultImpls.add(noSuchMethodFunc);
+ defaultImpls.add(element);
break;
case NsmCategory.THROWING:
- throwingImpls.add(noSuchMethodFunc);
+ throwingImpls.add(element);
break;
case NsmCategory.OTHER:
- otherImpls.add(noSuchMethodFunc);
+ otherImpls.add(element);
break;
}
return category;
- } else if (_hasThrowingSyntax(noSuchMethodFunc)) {
- throwingImpls.add(noSuchMethodFunc);
+ } else if (_hasThrowingSyntax(element)) {
+ throwingImpls.add(element);
return NsmCategory.THROWING;
} else {
- otherImpls.add(noSuchMethodFunc);
+ otherImpls.add(element);
return NsmCategory.OTHER;
}
}
- bool _isDefaultNoSuchMethodImplementation(Element element) {
+ bool _isDefaultNoSuchMethodImplementation(FunctionElement element) {
ClassElement classElement = element.enclosingClass;
return classElement == _compiler.objectClass
|| classElement == _backend.jsInterceptorClass
diff --git a/pkg/compiler/lib/src/js_backend/type_variable_handler.dart b/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
index 18d7f67..bf9a5f2 100644
--- a/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
+++ b/pkg/compiler/lib/src/js_backend/type_variable_handler.dart
@@ -93,7 +93,7 @@
typeVariableElement.node,
typeVariableType,
typeVariableConstructor,
- new Selector.callConstructor('', null, 3),
+ const CallStructure.unnamed(3),
arguments,
arguments);
ConstantValue value = constant.value;
diff --git a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
index 8ff364d..aef381f 100644
--- a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
@@ -151,7 +151,7 @@
new List.generate(selector.argumentCount, (i) => '\$$i');
List<jsAst.Expression> argNames =
- selector.getOrderedNamedArguments().map((String name) =>
+ selector.callStructure.getOrderedNamedArguments().map((String name) =>
js.string(name)).toList();
String methodName = selector.invocationMirrorMemberName;
diff --git a/pkg/compiler/lib/src/js_emitter/js_emitter.dart b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
index 38c4cda..510933b 100644
--- a/pkg/compiler/lib/src/js_emitter/js_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
@@ -27,7 +27,8 @@
ElementKind,
FieldElement,
ParameterElement,
- TypeVariableElement;
+ TypeVariableElement,
+ MethodElement;
import '../hash/sha1.dart' show Hasher;
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart
index 41ddf84..cd1c967 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart
@@ -48,7 +48,7 @@
// We add a special getter here to allow for tearing off a closure from
// itself.
jsAst.Fun function = js('function() { return this; }');
- String name = namer.getterForPublicMember(Compiler.CALL_OPERATOR_NAME);
+ String name = namer.getterForMember(Selector.CALL_NAME);
builder.addProperty(name, function);
}
@@ -103,7 +103,7 @@
bool fieldsAdded = false;
for (Field field in fields) {
- VariableElement fieldElement = field.element;
+ FieldElement fieldElement = field.element;
String name = field.name;
String accessorName = field.accessorName;
bool needsGetter = field.needsGetter;
@@ -126,7 +126,7 @@
}
fieldMetadata.add(metadata);
recordMangledField(fieldElement, accessorName,
- namer.privateName(fieldElement.library, fieldElement.name));
+ namer.privateName(fieldElement.memberName));
String fieldName = name;
String fieldCode = '';
String reflectionMarker = '';
@@ -376,7 +376,7 @@
bool isInstantiated =
compiler.codegenWorld.directlyInstantiatedClasses.contains(element);
- void visitField(Element holder, VariableElement field) {
+ void visitField(Element holder, FieldElement field) {
assert(invariant(element, field.isDeclaration));
String name = field.name;
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/container_builder.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/container_builder.dart
index 4624980..394a1ca 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/container_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/old_emitter/container_builder.dart
@@ -11,7 +11,7 @@
class ContainerBuilder extends CodeEmitterHelper {
void addMemberMethod(DartMethod method, ClassBuilder builder) {
- FunctionElement member = method.element;
+ MethodElement member = method.element;
String name = method.name;
FunctionSignature parameters = member.functionSignature;
jsAst.Expression code = method.code;
@@ -163,15 +163,14 @@
'"new ${Elements.reconstructConstructorName(member)}"');
} else {
reflectionName =
- js.string(namer.privateName(member.library, member.name));
+ js.string(namer.privateName(member.memberName));
}
expressions
..add(reflectionName)
..addAll(task.metadataCollector
.computeMetadata(member).map(js.number));
} else if (isClosure && canBeApplied) {
- expressions.add(js.string(namer.privateName(member.library,
- member.name)));
+ expressions.add(js.string(namer.privateName(member.memberName)));
}
jsAst.ArrayInitializer arrayInit =
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
index 0a8e2d1..4b2d79c 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
@@ -337,8 +337,7 @@
}
String getReflectionNameInternal(elementOrSelector, String mangledName) {
- String name =
- namer.privateName(elementOrSelector.library, elementOrSelector.name);
+ String name = namer.privateName(elementOrSelector.memberName);
if (elementOrSelector.isGetter) return name;
if (elementOrSelector.isSetter) {
if (!mangledName.startsWith(namer.setterPrefix)) return '$name=';
@@ -361,15 +360,13 @@
if (elementOrSelector is Selector
|| elementOrSelector.isFunction
|| elementOrSelector.isConstructor) {
- int requiredParameterCount;
- int optionalParameterCount;
+ int positionalParameterCount;
String namedArguments = '';
bool isConstructor = false;
if (elementOrSelector is Selector) {
- Selector selector = elementOrSelector;
- requiredParameterCount = selector.argumentCount;
- optionalParameterCount = 0;
- namedArguments = namedParametersAsReflectionNames(selector);
+ CallStructure callStructure = elementOrSelector.callStructure;
+ positionalParameterCount = callStructure.positionalArgumentCount;
+ namedArguments = namedParametersAsReflectionNames(callStructure);
} else {
FunctionElement function = elementOrSelector;
if (function.isConstructor) {
@@ -377,34 +374,25 @@
name = Elements.reconstructConstructorName(function);
}
FunctionSignature signature = function.functionSignature;
- requiredParameterCount = signature.requiredParameterCount;
- optionalParameterCount = signature.optionalParameterCount;
+ positionalParameterCount = signature.requiredParameterCount;
if (signature.optionalParametersAreNamed) {
var names = [];
for (Element e in signature.optionalParameters) {
names.add(e.name);
}
- Selector selector = new Selector.call(
- function.name,
- function.library,
- requiredParameterCount,
- names);
- namedArguments = namedParametersAsReflectionNames(selector);
+ CallStructure callStructure =
+ new CallStructure(positionalParameterCount, names);
+ namedArguments = namedParametersAsReflectionNames(callStructure);
} else {
- // Named parameters are handled differently by mirrors. For unnamed
+ // Named parameters are handled differently by mirrors. For unnamed
// parameters, they are actually required if invoked
// reflectively. Also, if you have a method c(x) and c([x]) they both
// get the same mangled name, so they must have the same reflection
// name.
- requiredParameterCount += optionalParameterCount;
- optionalParameterCount = 0;
+ positionalParameterCount += signature.optionalParameterCount;
}
}
- String suffix =
- // TODO(ahe): We probably don't need optionalParameterCount in the
- // reflection name.
- '$name:$requiredParameterCount:$optionalParameterCount'
- '$namedArguments';
+ String suffix = '$name:$positionalParameterCount$namedArguments';
return (isConstructor) ? 'new $suffix' : suffix;
}
Element element = elementOrSelector;
@@ -421,9 +409,9 @@
'Do not know how to reflect on this $element.');
}
- String namedParametersAsReflectionNames(Selector selector) {
- if (selector.getOrderedNamedArguments().isEmpty) return '';
- String names = selector.getOrderedNamedArguments().join(':');
+ String namedParametersAsReflectionNames(CallStructure structure) {
+ if (structure.isUnnamed) return '';
+ String names = structure.getOrderedNamedArguments().join(':');
return ':$names';
}
@@ -528,19 +516,68 @@
handler.getLazilyInitializedFieldsForEmission();
if (!lazyFields.isEmpty) {
needsLazyInitializer = true;
- for (VariableElement element in Elements.sortedByPosition(lazyFields)) {
- jsAst.Expression init =
- buildLazilyInitializedStaticField(element, isolateProperties);
- if (init == null) continue;
- output.addBuffer(
- jsAst.prettyPrint(init, compiler, monitor: compiler.dumpInfoTask));
- output.add("$N");
- }
+ List<jsAst.Expression> laziesInfo = buildLaziesInfo(lazyFields);
+ jsAst.Statement code = js.statement('''
+ (function(lazies) {
+ if (#notInMinifiedMode) {
+ var descriptorLength = 4;
+ } else {
+ var descriptorLength = 3;
+ }
+
+ for (var i = 0; i < lazies.length; i += descriptorLength) {
+ var fieldName = lazies [i];
+ var getterName = lazies[i + 1];
+ var lazyValue = lazies[i + 2];
+ if (#notInMinifiedMode) {
+ var staticName = lazies[i + 3];
+ }
+
+ // We build the lazy-check here:
+ // lazyInitializer(fieldName, getterName, lazyValue, staticName);
+ // 'staticName' is used for error reporting in non-minified mode.
+ // 'lazyValue' must be a closure that constructs the initial value.
+ if (#notInMinifiedMode) {
+ #lazy(fieldName, getterName, lazyValue, staticName);
+ } else {
+ #lazy(fieldName, getterName, lazyValue);
+ }
+ }
+ })(#laziesInfo)
+ ''', {'notInMinifiedMode': !compiler.enableMinification,
+ 'laziesInfo': new jsAst.ArrayInitializer(laziesInfo),
+ 'lazy': js(lazyInitializerName)});
+
+ output.addBuffer(
+ jsAst.prettyPrint(code, compiler, monitor: compiler.dumpInfoTask));
+ output.add("$N");
}
}
+ List<jsAst.Expression> buildLaziesInfo(List<VariableElement> lazies) {
+ List<jsAst.Expression> laziesInfo = <jsAst.Expression>[];
+ for (VariableElement element in Elements.sortedByPosition(lazies)) {
+ jsAst.Expression code = backend.generatedCode[element];
+ // The code is null if we ended up not needing the lazily
+ // initialized field after all because of constant folding
+ // before code generation.
+ if (code == null) continue;
+ if (compiler.enableMinification) {
+ laziesInfo.addAll([js.string(namer.globalPropertyName(element)),
+ js.string(namer.lazyInitializerName(element)),
+ code]);
+ } else {
+ laziesInfo.addAll([js.string(namer.globalPropertyName(element)),
+ js.string(namer.lazyInitializerName(element)),
+ code,
+ js.string(element.name)]);
+ }
+ }
+ return laziesInfo;
+ }
+
jsAst.Expression buildLazilyInitializedStaticField(
- VariableElement element, String isolateProperties) {
+ VariableElement element, {String isolateProperties}) {
jsAst.Expression code = backend.generatedCode[element];
// The code is null if we ended up not needing the lazily
// initialized field after all because of constant folding
@@ -548,16 +585,35 @@
if (code == null) return null;
// The code only computes the initial value. We build the lazy-check
// here:
- // lazyInitializer(prototype, 'name', fieldName, getterName, initial);
+ // lazyInitializer(fieldName, getterName, initial, name, prototype);
// The name is used for error reporting. The 'initial' must be a
// closure that constructs the initial value.
- return js('#(#,#,#,#,#)',
- [js(lazyInitializerName),
- js(isolateProperties),
- js.string(element.name),
- js.string(namer.globalPropertyName(element)),
- js.string(namer.lazyInitializerName(element)),
- code]);
+ if (isolateProperties != null) {
+ // This is currently only used in incremental compilation to patch
+ // in new lazy values.
+ return js('#(#,#,#,#,#)',
+ [js(lazyInitializerName),
+ js.string(namer.globalPropertyName(element)),
+ js.string(namer.lazyInitializerName(element)),
+ code,
+ js.string(element.name),
+ isolateProperties]);
+ }
+
+ if (compiler.enableMinification) {
+ return js('#(#,#,#)',
+ [js(lazyInitializerName),
+ js.string(namer.globalPropertyName(element)),
+ js.string(namer.lazyInitializerName(element)),
+ code]);
+ } else {
+ return js('#(#,#,#,#)',
+ [js(lazyInitializerName),
+ js.string(namer.globalPropertyName(element)),
+ js.string(namer.lazyInitializerName(element)),
+ code,
+ js.string(element.name)]);
+ }
}
void emitMetadata(Program program, CodeOutput output) {
@@ -674,7 +730,6 @@
}
void emitInitFunction(CodeOutput output) {
- String isolate = namer.currentIsolate;
jsAst.Expression allClassesAccess =
generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES);
jsAst.Expression getTypeFromNameAccess =
@@ -700,37 +755,46 @@
#finishedClasses = Object.create(null);
if (#needsLazyInitializer) {
- $lazyInitializerName = function (prototype, staticName, fieldName,
- getterName, lazyValue) {
+ // [staticName] is only provided in non-minified mode. If missing, we
+ // fall back to [fieldName]. Likewise, [prototype] is optional and
+ // defaults to the isolateProperties object.
+ $lazyInitializerName = function (fieldName, getterName, lazyValue,
+ staticName, prototype) {
if (!#lazies) #lazies = Object.create(null);
#lazies[fieldName] = getterName;
+ // 'prototype' will be undefined except if we are doing an update
+ // during incremental compilation. In this case we put the lazy
+ // field directly on the isolate instead of the isolateProperties.
+ prototype = prototype || $isolateProperties;
var sentinelUndefined = {};
var sentinelInProgress = {};
prototype[fieldName] = sentinelUndefined;
prototype[getterName] = function () {
- var result = $isolate[fieldName];
+ var result = this[fieldName];
try {
if (result === sentinelUndefined) {
- $isolate[fieldName] = sentinelInProgress;
+ this[fieldName] = sentinelInProgress;
try {
- result = $isolate[fieldName] = lazyValue();
+ result = this[fieldName] = lazyValue();
} finally {
// Use try-finally, not try-catch/throw as it destroys the
// stack trace.
if (result === sentinelUndefined)
- $isolate[fieldName] = null;
+ this[fieldName] = null;
}
} else {
if (result === sentinelInProgress)
- #cyclicThrow(staticName);
+ // In minified mode, static name is not provided, so fall
+ // back to the minified fieldName.
+ #cyclicThrow(staticName || fieldName);
}
return result;
} finally {
- $isolate[getterName] = function() { return this[fieldName]; };
+ this[getterName] = function() { return this[fieldName]; };
}
}
}
@@ -809,20 +873,6 @@
}
}
- String get markerFun => 'markerFun';
-
- void emitMarkerFun(CodeOutput output) {
- jsAst.Statement markerFunStmt = js.statement('''
- // This function is used to mark the end of the inheritance chain so that
- // finishAddStubsHelper knows where to stop searching for deferred work.
- // We have to put it at the top level so that we only get one instance of
- // it even if we call parseReflectionData multiple times, e.g., due to
- // deferred loading.
- function #() {}''', markerFun);
- output.addBuffer(jsAst.prettyPrint(markerFunStmt, compiler));
- output.add(N);
- }
-
void emitConvertToFastObjectFunction(CodeOutput output) {
List<jsAst.Statement> debugCode = <jsAst.Statement>[];
if (DEBUG_FAST_OBJECTS) {
@@ -1266,6 +1316,9 @@
// constants to be set up.
emitStaticNonFinalFieldInitializations(mainOutput, mainOutputUnit);
interceptorEmitter.emitTypeToInterceptorMap(program, mainOutput);
+ if (compiler.enableMinification) {
+ mainOutput.add(';');
+ }
emitLazilyInitializedStaticFields(mainOutput);
mainOutput.add('\n');
@@ -1283,7 +1336,6 @@
emitConvertToFastObjectFunction(mainOutput);
emitConvertToSlowObjectFunction(mainOutput);
- emitMarkerFun(mainOutput);
for (String globalObject in Namer.reservedGlobalObjectNames) {
mainOutput.add('$globalObject = convertToFastObject($globalObject)$N');
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/nsm_emitter.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/nsm_emitter.dart
index 5f955f3..86ff20a 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/nsm_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/old_emitter/nsm_emitter.dart
@@ -42,8 +42,8 @@
}
List<jsAst.Expression> argNames =
- selector.getOrderedNamedArguments().map((String name) =>
- js.string(name)).toList();
+ selector.callStructure.getOrderedNamedArguments().map((String name) =>
+ js.string(name)).toList();
int type = selector.invocationMirrorKind;
if (!haveVeryFewNoSuchMemberHandlers &&
isTrivialNsmHandler(type, argNames, selector, jsName) &&
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/setup_program_builder.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/setup_program_builder.dart
index 86fdcd8..906afab 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/setup_program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/old_emitter/setup_program_builder.dart
@@ -123,7 +123,6 @@
'isTreeShakingDisabled': backend.isTreeShakingDisabled,
'precompiled': precompiledAccess,
'finishedClassesAccess': finishedClassesAccess,
- 'markerFun': emitter.markerFun,
'needsMixinSupport': emitter.needsMixinSupport,
'needsNativeSupport': program.needsNativeSupport,
'isInterceptorClass': namer.operatorIs(backend.jsInterceptorClass),
@@ -405,7 +404,7 @@
var prototype = constructor.prototype;
prototype.constructor = constructor;
prototype.#isObject = constructor;
- prototype.#deferredAction = #markerFun;
+ prototype.#deferredAction = function() {};
return;
}
finishClass(superclass);
@@ -418,21 +417,26 @@
var constructor = allClasses[cls];
var prototype = inheritFrom(constructor, superConstructor);
+ if (#needsMixinSupport) {
+ if (mixinPrototype) {
+ prototype.#deferredAction
+ = mixinDeferredActionHelper(mixinPrototype, prototype);
+ }
+ }
+
if (#needsNativeSupport) {
if (Object.prototype.hasOwnProperty.call(prototype, #specProperty)) {
#nativeInfoHandler;
// As native classes can come into existence without a constructor
// call, we have to ensure that the class has been fully
// initialized.
- if (constructor.prototype.#deferredAction)
- finishAddStubsHelper(constructor.prototype);
+ prototype.#deferredAction();
}
}
// Interceptors (or rather their prototypes) are also used without
// first instantiating them first.
- if (prototype.#isInterceptorClass &&
- constructor.prototype.#deferredAction) {
- finishAddStubsHelper(constructor.prototype);
+ if (prototype.#isInterceptorClass) {
+ prototype.#deferredAction();
}
}
@@ -442,39 +446,70 @@
for (var i = 0; i < properties.length; i++) finishClass(properties[i]);
}
-
- // For convenience, this method can be called with a prototype as argument
- // or, if it was bound to an object, by invoking it as a method. Therefore,
- // if prototype is undefined, this is used as prototype.
- function finishAddStubsHelper(prototype) {
- var prototype = prototype || this;
- var object;
- while (prototype.#deferredAction != #markerFun) {
- if (prototype.hasOwnProperty(#deferredActionString)) {
- delete prototype.#deferredAction; // Intended to make it slow, too.
- var properties = Object.keys(prototype);
- for (var index = 0; index < properties.length; index++) {
- var property = properties[index];
- var firstChar = property.charCodeAt(0);
- var elem;
- // We have to filter out some special properties that are used for
- // metadata in descriptors. Currently, we filter everything that
- // starts with + or *. This has to stay in sync with the special
- // properties that are used by processClassData below.
- if (property !== "${namer.classDescriptorProperty}" &&
- property !== "$reflectableField" &&
- firstChar !== 43 && // 43 is aka "+".
- firstChar !== 42 && // 42 is aka "*"
- (elem = prototype[property]) != null &&
- elem.constructor === Array &&
- property !== "<>") {
- addStubs(prototype, elem, property, false, []);
- }
- }
- convertToFastObject(prototype);
- }
+ // Generic handler for deferred class setup. The handler updates the
+ // prototype that it is installed on (it traverses the prototype chain
+ // of [this] to find itself) and then removes itself. It recurses by
+ // calling deferred handling again, which terminates on Object due to
+ // the final handler.
+ function finishAddStubsHelper() {
+ var prototype = this;
+ // Find the actual prototype that this handler is installed on.
+ while (!prototype.hasOwnProperty(#deferredActionString)) {
prototype = prototype.__proto__;
}
+ delete prototype.#deferredAction; // Intended to make it slow, too.
+ var properties = Object.keys(prototype);
+ for (var index = 0; index < properties.length; index++) {
+ var property = properties[index];
+ var firstChar = property.charCodeAt(0);
+ var elem;
+ // We have to filter out some special properties that are used for
+ // metadata in descriptors. Currently, we filter everything that
+ // starts with + or *. This has to stay in sync with the special
+ // properties that are used by processClassData below.
+ if (property !== "${namer.classDescriptorProperty}" &&
+ property !== "$reflectableField" &&
+ firstChar !== 43 && // 43 is aka "+".
+ firstChar !== 42 && // 42 is aka "*"
+ (elem = prototype[property]) != null &&
+ elem.constructor === Array &&
+ property !== "<>") {
+ addStubs(prototype, elem, property, false, []);
+ }
+ }
+ convertToFastObject(prototype);
+ prototype = prototype.__proto__;
+ // Call other handlers.
+ prototype.#deferredAction();
+ }
+
+ if (#needsMixinSupport) {
+ // Returns a deferred class setup handler that first invokes the
+ // handler on [mixinPrototype] and then resumes handling on
+ // [targetPrototype]. If [targetPrototype] already has a handler
+ // installed, the handler is preserved in the generated closure and
+ // thus can be safely overwritten.
+ function mixinDeferredActionHelper(mixinPrototype, targetPrototype) {
+ var chain;
+ if (targetPrototype.hasOwnProperty(#deferredActionString)) {
+ chain = targetPrototype.#deferredAction;
+ }
+ return function foo() {
+ var prototype = this;
+ // Find the actual prototype that this handler is installed on.
+ while (!prototype.hasOwnProperty(#deferredActionString)) {
+ prototype = prototype.__proto__;
+ }
+ if (chain) {
+ prototype.#deferredAction = chain;
+ } else {
+ delete prototype.#deferredAction;
+ convertToFastObject(prototype);
+ }
+ mixinPrototype.#deferredAction();
+ prototype.#deferredAction();
+ }
+ }
}
function processClassData(cls, descriptor, processedClasses) {
@@ -683,8 +718,10 @@
if (#usesMangledNames) {
var isReflectable = array.length > unmangledNameIndex;
if (isReflectable) {
- for (var i = 0; i < funcs.length; i++) {
- funcs[i].$reflectableField = 1;
+ funcs[0].$reflectableField = 1;
+ funcs[0].$reflectionInfoField = array;
+ for (var i = 1; i < funcs.length; i++) {
+ funcs[i].$reflectableField = 2;
funcs[i].$reflectionInfoField = array;
}
var mangledNames = isStatic ? #mangledGlobalNames : #mangledNames;
@@ -697,8 +734,8 @@
if (isSetter) {
reflectionName += "=";
} else if (!isGetter) {
- reflectionName += ":" + requiredParameterCount +
- ":" + optionalParameterCount;
+ reflectionName += ":" +
+ (requiredParameterCount + optionalParameterCount);
}
mangledNames[name] = reflectionName;
funcs[0].$reflectionNameField = reflectionName;
diff --git a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
index 9009784..7d5122b 100644
--- a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
@@ -38,21 +38,22 @@
ParameterStubMethod generateParameterStub(FunctionElement member,
Selector selector,
Selector callSelector) {
+ CallStructure callStructure = selector.callStructure;
FunctionSignature parameters = member.functionSignature;
- int positionalArgumentCount = selector.positionalArgumentCount;
+ int positionalArgumentCount = callStructure.positionalArgumentCount;
if (positionalArgumentCount == parameters.parameterCount) {
- assert(selector.namedArgumentCount == 0);
+ assert(callStructure.isUnnamed);
return null;
}
- if (parameters.optionalParametersAreNamed
- && selector.namedArgumentCount == parameters.optionalParameterCount) {
+ if (parameters.optionalParametersAreNamed &&
+ callStructure.namedArgumentCount == parameters.optionalParameterCount) {
// If the selector has the same number of named arguments as the element,
// we don't need to add a stub. The call site will hit the method
// directly.
return null;
}
JavaScriptConstantCompiler handler = backend.constants;
- List<String> names = selector.getOrderedNamedArguments();
+ List<String> names = callStructure.getOrderedNamedArguments();
bool isInterceptedMethod = backend.isInterceptedMethod(member);
@@ -186,8 +187,8 @@
// (1) foo$2(a, b) => MyClass.foo$4$c$d.call(this, a, b, null, null)
// (2) foo$3$c(a, b, c) => MyClass.foo$4$c$d(this, a, b, c, null);
// (3) foo$3$d(a, b, d) => MyClass.foo$4$c$d(this, a, b, null, d);
- List<ParameterStubMethod> generateParameterStubs(FunctionElement member,
- {bool canTearOff: true}) {
+ List<ParameterStubMethod> generateParameterStubs(MethodElement member,
+ {bool canTearOff: true}) {
if (member.enclosingElement.isClosure) {
ClosureClassElement cls = member.enclosingElement;
if (cls.supertype.element == backend.boundClosureClass) {
@@ -243,9 +244,10 @@
// Start with the callSelectors since they imply the generation of the
// non-call version.
for (Selector selector in callSelectors) {
- Selector renamedSelector = new Selector.call(
- member.name, member.library,
- selector.argumentCount, selector.namedArguments);
+ Selector renamedSelector = new Selector(
+ SelectorKind.CALL,
+ member.memberName,
+ selector.callStructure);
renamedCallSelectors.add(renamedSelector);
if (!renamedSelector.appliesUnnamed(member, compiler.world)) continue;
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder.dart
index 829ad37..b2cb77f 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder.dart
@@ -24,7 +24,7 @@
RuntimeTypeGenerator,
TypeTestProperties;
-import '../elements/elements.dart' show ParameterElement;
+import '../elements/elements.dart' show ParameterElement, MethodElement;
import '../universe/universe.dart' show Universe;
import '../deferred_load.dart' show DeferredLoadTask, OutputUnit;
@@ -371,7 +371,7 @@
if (element == backend.closureClass) {
// We add a special getter here to allow for tearing off a closure from
// itself.
- String name = namer.getterForPublicMember(Compiler.CALL_OPERATOR_NAME);
+ String name = namer.getterForMember(Selector.CALL_NAME);
js.Fun function = js.js('function() { return this; }');
callStubs.add(_buildStubMethod(name, function));
}
@@ -485,7 +485,7 @@
return optionalParameterDefaultValues;
}
- DartMethod _buildMethod(FunctionElement element) {
+ DartMethod _buildMethod(MethodElement element) {
String name = namer.methodPropertyName(element);
js.Expression code = backend.generatedCode[element];
@@ -578,7 +578,7 @@
}
}
- List<ParameterStubMethod> _generateParameterStubs(FunctionElement element,
+ List<ParameterStubMethod> _generateParameterStubs(MethodElement element,
bool canTearOff) {
if (!_methodNeedsStubs(element)) return const <ParameterStubMethod>[];
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index 0d3ca81..3898e7d 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -6,13 +6,36 @@
/// This class is a temporary work-around until we get a more powerful DartType.
class SpecialType {
-final String name;
-const SpecialType._(this.name);
+ final String name;
+ const SpecialType._(this.name);
-/// The type Object, but no subtypes:
-static const JsObject = const SpecialType._('=Object');
+ /// The type Object, but no subtypes:
+ static const JsObject = const SpecialType._('=Object');
-int get hashCode => name.hashCode;
+ int get hashCode => name.hashCode;
+}
+
+/// Description of the exception behaviour of native code.
+///
+/// TODO(sra): Replace with something that better supports specialization on
+/// first argument properties.
+class NativeThrowBehavior {
+ static const NativeThrowBehavior NEVER = const NativeThrowBehavior._(0);
+ static const NativeThrowBehavior MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS =
+ const NativeThrowBehavior._(1);
+ static const NativeThrowBehavior MAY = const NativeThrowBehavior._(2);
+ static const NativeThrowBehavior MUST = const NativeThrowBehavior._(3);
+
+ final int _bits;
+ const NativeThrowBehavior._(this._bits);
+
+ String toString() {
+ if (this == NEVER) return 'never';
+ if (this == MAY) return 'may';
+ if (this == MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS) return 'null(1)';
+ if (this == MUST) return 'must';
+ return 'NativeThrowBehavior($_bits)';
+ }
}
/**
@@ -59,6 +82,23 @@
final SideEffects sideEffects = new SideEffects.empty();
+ NativeThrowBehavior throwBehavior = NativeThrowBehavior.MAY;
+
+ bool isAllocation = false;
+ bool useGvn = false;
+
+ String toString() {
+ return 'NativeBehavior('
+ 'returns: ${typesReturned}, '
+ 'creates: ${typesInstantiated}, '
+ 'sideEffects: ${sideEffects}, '
+ 'throws: ${throwBehavior}'
+ '${isAllocation ? ", isAllocation" : ""}'
+ '${useGvn ? ", useGvn" : ""}'
+ ')';
+ }
+
+
/// Processes the type specification string of a call to JS and stores the
/// result in the [typesReturned] and [typesInstantiated]. It furthermore
/// computes the side effects, and, if given, invokes [setSideEffects] with
@@ -66,19 +106,27 @@
/// the [setSideEffects] method is not invoked.
///
/// Two forms of the string is supported:
+ ///
/// 1) A single type string of the form 'void', '', 'var' or 'T1|...|Tn'
/// which defines the types returned and for the later form also created by
/// the call to JS.
- /// 2) A sequence of the form
- /// '<type-tag>:<type-string>;<effect-tag>:<effect-string>'
- /// where <type-tag> is either 'returns' or 'creates' and where
- /// <type-string> is a type string like in 1). The type string marked by
- /// 'returns' defines the types returned and 'creates' defines the types
- /// created by the call to JS.
///
- /// The <effect-tag> is either 'effects' or 'depends' and
- /// <effect-string> is either 'all', 'none' or a comma-separated list of
- /// 'no-index', 'no-instance', 'no-static'.
+ /// 2) A sequence of <tag>:<value> pairs of the following kinds
+ ///
+ /// <type-tag>:<type-string>
+ /// <effect-tag>:<effect-string>
+ /// throws:<throws-string>
+ /// gvn:<gvn-string>
+ /// new:<new-string>
+ ///
+ /// A <type-tag> is either 'returns' or 'creates' and <type-string> is a
+ /// type string like in 1). The type string marked by 'returns' defines the
+ /// types returned and 'creates' defines the types created by the call to
+ /// JS.
+ ///
+ /// An <effect-tag> is either 'effects' or 'depends' and <effect-string> is
+ /// either 'all', 'none' or a comma-separated list of 'no-index',
+ /// 'no-instance', 'no-static'.
///
/// The flag 'all' indicates that the call affects/depends on every
/// side-effect. The flag 'none' indicates that the call does not affect
@@ -91,6 +139,20 @@
/// indicated with 'no-static'. The flags 'effects' and 'depends' must be
/// used in unison (either both are present or none is).
///
+ /// The <throws-string> values are 'never', 'may', 'must', and 'null(1)'.
+ /// The default if unspecified is 'may'. 'null(1)' means that the template
+ /// expression throws if and only if the first template parameter is `null`
+ /// or `undefined`.
+ /// TODO(sra): Can we simplify to must/may/never and add null(1) by
+ /// inspection as an orthogonal attribute?
+ ///
+ /// <gvn-string> values are 'true' and 'false'. The default if unspecified
+ /// is 'false'.
+ ///
+ /// <new-string> values are 'true' and 'false'. The default if unspecified
+ /// is 'false'. A 'true' value means that each evaluation returns a fresh
+ /// (new) object that cannot be unaliased with existing objects.
+ ///
/// Each tag kind (including the 'type-tag's) can only occur once in the
/// sequence.
///
@@ -99,20 +161,37 @@
/// the types defined by the specification string, and [objectType] and
/// [nullType] define the types for `Object` and `Null`, respectively. The
/// latter is used for the type strings of the form '' and 'var'.
- // TODO(johnniwinther): Use ';' as a separator instead of a terminator.
+ /// [validTags] can be used to restrict which tags are accepted.
static void processSpecString(
DiagnosticListener listener,
Spannable spannable,
String specString,
- {void setSideEffects(SideEffects newEffects),
+ {Iterable<String> validTags,
+ void setSideEffects(SideEffects newEffects),
+ void setThrows(NativeThrowBehavior throwKind),
+ void setIsAllocation(bool isAllocation),
+ void setUseGvn(bool useGvn),
dynamic resolveType(String typeString),
- List typesReturned, List typesInstantiated,
+ List typesReturned,
+ List typesInstantiated,
objectType, nullType}) {
+
+ bool seenError = false;
+
+ void reportError(String message) {
+ seenError = true;
+ listener.reportError(spannable, MessageKind.GENERIC, {'text': message});
+ }
+
+ const List<String> knownTags = const [
+ 'creates', 'returns', 'depends', 'effects',
+ 'throws', 'gvn', 'new'];
+
/// Resolve a type string of one of the three forms:
/// * 'void' - in which case [onVoid] is called,
/// * '' or 'var' - in which case [onVar] is called,
- /// * 'T1|...|Tn' - in which case [onType] is called for each Ti.
+ /// * 'T1|...|Tn' - in which case [onType] is called for each resolved Ti.
void resolveTypesString(String typesString,
{onVoid(), onVar(), onType(type)}) {
// Various things that are not in fact types.
@@ -129,131 +208,186 @@
return;
}
for (final typeString in typesString.split('|')) {
- onType(resolveType(typeString));
+ onType(resolveType(typeString.trim()));
}
}
-
- if (specString.contains(':')) {
- /// Find and remove a substring of the form 'tag:<string>;' from
- /// [specString].
- String getTagString(String tag) {
- String marker = '$tag:';
- int startPos = specString.indexOf(marker);
- if (startPos == -1) return null;
- int endPos = specString.indexOf(';', startPos);
- if (endPos == -1) return null;
- String typeString =
- specString.substring(startPos + marker.length, endPos);
- specString = '${specString.substring(0, startPos)}'
- '${specString.substring(endPos + 1)}'.trim();
- return typeString;
- }
-
- String returns = getTagString('returns');
- if (returns != null) {
- resolveTypesString(returns, onVar: () {
- typesReturned.add(objectType);
- typesReturned.add(nullType);
- }, onType: (type) {
- typesReturned.add(type);
- });
- }
-
- String creates = getTagString('creates');
- if (creates != null) {
- resolveTypesString(creates, onVoid: () {
- listener.internalError(spannable,
- "Invalid type string 'creates:$creates'");
- }, onVar: () {
- listener.internalError(spannable,
- "Invalid type string 'creates:$creates'");
- }, onType: (type) {
- typesInstantiated.add(type);
- });
- }
-
- String effects = getTagString('effects');
- String depends = getTagString('depends');
- if (effects != null && depends == null ||
- effects == null && depends != null) {
- listener.internalError(spannable,
- "Invalid JS spec string. "
- "'effects' and 'depends' must occur together.");
- }
-
- if (effects != null) {
- SideEffects sideEffects = new SideEffects();
- if (effects == "none") {
- sideEffects.clearAllSideEffects();
- } else if (effects == "all") {
- // Don't do anything.
- } else {
- List<String> splitEffects = effects.split(",");
- if (splitEffects.isEmpty) {
- listener.internalError(spannable, "Missing side-effect flag.");
- }
- for (String effect in splitEffects) {
- switch (effect) {
- case "no-index":
- sideEffects.clearChangesIndex();
- break;
- case "no-instance":
- sideEffects.clearChangesInstanceProperty();
- break;
- case "no-static":
- sideEffects.clearChangesStaticProperty();
- break;
- default:
- listener.internalError(spannable,
- "Unrecognized side-effect flag: $effect.");
- }
- }
- }
-
- if (depends == "none") {
- sideEffects.clearAllDependencies();
- } else if (depends == "all") {
- // Don't do anything.
- } else {
- List<String> splitDependencies = depends.split(",");
- if (splitDependencies.isEmpty) {
- listener.internalError(spannable,
- "Missing side-effect dependency flag.");
- }
- for (String dependency in splitDependencies) {
- switch (dependency) {
- case "no-index":
- sideEffects.clearDependsOnIndexStore();
- break;
- case "no-instance":
- sideEffects.clearDependsOnInstancePropertyStore();
- break;
- case "no-static":
- sideEffects.clearDependsOnStaticPropertyStore();
- break;
- default:
- listener.internalError(spannable,
- "Unrecognized side-effect flag: $dependency.");
- }
- }
- }
-
- setSideEffects(sideEffects);
- }
-
- if (!specString.isEmpty) {
- listener.internalError(spannable, "Invalid JS spec string.");
- }
- } else {
- resolveTypesString(specString, onVar: () {
+ if (!specString.contains(';') && !specString.contains(':')) {
+ // Form (1), types or pseudo-types like 'void' and 'var'.
+ resolveTypesString(specString.trim(), onVar: () {
typesReturned.add(objectType);
typesReturned.add(nullType);
}, onType: (type) {
typesInstantiated.add(type);
typesReturned.add(type);
});
+ return;
}
+
+ List<String> specs = specString.split(';')
+ .map((s) => s.trim())
+ .toList();
+ if (specs.last == "") specs.removeLast(); // Allow separator to terminate.
+
+ assert(validTags == null ||
+ (validTags.toSet()..removeAll(validTags)).isEmpty);
+ if (validTags == null) validTags = knownTags;
+
+ Map<String, String> values = <String, String>{};
+
+ for (String spec in specs) {
+ List<String> tagAndValue = spec.split(':');
+ if (tagAndValue.length != 2) {
+ reportError("Invalid <tag>:<value> pair '$spec'.");
+ continue;
+ }
+ String tag = tagAndValue[0].trim();
+ String value = tagAndValue[1].trim();
+
+ if (validTags.contains(tag)) {
+ if (values[tag] == null) {
+ values[tag] = value;
+ } else {
+ reportError("Duplicate tag '$tag'.");
+ }
+ } else {
+ if (knownTags.contains(tag)) {
+ reportError("Tag '$tag' is not valid here.");
+ } else {
+ reportError("Unknown tag '$tag'.");
+ }
+ }
+ }
+
+ // Enum-like tags are looked up in a map. True signature is:
+ //
+ // T tagValueLookup<T>(String tag, Map<String, T> map);
+ //
+ dynamic tagValueLookup(String tag, Map<String, dynamic> map) {
+ String tagString = values[tag];
+ if (tagString == null) return null;
+ var value = map[tagString];
+ if (value == null) {
+ reportError("Unknown '$tag' specification: '$tagString'.");
+ }
+ return value;
+ }
+
+ String returns = values['returns'];
+ if (returns != null) {
+ resolveTypesString(returns, onVar: () {
+ typesReturned.add(objectType);
+ typesReturned.add(nullType);
+ }, onType: (type) {
+ typesReturned.add(type);
+ });
+ }
+
+ String creates = values['creates'];
+ if (creates != null) {
+ resolveTypesString(creates, onVoid: () {
+ reportError("Invalid type string 'creates:$creates'");
+ }, onVar: () {
+ reportError("Invalid type string 'creates:$creates'");
+ }, onType: (type) {
+ typesInstantiated.add(type);
+ });
+ }
+
+ const throwsOption = const <String, NativeThrowBehavior>{
+ 'never': NativeThrowBehavior.NEVER,
+ 'null(1)': NativeThrowBehavior.MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS,
+ 'may': NativeThrowBehavior.MAY,
+ 'must': NativeThrowBehavior.MUST };
+
+ const boolOptions = const<String, bool>{'true': true, 'false': false};
+
+ SideEffects sideEffects = processEffects(reportError,
+ values['effects'], values['depends']);
+ NativeThrowBehavior throwsKind = tagValueLookup('throws', throwsOption);
+ bool isAllocation = tagValueLookup('new', boolOptions);
+ bool useGvn = tagValueLookup('gvn', boolOptions);
+
+ if (isAllocation == true && useGvn == true) {
+ reportError("'new' and 'gvn' are incompatible");
+ }
+
+ if (seenError) return; // Avoid callbacks.
+
+ // TODO(sra): Simplify [throwBehavior] using [sideEffects].
+
+ if (sideEffects != null) setSideEffects(sideEffects);
+ if (throwsKind != null) setThrows(throwsKind);
+ if (isAllocation != null) setIsAllocation(isAllocation);
+ if (useGvn != null) setUseGvn(useGvn);
+ }
+
+ static SideEffects processEffects(
+ void reportError(String message),
+ String effects,
+ String depends) {
+
+ if (effects == null && depends == null) return null;
+
+ if (effects == null || depends == null) {
+ reportError("'effects' and 'depends' must occur together.");
+ return null;
+ }
+
+ SideEffects sideEffects = new SideEffects();
+ if (effects == "none") {
+ sideEffects.clearAllSideEffects();
+ } else if (effects == "all") {
+ // Don't do anything.
+ } else {
+ List<String> splitEffects = effects.split(",");
+ if (splitEffects.isEmpty) {
+ reportError("Missing side-effect flag.");
+ }
+ for (String effect in splitEffects) {
+ switch (effect) {
+ case "no-index":
+ sideEffects.clearChangesIndex();
+ break;
+ case "no-instance":
+ sideEffects.clearChangesInstanceProperty();
+ break;
+ case "no-static":
+ sideEffects.clearChangesStaticProperty();
+ break;
+ default:
+ reportError("Unrecognized side-effect flag: '$effect'.");
+ }
+ }
+ }
+
+ if (depends == "none") {
+ sideEffects.clearAllDependencies();
+ } else if (depends == "all") {
+ // Don't do anything.
+ } else {
+ List<String> splitDependencies = depends.split(",");
+ if (splitDependencies.isEmpty) {
+ reportError("Missing side-effect dependency flag.");
+ }
+ for (String dependency in splitDependencies) {
+ switch (dependency) {
+ case "no-index":
+ sideEffects.clearDependsOnIndexStore();
+ break;
+ case "no-instance":
+ sideEffects.clearDependsOnInstancePropertyStore();
+ break;
+ case "no-static":
+ sideEffects.clearDependsOnStaticPropertyStore();
+ break;
+ default:
+ reportError("Unrecognized side-effect flag: '$dependency'.");
+ }
+ }
+ }
+
+ return sideEffects;
}
static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) {
@@ -263,35 +397,40 @@
// 'Type1|Type2'. A union type.
// '=Object'. A JavaScript Object, no subtype.
- var argNodes = jsCall.arguments;
- if (argNodes.isEmpty) {
- compiler.internalError(jsCall, "JS expression has no type.");
- }
-
- var code = argNodes.tail.head;
- if (code is !StringNode || code.isInterpolation) {
- compiler.internalError(code, 'JS code must be a string literal.');
- }
-
- LiteralString specLiteral = argNodes.head.asLiteralString();
- if (specLiteral == null) {
- // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
- // is not very satisfactory because it does not work for void, dynamic.
- compiler.internalError(argNodes.head, "Unexpected JS first argument.");
- }
-
NativeBehavior behavior = new NativeBehavior();
- behavior.codeTemplate =
- js.js.parseForeignJS(code.dartString.slowToString());
- String specString = specLiteral.dartString.slowToString();
+ var argNodes = jsCall.arguments;
+ if (argNodes.isEmpty || argNodes.tail.isEmpty) {
+ compiler.reportError(jsCall, MessageKind.GENERIC,
+ {'text': "JS expression takes two or more arguments."});
+ return behavior;
+ }
+
+ var specArgument = argNodes.head;
+ if (specArgument is !StringNode || specArgument.isInterpolation) {
+ compiler.reportError(specArgument, MessageKind.GENERIC,
+ {'text': "JS first argument must be a string literal."});
+ return behavior;
+ }
+
+ var codeArgument = argNodes.tail.head;
+ if (codeArgument is !StringNode || codeArgument.isInterpolation) {
+ compiler.reportError(codeArgument, MessageKind.GENERIC,
+ {'text': "JS second argument must be a string literal."});
+ return behavior;
+ }
+
+ behavior.codeTemplate =
+ js.js.parseForeignJS(codeArgument.dartString.slowToString());
+
+ String specString = specArgument.dartString.slowToString();
dynamic resolveType(String typeString) {
return _parseType(
typeString,
compiler,
- (name) => resolver.resolveTypeFromString(specLiteral, name),
- jsCall);
+ (name) => resolver.resolveTypeFromString(specArgument, name),
+ specArgument);
}
bool sideEffectsAreEncodedInSpecString = false;
@@ -301,14 +440,31 @@
behavior.sideEffects.setTo(newEffects);
}
- processSpecString(compiler, jsCall,
- specString,
- setSideEffects: setSideEffects,
- resolveType: resolveType,
- typesReturned: behavior.typesReturned,
- typesInstantiated: behavior.typesInstantiated,
- objectType: compiler.objectClass.computeType(compiler),
- nullType: compiler.nullClass.computeType(compiler));
+ bool throwBehaviorFromSpecString = false;
+ void setThrows(NativeThrowBehavior throwBehavior) {
+ throwBehaviorFromSpecString = true;
+ behavior.throwBehavior = throwBehavior;
+ }
+
+ void setIsAllocation(bool isAllocation) {
+ behavior.isAllocation = isAllocation;
+ }
+
+ void setUseGvn(bool useGvn) {
+ behavior.useGvn = useGvn;
+ }
+
+ processSpecString(compiler, specArgument,
+ specString,
+ setSideEffects: setSideEffects,
+ setThrows: setThrows,
+ setIsAllocation: setIsAllocation,
+ setUseGvn: setUseGvn,
+ resolveType: resolveType,
+ typesReturned: behavior.typesReturned,
+ typesInstantiated: behavior.typesInstantiated,
+ objectType: compiler.objectClass.computeType(compiler),
+ nullType: compiler.nullClass.computeType(compiler));
if (!sideEffectsAreEncodedInSpecString) {
new SideEffectsVisitor(behavior.sideEffects)
@@ -336,7 +492,7 @@
// We don't check the given name. That needs to be done at a later point.
// This is, because we want to allow non-literals as names.
if (argNodes.tail.isEmpty) {
- compiler.internalError(jsGlobalCall, 'Embedded Global is missing name');
+ compiler.internalError(jsGlobalCall, 'Embedded Global is missing name.');
}
if (!argNodes.tail.tail.isEmpty) {
@@ -363,15 +519,9 @@
jsGlobalCall);
}
- void setSideEffects(SideEffects newEffects) {
- compiler.internalError(jsGlobalCall,
- 'Embedded global calls may not have any side-effect overwrites: '
- '$specString');
- }
-
processSpecString(compiler, jsGlobalCall,
specString,
- setSideEffects: setSideEffects,
+ validTags: const ['returns', 'creates'],
resolveType: resolveType,
typesReturned: behavior.typesReturned,
typesInstantiated: behavior.typesInstantiated,
@@ -526,19 +676,22 @@
int index = typeString.indexOf('<');
if (index < 1) {
- compiler.internalError(
+ compiler.reportError(
_errorNode(locationNodeOrElement, compiler),
- "Type '$typeString' not found.");
+ MessageKind.GENERIC,
+ {'text': "Type '$typeString' not found."});
+ return const DynamicType();
}
type = lookup(typeString.substring(0, index));
if (type != null) {
// TODO(sra): Parse type parameters.
return type;
}
- compiler.internalError(
+ compiler.reportError(
_errorNode(locationNodeOrElement, compiler),
- "Type '$typeString' not found.");
- return null;
+ MessageKind.GENERIC,
+ {'text': "Type '$typeString' not found."});
+ return const DynamicType();
}
static _errorNode(locationNodeOrElement, compiler) {
diff --git a/pkg/compiler/lib/src/resolution/access_semantics.dart b/pkg/compiler/lib/src/resolution/access_semantics.dart
index 6aaabf6..10800dd 100644
--- a/pkg/compiler/lib/src/resolution/access_semantics.dart
+++ b/pkg/compiler/lib/src/resolution/access_semantics.dart
@@ -12,6 +12,7 @@
import '../constants/expressions.dart';
import '../elements/elements.dart';
+import '../dart_types.dart';
/// Enum representing the different kinds of destinations which a property
/// access or method or function invocation might refer to.
@@ -307,3 +308,124 @@
Element get element => setter;
}
+
+/// Enum representing the different kinds of destinations which a constructor
+/// invocation might refer to.
+enum ConstructorAccessKind {
+ /// An invocation of a generative constructor.
+ ///
+ /// For instance
+ /// class C {
+ /// C();
+ /// }
+ /// m() => new C();
+ ///
+ GENERATIVE,
+
+ /// An invocation of a redirecting generative constructor.
+ ///
+ /// For instance
+ /// class C {
+ /// C() : this._();
+ /// C._();
+ /// }
+ /// m() => new C();
+ ///
+ REDIRECTING_GENERATIVE,
+
+ /// An invocation of a factory constructor.
+ ///
+ /// For instance
+ /// class C {
+ /// factory C() => new C._();
+ /// C._();
+ /// }
+ /// m() => new C();
+ ///
+ FACTORY,
+
+ /// An invocation of a redirecting factory constructor.
+ ///
+ /// For instance
+ /// class C {
+ /// factory C() = C._;
+ /// C._();
+ /// }
+ /// m() => new C();
+ ///
+ REDIRECTING_FACTORY,
+
+ /// An invocation of a (redirecting) generative constructor of an abstract
+ /// class.
+ ///
+ /// For instance
+ /// abstract class C {
+ /// C();
+ /// }
+ /// m() => new C();
+ ///
+ ABSTRACT,
+
+ /// An invocation of an unresolved constructor or an unresolved type.
+ ///
+ /// For instance
+ /// class C {
+ /// C();
+ /// }
+ /// m1() => new C.unresolved();
+ /// m2() => new Unresolved();
+ ///
+ // TODO(johnniwinther): Differentiate between error types.
+ ERRONEOUS,
+
+ /// An invocation of an ill-defined redirecting factory constructor.
+ ///
+ /// For instance
+ /// class C {
+ /// factory C() = Unresolved;
+ /// }
+ /// m() => new C();
+ ///
+ ERRONEOUS_REDIRECTING_FACTORY,
+}
+
+/// Data structure used to classify the semantics of a constructor invocation.
+class ConstructorAccessSemantics {
+ /// The kind of constructor invocation.
+ final ConstructorAccessKind kind;
+
+ /// The invoked constructor.
+ final Element element;
+
+ /// The type on which the constructor is invoked.
+ final DartType type;
+
+ ConstructorAccessSemantics(this.kind, this.element, this.type);
+
+ /// The effect target of the access. Used to defined redirecting factory
+ /// constructor invocations.
+ ConstructorAccessSemantics get effectiveTargetSemantics => this;
+
+ /// `true` if this invocation is erroneous.
+ bool get isErroneous {
+ return kind == ConstructorAccessKind.ABSTRACT ||
+ kind == ConstructorAccessKind.ERRONEOUS ||
+ kind == ConstructorAccessKind.ERRONEOUS_REDIRECTING_FACTORY;
+ }
+}
+
+/// Data structure used to classify the semantics of a redirecting factory
+/// constructor invocation.
+class RedirectingFactoryConstructorAccessSemantics
+ extends ConstructorAccessSemantics {
+ final ConstructorAccessSemantics effectiveTargetSemantics;
+
+ RedirectingFactoryConstructorAccessSemantics(
+ ConstructorAccessKind kind,
+ Element element,
+ DartType type,
+ this.effectiveTargetSemantics)
+ : super(kind, element, type);
+}
+
+
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 40ed27d..652387b 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -1500,7 +1500,7 @@
final String className = lookupTarget.name;
verifyThatConstructorMatchesCall(constructor,
calledConstructor,
- selector,
+ selector.callStructure,
isImplicitSuperCall,
call,
className,
@@ -1519,11 +1519,6 @@
if (classElement != visitor.compiler.objectClass) {
assert(superClass != null);
assert(superClass.resolutionState == STATE_DONE);
- String constructorName = '';
- Selector callToMatch = new Selector.call(
- constructorName,
- classElement.library,
- 0);
final bool isSuperCall = true;
ClassElement lookupTarget = getSuperOrThisLookupTarget(constructor,
@@ -1537,7 +1532,7 @@
final bool isImplicitSuperCall = true;
verifyThatConstructorMatchesCall(constructor,
calledConstructor,
- callToMatch,
+ CallStructure.NO_ARGS,
isImplicitSuperCall,
functionNode,
className,
@@ -1549,8 +1544,8 @@
void verifyThatConstructorMatchesCall(
FunctionElement caller,
- FunctionElement lookedupConstructor,
- Selector call,
+ ConstructorElementX lookedupConstructor,
+ CallStructure call,
bool isImplicitSuperCall,
Node diagnosticNode,
String className,
@@ -1567,7 +1562,7 @@
diagnosticNode, kind, {'constructorName': fullConstructorName});
} else {
lookedupConstructor.computeSignature(visitor.compiler);
- if (!call.applies(lookedupConstructor, visitor.compiler.world)) {
+ if (!call.signatureApplies(lookedupConstructor)) {
MessageKind kind = isImplicitSuperCall
? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT
: MessageKind.NO_MATCHING_CONSTRUCTOR;
@@ -1584,8 +1579,8 @@
* Resolve all initializers of this constructor. In the case of a redirecting
* constructor, the resolved constructor's function element is returned.
*/
- FunctionElement resolveInitializers(FunctionElement constructor,
- FunctionExpression functionNode) {
+ ConstructorElement resolveInitializers(ConstructorElementX constructor,
+ FunctionExpression functionNode) {
// Keep track of all "this.param" parameters specified for constructor so
// that we can ensure that fields are initialized only once.
FunctionSignature functionParameters = constructor.functionSignature;
@@ -1630,6 +1625,8 @@
// Check that there are no other initializers.
if (!initializers.tail.isEmpty) {
error(call, MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER);
+ } else {
+ constructor.isRedirectingGenerative = true;
}
// Check that there are no field initializing parameters.
Compiler compiler = visitor.compiler;
@@ -3152,8 +3149,8 @@
MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR);
} else if (!node.isArrowBody && currentAsyncMarker.isYielding) {
compiler.reportError(
- node,
- MessageKind.RETURN_IN_GENERATOR,
+ node,
+ MessageKind.RETURN_IN_GENERATOR,
{'modifier': currentAsyncMarker});
}
}
@@ -4830,22 +4827,26 @@
throw 'not supported';
}
- failOrReturnErroneousConstructorElement(
- Element enclosing, Node diagnosticNode,
- String targetName, MessageKind kind,
- Map arguments) {
- if (kind == MessageKind.CANNOT_FIND_CONSTRUCTOR) {
+ ErroneousConstructorElementX failOrReturnErroneousConstructorElement(
+ Spannable diagnosticNode,
+ Element enclosing,
+ String name,
+ MessageKind kind,
+ Map arguments,
+ {bool isError: false,
+ bool missingConstructor: false}) {
+ if (missingConstructor) {
registry.registerThrowNoSuchMethod();
} else {
registry.registerThrowRuntimeError();
}
- if (inConstContext) {
+ if (isError || inConstContext) {
compiler.reportError(diagnosticNode, kind, arguments);
} else {
compiler.reportWarning(diagnosticNode, kind, arguments);
}
return new ErroneousConstructorElementX(
- kind, arguments, targetName, enclosing);
+ kind, arguments, name, enclosing);
}
FunctionElement resolveConstructor(ClassElement cls,
@@ -4853,16 +4854,21 @@
String constructorName) {
cls.ensureResolved(compiler);
Element result = cls.lookupConstructor(constructorName);
+ // TODO(johnniwinther): Use [Name] for lookup.
+ if (isPrivateName(constructorName) &&
+ resolver.enclosingElement.library != cls.library) {
+ result = null;
+ }
if (result == null) {
String fullConstructorName = Elements.constructorNameForDiagnostics(
cls.name,
constructorName);
return failOrReturnErroneousConstructorElement(
- cls,
diagnosticNode,
- fullConstructorName,
+ cls, constructorName,
MessageKind.CANNOT_FIND_CONSTRUCTOR,
- {'constructorName': fullConstructorName});
+ {'constructorName': fullConstructorName},
+ missingConstructor: true);
} else if (inConstContext && !result.isConst) {
error(diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
}
@@ -4895,10 +4901,12 @@
element = resolveConstructor(cls, diagnosticNode, '');
} else {
element = failOrReturnErroneousConstructorElement(
- element, diagnosticNode, element.name, MessageKind.NOT_A_TYPE,
- {'node': diagnosticNode});
+ diagnosticNode,
+ element, element.name,
+ MessageKind.NOT_A_TYPE, {'node': diagnosticNode});
}
} else if (element.isErroneous && element is! ErroneousElementX) {
+ // Parser error. The error has already been reported.
element = new ErroneousConstructorElementX(
MessageKind.NOT_A_TYPE, {'node': diagnosticNode},
element.name, element);
@@ -4945,12 +4953,15 @@
element = Elements.unwrap(element, compiler, node);
if (element == null) {
return failOrReturnErroneousConstructorElement(
- resolver.enclosingElement, name,
- name.source,
- MessageKind.CANNOT_RESOLVE,
- {'name': name});
+ name,
+ resolver.enclosingElement, name.source,
+ MessageKind.CANNOT_RESOLVE, {'name': name});
} else if (!element.isClass) {
- error(node, MessageKind.NOT_A_TYPE, {'node': name});
+ return failOrReturnErroneousConstructorElement(
+ name,
+ resolver.enclosingElement, name.source,
+ MessageKind.NOT_A_TYPE, {'node': name},
+ isError: true);
}
} else {
internalError(node.receiver, 'unexpected element $element');
@@ -4966,31 +4977,31 @@
// TODO(johnniwinther): Change errors to warnings, cf. 11.11.1.
if (element == null) {
return failOrReturnErroneousConstructorElement(
- resolver.enclosingElement, node, name,
+ node,
+ resolver.enclosingElement, name,
MessageKind.CANNOT_RESOLVE,
{'name': name});
} else if (element.isErroneous) {
return element;
} else if (element.isTypedef) {
- error(node, MessageKind.CANNOT_INSTANTIATE_TYPEDEF,
- {'typedefName': name});
- element = new ErroneousConstructorElementX(
- MessageKind.CANNOT_INSTANTIATE_TYPEDEF,
- {'typedefName': name}, name, resolver.enclosingElement);
- registry.registerThrowRuntimeError();
+ element = failOrReturnErroneousConstructorElement(
+ node,
+ resolver.enclosingElement, name,
+ MessageKind.CANNOT_INSTANTIATE_TYPEDEF, {'typedefName': name},
+ isError: true);
} else if (element.isTypeVariable) {
- error(node, MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
- {'typeVariableName': name});
- element = new ErroneousConstructorElementX(
+ element = failOrReturnErroneousConstructorElement(
+ node,
+ resolver.enclosingElement, name,
MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
- {'typeVariableName': name}, name, resolver.enclosingElement);
- registry.registerThrowRuntimeError();
+ {'typeVariableName': name},
+ isError: true);
} else if (!element.isClass && !element.isPrefix) {
- error(node, MessageKind.NOT_A_TYPE, {'node': name});
- element = new ErroneousConstructorElementX(
- MessageKind.NOT_A_TYPE, {'node': name}, name,
- resolver.enclosingElement);
- registry.registerThrowRuntimeError();
+ element = failOrReturnErroneousConstructorElement(
+ node,
+ resolver.enclosingElement, name,
+ MessageKind.NOT_A_TYPE, {'node': name},
+ isError: true);
}
return element;
}
diff --git a/pkg/compiler/lib/src/resolution/resolution.dart b/pkg/compiler/lib/src/resolution/resolution.dart
index 3489fbd..326bd39 100644
--- a/pkg/compiler/lib/src/resolution/resolution.dart
+++ b/pkg/compiler/lib/src/resolution/resolution.dart
@@ -45,6 +45,7 @@
import '../ordered_typeset.dart' show OrderedTypeSet, OrderedTypeSetBuilder;
import '../util/util.dart';
+import '../universe/universe.dart' show CallStructure;
import 'class_members.dart' show MembersCreator;
import 'enum_creator.dart';
diff --git a/pkg/compiler/lib/src/resolution/semantic_visitor.dart b/pkg/compiler/lib/src/resolution/semantic_visitor.dart
index 7e259aa..3957d1d 100644
--- a/pkg/compiler/lib/src/resolution/semantic_visitor.dart
+++ b/pkg/compiler/lib/src/resolution/semantic_visitor.dart
@@ -8,6 +8,7 @@
import '../dart2jslib.dart' show invariant;
import '../dart_types.dart';
import '../elements/elements.dart';
+import '../helpers/helpers.dart';
import '../tree/tree.dart';
import '../universe/universe.dart';
import '../util/util.dart' show Spannable, SpannableAssertionFailure;
@@ -56,6 +57,19 @@
R visitSendSet(SendSet node) {
return visitSend(node);
}
+
+ @override
+ R visitNewExpression(NewExpression node) {
+ // TODO(johnniwinther): Support argument.
+ A arg = null;
+
+ NewStructure structure = computeNewStructure(node);
+ if (structure == null) {
+ return internalError(node, 'No structure for $node');
+ } else {
+ return structure.dispatch(sendVisitor, node, arg);
+ }
+ }
}
// TODO(johnniwinther): Add visits for [visitLocalConstantGet],
@@ -900,7 +914,7 @@
///
R visitClassTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg);
/// Invocation of the type literal for class [element] with [arguments].
@@ -911,7 +925,7 @@
///
R visitClassTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
A arg);
@@ -924,7 +938,7 @@
///
R errorClassTypeLiteralSet(
SendSet node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
Node rhs,
A arg);
@@ -936,7 +950,7 @@
///
R visitTypedefTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg);
/// Invocation of the type literal for typedef [element] with [arguments].
@@ -947,7 +961,7 @@
///
R visitTypedefTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
A arg);
@@ -960,7 +974,7 @@
///
R errorTypedefTypeLiteralSet(
SendSet node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
Node rhs,
A arg);
@@ -1011,7 +1025,7 @@
///
R visitDynamicTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg);
/// Invocation of the type literal for `dynamic` with [arguments].
@@ -1021,7 +1035,7 @@
///
R visitDynamicTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
A arg);
@@ -1033,7 +1047,7 @@
///
R errorDynamicTypeLiteralSet(
SendSet node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
Node rhs,
A arg);
@@ -1794,7 +1808,7 @@
///
R errorClassTypeLiteralCompound(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
AssignmentOperator operator,
Node rhs,
A arg);
@@ -1808,7 +1822,7 @@
///
R errorTypedefTypeLiteralCompound(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
AssignmentOperator operator,
Node rhs,
A arg);
@@ -1836,7 +1850,7 @@
///
R errorDynamicTypeLiteralCompound(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
AssignmentOperator operator,
Node rhs,
A arg);
@@ -2169,7 +2183,7 @@
///
R errorClassTypeLiteralPrefix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg);
@@ -2182,7 +2196,7 @@
///
R errorTypedefTypeLiteralPrefix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg);
@@ -2207,7 +2221,7 @@
///
R errorDynamicTypeLiteralPrefix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg);
@@ -2504,7 +2518,7 @@
///
R errorClassTypeLiteralPostfix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg);
@@ -2517,7 +2531,7 @@
///
R errorTypedefTypeLiteralPostfix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg);
@@ -2542,7 +2556,7 @@
///
R errorDynamicTypeLiteralPostfix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg);
@@ -2765,4 +2779,169 @@
Operator operator,
Node right,
A arg);
+
+ /// Const invocation of a [constructor].
+ ///
+ /// For instance
+ /// class C<T> {
+ /// const C(a, b);
+ /// }
+ /// m() => const C<int>(true, 42);
+ ///
+ R visitConstConstructorInvoke(
+ NewExpression node,
+ ConstructedConstantExpression constant,
+ A arg);
+
+ /// Invocation of a generative [constructor] on [type] with [arguments].
+ ///
+ /// For instance
+ /// class C<T> {
+ /// C(a, b);
+ /// }
+ /// m() => new C<int>(true, 42);
+ ///
+ /// where [type] is `C<int>`.
+ ///
+ R visitGenerativeConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg);
+
+ /// Invocation of a redirecting generative [constructor] on [type] with
+ /// [arguments].
+ ///
+ /// For instance
+ /// class C<T> {
+ /// C(a, b) : this._(b, a);
+ /// C._(b, a);
+ /// }
+ /// m() => new C<int>(true, 42);
+ ///
+ /// where [type] is `C<int>`.
+ ///
+ R visitRedirectingGenerativeConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg);
+
+ /// Invocation of a factory [constructor] on [type] with [arguments].
+ ///
+ /// For instance
+ /// class C<T> {
+ /// factory C(a, b) => new C<T>._(b, a);
+ /// C._(b, a);
+ /// }
+ /// m() => new C<int>(true, 42);
+ ///
+ /// where [type] is `C<int>`.
+ ///
+ R visitFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg);
+
+ /// Invocation of a factory [constructor] on [type] with [arguments] where
+ /// [effectiveTarget] and [effectiveTargetType] are the constructor effective
+ /// invoked and its type, respectively.
+ ///
+ /// For instance
+ /// class C<T> {
+ /// factory C(a, b) = C<int>.a;
+ /// factory C.a(a, b) = C<C<T>>.b;
+ /// C.b(a, b);
+ /// }
+ /// m() => new C<double>(true, 42);
+ ///
+ /// where [type] is `C<double>`, [effectiveTarget] is `C.b` and
+ /// [effectiveTargetType] is `C<C<int>>`.
+ ///
+ R visitRedirectingFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ ConstructorElement effectiveTarget,
+ InterfaceType effectiveTargetType,
+ NodeList arguments,
+ Selector selector,
+ A arg);
+
+ /// Invocation of an unresolved [constructor] on [type] with [arguments].
+ ///
+ /// For instance
+ /// class C<T> {
+ /// C();
+ /// }
+ /// m() => new C<int>.unresolved(true, 42);
+ ///
+ /// where [type] is `C<int>`.
+ ///
+ // TODO(johnniwinther): Update [type] to be [InterfaceType] when this is no
+ // longer a catch-all clause for the erroneous constructor invocations.
+ R errorUnresolvedConstructorInvoke(
+ NewExpression node,
+ Element constructor,
+ DartType type,
+ NodeList arguments,
+ Selector selector,
+ A arg);
+
+ /// Invocation of a constructor on an unresolved [type] with [arguments].
+ ///
+ /// For instance
+ /// m() => new Unresolved(true, 42);
+ ///
+ /// where [type] is the malformed type `Unresolved`.
+ ///
+ R errorUnresolvedClassConstructorInvoke(
+ NewExpression node,
+ Element element,
+ MalformedType type,
+ NodeList arguments,
+ Selector selector,
+ A arg);
+
+ /// Invocation of a constructor on an abstract [type] with [arguments].
+ ///
+ /// For instance
+ /// m() => new Unresolved(true, 42);
+ ///
+ /// where [type] is the malformed type `Unresolved`.
+ ///
+ R errorAbstractClassConstructorInvoke(
+ NewExpression node,
+ ConstructorElement element,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg);
+
+ /// Invocation of a factory [constructor] on [type] with [arguments] where
+ /// [effectiveTarget] and [effectiveTargetType] are the constructor effective
+ /// invoked and its type, respectively.
+ ///
+ /// For instance
+ /// class C {
+ /// factory C(a, b) = Unresolved;
+ /// factory C.a(a, b) = C.unresolved;
+ /// }
+ /// m1() => new C(true, 42);
+ /// m2() => new C.a(true, 42);
+ ///
+ R errorUnresolvedRedirectingFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg);
}
diff --git a/pkg/compiler/lib/src/resolution/semantic_visitor_mixins.dart b/pkg/compiler/lib/src/resolution/semantic_visitor_mixins.dart
index 47846a6..f1951bf 100644
--- a/pkg/compiler/lib/src/resolution/semantic_visitor_mixins.dart
+++ b/pkg/compiler/lib/src/resolution/semantic_visitor_mixins.dart
@@ -9,10 +9,10 @@
///
/// Use this mixin to provide a trivial implementation for all `errorX` methods.
abstract class ErrorBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
- R bulkHandleNode(Node node, String message);
+ R bulkHandleNode(Node node, String message, A arg);
- R bulkHandleError(Send node) {
- return bulkHandleNode(node, "Error expression `$node` unhandled.");
+ R bulkHandleError(Node node, A arg) {
+ return bulkHandleNode(node, "Error expression `$node` unhandled.", arg);
}
@override
@@ -20,81 +20,92 @@
Send node,
NodeList arguments,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
+ }
+
+ @override
+ R errorAbstractClassConstructorInvoke(
+ NewExpression node,
+ ConstructorElement element,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return bulkHandleError(node, arg);
}
@override
R errorClassTypeLiteralCompound(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
R errorClassTypeLiteralPostfix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
R errorClassTypeLiteralPrefix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
R errorClassTypeLiteralSet(
SendSet node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
R errorDynamicTypeLiteralCompound(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
R errorDynamicTypeLiteralPostfix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
R errorDynamicTypeLiteralPrefix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
R errorDynamicTypeLiteralSet(
SendSet node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -105,7 +116,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -114,7 +125,7 @@
LocalVariableElement variable,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -124,7 +135,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -133,7 +144,7 @@
ParameterElement parameter,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -143,7 +154,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -152,7 +163,7 @@
FieldElement field,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -162,7 +173,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -171,7 +182,7 @@
FieldElement field,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -181,7 +192,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -190,7 +201,7 @@
FieldElement field,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -200,7 +211,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -209,7 +220,7 @@
LocalFunctionElement function,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -218,7 +229,7 @@
LocalFunctionElement function,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -227,7 +238,7 @@
LocalFunctionElement function,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -236,7 +247,7 @@
MethodElement function,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -245,7 +256,7 @@
FunctionElement getter,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -253,7 +264,7 @@
Send node,
FunctionElement setter,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -263,7 +274,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -272,7 +283,7 @@
FunctionElement getter,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -281,7 +292,7 @@
MethodElement method,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -289,7 +300,7 @@
Send node,
FunctionElement setter,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -299,7 +310,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -308,7 +319,7 @@
MethodElement function,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -317,7 +328,7 @@
FunctionElement getter,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -325,7 +336,7 @@
Send node,
FunctionElement setter,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -335,7 +346,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -345,7 +356,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -354,7 +365,7 @@
TypeVariableElement element,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -363,7 +374,7 @@
TypeVariableElement element,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -372,44 +383,44 @@
TypeVariableElement element,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
R errorTypedefTypeLiteralCompound(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
R errorTypedefTypeLiteralPostfix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
R errorTypedefTypeLiteralPrefix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
R errorTypedefTypeLiteralSet(
SendSet node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -419,7 +430,29 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
+ }
+
+ @override
+ R errorUnresolvedClassConstructorInvoke(
+ NewExpression node,
+ Element element,
+ MalformedType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return bulkHandleError(node, arg);
+ }
+
+ @override
+ R errorUnresolvedConstructorInvoke(
+ NewExpression node,
+ Element constructor,
+ DartType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return bulkHandleError(node, arg);
}
@override
@@ -427,7 +460,7 @@
Send node,
Element element,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -437,7 +470,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -446,7 +479,7 @@
Element element,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -455,7 +488,18 @@
Element element,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
+ }
+
+ @override
+ R errorUnresolvedRedirectingFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return bulkHandleError(node, arg);
}
@override
@@ -464,7 +508,7 @@
Element element,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -475,7 +519,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -484,7 +528,7 @@
Element function,
Node index,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -494,7 +538,7 @@
Node index,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -504,7 +548,7 @@
Node index,
IncDecOperator operator,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -514,7 +558,7 @@
Node index,
Node rhs,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -524,7 +568,7 @@
BinaryOperator operator,
Node argument,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -533,7 +577,7 @@
UnaryOperator operator,
Element element,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -543,7 +587,7 @@
Operator operator,
Node right,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
@override
@@ -552,7 +596,7 @@
Operator operator,
Node expression,
A arg) {
- return bulkHandleError(node);
+ return bulkHandleError(node, arg);
}
}
@@ -562,10 +606,10 @@
/// Use this mixin to provide a trivial implementation for all `visitXPrefix`
/// methods.
abstract class PrefixBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
- R bulkHandleNode(Node node, String message);
+ R bulkHandleNode(Node node, String message, A arg);
- R bulkHandlePrefix(Send node) {
- return bulkHandleNode(node, "Prefix expression `$node` unhandled.");
+ R bulkHandlePrefix(Send node, A arg) {
+ return bulkHandleNode(node, "Prefix expression `$node` unhandled.", arg);
}
@override
@@ -576,7 +620,7 @@
Selector getterSelector,
Selector setterSelector,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -586,7 +630,7 @@
Node index,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -595,7 +639,7 @@
LocalVariableElement variable,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -604,7 +648,7 @@
ParameterElement parameter,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -613,7 +657,7 @@
FieldElement field,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -623,7 +667,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -633,7 +677,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -643,7 +687,7 @@
FieldElement writtenField,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -652,7 +696,7 @@
FieldElement field,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -662,7 +706,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -672,7 +716,7 @@
FieldElement field,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -682,7 +726,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -693,7 +737,7 @@
Node index,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -703,7 +747,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -713,7 +757,7 @@
Selector getterSelector,
Selector setterSelector,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -722,7 +766,7 @@
FieldElement field,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -732,7 +776,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
@override
@@ -742,7 +786,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePrefix(node);
+ return bulkHandlePrefix(node, arg);
}
}
@@ -752,10 +796,10 @@
/// Use this mixin to provide a trivial implementation for all `visitXPostfix`
/// methods.
abstract class PostfixBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
- R bulkHandleNode(Node node, String message);
+ R bulkHandleNode(Node node, String message, A arg);
- R bulkHandlePostfix(Send node) {
- return bulkHandleNode(node, "Postfix expression `$node` unhandled.");
+ R bulkHandlePostfix(Send node, A arg) {
+ return bulkHandleNode(node, "Postfix expression `$node` unhandled.", arg);
}
@override
@@ -766,7 +810,7 @@
Selector getterSelector,
Selector setterSelector,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -776,7 +820,7 @@
Node index,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -785,7 +829,7 @@
LocalVariableElement variable,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -794,7 +838,7 @@
ParameterElement parameter,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -803,7 +847,7 @@
FieldElement field,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -813,7 +857,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -823,7 +867,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -833,7 +877,7 @@
FieldElement writtenField,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -842,7 +886,7 @@
FieldElement field,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -852,7 +896,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -862,7 +906,7 @@
FieldElement field,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -872,7 +916,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -883,7 +927,7 @@
Node index,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -893,7 +937,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -903,7 +947,7 @@
Selector getterSelector,
Selector setterSelector,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -912,7 +956,7 @@
FieldElement field,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -922,7 +966,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
@override
@@ -932,7 +976,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandlePostfix(node);
+ return bulkHandlePostfix(node, arg);
}
}
@@ -942,10 +986,10 @@
/// Use this mixin to provide a trivial implementation for all `xCompound`
/// methods.
abstract class CompoundBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
- R bulkHandleNode(Node node, String message);
+ R bulkHandleNode(Node node, String message, A arg);
- R bulkHandleCompound(Send node) {
- return bulkHandleNode(node, "Compound assignment `$node` unhandled.");
+ R bulkHandleCompound(Send node, A arg) {
+ return bulkHandleNode(node, "Compound assignment `$node` unhandled.", arg);
}
@override
@@ -957,7 +1001,7 @@
Selector getterSelector,
Selector setterSelector,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -967,7 +1011,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -977,7 +1021,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -987,7 +1031,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -998,7 +1042,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -1009,7 +1053,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -1019,7 +1063,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -1030,7 +1074,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -1041,7 +1085,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -1052,7 +1096,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -1063,7 +1107,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -1074,7 +1118,7 @@
Selector getterSelector,
Selector setterSelector,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -1084,7 +1128,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -1095,7 +1139,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
@override
@@ -1106,7 +1150,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleCompound(node);
+ return bulkHandleCompound(node, arg);
}
}
@@ -1116,20 +1160,20 @@
/// Use this mixin to provide a trivial implementation for all `visitXInvoke`
/// methods.
abstract class InvokeBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
- R bulkHandleNode(Node node, String message);
+ R bulkHandleNode(Node node, String message, A arg);
- R bulkHandleInvoke(Send node) {
- return bulkHandleNode(node, "Invocation `$node` unhandled.");
+ R bulkHandleInvoke(Send node, A arg) {
+ return bulkHandleNode(node, "Invocation `$node` unhandled.", arg);
}
@override
R visitClassTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1139,17 +1183,17 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
R visitDynamicTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1159,7 +1203,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1169,7 +1213,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1179,7 +1223,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1189,7 +1233,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1199,7 +1243,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1209,7 +1253,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1219,7 +1263,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1229,7 +1273,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1239,7 +1283,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1249,7 +1293,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1258,7 +1302,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1267,7 +1311,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1277,7 +1321,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1287,7 +1331,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1297,7 +1341,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1307,17 +1351,17 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
R visitTypedefTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
@override
@@ -1327,7 +1371,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleInvoke(node);
+ return bulkHandleInvoke(node, arg);
}
}
@@ -1337,18 +1381,18 @@
/// Use this mixin to provide a trivial implementation for all `visitXGet`
/// methods.
abstract class GetBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
- R bulkHandleNode(Node node, String message);
+ R bulkHandleNode(Node node, String message, A arg);
- R bulkHandleGet(Node node) {
- return bulkHandleNode(node, "Read `$node` unhandled.");
+ R bulkHandleGet(Node node, A arg) {
+ return bulkHandleNode(node, "Read `$node` unhandled.", arg);
}
@override
R visitClassTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1357,15 +1401,15 @@
Node receiver,
Selector selector,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
R visitDynamicTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1373,7 +1417,7 @@
Send node,
LocalFunctionElement function,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1381,7 +1425,7 @@
Send node,
LocalVariableElement variable,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1389,7 +1433,7 @@
Send node,
ParameterElement parameter,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1397,7 +1441,7 @@
Send node,
FieldElement field,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1405,7 +1449,7 @@
Send node,
MethodElement function,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1413,7 +1457,7 @@
Send node,
FunctionElement getter,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1421,7 +1465,7 @@
Send node,
FieldElement field,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1429,7 +1473,7 @@
Send node,
FunctionElement getter,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1437,12 +1481,12 @@
Send node,
MethodElement method,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
R visitThisGet(Identifier node, A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1450,7 +1494,7 @@
Send node,
Selector selector,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1458,7 +1502,7 @@
Send node,
FieldElement field,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1466,7 +1510,7 @@
Send node,
MethodElement function,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1474,7 +1518,7 @@
Send node,
FunctionElement getter,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
@@ -1482,23 +1526,23 @@
Send node,
TypeVariableElement element,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
R visitTypedefTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
@override
R visitConstantGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg) {
- return bulkHandleGet(node);
+ return bulkHandleGet(node, arg);
}
}
@@ -1508,10 +1552,10 @@
/// Use this mixin to provide a trivial implementation for all `visitXSet`
/// methods.
abstract class SetBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
- R bulkHandleNode(Node node, String message);
+ R bulkHandleNode(Node node, String message, A arg);
- R bulkHandleSet(Send node) {
- return bulkHandleNode(node, "Assignment `$node` unhandled.");
+ R bulkHandleSet(Send node, A arg) {
+ return bulkHandleNode(node, "Assignment `$node` unhandled.", arg);
}
@override
@@ -1521,7 +1565,7 @@
Selector selector,
Node rhs,
A arg) {
- return bulkHandleSet(node);
+ return bulkHandleSet(node, arg);
}
@override
@@ -1530,7 +1574,7 @@
LocalVariableElement variable,
Node rhs,
A arg) {
- return bulkHandleSet(node);
+ return bulkHandleSet(node, arg);
}
@override
@@ -1539,7 +1583,7 @@
ParameterElement parameter,
Node rhs,
A arg) {
- return bulkHandleSet(node);
+ return bulkHandleSet(node, arg);
}
@override
@@ -1548,7 +1592,7 @@
FieldElement field,
Node rhs,
A arg) {
- return bulkHandleSet(node);
+ return bulkHandleSet(node, arg);
}
@override
@@ -1557,7 +1601,7 @@
FunctionElement setter,
Node rhs,
A arg) {
- return bulkHandleSet(node);
+ return bulkHandleSet(node, arg);
}
@override
@@ -1566,7 +1610,7 @@
FieldElement field,
Node rhs,
A arg) {
- return bulkHandleSet(node);
+ return bulkHandleSet(node, arg);
}
@override
@@ -1575,7 +1619,7 @@
FunctionElement setter,
Node rhs,
A arg) {
- return bulkHandleSet(node);
+ return bulkHandleSet(node, arg);
}
@override
@@ -1584,7 +1628,7 @@
Selector selector,
Node rhs,
A arg) {
- return bulkHandleSet(node);
+ return bulkHandleSet(node, arg);
}
@override
@@ -1593,7 +1637,7 @@
FieldElement field,
Node rhs,
A arg) {
- return bulkHandleSet(node);
+ return bulkHandleSet(node, arg);
}
@override
@@ -1602,7 +1646,7 @@
FunctionElement setter,
Node rhs,
A arg) {
- return bulkHandleSet(node);
+ return bulkHandleSet(node, arg);
}
}
@@ -1612,10 +1656,10 @@
/// Use this mixin to provide a trivial implementation for all `visitXIndexSet`
/// methods.
abstract class IndexSetBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
- R bulkHandleNode(Node node, String message);
+ R bulkHandleNode(Node node, String message, A arg);
- R bulkHandleIndexSet(Send node) {
- return bulkHandleNode(node, "Index set expression `$node` unhandled.");
+ R bulkHandleIndexSet(Send node, A arg) {
+ return bulkHandleNode(node, "Index set expression `$node` unhandled.", arg);
}
@override
@@ -1626,7 +1670,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleIndexSet(node);
+ return bulkHandleIndexSet(node, arg);
}
@override
@@ -1636,7 +1680,7 @@
Node index,
Node rhs,
A arg) {
- return bulkHandleIndexSet(node);
+ return bulkHandleIndexSet(node, arg);
}
@override
@@ -1648,7 +1692,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleIndexSet(node);
+ return bulkHandleIndexSet(node, arg);
}
@override
@@ -1658,7 +1702,7 @@
Node index,
Node rhs,
A arg) {
- return bulkHandleIndexSet(node);
+ return bulkHandleIndexSet(node, arg);
}
}
@@ -1668,10 +1712,10 @@
/// Use this mixin to provide a trivial implementation for all binary visitor
/// methods.
abstract class BinaryBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
- R bulkHandleNode(Node node, String message);
+ R bulkHandleNode(Node node, String message, A arg);
- R bulkHandleBinary(Send node) {
- return bulkHandleNode(node, "Binary expression `$node` unhandled.");
+ R bulkHandleBinary(Send node, A arg) {
+ return bulkHandleNode(node, "Binary expression `$node` unhandled.", arg);
}
@override
@@ -1681,7 +1725,7 @@
BinaryOperator operator,
Node right,
A arg) {
- return bulkHandleBinary(node);
+ return bulkHandleBinary(node, arg);
}
@override
@@ -1690,7 +1734,7 @@
Node left,
Node right,
A arg) {
- return bulkHandleBinary(node);
+ return bulkHandleBinary(node, arg);
}
@override
@@ -1699,7 +1743,7 @@
Node left,
Node right,
A arg) {
- return bulkHandleBinary(node);
+ return bulkHandleBinary(node, arg);
}
@override
@@ -1708,7 +1752,7 @@
Node receiver,
Node index,
A arg) {
- return bulkHandleBinary(node);
+ return bulkHandleBinary(node, arg);
}
@override
@@ -1718,7 +1762,7 @@
BinaryOperator operator,
Node argument,
A arg) {
- return bulkHandleBinary(node);
+ return bulkHandleBinary(node, arg);
}
@override
@@ -1727,7 +1771,7 @@
FunctionElement function,
Node argument,
A arg) {
- return bulkHandleBinary(node);
+ return bulkHandleBinary(node, arg);
}
@override
@@ -1736,7 +1780,7 @@
FunctionElement function,
Node argument,
A arg) {
- return bulkHandleBinary(node);
+ return bulkHandleBinary(node, arg);
}
@override
@@ -1745,7 +1789,7 @@
FunctionElement function,
Node index,
A arg) {
- return bulkHandleBinary(node);
+ return bulkHandleBinary(node, arg);
}
}
@@ -1755,10 +1799,10 @@
/// Use this mixin to provide a trivial implementation for all unary visitor
/// methods.
abstract class UnaryBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
- R bulkHandleNode(Node node, String message);
+ R bulkHandleNode(Node node, String message, A arg);
- R bulkHandleUnary(Send node) {
- return bulkHandleNode(node, "Unary expression `$node` unhandled.");
+ R bulkHandleUnary(Send node, A arg) {
+ return bulkHandleNode(node, "Unary expression `$node` unhandled.", arg);
}
@override
@@ -1766,13 +1810,13 @@
Send node,
Node expression,
A arg) {
- return bulkHandleUnary(node);
+ return bulkHandleUnary(node, arg);
}
@override
R visitSuperUnary(Send node, UnaryOperator operator,
FunctionElement function, A arg) {
- return bulkHandleUnary(node);
+ return bulkHandleUnary(node, arg);
}
@override
@@ -1781,7 +1825,7 @@
UnaryOperator operator,
Node expression,
A arg) {
- return bulkHandleUnary(node);
+ return bulkHandleUnary(node, arg);
}
}
@@ -1791,7 +1835,7 @@
/// Use this mixin to provide a trivial implementation for all purely structural
/// visitor methods.
abstract class BaseBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
- R bulkHandleNode(Node node, String message);
+ R bulkHandleNode(Node node, String message, A arg);
@override
R visitAs(
@@ -1799,7 +1843,7 @@
Node expression,
DartType type,
A arg) {
- return bulkHandleNode(node, 'As cast `$node` unhandled.');
+ return bulkHandleNode(node, 'As cast `$node` unhandled.', arg);
}
@override
@@ -1807,7 +1851,7 @@
Send node,
Node expression,
A arg) {
- return bulkHandleNode(node, 'Assert `$node` unhandled.');
+ return bulkHandleNode(node, 'Assert `$node` unhandled.', arg);
}
@override
@@ -1816,7 +1860,7 @@
Node expression,
DartType type,
A arg) {
- return bulkHandleNode(node, 'Is test `$node` unhandled.');
+ return bulkHandleNode(node, 'Is test `$node` unhandled.', arg);
}
@override
@@ -1825,7 +1869,7 @@
Node expression,
DartType type,
A arg) {
- return bulkHandleNode(node, 'Is not test `$node` unhandled.');
+ return bulkHandleNode(node, 'Is not test `$node` unhandled.', arg);
}
@override
@@ -1834,7 +1878,7 @@
Node left,
Node right,
A arg) {
- return bulkHandleNode(node, 'Lazy and `$node` unhandled.');
+ return bulkHandleNode(node, 'Lazy and `$node` unhandled.', arg);
}
@override
@@ -1843,7 +1887,7 @@
Node left,
Node right,
A arg) {
- return bulkHandleNode(node, 'Lazy or `$node` unhandled.');
+ return bulkHandleNode(node, 'Lazy or `$node` unhandled.', arg);
}
}
@@ -1853,10 +1897,10 @@
/// Use this mixin to provide a trivial implementation for `super` calls
/// visitor methods.
abstract class SuperBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
- R bulkHandleNode(Node node, String message);
+ R bulkHandleNode(Node node, String message, A arg);
- R bulkHandleSuper(Send node) {
- return bulkHandleNode(node, "Super call `$node` unhandled.");
+ R bulkHandleSuper(Send node, A arg) {
+ return bulkHandleNode(node, "Super call `$node` unhandled.", arg);
}
@override
@@ -1866,7 +1910,7 @@
BinaryOperator operator,
Node argument,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1878,7 +1922,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1887,7 +1931,7 @@
FunctionElement function,
Node argument,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1897,7 +1941,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1907,7 +1951,7 @@
FieldElement writtenField,
IncDecOperator operator,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1917,7 +1961,7 @@
FieldElement writtenField,
IncDecOperator operator,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1925,7 +1969,7 @@
Send node,
FieldElement field,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1935,7 +1979,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1944,7 +1988,7 @@
FieldElement field,
IncDecOperator operator,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1953,7 +1997,7 @@
FieldElement field,
IncDecOperator operator,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1962,7 +2006,7 @@
FieldElement field,
Node rhs,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1973,7 +2017,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1983,7 +2027,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -1993,7 +2037,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2004,7 +2048,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2014,7 +2058,7 @@
FieldElement field,
IncDecOperator operator,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2024,7 +2068,7 @@
FieldElement field,
IncDecOperator operator,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2032,7 +2076,7 @@
Send node,
FunctionElement getter,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2042,7 +2086,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2053,7 +2097,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2063,7 +2107,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2073,7 +2117,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2083,7 +2127,7 @@
Node index,
Node rhs,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2091,7 +2135,7 @@
Send node,
MethodElement method,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2101,7 +2145,7 @@
NodeList arguments,
Selector selector,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2112,7 +2156,7 @@
AssignmentOperator operator,
Node rhs,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2122,7 +2166,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2132,7 +2176,7 @@
FunctionElement setter,
IncDecOperator operator,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2141,7 +2185,7 @@
FunctionElement function,
Node argument,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2150,7 +2194,7 @@
FunctionElement setter,
Node rhs,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
}
@override
@@ -2159,7 +2203,66 @@
UnaryOperator operator,
FunctionElement function,
A arg) {
- return bulkHandleSuper(node);
+ return bulkHandleSuper(node, arg);
+ }
+}
+
+abstract class NewBulkMixin<R, A> implements SemanticSendVisitor<R, A> {
+ R bulkHandleNode(Node node, String message, A arg);
+
+ R bulkHandleNew(NewExpression node, A arg) {
+ return bulkHandleNode(
+ node, "Constructor invocation `$node` unhandled.", arg);
+ }
+
+ @override
+ R visitConstConstructorInvoke(
+ NewExpression node,
+ ConstructedConstantExpression constant,
+ A arg) {
+ return bulkHandleNew(node, arg);
+ }
+
+ R visitGenerativeConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return bulkHandleNew(node, arg);
+ }
+
+ R visitRedirectingGenerativeConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return bulkHandleNew(node, arg);
+ }
+
+ R visitFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return bulkHandleNew(node, arg);
+ }
+
+ R visitRedirectingFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ ConstructorElement effectiveTarget,
+ InterfaceType effectiveTargetType,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return bulkHandleNew(node, arg);
}
}
@@ -2179,15 +2282,15 @@
BaseBulkMixin<R, A>,
BinaryBulkMixin<R, A>,
PrefixBulkMixin<R, A>,
- PostfixBulkMixin<R, A> {
-
+ PostfixBulkMixin<R, A>,
+ NewBulkMixin<R, A> {
@override
R apply(Node node, A arg) {
throw new UnimplementedError("BulkVisitor.apply unimplemented");
}
@override
- R bulkHandleNode(Node node, String message) {
+ R bulkHandleNode(Node node, String message, A arg) {
throw new UnimplementedError("BulkVisitor.bulkHandleNode unimplemented");
}
}
@@ -2211,7 +2314,7 @@
@override
R errorClassTypeLiteralSet(
SendSet node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
Node rhs,
A arg) {
apply(rhs, arg);
@@ -2221,7 +2324,7 @@
@override
R errorDynamicTypeLiteralSet(
SendSet node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
Node rhs,
A arg) {
apply(rhs, arg);
@@ -2502,7 +2605,7 @@
@override
R errorTypedefTypeLiteralSet(
SendSet node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
Node rhs,
A arg) {
apply(rhs, arg);
@@ -2553,7 +2656,7 @@
@override
R errorClassTypeLiteralCompound(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
AssignmentOperator operator,
Node rhs,
A arg) {
@@ -2564,7 +2667,7 @@
@override
R visitClassTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg) {
return null;
}
@@ -2572,7 +2675,7 @@
@override
R visitClassTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
A arg) {
@@ -2583,7 +2686,7 @@
@override
R errorClassTypeLiteralPostfix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg) {
return null;
@@ -2592,7 +2695,7 @@
@override
R errorClassTypeLiteralPrefix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg) {
return null;
@@ -2705,7 +2808,7 @@
@override
R errorDynamicTypeLiteralCompound(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
AssignmentOperator operator,
Node rhs,
A arg) {
@@ -2716,7 +2819,7 @@
@override
R visitDynamicTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg) {
return null;
}
@@ -2724,7 +2827,7 @@
@override
R visitDynamicTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
A arg) {
@@ -2735,7 +2838,7 @@
@override
R errorDynamicTypeLiteralPostfix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg) {
return null;
@@ -2744,7 +2847,7 @@
@override
R errorDynamicTypeLiteralPrefix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg) {
return null;
@@ -3789,7 +3892,7 @@
@override
R errorTypedefTypeLiteralCompound(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
AssignmentOperator operator,
Node rhs,
A arg) {
@@ -3800,7 +3903,7 @@
@override
R visitTypedefTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg) {
return null;
}
@@ -3808,7 +3911,7 @@
@override
R visitTypedefTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
A arg) {
@@ -3819,7 +3922,7 @@
@override
R errorTypedefTypeLiteralPostfix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg) {
return null;
@@ -3828,7 +3931,7 @@
@override
R errorTypedefTypeLiteralPrefix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
A arg) {
return null;
@@ -3976,7 +4079,8 @@
Node index,
IncDecOperator operator,
A arg) {
- // TODO: implement errorUnresolvedSuperIndexPostfix
+ apply(index, arg);
+ return null;
}
@override
@@ -3986,7 +4090,8 @@
Node index,
IncDecOperator operator,
A arg) {
- // TODO: implement errorUnresolvedSuperIndexPrefix
+ apply(index, arg);
+ return null;
}
@override
@@ -3996,7 +4101,9 @@
Node index,
IncDecOperator operator,
A arg) {
- // TODO: implement visitIndexPostfix
+ apply(receiver, arg);
+ apply(index, arg);
+ return null;
}
@override
@@ -4006,7 +4113,9 @@
Node index,
IncDecOperator operator,
A arg) {
- // TODO: implement visitIndexPrefix
+ apply(receiver, arg);
+ apply(index, arg);
+ return null;
}
@override
@@ -4017,7 +4126,8 @@
Node index,
IncDecOperator operator,
A arg) {
- // TODO: implement visitSuperIndexPostfix
+ apply(index, arg);
+ return null;
}
@override
@@ -4028,7 +4138,112 @@
Node index,
IncDecOperator operator,
A arg) {
- // TODO: implement visitSuperIndexPrefix
+ apply(index, arg);
+ return null;
+ }
+
+ @override
+ R visitConstConstructorInvoke(
+ NewExpression node,
+ ConstructedConstantExpression constant,
+ A arg) {
+ return null;
+ }
+
+ @override
+ R errorUnresolvedClassConstructorInvoke(
+ NewExpression node,
+ Element constructor,
+ MalformedType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ apply(arguments, arg);
+ return null;
+ }
+
+ @override
+ R errorUnresolvedConstructorInvoke(
+ NewExpression node,
+ Element constructor,
+ DartType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ apply(arguments, arg);
+ return null;
+ }
+ R visitFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ apply(arguments, arg);
+ return null;
+ }
+
+ @override
+ R visitGenerativeConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ apply(arguments, arg);
+ return null;
+ }
+
+ @override
+ R visitRedirectingFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ ConstructorElement effectiveTarget,
+ InterfaceType effectiveTargetType,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ apply(arguments, arg);
+ return null;
+ }
+
+ @override
+ R visitRedirectingGenerativeConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ apply(arguments, arg);
+ return null;
+ }
+
+ @override
+ R errorAbstractClassConstructorInvoke(
+ NewExpression node,
+ ConstructorElement element,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ apply(arguments, arg);
+ return null;
+ }
+
+ @override
+ R errorUnresolvedRedirectingFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ apply(arguments, arg);
+ return null;
}
}
@@ -4056,12 +4271,6 @@
return null;
}
- @override
- R visitNewExpression(NewExpression node) {
- // Bypass the [Send] holding the class/constructor name.
- return apply(node.send.argumentsNode, null);
- }
-
void visitParameters(NodeList parameters) {
}
@@ -4707,7 +4916,7 @@
abstract class BaseImplementationOfConstantsMixin<R, A>
implements SemanticSendVisitor<R, A> {
R handleConstantGet(
- Send node,
+ Node node,
ConstantExpression constant,
A arg);
@@ -4721,7 +4930,7 @@
@override
R visitClassTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg) {
return handleConstantGet(node, constant, arg);
}
@@ -4729,7 +4938,7 @@
@override
R visitClassTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
A arg) {
@@ -4737,6 +4946,14 @@
}
@override
+ R visitConstConstructorInvoke(
+ NewExpression node,
+ ConstructedConstantExpression constant,
+ A arg) {
+ return handleConstantGet(node, constant, arg);
+ }
+
+ @override
R visitConstantGet(
Send node,
ConstantExpression constant,
@@ -4757,7 +4974,7 @@
@override
R visitDynamicTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg) {
return handleConstantGet(node, constant, arg);
}
@@ -4765,7 +4982,7 @@
@override
R visitDynamicTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
A arg) {
@@ -4775,7 +4992,7 @@
@override
R visitTypedefTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
A arg) {
return handleConstantGet(node, constant, arg);
}
@@ -4783,7 +5000,7 @@
@override
R visitTypedefTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
A arg) {
@@ -4998,8 +5215,8 @@
}
}
-/// Mixin that groups all `visitSuperXPrefix`, `visitSuperXPostfix` methods for
-/// by delegating calls to `handleSuperXPostfixPrefix` methods.
+/// Mixin that groups all `visitSuperXPrefix`, `visitSuperXPostfix` methods by
+/// delegating calls to `handleSuperXPostfixPrefix` methods.
///
/// This mixin is useful for the cases where super prefix/postfix expression are
/// handled uniformly.
@@ -5210,3 +5427,66 @@
index, operator, arg, isPrefix: true);
}
}
+
+/// Mixin that groups the non-constant `visitXConstructorInvoke` methods by
+/// delegating calls to the `handleConstructorInvoke` method.
+///
+/// This mixin is useful for the cases where all constructor invocations are
+/// handled uniformly.
+abstract class BaseImplementationOfNewMixin<R, A>
+ implements SemanticSendVisitor<R, A> {
+
+ R handleConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ DartType type,
+ NodeList arguments,
+ Selector selector,
+ A arg);
+
+ R visitGenerativeConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return handleConstructorInvoke(
+ node, constructor, type, arguments, selector, arg);
+ }
+
+ R visitRedirectingGenerativeConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return handleConstructorInvoke(
+ node, constructor, type, arguments, selector, arg);
+ }
+
+ R visitFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return handleConstructorInvoke(
+ node, constructor, type, arguments, selector, arg);
+ }
+
+ R visitRedirectingFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ ConstructorElement effectiveTarget,
+ InterfaceType effectiveTargetType,
+ NodeList arguments,
+ Selector selector,
+ A arg) {
+ return handleConstructorInvoke(
+ node, constructor, type, arguments, selector, arg);
+ }
+}
diff --git a/pkg/compiler/lib/src/resolution/send_resolver.dart b/pkg/compiler/lib/src/resolution/send_resolver.dart
index aa5a747..0ddce75 100644
--- a/pkg/compiler/lib/src/resolution/send_resolver.dart
+++ b/pkg/compiler/lib/src/resolution/send_resolver.dart
@@ -309,7 +309,10 @@
Element getter = isCompound ? elements[node.selector] : null;
if (elements.isTypeLiteral(node)) {
DartType dartType = elements.getTypeLiteralType(node);
- TypeConstantExpression constant = elements.getConstant(
+ // TODO(johnniwinther): Handle deferred constants. There are runtime
+ // but not compile-time constants and should have their own
+ // [DeferredConstantExpression] class.
+ ConstantExpression constant = elements.getConstant(
isInvoke ? node.selector : node);
switch (dartType.kind) {
case TypeKind.INTERFACE:
@@ -397,5 +400,68 @@
}
}
}
+
+ ConstructorAccessSemantics computeConstructorAccessSemantics(
+ ConstructorElement constructor,
+ DartType type) {
+ if (constructor.isErroneous) {
+ return new ConstructorAccessSemantics(
+ ConstructorAccessKind.ERRONEOUS, constructor, type);
+ } else if (constructor.isRedirectingFactory) {
+ ConstructorElement effectiveTarget = constructor.effectiveTarget;
+ if (effectiveTarget == constructor ||
+ effectiveTarget.isErroneous) {
+ return new ConstructorAccessSemantics(
+ ConstructorAccessKind.ERRONEOUS_REDIRECTING_FACTORY,
+ constructor,
+ type);
+ }
+ ConstructorAccessSemantics effectiveTargetSemantics =
+ computeConstructorAccessSemantics(
+ effectiveTarget,
+ constructor.computeEffectiveTargetType(type));
+ if (effectiveTargetSemantics.isErroneous) {
+ return new RedirectingFactoryConstructorAccessSemantics(
+ ConstructorAccessKind.ERRONEOUS_REDIRECTING_FACTORY,
+ constructor,
+ type,
+ effectiveTargetSemantics);
+ }
+ return new RedirectingFactoryConstructorAccessSemantics(
+ ConstructorAccessKind.REDIRECTING_FACTORY,
+ constructor,
+ type,
+ effectiveTargetSemantics);
+ } else if (constructor.isFactoryConstructor) {
+ return new ConstructorAccessSemantics(
+ ConstructorAccessKind.FACTORY, constructor, type);
+ } else if (constructor.isRedirectingGenerative) {
+ if (constructor.enclosingClass.isAbstract) {
+ return new ConstructorAccessSemantics(
+ ConstructorAccessKind.ABSTRACT, constructor, type);
+ }
+ return new ConstructorAccessSemantics(
+ ConstructorAccessKind.REDIRECTING_GENERATIVE, constructor, type);
+ } else if (constructor.enclosingClass.isAbstract) {
+ return new ConstructorAccessSemantics(
+ ConstructorAccessKind.ABSTRACT, constructor, type);
+ } else {
+ return new ConstructorAccessSemantics(
+ ConstructorAccessKind.GENERATIVE, constructor, type);
+ }
+ }
+
+ NewStructure computeNewStructure(NewExpression node) {
+ if (node.isConst) {
+ return new ConstInvokeStructure(elements.getConstant(node));
+ }
+ Element element = elements[node.send];
+ Selector selector = elements.getSelector(node.send);
+ DartType type = elements.getType(node);
+
+ ConstructorAccessSemantics constructorAccessSemantics =
+ computeConstructorAccessSemantics(element, type);
+ return new NewInvokeStructure(constructorAccessSemantics, selector);
+ }
}
diff --git a/pkg/compiler/lib/src/resolution/send_structure.dart b/pkg/compiler/lib/src/resolution/send_structure.dart
index c233b35..d507dda 100644
--- a/pkg/compiler/lib/src/resolution/send_structure.dart
+++ b/pkg/compiler/lib/src/resolution/send_structure.dart
@@ -7,8 +7,10 @@
import 'access_semantics.dart';
import 'operators.dart';
import 'semantic_visitor.dart';
-import '../tree/tree.dart';
import '../dart_types.dart';
+import '../constants/expressions.dart';
+import '../elements/elements.dart';
+import '../tree/tree.dart';
import '../universe/universe.dart';
import '../util/util.dart';
@@ -31,6 +33,8 @@
node.arguments.single,
arg);
}
+
+ String toString() => 'assert';
}
/// The structure for a [Send] of the form an `assert` with less or more than
@@ -44,6 +48,8 @@
node.argumentsNode,
arg);
}
+
+ String toString() => 'invalid assert';
}
/// The structure for a [Send] of the form `a && b`.
@@ -57,6 +63,8 @@
node.arguments.single,
arg);
}
+
+ String toString() => '&&';
}
/// The structure for a [Send] of the form `a || b`.
@@ -70,6 +78,8 @@
node.arguments.single,
arg);
}
+
+ String toString() => '||';
}
/// The structure for a [Send] of the form `a is T`.
@@ -86,6 +96,8 @@
type,
arg);
}
+
+ String toString() => 'is $type';
}
/// The structure for a [Send] of the form `a is! T`.
@@ -102,6 +114,8 @@
type,
arg);
}
+
+ String toString() => 'is! $type';
}
/// The structure for a [Send] of the form `a as T`.
@@ -118,6 +132,8 @@
type,
arg);
}
+
+ String toString() => 'as $type';
}
/// The structure for a [Send] that is an invocation.
@@ -317,6 +333,8 @@
}
throw new SpannableAssertionFailure(node, "Invalid invoke: ${semantics}");
}
+
+ String toString() => 'invoke($selector,$semantics)';
}
/// The structure for a [Send] that is a read access.
@@ -459,6 +477,8 @@
}
throw new SpannableAssertionFailure(node, "Invalid getter: ${semantics}");
}
+
+ String toString() => 'get($selector,$semantics)';
}
/// The structure for a [Send] that is an assignment.
@@ -621,6 +641,8 @@
}
throw new SpannableAssertionFailure(node, "Invalid setter: ${semantics}");
}
+
+ String toString() => 'set($selector,$semantics)';
}
/// The structure for a [Send] that is a negation, i.e. of the form `!e`.
@@ -646,6 +668,8 @@
}
throw new SpannableAssertionFailure(node, "Invalid setter: ${semantics}");
}
+
+ String toString() => 'not($selector,$semantics)';
}
/// The structure for a [Send] that is an invocation of a user definable unary
@@ -689,6 +713,8 @@
}
throw new SpannableAssertionFailure(node, "Invalid setter: ${semantics}");
}
+
+ String toString() => 'unary($operator,$semantics)';
}
/// The structure for a [Send] that is an invocation of a undefined unary
@@ -704,6 +730,8 @@
node.receiver,
arg);
}
+
+ String toString() => 'invalid unary';
}
/// The structure for a [Send] that is an index expression, i.e. of the form
@@ -778,6 +806,8 @@
}
throw new SpannableAssertionFailure(node, "Invalid equals: ${semantics}");
}
+
+ String toString() => '==($semantics)';
}
/// The structure for a [Send] that is a not-equals test, i.e. of the form
@@ -813,6 +843,8 @@
throw new SpannableAssertionFailure(
node, "Invalid not equals: ${semantics}");
}
+
+ String toString() => '!=($semantics)';
}
/// The structure for a [Send] that is an invocation of a user-definable binary
@@ -860,6 +892,8 @@
throw new SpannableAssertionFailure(
node, "Invalid binary: ${semantics}");
}
+
+ String toString() => 'binary($operator,$semantics)';
}
/// The structure for a [Send] that is an invocation of a undefined binary
@@ -876,6 +910,8 @@
node.arguments.single,
arg);
}
+
+ String toString() => 'invalid binary';
}
/// The structure for a [Send] that is of the form `a[b] = c`.
@@ -919,6 +955,8 @@
throw new SpannableAssertionFailure(
node, "Invalid index set: ${semantics}");
}
+
+ String toString() => '[]=($semantics)';
}
/// The structure for a [Send] that is an prefix operation on an index
@@ -1275,6 +1313,8 @@
throw new SpannableAssertionFailure(node,
"Invalid compound assigment: ${semantics}");
}
+
+ String toString() => 'compound($operator,$semantics)';
}
/// The structure for a [Send] that is a compound assignment on the index
@@ -1338,6 +1378,8 @@
throw new SpannableAssertionFailure(
node, "Invalid compound index set: ${semantics}");
}
+
+ String toString() => 'compound []=($operator,$semantics)';
}
/// The structure for a [Send] that is a prefix operations. For instance
@@ -1550,6 +1592,8 @@
throw new SpannableAssertionFailure(node,
"Invalid compound assigment: ${semantics}");
}
+
+ String toString() => 'prefix($operator,$semantics)';
}
/// The structure for a [Send] that is a postfix operations. For instance
@@ -1762,5 +1806,71 @@
throw new SpannableAssertionFailure(node,
"Invalid compound assigment: ${semantics}");
}
+
+ String toString() => 'postfix($operator,$semantics)';
+}
+
+/// The structure for a [NewExpression] of a new invocation.
+abstract class NewStructure<R, A> {
+ /// Calls the matching visit method on [visitor] with [node] and [arg].
+ R dispatch(SemanticSendVisitor<R, A> visitor, NewExpression node, A arg);
+}
+
+/// The structure for a [NewExpression] of a new invocation. For instance
+/// `new C()`.
+class NewInvokeStructure<R, A> extends NewStructure<R, A> {
+ final ConstructorAccessSemantics semantics;
+ final Selector selector;
+
+ NewInvokeStructure(this.semantics, this.selector);
+
+ R dispatch(SemanticSendVisitor<R, A> visitor, NewExpression node, A arg) {
+ switch (semantics.kind) {
+ case ConstructorAccessKind.GENERATIVE:
+ return visitor.visitGenerativeConstructorInvoke(
+ node, semantics.element, semantics.type,
+ node.send.argumentsNode, selector, arg);
+ case ConstructorAccessKind.REDIRECTING_GENERATIVE:
+ return visitor.visitRedirectingGenerativeConstructorInvoke(
+ node, semantics.element, semantics.type,
+ node.send.argumentsNode, selector, arg);
+ case ConstructorAccessKind.FACTORY:
+ return visitor.visitFactoryConstructorInvoke(
+ node, semantics.element, semantics.type,
+ node.send.argumentsNode, selector, arg);
+ case ConstructorAccessKind.REDIRECTING_FACTORY:
+ return visitor.visitRedirectingFactoryConstructorInvoke(
+ node, semantics.element, semantics.type,
+ semantics.effectiveTargetSemantics.element,
+ semantics.effectiveTargetSemantics.type,
+ node.send.argumentsNode, selector, arg);
+ case ConstructorAccessKind.ABSTRACT:
+ return visitor.errorAbstractClassConstructorInvoke(
+ node, semantics.element, semantics.type,
+ node.send.argumentsNode, selector, arg);
+ case ConstructorAccessKind.ERRONEOUS:
+ return visitor.errorUnresolvedConstructorInvoke(
+ node, semantics.element, semantics.type,
+ node.send.argumentsNode, selector, arg);
+ case ConstructorAccessKind.ERRONEOUS_REDIRECTING_FACTORY:
+ return visitor.errorUnresolvedRedirectingFactoryConstructorInvoke(
+ node, semantics.element, semantics.type,
+ node.send.argumentsNode, selector, arg);
+ }
+ throw new SpannableAssertionFailure(node,
+ "Unhandled constructor invocation kind: ${semantics.kind}");
+ }
+}
+
+/// The structure for a [NewExpression] of a constant invocation. For instance
+/// `const C()`.
+class ConstInvokeStructure<R, A> extends NewStructure<R, A> {
+ final ConstructedConstantExpression constant;
+
+ ConstInvokeStructure(this.constant);
+
+ R dispatch(SemanticSendVisitor<R, A> visitor, NewExpression node, A arg) {
+ return visitor.visitConstConstructorInvoke(node, constant, arg);
+ }
}
diff --git a/pkg/compiler/lib/src/resolved_visitor.dart b/pkg/compiler/lib/src/resolved_visitor.dart
index 5d4ae3b..561746b 100644
--- a/pkg/compiler/lib/src/resolved_visitor.dart
+++ b/pkg/compiler/lib/src/resolved_visitor.dart
@@ -4,55 +4,24 @@
part of dart2js;
-abstract class ResolvedVisitor<R> extends Visitor<R> {
- TreeElements elements;
+/// Enum for the visit methods added in [ResolvedVisitor].
+// TODO(johnniwinther): Remove this.
+enum ResolvedKind {
+ ASSERT,
+ TYPE_LITERAL,
+ SUPER,
+ OPERATOR,
+ TYPE_PREFIX,
+ GETTER,
+ STATIC,
+ CLOSURE,
+ DYNAMIC,
+ ERROR,
+}
- ResolvedVisitor(this.elements);
-
- R visitSend(Send node) {
- Element element = elements[node];
- if (elements.isAssert(node)) {
- return visitAssert(node);
- } else if (elements.isTypeLiteral(node)) {
- return visitTypeLiteralSend(node);
- } else if (node.isSuperCall) {
- return visitSuperSend(node);
- } else if (node.isOperator) {
- return visitOperatorSend(node);
- } else if (node.isPropertyAccess) {
- if (!Elements.isUnresolved(element) && element.impliesType) {
- return visitTypePrefixSend(node);
- } else {
- return visitGetterSend(node);
- }
- } else if (element != null && Initializers.isConstructorRedirect(node)) {
- return visitStaticSend(node);
- } else if (Elements.isClosureSend(node, element)) {
- return visitClosureSend(node);
- } else {
- if (Elements.isUnresolved(element)) {
- if (element == null) {
- // Example: f() with 'f' unbound.
- // This can only happen inside an instance method.
- return visitDynamicSend(node);
- } else {
- return visitStaticSend(node);
- }
- } else if (element.isInstanceMember) {
- // Example: f() with 'f' bound to instance method.
- return visitDynamicSend(node);
- } else if (!element.isInstanceMember) {
- // Example: A.f() or f() with 'f' bound to a static function.
- // Also includes new A() or new A.named() which is treated like a
- // static call to a factory.
- return visitStaticSend(node);
- } else {
- internalError("Cannot generate code for send", node: node);
- return null;
- }
- }
- }
-
+/// Abstract interface for a [ResolvedVisitor].
+// TODO(johnniwinther): Remove this.
+abstract class ResolvedKindVisitor<R> {
R visitSuperSend(Send node);
R visitOperatorSend(Send node);
R visitGetterSend(Send node);
@@ -68,12 +37,671 @@
// TODO(johnniwinther): Remove this when not needed by the dart backend.
R visitTypePrefixSend(Send node);
- R visitAssert(Send node);
+ R visitAssertSend(Send node);
- void internalError(String reason, {Node node});
+ internalError(Spannable node, String reason);
+}
+
+/// Visitor that returns the [ResolvedKind] corresponding to the called visitor
+/// method.
+class ResolvedKindComputer implements ResolvedKindVisitor {
+ const ResolvedKindComputer();
+
+ ResolvedKind visitSuperSend(Send node) => ResolvedKind.SUPER;
+ ResolvedKind visitOperatorSend(Send node) => ResolvedKind.OPERATOR;
+ ResolvedKind visitGetterSend(Send node) => ResolvedKind.GETTER;
+ ResolvedKind visitClosureSend(Send node) => ResolvedKind.CLOSURE;
+ ResolvedKind visitDynamicSend(Send node) => ResolvedKind.DYNAMIC;
+ ResolvedKind visitStaticSend(Send node) => ResolvedKind.STATIC;
+ ResolvedKind visitTypeLiteralSend(Send node) => ResolvedKind.TYPE_LITERAL;
+ ResolvedKind visitTypePrefixSend(Send node) => ResolvedKind.TYPE_PREFIX;
+ ResolvedKind visitAssertSend(Send node) => ResolvedKind.ASSERT;
+ internalError(Spannable node, String reason) => ResolvedKind.ERROR;
+}
+
+abstract class ResolvedVisitor<R>
+ implements Visitor<R>, ResolvedKindVisitor<R> {}
+
+abstract class BaseResolvedVisitor<R> extends Visitor<R>
+ implements ResolvedVisitor<R> {
+
+ TreeElements elements;
+
+ BaseResolvedVisitor(this.elements);
+
+ /// Dispatch using the old [ResolvedVisitor] logic.
+ // TODO(johnniwinther): Remove this.
+ _oldDispatch(Send node, ResolvedKindVisitor visitor) {
+ Element element = elements[node];
+ if (elements.isAssert(node)) {
+ return visitor.visitAssertSend(node);
+ } else if (elements.isTypeLiteral(node)) {
+ return visitor.visitTypeLiteralSend(node);
+ } else if (node.isSuperCall) {
+ return visitor.visitSuperSend(node);
+ } else if (node.isOperator) {
+ return visitor.visitOperatorSend(node);
+ } else if (node.isPropertyAccess) {
+ if (!Elements.isUnresolved(element) && element.impliesType) {
+ return visitor.visitTypePrefixSend(node);
+ } else {
+ return visitor.visitGetterSend(node);
+ }
+ } else if (element != null && Initializers.isConstructorRedirect(node)) {
+ return visitor.visitStaticSend(node);
+ } else if (Elements.isClosureSend(node, element)) {
+ return visitor.visitClosureSend(node);
+ } else {
+ if (Elements.isUnresolved(element)) {
+ if (element == null) {
+ // Example: f() with 'f' unbound.
+ // This can only happen inside an instance method.
+ return visitor.visitDynamicSend(node);
+ } else {
+ return visitor.visitStaticSend(node);
+ }
+ } else if (element.isInstanceMember) {
+ // Example: f() with 'f' bound to instance method.
+ return visitor.visitDynamicSend(node);
+ } else if (!element.isInstanceMember) {
+ // Example: A.f() or f() with 'f' bound to a static function.
+ // Also includes new A() or new A.named() which is treated like a
+ // static call to a factory.
+ return visitor.visitStaticSend(node);
+ } else {
+ return visitor.internalError(node, "Cannot generate code for send");
+ }
+ }
+ }
+
+ internalError(Spannable node, String reason);
R visitNode(Node node) {
- internalError("Unhandled node", node: node);
+ internalError(node, "Unhandled node");
return null;
}
}
+
+// TODO(johnniwinther): Remove this. Currently need by the old dart2dart
+// backend.
+abstract class OldResolvedVisitor<R> extends BaseResolvedVisitor<R> {
+ OldResolvedVisitor(TreeElements elements) : super(elements);
+
+ R visitSend(Send node) {
+ return _oldDispatch(node, this);
+ }
+}
+
+abstract class NewResolvedVisitor<R> extends BaseResolvedVisitor<R>
+ with SendResolverMixin,
+ GetBulkMixin<R, dynamic>,
+ SetBulkMixin<R, dynamic>,
+ ErrorBulkMixin<R, dynamic>,
+ InvokeBulkMixin<R, dynamic>,
+ IndexSetBulkMixin<R, dynamic>,
+ CompoundBulkMixin<R, dynamic>,
+ UnaryBulkMixin<R, dynamic>,
+ BaseBulkMixin<R, dynamic>,
+ BinaryBulkMixin<R, dynamic>,
+ PrefixBulkMixin<R, dynamic>,
+ PostfixBulkMixin<R, dynamic>,
+ NewBulkMixin<R, dynamic> {
+
+ final ResolvedSemanticDispatcher<R> _semanticDispatcher =
+ new ResolvedSemanticDispatcher<R>();
+
+ final ResolvedSemanticDispatcher<ResolvedKind> _resolvedKindDispatcher =
+ new ResolvedSemanticDispatcher<ResolvedKind>();
+
+ NewResolvedVisitor(TreeElements elements) : super(elements);
+
+ /// Dispatch using the new [SemanticSendVisitor] logic.
+ _newDispatch(Send node,
+ ResolvedKindVisitor kindVisitor,
+ SemanticSendVisitor sendVisitor) {
+ Element element = elements[node];
+ if (element != null && element.isConstructor) {
+ if (node.isSuperCall) {
+ return kindVisitor.visitSuperSend(node);
+ } else {
+ return kindVisitor.visitStaticSend(node);
+ }
+ } else if (element != null && element.isPrefix) {
+ return kindVisitor.visitGetterSend(node);
+ } else if (!elements.isTypeLiteral(node) &&
+ node.isPropertyAccess &&
+ !Elements.isUnresolved(element) &&
+ element.impliesType) {
+ return kindVisitor.visitTypePrefixSend(node);
+ } else {
+ SendStructure sendStructure = computeSendStructure(node);
+ if (sendStructure != null) {
+ var arg = sendVisitor == _resolvedKindDispatcher
+ ? kindVisitor : sendStructure;
+ return sendStructure.dispatch(sendVisitor, node, arg);
+ } else {
+ return kindVisitor.visitStaticSend(node);
+ }
+ }
+ }
+
+ R visitSend(Send node) {
+ ResolvedKind oldKind;
+ ResolvedKind newKind;
+ assert(invariant(node, () {
+ oldKind = _oldDispatch(node, const ResolvedKindComputer());
+ newKind = _newDispatch(
+ node, const ResolvedKindComputer(), _resolvedKindDispatcher);
+ return oldKind == newKind;
+ }, message: () => '$oldKind != $newKind'));
+ return _newDispatch(node, this, this);
+ }
+
+ @override
+ R apply(Node node, arg) {
+ return visitNode(node);
+ }
+
+ @override
+ R bulkHandleNode(
+ Node node,
+ String message,
+ SendStructure sendStructure) {
+ return sendStructure.dispatch(_semanticDispatcher, node, this);
+ }
+}
+
+/// Visitor that dispatches [SemanticSendVisitor] calls to the corresponding
+/// visit methods in [ResolvedVisitor].
+class ResolvedSemanticDispatcher<R> extends Object
+ with GetBulkMixin<R, ResolvedKindVisitor<R>>,
+ SetBulkMixin<R, ResolvedKindVisitor<R>>,
+ InvokeBulkMixin<R, ResolvedKindVisitor<R>>,
+ PrefixBulkMixin<R, ResolvedKindVisitor<R>>,
+ PostfixBulkMixin<R, ResolvedKindVisitor<R>>,
+ SuperBulkMixin<R, ResolvedKindVisitor<R>>,
+ CompoundBulkMixin<R, ResolvedKindVisitor<R>>,
+ IndexSetBulkMixin<R, ResolvedKindVisitor<R>>,
+ NewBulkMixin<R, ResolvedKindVisitor<R>>,
+ ErrorBulkMixin<R, ResolvedKindVisitor<R>>
+ implements SemanticSendVisitor<R, ResolvedKindVisitor<R>> {
+
+ ResolvedSemanticDispatcher();
+
+ @override
+ R apply(Node node, ResolvedKindVisitor<R> visitor) {
+ return visitor.internalError(
+ node, "ResolvedSemanticDispatcher.apply unsupported.");
+ }
+
+ @override
+ R bulkHandleNode(
+ Node node,
+ String message,
+ ResolvedKindVisitor<R> visitor) {
+ // Set, Compound, IndexSet, and NewExpression are not handled by
+ // [ResolvedVisitor].
+ return bulkHandleError(node, visitor);
+ }
+
+ R bulkHandleError(Node node, ResolvedKindVisitor<R> visitor) {
+ return visitor.internalError(node, "No resolved kind for node.");
+ }
+
+ @override
+ R bulkHandleGet(Node node, ResolvedKindVisitor<R> visitor) {
+ return visitor.visitGetterSend(node);
+ }
+
+ @override
+ R bulkHandleInvoke(Node node, ResolvedKindVisitor<R> visitor) {
+ // Most invokes are static.
+ return visitor.visitStaticSend(node);
+ }
+
+ @override
+ R bulkHandlePrefix(Node node, ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R bulkHandlePostfix(Node node, ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R bulkHandleSuper(Node node, ResolvedKindVisitor<R> visitor) {
+ return visitor.visitSuperSend(node);
+ }
+
+ @override
+ R errorInvalidAssert(
+ Send node,
+ NodeList arguments,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitAssertSend(node);
+ }
+
+ @override
+ R errorLocalFunctionPostfix(
+ Send node,
+ LocalFunctionElement function,
+ op.IncDecOperator operator,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R errorLocalFunctionPrefix(
+ Send node,
+ LocalFunctionElement function,
+ op.IncDecOperator operator,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R errorStaticSetterGet(
+ Send node,
+ FunctionElement setter,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitGetterSend(node);
+ }
+
+ @override
+ R errorStaticSetterInvoke(
+ Send node,
+ FunctionElement setter,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitStaticSend(node);
+ }
+
+ @override
+ R errorSuperSetterGet(
+ Send node,
+ FunctionElement setter,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitGetterSend(node);
+ }
+
+ @override
+ R errorSuperSetterInvoke(
+ Send node,
+ FunctionElement setter,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitSuperSend(node);
+ }
+
+ @override
+ R errorTopLevelSetterGet(
+ Send node,
+ FunctionElement setter,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitGetterSend(node);
+ }
+
+ @override
+ R errorTopLevelSetterInvoke(
+ Send node,
+ FunctionElement setter,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitStaticSend(node);
+ }
+
+ @override
+ R errorUndefinedBinaryExpression(
+ Send node,
+ Node left,
+ Operator operator,
+ Node right,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R errorUndefinedUnaryExpression(
+ Send node,
+ Operator operator,
+ Node expression,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R errorUnresolvedGet(
+ Send node,
+ Element element,
+ ResolvedKindVisitor<R> visitor) {
+ if (node.isSuperCall) {
+ return visitor.visitSuperSend(node);
+ }
+ return visitor.visitGetterSend(node);
+ }
+
+ @override
+ R errorUnresolvedInvoke(
+ Send node,
+ Element element,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ if (node.isSuperCall) {
+ return visitor.visitSuperSend(node);
+ }
+ return visitor.visitStaticSend(node);
+ }
+
+ @override
+ R errorUnresolvedPostfix(
+ Send node,
+ Element element,
+ op.IncDecOperator operator,
+ ResolvedKindVisitor<R> visitor) {
+ if (node.isSuperCall) {
+ return visitor.visitSuperSend(node);
+ }
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R errorUnresolvedPrefix(
+ Send node,
+ Element element,
+ op.IncDecOperator operator,
+ ResolvedKindVisitor<R> visitor) {
+ if (node.isSuperCall) {
+ return visitor.visitSuperSend(node);
+ }
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R errorUnresolvedSuperBinary(
+ Send node,
+ Element element,
+ op.BinaryOperator operator,
+ Node argument,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitSuperSend(node);
+ }
+
+ @override
+ R errorUnresolvedSuperUnary(
+ Send node,
+ op.UnaryOperator operator,
+ Element element,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitSuperSend(node);
+ }
+
+ @override
+ R visitAs(
+ Send node,
+ Node expression,
+ DartType type,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R visitAssert(
+ Send node,
+ Node expression,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitAssertSend(node);
+ }
+
+ @override
+ R visitBinary(
+ Send node,
+ Node left,
+ op.BinaryOperator operator,
+ Node right,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R visitEquals(
+ Send node,
+ Node left,
+ Node right,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R visitIs(
+ Send node,
+ Node expression,
+ DartType type,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R visitIsNot(
+ Send node,
+ Node expression,
+ DartType type,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R visitLogicalAnd(
+ Send node,
+ Node left,
+ Node right,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R visitLogicalOr(
+ Send node,
+ Node left,
+ Node right,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R visitNot(
+ Send node,
+ Node expression,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R visitNotEquals(
+ Send node,
+ Node left,
+ Node right,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R visitUnary(
+ Send node,
+ op.UnaryOperator operator,
+ Node expression,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R visitDynamicPropertyInvoke(
+ Send node,
+ Node receiver,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitDynamicSend(node);
+ }
+
+ @override
+ R visitThisPropertyInvoke(
+ Send node,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitDynamicSend(node);
+ }
+
+ @override
+ R visitExpressionInvoke(
+ Send node,
+ Node receiver,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitClosureSend(node);
+ }
+
+ @override
+ R visitParameterInvoke(
+ Send node,
+ ParameterElement parameter,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitClosureSend(node);
+ }
+
+ @override
+ R visitLocalVariableInvoke(
+ Send node,
+ LocalVariableElement variable,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitClosureSend(node);
+ }
+
+ @override
+ R visitLocalFunctionInvoke(
+ Send node,
+ LocalFunctionElement function,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitClosureSend(node);
+ }
+
+ @override
+ R visitThisInvoke(
+ Send node,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitClosureSend(node);
+ }
+
+ @override
+ R visitClassTypeLiteralGet(
+ Send node,
+ ConstantExpression constant,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitTypeLiteralSend(node);
+ }
+
+ @override
+ R visitTypedefTypeLiteralGet(
+ Send node,
+ ConstantExpression constant,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitTypeLiteralSend(node);
+ }
+
+ @override
+ R visitDynamicTypeLiteralGet(
+ Send node,
+ ConstantExpression constant,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitTypeLiteralSend(node);
+ }
+
+ @override
+ R visitTypeVariableTypeLiteralGet(
+ Send node,
+ TypeVariableElement element,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitTypeLiteralSend(node);
+ }
+
+ @override
+ R visitClassTypeLiteralInvoke(
+ Send node,
+ ConstantExpression constant,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitTypeLiteralSend(node);
+ }
+
+ @override
+ R visitTypedefTypeLiteralInvoke(
+ Send node,
+ ConstantExpression constant,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitTypeLiteralSend(node);
+ }
+
+ @override
+ R visitDynamicTypeLiteralInvoke(
+ Send node,
+ ConstantExpression constant,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitTypeLiteralSend(node);
+ }
+
+ @override
+ R visitTypeVariableTypeLiteralInvoke(
+ Send node,
+ TypeVariableElement element,
+ NodeList arguments,
+ Selector selector,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitTypeLiteralSend(node);
+ }
+
+ @override
+ R visitIndex(
+ Send node,
+ Node receiver,
+ Node index,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitOperatorSend(node);
+ }
+
+ @override
+ R visitSuperIndex(
+ Send node,
+ FunctionElement function,
+ Node index,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitSuperSend(node);
+ }
+
+ @override
+ R errorUnresolvedSuperIndex(
+ Send node,
+ Element function,
+ Node index,
+ ResolvedKindVisitor<R> visitor) {
+ return visitor.visitSuperSend(node);
+ }
+}
diff --git a/pkg/compiler/lib/src/scanner/parser.dart b/pkg/compiler/lib/src/scanner/parser.dart
index 00e599f..7957b5e 100644
--- a/pkg/compiler/lib/src/scanner/parser.dart
+++ b/pkg/compiler/lib/src/scanner/parser.dart
@@ -1073,6 +1073,8 @@
parseModifier(token);
} else {
listener.unexpected(token);
+ // Skip the remaining modifiers.
+ break;
}
count++;
}
diff --git a/pkg/compiler/lib/src/scanner/token.dart b/pkg/compiler/lib/src/scanner/token.dart
index 483eda9..76229cd 100644
--- a/pkg/compiler/lib/src/scanner/token.dart
+++ b/pkg/compiler/lib/src/scanner/token.dart
@@ -385,12 +385,9 @@
static String decodeUtf8(List<int> data, int start, int end, bool asciiOnly) {
var s;
if (asciiOnly) {
- // getRange returns an iterator, it does not copy the data.
- s = new String.fromCharCodes(data.getRange(start, end));
+ s = new String.fromCharCodes(data, start, end);
} else {
- // TODO(lry): this is measurably slow. Also sublist is copied eagerly.
- var bytes = data.sublist(start, end);
- s = UTF8.decode(bytes);
+ s = UTF8.decoder.convert(data, start, end);
}
return canonicalizedString(s, true);
}
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 590dd80..195b188 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -89,6 +89,8 @@
final ExecutableElement executableContext;
SyntheticLocal(this.name, this.executableContext);
+
+ toString() => 'SyntheticLocal($name)';
}
class SsaBuilderTask extends CompilerTask {
@@ -389,8 +391,11 @@
HParameterValue value =
new HParameterValue(parameter, builder.getTypeOfThis());
builder.graph.explicitReceiverParameter = value;
- builder.graph.entry.addAfter(
- directLocals[closureData.thisLocal], value);
+ builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value);
+ if (builder.lastAddedParameter == null) {
+ // If this is the first parameter inserted, make sure it stays first.
+ builder.lastAddedParameter = value;
+ }
if (isInterceptorClass) {
// Only use the extra parameter in intercepted classes.
directLocals[closureData.thisLocal] = value;
@@ -980,7 +985,7 @@
/**
* This class builds SSA nodes for functions represented in AST.
*/
-class SsaBuilder extends ResolvedVisitor {
+class SsaBuilder extends NewResolvedVisitor {
final Compiler compiler;
final JavaScriptBackend backend;
final ConstantSystem constantSystem;
@@ -1244,7 +1249,8 @@
* For each parameter name in the signature, if the argument name matches
* we use the next provided argument, otherwise we get the default.
*/
- List<String> selectorArgumentNames = selector.getOrderedNamedArguments();
+ List<String> selectorArgumentNames =
+ selector.callStructure.getOrderedNamedArguments();
int namedArgumentIndex = 0;
int firstProvidedNamedArgument = index;
signature.orderedOptionalParameters.forEach((element) {
@@ -1893,13 +1899,12 @@
}
Element target = constructor.definingConstructor.implementation;
- bool match = Selector.addForwardingElementArgumentsToList(
+ bool match = CallStructure.addForwardingElementArgumentsToList(
constructor,
arguments,
target,
compileArgument,
- handleConstantForOptionalParameter,
- compiler.world);
+ handleConstantForOptionalParameter);
if (!match) {
if (compiler.elementHasCompileTimeError(constructor)) {
return;
@@ -1933,12 +1938,13 @@
assert(ast.Initializers.isSuperConstructorCall(call) ||
ast.Initializers.isConstructorRedirect(call));
FunctionElement target = elements[call].implementation;
- Selector selector = elements.getSelector(call);
+ CallStructure callStructure =
+ elements.getSelector(call).callStructure;
Link<ast.Node> arguments = call.arguments;
List<HInstruction> compiledArguments;
inlinedFrom(constructor, () {
compiledArguments =
- makeStaticArgumentList(selector, arguments, target);
+ makeStaticArgumentList(callStructure, arguments, target);
});
inlineSuperOrRedirect(target,
compiledArguments,
@@ -1972,12 +1978,12 @@
compiler.internalError(superClass,
"No default constructor available.");
}
- Selector selector = new Selector.callDefaultConstructor();
List<HInstruction> arguments =
- selector.makeArgumentsList(const Link<ast.Node>(),
- target.implementation,
- null,
- handleConstantForOptionalParameter);
+ CallStructure.NO_ARGS.makeArgumentsList(
+ const Link<ast.Node>(),
+ target.implementation,
+ null,
+ handleConstantForOptionalParameter);
inlineSuperOrRedirect(target,
arguments,
constructors,
@@ -3133,7 +3139,7 @@
pushWithPosition(not, node);
}
- void visitUnary(ast.Send node, ast.Operator op) {
+ void visitUnarySend(ast.Send node, ast.Operator op) {
assert(node.argumentsNode is ast.Prefix);
visit(node.receiver);
assert(!identical(op.token.kind, PLUS_TOKEN));
@@ -3153,11 +3159,11 @@
pushInvokeDynamic(node, elements.getSelector(node), [operand]);
}
- void visitBinary(HInstruction left,
- ast.Operator op,
- HInstruction right,
- Selector selector,
- ast.Send send) {
+ void visitBinarySend(HInstruction left,
+ ast.Operator op,
+ HInstruction right,
+ Selector selector,
+ ast.Send send) {
switch (op.source) {
case "===":
pushWithPosition(
@@ -3425,7 +3431,7 @@
} else if ("!" == op.source) {
visitLogicalNot(node);
} else if (node.argumentsNode is ast.Prefix) {
- visitUnary(node, op);
+ visitUnarySend(node, op);
} else if ("is" == op.source) {
visitIsSend(node);
} else if ("as" == op.source) {
@@ -3448,7 +3454,7 @@
visit(node.argumentsNode);
var right = pop();
var left = pop();
- visitBinary(left, op, right, elements.getSelector(node), node);
+ visitBinarySend(left, op, right, elements.getSelector(node), node);
}
}
@@ -3522,13 +3528,13 @@
}
void addDynamicSendArgumentsToList(ast.Send node, List<HInstruction> list) {
- Selector selector = elements.getSelector(node);
- if (selector.namedArgumentCount == 0) {
+ CallStructure callStructure = elements.getSelector(node).callStructure;
+ if (callStructure.namedArgumentCount == 0) {
addGenericSendArgumentsToList(node.arguments, list);
} else {
// Visit positional arguments and add them to the list.
Link<ast.Node> arguments = node.arguments;
- int positionalArgumentCount = selector.positionalArgumentCount;
+ int positionalArgumentCount = callStructure.positionalArgumentCount;
for (int i = 0;
i < positionalArgumentCount;
arguments = arguments.tail, i++) {
@@ -3539,7 +3545,7 @@
// Visit named arguments and add them into a temporary map.
Map<String, HInstruction> instructions =
new Map<String, HInstruction>();
- List<String> namedArguments = selector.namedArguments;
+ List<String> namedArguments = callStructure.namedArguments;
int nameIndex = 0;
for (; !arguments.isEmpty; arguments = arguments.tail) {
visit(arguments.head);
@@ -3549,7 +3555,7 @@
// Iterate through the named arguments to add them to the list
// of instructions, in an order that can be shared with
// selectors with the same named arguments.
- List<String> orderedNames = selector.getOrderedNamedArguments();
+ List<String> orderedNames = callStructure.getOrderedNamedArguments();
for (String name in orderedNames) {
list.add(instructions[name]);
}
@@ -3562,7 +3568,7 @@
* Precondition: `this.applies(element, world)`.
* Invariant: [element] must be an implementation element.
*/
- List<HInstruction> makeStaticArgumentList(Selector selector,
+ List<HInstruction> makeStaticArgumentList(CallStructure callStructure,
Link<ast.Node> arguments,
FunctionElement element) {
assert(invariant(element, element.isImplementation));
@@ -3572,10 +3578,11 @@
return pop();
}
- return selector.makeArgumentsList(arguments,
- element,
- compileArgument,
- handleConstantForOptionalParameter);
+ return callStructure.makeArgumentsList(
+ arguments,
+ element,
+ compileArgument,
+ handleConstantForOptionalParameter);
}
void addGenericSendArgumentsToList(Link<ast.Node> link, List<HInstruction> list) {
@@ -4103,7 +4110,7 @@
// calling [makeStaticArgumentList].
FunctionElement function = element.implementation;
assert(selector.applies(function, compiler.world));
- inputs = makeStaticArgumentList(selector,
+ inputs = makeStaticArgumentList(selector.callStructure,
node.arguments,
function);
push(buildInvokeSuper(selector, element, inputs));
@@ -4347,7 +4354,7 @@
}
Element constructor = elements[send];
- Selector selector = elements.getSelector(send);
+ CallStructure callStructure = elements.getSelector(send).callStructure;
ConstructorElement constructorDeclaration = constructor;
ConstructorElement constructorImplementation = constructor.implementation;
constructor = constructorImplementation.effectiveTarget;
@@ -4361,8 +4368,8 @@
constructor = compiler.symbolValidatedConstructor;
assert(invariant(send, constructor != null,
message: 'Constructor Symbol.validated is missing'));
- selector = compiler.symbolValidatedConstructorSelector;
- assert(invariant(send, selector != null,
+ callStructure = compiler.symbolValidatedConstructorSelector.callStructure;
+ assert(invariant(send, callStructure != null,
message: 'Constructor Symbol.validated is missing'));
}
@@ -4387,11 +4394,11 @@
}
// TODO(5347): Try to avoid the need for calling [implementation] before
// calling [makeStaticArgumentList].
- if (!selector.applies(constructor.implementation, compiler.world)) {
+ if (!callStructure.signatureApplies(constructor.implementation)) {
generateWrongArgumentCountError(send, constructor, send.arguments);
return;
}
- inputs.addAll(makeStaticArgumentList(selector,
+ inputs.addAll(makeStaticArgumentList(callStructure,
send.arguments,
constructor.implementation));
@@ -4537,7 +4544,7 @@
return false;
}
- visitAssert(node) {
+ visitAssertSend(node) {
if (!compiler.enableUserAssertions) {
stack.add(graph.addConstantNull(compiler));
return;
@@ -4550,7 +4557,7 @@
}
visitStaticSend(ast.Send node) {
- Selector selector = elements.getSelector(node);
+ CallStructure callStructure = elements.getSelector(node).callStructure;
Element element = elements[node];
if (elements.isAssert(node)) {
element = backend.assertMethod;
@@ -4577,13 +4584,13 @@
if (element.isFunction) {
// TODO(5347): Try to avoid the need for calling [implementation] before
// calling [makeStaticArgumentList].
- if (!selector.applies(element.implementation, compiler.world)) {
+ if (!callStructure.signatureApplies(element.implementation)) {
generateWrongArgumentCountError(node, element, node.arguments);
return;
}
List<HInstruction> inputs =
- makeStaticArgumentList(selector,
+ makeStaticArgumentList(callStructure,
node.arguments,
element.implementation);
@@ -4598,7 +4605,7 @@
generateGetter(node, element);
List<HInstruction> inputs = <HInstruction>[pop()];
addDynamicSendArgumentsToList(node, inputs);
- Selector closureSelector = new Selector.callClosureFrom(selector);
+ Selector closureSelector = callStructure.callSelector;
pushWithPosition(
new HInvokeClosure(closureSelector, inputs, backend.dynamicType),
node);
@@ -4637,7 +4644,7 @@
backend.getCreateRuntimeType(),
[pop()]);
} else {
- internalError('unexpected type kind ${type.kind}', node: node);
+ internalError(node, 'unexpected type kind ${type.kind}');
}
if (node.isCall) {
// This send is of the form 'e(...)', where e is resolved to a type
@@ -4659,7 +4666,7 @@
}
// TODO(antonm): migrate rest of SsaFromAstMixin to internalError.
- internalError(String reason, {ast.Node node}) {
+ internalError(Spannable node, String reason) {
compiler.internalError(node, reason);
}
@@ -4924,8 +4931,8 @@
assert(arguments.tail.isEmpty);
rhs = pop();
}
- visitBinary(receiver, node.assignmentOperator, rhs,
- elements.getOperatorSelectorInComplexSendSet(node), node);
+ visitBinarySend(receiver, node.assignmentOperator, rhs,
+ elements.getOperatorSelectorInComplexSendSet(node), node);
}
visitSendSet(ast.SendSet node) {
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 60403c3..ea200c3 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -1472,14 +1472,25 @@
}
void visitInterceptor(HInterceptor node) {
- registry.registerSpecializedGetInterceptor(node.interceptedClasses);
- String name = backend.namer.nameForGetInterceptor(node.interceptedClasses);
- var isolate = new js.VariableUse(
- backend.namer.globalObjectFor(backend.interceptorsLibrary));
- use(node.receiver);
- List<js.Expression> arguments = <js.Expression>[pop()];
- push(js.propertyCall(isolate, name, arguments), node);
- registry.registerUseInterceptor();
+ if (node.isConditionalConstantInterceptor) {
+ assert(node.inputs.length == 2);
+ use(node.receiver);
+ js.Expression receiverExpression = pop();
+ use(node.conditionalConstantInterceptor);
+ js.Expression constant = pop();
+ push(js.js('# && #', [receiverExpression, constant]));
+ } else {
+ assert(node.inputs.length == 1);
+ registry.registerSpecializedGetInterceptor(node.interceptedClasses);
+ String name =
+ backend.namer.nameForGetInterceptor(node.interceptedClasses);
+ var isolate = new js.VariableUse(
+ backend.namer.globalObjectFor(backend.interceptorsLibrary));
+ use(node.receiver);
+ List<js.Expression> arguments = <js.Expression>[pop()];
+ push(js.propertyCall(isolate, name, arguments), node);
+ registry.registerUseInterceptor();
+ }
}
visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index d8213e2..a22b94d 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
@@ -110,47 +110,8 @@
return graph.thisInstruction;
}
- ClassElement constantInterceptor;
- ClassWorld classWorld = compiler.world;
- JavaScriptBackend backend = compiler.backend;
- if (input.canBeNull()) {
- if (input.isNull()) {
- constantInterceptor = backend.jsNullClass;
- }
- } else if (input.isInteger(compiler)) {
- constantInterceptor = backend.jsIntClass;
- } else if (input.isDouble(compiler)) {
- constantInterceptor = backend.jsDoubleClass;
- } else if (input.isBoolean(compiler)) {
- constantInterceptor = backend.jsBoolClass;
- } else if (input.isString(compiler)) {
- constantInterceptor = backend.jsStringClass;
- } else if (input.isArray(compiler)) {
- constantInterceptor = backend.jsArrayClass;
- } else if (input.isNumber(compiler) &&
- !interceptedClasses.contains(backend.jsIntClass) &&
- !interceptedClasses.contains(backend.jsDoubleClass)) {
- // If the method being intercepted is not defined in [int] or [double] we
- // can safely use the number interceptor. This is because none of the
- // [int] or [double] methods are called from a method defined on [num].
- constantInterceptor = backend.jsNumberClass;
- } else {
- // Try to find constant interceptor for a native class. If the receiver
- // is constrained to a leaf native class, we can use the class's
- // interceptor directly.
-
- // TODO(sra): Key DOM classes like Node, Element and Event are not leaf
- // classes. When the receiver type is not a leaf class, we might still be
- // able to use the receiver class as a constant interceptor. It is
- // usually the case that methods defined on a non-leaf class don't test
- // for a subclass or call methods defined on a subclass. Provided the
- // code is completely insensitive to the specific instance subclasses, we
- // can use the non-leaf class directly.
- ClassElement element = input.instructionType.singleClass(classWorld);
- if (element != null && element.isNative) {
- constantInterceptor = element;
- }
- }
+ ClassElement constantInterceptor = tryComputeConstantInterceptorFromType(
+ input.instructionType, interceptedClasses);
if (constantInterceptor == null) return null;
@@ -166,6 +127,54 @@
return graph.addConstant(constant, compiler);
}
+ ClassElement tryComputeConstantInterceptorFromType(
+ TypeMask type,
+ Set<ClassElement> interceptedClasses) {
+
+ ClassWorld classWorld = compiler.world;
+ JavaScriptBackend backend = compiler.backend;
+ if (type.isNullable) {
+ if (type.isEmpty) {
+ return backend.jsNullClass;
+ }
+ } else if (type.containsOnlyInt(classWorld)) {
+ return backend.jsIntClass;
+ } else if (type.containsOnlyDouble(classWorld)) {
+ return backend.jsDoubleClass;
+ } else if (type.containsOnlyBool(classWorld)) {
+ return backend.jsBoolClass;
+ } else if (type.containsOnlyString(classWorld)) {
+ return backend.jsStringClass;
+ } else if (type.satisfies(backend.jsArrayClass, classWorld)) {
+ return backend.jsArrayClass;
+ } else if (type.containsOnlyNum(classWorld) &&
+ !interceptedClasses.contains(backend.jsIntClass) &&
+ !interceptedClasses.contains(backend.jsDoubleClass)) {
+ // If the method being intercepted is not defined in [int] or [double] we
+ // can safely use the number interceptor. This is because none of the
+ // [int] or [double] methods are called from a method defined on [num].
+ return backend.jsNumberClass;
+ } else {
+ // Try to find constant interceptor for a native class. If the receiver
+ // is constrained to a leaf native class, we can use the class's
+ // interceptor directly.
+
+ // TODO(sra): Key DOM classes like Node, Element and Event are not leaf
+ // classes. When the receiver type is not a leaf class, we might still be
+ // able to use the receiver class as a constant interceptor. It is
+ // usually the case that methods defined on a non-leaf class don't test
+ // for a subclass or call methods defined on a subclass. Provided the
+ // code is completely insensitive to the specific instance subclasses, we
+ // can use the non-leaf class directly.
+ ClassElement element = type.singleClass(classWorld);
+ if (element != null && element.isNative) {
+ return element;
+ }
+ }
+
+ return null;
+ }
+
HInstruction findDominator(Iterable<HInstruction> instructions) {
HInstruction result;
L1: for (HInstruction candidate in instructions) {
@@ -276,6 +285,32 @@
return false;
}
+ // Do we have an 'almost constant' interceptor? The receiver could be
+ // `null` but not any other JavaScript falsy value, `null` values cause
+ // `NoSuchMethodError`s, and if the receiver was not null we would have a
+ // constant interceptor `C`. Then we can use `(receiver && C)` for the
+ // interceptor.
+ if (receiver.canBeNull() && !node.isConditionalConstantInterceptor) {
+ if (!interceptedClasses.contains(backend.jsNullClass)) {
+ // Can use `(receiver && C)` only if receiver is either null or truthy.
+ if (!(receiver.canBePrimitiveNumber(compiler) ||
+ receiver.canBePrimitiveBoolean(compiler) ||
+ receiver.canBePrimitiveString(compiler))) {
+ ClassElement interceptorClass = tryComputeConstantInterceptorFromType(
+ receiver.instructionType.nonNullable(), interceptedClasses);
+ if (interceptorClass != null) {
+ HInstruction constantInstruction =
+ graph.addConstant(
+ new InterceptorConstantValue(interceptorClass.thisType),
+ compiler);
+ node.conditionalConstantInterceptor = constantInstruction;
+ constantInstruction.usedBy.add(node);
+ return false;
+ }
+ }
+ }
+ }
+
// Try creating a one-shot interceptor or optimized is-check
if (compiler.hasIncrementalSupport) return false;
if (node.usedBy.length != 1) return false;
diff --git a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
index c5cdc94..7f5ff1d 100644
--- a/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
+++ b/pkg/compiler/lib/src/ssa/invoke_dynamic_specializers.dart
@@ -236,8 +236,8 @@
if (selector.name == name) return selector;
JavaScriptBackend backend = compiler.backend;
Selector newSelector = new Selector(
- SelectorKind.CALL, name, backend.interceptorsLibrary,
- selector.argumentCount);
+ SelectorKind.CALL, new Name(name, backend.interceptorsLibrary),
+ new CallStructure(selector.argumentCount));
return selector.mask == null
? newSelector
: new TypedSelector(selector.mask, newSelector, compiler.world);
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index f4e813b..fd28580 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -2057,7 +2057,7 @@
HConstant.internal(this.constant, TypeMask constantType)
: super(<HInstruction>[], constantType);
- toString() => 'literal: $constant';
+ toString() => 'literal: ${constant.toStructuredString()}';
accept(HVisitor visitor) => visitor.visitConstant(this);
bool isConstant() => true;
@@ -2300,15 +2300,34 @@
// This field should originally be null to allow GVN'ing all
// [HInterceptor] on the same input.
Set<ClassElement> interceptedClasses;
+
+ // inputs[0] is initially the only input, the receiver.
+
+ // inputs[1] is a constant interceptor when the interceptor is a constant
+ // except for a `null` receiver. This is used when the receiver can't be
+ // falsy, except for `null`, allowing the generation of code like
+ //
+ // (a && C.JSArray_methods).get$first(a)
+ //
+
HInterceptor(HInstruction receiver, TypeMask type)
: super(<HInstruction>[receiver], type) {
sideEffects.clearAllSideEffects();
sideEffects.clearAllDependencies();
setUseGvn();
}
+
String toString() => 'interceptor on $interceptedClasses';
accept(HVisitor visitor) => visitor.visitInterceptor(this);
HInstruction get receiver => inputs[0];
+
+ bool get isConditionalConstantInterceptor => inputs.length == 2;
+ HInstruction get conditionalConstantInterceptor => inputs[1];
+ void set conditionalConstantInterceptor(HConstant constant) {
+ assert(!isConditionalConstantInterceptor);
+ inputs.add(constant);
+ }
+
bool isInterceptor(Compiler compiler) => true;
int typeCode() => HInstruction.INTERCEPTOR_TYPECODE;
diff --git a/pkg/compiler/lib/src/tracer.dart b/pkg/compiler/lib/src/tracer.dart
index ac930ce..8491860 100644
--- a/pkg/compiler/lib/src/tracer.dart
+++ b/pkg/compiler/lib/src/tracer.dart
@@ -57,10 +57,10 @@
if (irObject is ssa.HGraph) {
new HTracer(output, compiler, context).traceGraph(name, irObject);
}
- else if (irObject is cps_ir.ExecutableDefinition) {
+ else if (irObject is cps_ir.RootNode) {
new IRTracer(output).traceGraph(name, irObject);
}
- else if (irObject is tree_ir.ExecutableDefinition) {
+ else if (irObject is tree_ir.RootNode) {
new TreeTracer(output).traceGraph(name, irObject);
}
}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/copy_propagator.dart b/pkg/compiler/lib/src/tree_ir/optimization/copy_propagator.dart
deleted file mode 100644
index f7e5369..0000000
--- a/pkg/compiler/lib/src/tree_ir/optimization/copy_propagator.dart
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of tree_ir.optimization;
-
-/// Eliminates moving assignments, such as w := v, by assigning directly to w
-/// at the definition of v.
-///
-/// This compensates for suboptimal register allocation, and merges closure
-/// variables with local temporaries that were left behind when translating
-/// out of CPS (where closure variables live in a separate space).
-class CopyPropagator extends RecursiveVisitor with PassMixin {
- String get passName => 'Copy propagation';
-
- /// After visitStatement returns, [move] maps a variable v to an
- /// assignment A of form w := v, under the following conditions:
- /// - there are no reads or writes of w before A
- /// - A is the only use of v
- Map<Variable, Assign> move = <Variable, Assign>{};
-
- /// Like [move], except w is the key instead of v.
- Map<Variable, Assign> inverseMove = <Variable, Assign>{};
-
- ExecutableElement currentElement;
-
- /// Number of try blocks enclosing the currently visited node.
- int enclosingTrys = 0;
-
- void rewriteExecutableDefinition(ExecutableDefinition root) {
- currentElement = root.element;
- root.body = visitStatement(root.body);
- }
-
- rewriteFunctionDefinition(FunctionDefinition node) {
- if (node.isAbstract) return;
- rewriteExecutableDefinition(node);
-
- // Try to propagate moving assignments into function parameters.
- // For example:
- // foo(x) {
- // var v1 = x;
- // BODY
- // }
- // ==>
- // foo(v1) {
- // BODY
- // }
-
- // Variables must not occur more than once in the parameter list, so
- // invalidate all moving assignments that would propagate a parameter
- // into another parameter. For example:
- // foo(x,y) {
- // y = x;
- // BODY
- // }
- // Cannot declare function as foo(x,x)!
- node.parameters.forEach(invalidateMovingAssignment);
-
- // Now do the propagation.
- for (int i = 0; i < node.parameters.length; i++) {
- Variable param = node.parameters[i];
- Variable replacement = copyPropagateVariable(param);
- replacement.element = param.element; // Preserve parameter name.
- node.parameters[i] = replacement;
- }
- }
-
- rewriteConstructorDefinition(ConstructorDefinition node) {
- if (node.isAbstract) return;
- node.initializers.forEach(visitExpression);
- rewriteExecutableDefinition(node);
-
-
- // Try to propagate moving assignments into function parameters.
- // For example:
- // foo(x) {
- // var v1 = x;
- // BODY
- // }
- // ==>
- // foo(v1) {
- // BODY
- // }
-
- // Variables must not occur more than once in the parameter list, so
- // invalidate all moving assignments that would propagate a parameter
- // into another parameter. For example:
- // foo(x,y) {
- // y = x;
- // BODY
- // }
- // Cannot declare function as foo(x,x)!
- node.parameters.forEach(invalidateMovingAssignment);
-
- // Now do the propagation.
- for (int i = 0; i < node.parameters.length; i++) {
- Variable param = node.parameters[i];
- Variable replacement = copyPropagateVariable(param);
- replacement.element = param.element; // Preserve parameter name.
- node.parameters[i] = replacement;
- }
-
- }
-
-
- Statement visitBasicBlock(Statement node) {
- node = visitStatement(node);
- move.clear();
- inverseMove.clear();
- return node;
- }
-
- /// Remove an assignment of form [w] := v from the move maps.
- void invalidateMovingAssignment(Variable w) {
- Assign movingAssignment = inverseMove.remove(w);
- if (movingAssignment != null) {
- VariableUse value = movingAssignment.value;
- move.remove(value.variable);
- }
- }
-
- visitVariableUse(VariableUse node) {
- // We found a use of w; we can't propagate assignments across this use.
- invalidateMovingAssignment(node.variable);
- }
-
- /**
- * Called when a definition of [v] is encountered.
- * Attempts to propagate the assignment through a moving assignment.
- * Returns the variable to be assigned into, defaulting to [v] itself if
- * no optimization could be performed.
- */
- Variable copyPropagateVariable(Variable v) {
- Assign movingAssign = move[v];
- if (movingAssign != null) {
- // We found the pattern:
- // v := EXPR
- // BLOCK (does not use w)
- // w := v (only use of v)
- //
- // Rewrite to:
- // w := EXPR
- // BLOCK
- // w := w (to be removed later)
- Variable w = movingAssign.variable;
-
- // Make w := w.
- // We can't remove the statement from here because we don't have
- // parent pointers. So just make it a no-op so it can be removed later.
- movingAssign.value = new VariableUse(w);
-
- // The intermediate variable 'v' should now be orphaned, so don't bother
- // updating its read/write counters.
-
- // Make w := EXPR
- ++w.writeCount;
- return w;
- }
- return v;
- }
-
- Statement visitAssign(Assign node) {
- node.next = visitStatement(node.next);
- node.variable = copyPropagateVariable(node.variable);
-
- // If a moving assignment w := v exists later, and we assign to w here,
- // the moving assignment is no longer a candidate for copy propagation.
- invalidateMovingAssignment(node.variable);
-
- visitExpression(node.value);
-
- // If this is a moving assignment w := v, with this being the only use of v,
- // try to propagate it backwards.
- // Do not propagate assignments where w is captured or if where are inside a
- // try block, because then we can't isolate the uses of w to a single block.
- // We currently do not support propagation if the assignment is a
- // declaration. To support this we would need to ensure that the target
- // assignment is turned into a declaration as well.
- if (node.value is VariableUse &&
- !node.variable.isCaptured &&
- enclosingTrys == 0 &&
- !node.isDeclaration) {
- VariableUse value = node.value;
- if (value.variable.readCount == 1) {
- move[value.variable] = node;
- inverseMove[node.variable] = node;
- }
- }
-
- return node;
- }
-
- Statement visitLabeledStatement(LabeledStatement node) {
- node.next = visitBasicBlock(node.next);
- node.body = visitStatement(node.body);
- return node;
- }
-
- Statement visitReturn(Return node) {
- visitExpression(node.value);
- return node;
- }
-
- Statement visitBreak(Break node) {
- return node;
- }
-
- Statement visitContinue(Continue node) {
- return node;
- }
-
- Statement visitIf(If node) {
- visitExpression(node.condition);
- node.thenStatement = visitBasicBlock(node.thenStatement);
- node.elseStatement = visitBasicBlock(node.elseStatement);
- return node;
- }
-
- Statement visitWhileTrue(WhileTrue node) {
- node.body = visitBasicBlock(node.body);
- return node;
- }
-
- Statement visitWhileCondition(WhileCondition node) {
- throw "WhileCondition before LoopRewriter";
- }
-
- Statement visitTry(Try node) {
- enclosingTrys++;
- node.tryBody = visitBasicBlock(node.tryBody);
- enclosingTrys--;
- node.catchBody = visitBasicBlock(node.catchBody);
- return node;
- }
-
- Statement visitFunctionDeclaration(FunctionDeclaration node) {
- // Unlike var declarations, function declarations are not hoisted, so we
- // can't do copy propagation of the variable.
- new CopyPropagator().rewrite(node.definition);
- node.next = visitStatement(node.next);
- return node;
- }
-
- Statement visitExpressionStatement(ExpressionStatement node) {
- node.next = visitStatement(node.next);
- visitExpression(node.expression);
- return node;
- }
-
- Statement visitSetField(SetField node) {
- node.next = visitStatement(node.next);
- visitExpression(node.value);
- visitExpression(node.object);
- return node;
- }
-
- void visitFunctionExpression(FunctionExpression node) {
- new CopyPropagator().rewrite(node.definition);
- }
-
- void visitFieldInitializer(FieldInitializer node) {
- visitStatement(node.body);
- }
-
-}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
index f68677b..9a856ba 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
@@ -54,38 +54,23 @@
/// x && !!y (!!y validated by [isBooleanValued])
/// x && y (double negation removed by [putInBooleanContext])
///
-class LogicalRewriter extends Visitor<Statement, Expression> with PassMixin {
+class LogicalRewriter extends RecursiveTransformer
+ implements Pass {
String get passName => 'Logical rewriter';
+ @override
+ void rewrite(RootNode node) {
+ node.replaceEachBody(visitStatement);
+ }
+
/// Statement to be executed next by natural fallthrough. Although fallthrough
/// is not introduced in this phase, we need to reason about fallthrough when
/// evaluating the benefit of swapping the branches of an [If].
Statement fallthrough;
- void rewriteExecutableDefinition(ExecutableDefinition root) {
- root.body = visitStatement(root.body);
- }
-
- void rewriteConstructorDefinition(ConstructorDefinition root) {
- if (root.isAbstract) return;
- List<Initializer> initializers = root.initializers;
- for (int i = 0; i < initializers.length; ++i) {
- initializers[i] = visitExpression(initializers[i]);
- }
- root.body = visitStatement(root.body);
- }
-
- Expression visitFieldInitializer(FieldInitializer node) {
- node.body = visitStatement(node.body);
- return node;
- }
-
- visitSuperInitializer(SuperInitializer node) {
- List<Statement> arguments = node.arguments;
- for (int i = 0; i < arguments.length; ++i) {
- arguments[i] = visitStatement(arguments[i]);
- }
- return node;
+ @override
+ void visitInnerFunction(FunctionDefinition node) {
+ new LogicalRewriter().rewrite(node);
}
Statement visitLabeledStatement(LabeledStatement node) {
@@ -97,25 +82,6 @@
return node;
}
- Statement visitAssign(Assign node) {
- node.value = visitExpression(node.value);
- node.next = visitStatement(node.next);
- return node;
- }
-
- Statement visitReturn(Return node) {
- node.value = visitExpression(node.value);
- return node;
- }
-
- Statement visitBreak(Break node) {
- return node;
- }
-
- Statement visitContinue(Continue node) {
- return node;
- }
-
bool isFallthroughBreak(Statement node) {
return node is Break && node.target.binding.next == fallthrough;
}
@@ -160,11 +126,6 @@
return node;
}
- Statement visitWhileTrue(WhileTrue node) {
- node.body = visitStatement(node.body);
- return node;
- }
-
Statement visitWhileCondition(WhileCondition node) {
node.condition = makeCondition(node.condition, true, liftNots: false);
node.body = visitStatement(node.body);
@@ -172,90 +133,6 @@
return node;
}
- Statement visitTry(Try node) {
- node.tryBody = visitStatement(node.tryBody);
- node.catchBody = visitStatement(node.catchBody);
- return node;
- }
-
- Statement visitExpressionStatement(ExpressionStatement node) {
- node.expression = visitExpression(node.expression);
- node.next = visitStatement(node.next);
- return node;
- }
-
- Expression visitVariableUse(VariableUse node) {
- return node;
- }
-
- Expression visitInvokeStatic(InvokeStatic node) {
- _rewriteList(node.arguments);
- return node;
- }
-
- Expression visitInvokeMethod(InvokeMethod node) {
- node.receiver = visitExpression(node.receiver);
- _rewriteList(node.arguments);
- return node;
- }
-
- Expression visitInvokeMethodDirectly(InvokeMethodDirectly node) {
- node.receiver = visitExpression(node.receiver);
- _rewriteList(node.arguments);
- return node;
- }
-
- Expression visitInvokeConstructor(InvokeConstructor node) {
- _rewriteList(node.arguments);
- return node;
- }
-
- Expression visitConcatenateStrings(ConcatenateStrings node) {
- _rewriteList(node.arguments);
- return node;
- }
-
- Expression visitLiteralList(LiteralList node) {
- _rewriteList(node.values);
- return node;
- }
-
- Expression visitLiteralMap(LiteralMap node) {
- node.entries.forEach((LiteralMapEntry entry) {
- entry.key = visitExpression(entry.key);
- entry.value = visitExpression(entry.value);
- });
- return node;
- }
-
- Expression visitTypeOperator(TypeOperator node) {
- node.receiver = visitExpression(node.receiver);
- return node;
- }
-
- Expression visitConstant(Constant node) {
- return node;
- }
-
- Expression visitThis(This node) {
- return node;
- }
-
- Expression visitReifyTypeVar(ReifyTypeVar node) {
- return node;
- }
-
- Expression visitFunctionExpression(FunctionExpression node) {
- new LogicalRewriter().rewrite(node.definition);
- return node;
- }
-
- Statement visitFunctionDeclaration(FunctionDeclaration node) {
- new LogicalRewriter().rewrite(node.definition);
- node.next = visitStatement(node.next);
- return node;
- }
-
Expression visitNot(Not node) {
return toBoolean(makeCondition(node.operand, false, liftNots: false));
}
@@ -322,37 +199,6 @@
return node;
}
- Statement visitSetField(SetField node) {
- node.object = visitExpression(node.object);
- node.value = visitExpression(node.value);
- node.next = visitStatement(node.next);
- return node;
- }
-
- Expression visitGetField(GetField node) {
- node.object = visitExpression(node.object);
- return node;
- }
-
- Expression visitCreateBox(CreateBox node) {
- return node;
- }
-
- Expression visitCreateInstance(CreateInstance node) {
- _rewriteList(node.arguments);
- return node;
- }
-
- Expression visitReifyRuntimeType(ReifyRuntimeType node) {
- node.value = visitExpression(node.value);
- return node;
- }
-
- Expression visitReadTypeVariable(ReadTypeVariable node) {
- node.target = visitExpression(node.target);
- return node;
- }
-
/// True if the given expression is known to evaluate to a boolean.
/// This will not recursively traverse [Conditional] expressions, but if
/// applied to the result of [visitExpression] conditionals will have been
@@ -498,11 +344,5 @@
}
}
- /// Destructively updates each entry of [l] with the result of visiting it.
- void _rewriteList(List<Expression> l) {
- for (int i = 0; i < l.length; i++) {
- l[i] = visitExpression(l[i]);
- }
- }
}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart
index d02e1ac..e2b7011 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart
@@ -27,41 +27,19 @@
///
/// Note that the above pattern needs no iteration since nested ifs
/// have been collapsed previously in the [StatementRewriter] phase.
-class LoopRewriter extends RecursiveVisitor with PassMixin {
+class LoopRewriter extends RecursiveTransformer
+ implements Pass {
String get passName => 'Loop rewriter';
Set<Label> usedContinueLabels = new Set<Label>();
- void rewriteExecutableDefinition(ExecutableDefinition root) {
- root.body = visitStatement(root.body);
+ void rewrite(RootNode root) {
+ root.replaceEachBody(visitStatement);
}
- Statement visitLabeledStatement(LabeledStatement node) {
- node.body = visitStatement(node.body);
- node.next = visitStatement(node.next);
- return node;
- }
-
- Statement visitAssign(Assign node) {
- // Clean up redundant assignments left behind in the previous phase.
- Expression value = node.value;
- if (value is VariableUse && node.variable == value.variable) {
- --node.variable.readCount;
- --node.variable.writeCount;
- return visitStatement(node.next);
- }
- visitExpression(node.value);
- node.next = visitStatement(node.next);
- return node;
- }
-
- Statement visitReturn(Return node) {
- visitExpression(node.value);
- return node;
- }
-
- Statement visitBreak(Break node) {
- return node;
+ @override
+ void visitInnerFunction(FunctionDefinition node) {
+ node.body = new LoopRewriter().visitStatement(node.body);
}
Statement visitContinue(Continue node) {
@@ -69,13 +47,6 @@
return node;
}
- Statement visitIf(If node) {
- visitExpression(node.condition);
- node.thenStatement = visitStatement(node.thenStatement);
- node.elseStatement = visitStatement(node.elseStatement);
- return node;
- }
-
Statement visitWhileTrue(WhileTrue node) {
assert(!usedContinueLabels.contains(node.label));
if (node.body is If) {
@@ -105,42 +76,4 @@
}
return node;
}
-
- Statement visitWhileCondition(WhileCondition node) {
- // Note: not reachable but the implementation is trivial
- visitExpression(node.condition);
- node.body = visitStatement(node.body);
- node.next = visitStatement(node.next);
- return node;
- }
-
- Statement visitExpressionStatement(ExpressionStatement node) {
- visitExpression(node.expression);
- node.next = visitStatement(node.next);
- return node;
- }
-
- Statement visitTry(Try node) {
- node.tryBody = visitStatement(node.tryBody);
- node.catchBody = visitStatement(node.catchBody);
- return node;
- }
-
- Statement visitFunctionDeclaration(FunctionDeclaration node) {
- new LoopRewriter().rewrite(node.definition);
- node.next = visitStatement(node.next);
- return node;
- }
-
- void visitFunctionExpression(FunctionExpression node) {
- new LoopRewriter().rewrite(node.definition);
- }
-
- Statement visitSetField(SetField node) {
- visitExpression(node.object);
- visitExpression(node.value);
- node.next = visitStatement(node.next);
- return node;
- }
-
}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/optimization.dart b/pkg/compiler/lib/src/tree_ir/optimization/optimization.dart
index fc7aca1..7dae5cd 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/optimization.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/optimization.dart
@@ -1,10 +1,11 @@
library tree_ir.optimization;
import '../tree_ir_nodes.dart';
-import '../../elements/elements.dart';
import '../../constants/values.dart' as values;
+import 'variable_merger.dart';
-part 'copy_propagator.dart';
+export 'variable_merger.dart' show VariableMerger;
+
part 'logical_rewriter.dart';
part 'loop_rewriter.dart';
part 'statement_rewriter.dart';
@@ -12,28 +13,7 @@
/// An optimization pass over the Tree IR.
abstract class Pass {
/// Applies optimizations to root, rewriting it in the process.
- void rewrite(ExecutableDefinition root) => root.applyPass(this);
- void rewriteFieldDefinition(FieldDefinition root);
- void rewriteFunctionDefinition(FunctionDefinition root);
- void rewriteConstructorDefinition(ConstructorDefinition root);
+ void rewrite(RootNode root);
String get passName;
}
-
-
-abstract class PassMixin implements Pass {
- void rewrite(ExecutableDefinition root) => root.applyPass(this);
- void rewriteExecutableDefinition(ExecutableDefinition root);
- void rewriteFieldDefinition(FieldDefinition root) {
- if (!root.hasInitializer) return;
- rewriteExecutableDefinition(root);
- }
- void rewriteFunctionDefinition(FunctionDefinition root) {
- if (root.isAbstract) return;
- rewriteExecutableDefinition(root);
- }
- void rewriteConstructorDefinition(ConstructorDefinition root) {
- if (root.isAbstract) return;
- rewriteExecutableDefinition(root);
- }
-}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
index 1902e8f..88ab5d8 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
@@ -91,12 +91,17 @@
* This may trigger a flattening of nested ifs in case the eliminated label
* separated two ifs.
*/
-class StatementRewriter extends Visitor<Statement, Expression> with PassMixin {
+class StatementRewriter extends Transformer implements Pass {
String get passName => 'Statement rewriter';
+ @override
+ void rewrite(RootNode node) {
+ node.replaceEachBody(visitStatement);
+ }
+
// The binding environment. The rightmost element of the list is the nearest
// available enclosing binding.
- List<Assign> environment;
+ List<Assign> environment = <Assign>[];
/// Binding environment for variables that are assigned to effectively
/// constant expressions (see [isEffectivelyConstant]).
@@ -128,18 +133,6 @@
return newJump != null ? newJump : jump;
}
- rewriteExecutableDefinition(ExecutableDefinition definition) {
- inEmptyEnvironment(() {
- definition.body = visitStatement(definition.body);
- });
- }
-
- void rewriteConstructorDefinition(ConstructorDefinition definition) {
- if (definition.isAbstract) return;
- definition.initializers.forEach(visitExpression);
- rewriteExecutableDefinition(definition);
- }
-
void inEmptyEnvironment(void action()) {
List<Assign> oldEnvironment = environment;
environment = <Assign>[];
@@ -148,23 +141,6 @@
environment = oldEnvironment;
}
- Expression visitFieldInitializer(FieldInitializer node) {
- inEmptyEnvironment(() {
- node.body = visitStatement(node.body);
- });
- return node;
- }
-
- Expression visitSuperInitializer(SuperInitializer node) {
- inEmptyEnvironment(() {
- for (int i = node.arguments.length - 1; i >= 0; --i) {
- node.arguments[i] = visitStatement(node.arguments[i]);
- assert(environment.isEmpty);
- }
- });
- return node;
- }
-
Expression visitExpression(Expression e) => e.processed ? e : e.accept(this);
@override
@@ -395,11 +371,11 @@
node.elseStatement,
(t,f) => new Conditional(node.condition, t, f)..processed = true);
if (reduced != null) {
- if (reduced.next is Break) {
- // In case the break can now be inlined.
- reduced = visitStatement(reduced);
- }
- return reduced;
+ // TODO(asgerf): Avoid revisiting nodes or visiting nodes that we created.
+ // This breaks the assumption that all subexpressions are
+ // variable uses, and it can be expensive.
+ // Revisit in case the break can now be inlined.
+ return visitStatement(reduced);
}
return node;
@@ -511,6 +487,14 @@
return node;
}
+ @override
+ Expression visitTypeExpression(TypeExpression node) {
+ for (int i = node.arguments.length - 1; i >= 0; --i) {
+ node.arguments[i] = visitExpression(node.arguments[i]);
+ }
+ return node;
+ }
+
/// If [s] and [t] are similar statements we extract their subexpressions
/// and returns a new statement of the same type using expressions combined
/// with the [combine] callback. For example:
@@ -576,6 +560,17 @@
return new Return(e);
}
}
+ if (s is Assign && t is Assign &&
+ s.variable == t.variable &&
+ isSameVariable(s.value, t.value)) {
+ Statement next = combineStatements(s.next, t.next);
+ if (next != null) {
+ s.next = next;
+ --t.variable.writeCount;
+ --(t.value as VariableUse).variable.readCount;
+ return s;
+ }
+ }
return null;
}
@@ -646,30 +641,36 @@
// NOTE: We name variables here as if S is in the then-then position.
Statement outerThen = getBranch(outerIf, branch1);
Statement outerElse = getBranch(outerIf, !branch1);
- if (outerThen is If && outerElse is Break) {
+ if (outerThen is If) {
If innerIf = outerThen;
Statement innerThen = getBranch(innerIf, branch2);
Statement innerElse = getBranch(innerIf, !branch2);
- if (innerElse is Break && innerElse.target == outerElse.target) {
+ Statement combinedElse = combineStatements(innerElse, outerElse);
+ if (combinedElse != null) {
// We always put S in the then branch of the result, and adjust the
// condition expression if S was actually found in the else branch(es).
outerIf.condition = new LogicalOperator.and(
makeCondition(outerIf.condition, branch1),
makeCondition(innerIf.condition, branch2));
outerIf.thenStatement = innerThen;
- --innerElse.target.useCount;
// Try to inline the remaining break. Do not propagate assignments.
inEmptyEnvironment(() {
- outerIf.elseStatement = visitStatement(outerElse);
+ // TODO(asgerf): Avoid quadratic cost from repeated processing. This
+ // should be easier after we introduce basic blocks.
+ outerIf.elseStatement = visitStatement(combinedElse);
});
- return outerIf.elseStatement is If && innerThen is Break;
+ return outerIf.elseStatement is If;
}
}
return false;
}
+ static bool isSameVariable(Expression e1, Expression e2) {
+ return e1 is VariableUse && e2 is VariableUse && e1.variable == e2.variable;
+ }
+
Expression makeCondition(Expression e, bool polarity) {
return polarity ? e : new Not(e);
}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart b/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
new file mode 100644
index 0000000..f1b64cf
--- /dev/null
+++ b/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
@@ -0,0 +1,514 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library tree_ir.optimization.variable_merger;
+
+import 'optimization.dart' show Pass, PassMixin;
+import '../tree_ir_nodes.dart';
+import '../../elements/elements.dart' show Local, ParameterElement;
+
+/// Merges variables based on liveness and source variable information.
+///
+/// This phase cleans up artifacts introduced by the translation through CPS,
+/// where each source variable is translated into several copies. The copies
+/// are merged again when they are not live simultaneously.
+class VariableMerger extends RecursiveVisitor implements Pass {
+ String get passName => 'Variable merger';
+
+ void rewrite(RootNode node) {
+ rewriteFunction(node);
+ node.forEachBody(visitStatement);
+ }
+
+ @override
+ void visitInnerFunction(FunctionDefinition node) {
+ rewriteFunction(node);
+ }
+
+ /// Rewrites the given function.
+ /// This is called for the outermost function and inner functions.
+ void rewriteFunction(RootNode node) {
+ node.forEachBody((Statement body) {
+ BlockGraphBuilder builder = new BlockGraphBuilder();
+ builder.build(node.parameters, body);
+ _computeLiveness(builder.blocks);
+ Map<Variable, Variable> subst =
+ _computeRegisterAllocation(builder.blocks);
+ new SubstituteVariables(subst).apply(node);
+ });
+ }
+}
+
+/// A read or write access to a variable.
+class VariableAccess {
+ Variable variable;
+ bool isRead;
+ bool get isWrite => !isRead;
+
+ VariableAccess.read(this.variable) : isRead = true;
+ VariableAccess.write(this.variable) : isRead = false;
+}
+
+/// Basic block in a control-flow graph.
+class Block {
+ /// List of predecessors in the control-flow graph.
+ final List<Block> predecessors = <Block>[];
+
+ /// Entry to the catch block for the enclosing try, or `null`.
+ final Block catchBlock;
+
+ /// List of nodes with this block as [catchBlock].
+ final List<Block> catchPredecessors = <Block>[];
+
+ /// Sequence of read and write accesses in the block.
+ final List<VariableAccess> accesses = <VariableAccess>[];
+
+ /// Auxiliary fields used by the liveness analysis.
+ bool inWorklist = true;
+ Set<Variable> liveIn;
+ Set<Variable> liveOut = new Set<Variable>();
+ Set<Variable> gen = new Set<Variable>();
+ Set<Variable> kill = new Set<Variable>();
+
+ /// Adds a read operation to the block and updates gen/kill sets accordingly.
+ void addRead(Variable variable) {
+ // Operations are seen in forward order.
+ // If the read is not preceded by a write, then add it to the GEN set.
+ if (!kill.contains(variable)) {
+ gen.add(variable);
+ }
+ accesses.add(new VariableAccess.read(variable));
+ }
+
+ /// Adds a write operation to the block and updates gen/kill sets accordingly.
+ void addWrite(Variable variable) {
+ // If the write is not preceded by a read, then add it to the KILL set.
+ if (!gen.contains(variable)) {
+ kill.add(variable);
+ }
+ accesses.add(new VariableAccess.write(variable));
+ }
+
+ Block(this.catchBlock) {
+ if (catchBlock != null) {
+ catchBlock.catchPredecessors.add(this);
+ }
+ }
+}
+
+/// Builds a control-flow graph suitable for performing liveness analysis.
+class BlockGraphBuilder extends RecursiveVisitor {
+ Map<Label, Block> _jumpTarget = <Label, Block>{};
+ Block _currentBlock;
+ List<Block> blocks = <Block>[];
+
+ /// Variables with an assignment that should be treated as final.
+ ///
+ /// Such variables cannot be merged with any other variables, so we exclude
+ /// them from the control-flow graph entirely.
+ Set<Variable> _ignoredVariables = new Set<Variable>();
+
+ void build(List<Variable> parameters, Statement body) {
+ _currentBlock = newBlock();
+ parameters.forEach(write);
+ visitStatement(body);
+ }
+
+ @override
+ void visitInnerFunction(FunctionDefinition node) {
+ // Do nothing. Inner functions are traversed in VariableMerger.
+ }
+
+ /// Creates a new block with the current exception handler or [catchBlock]
+ /// if provided.
+ Block newBlock({Block catchBlock}) {
+ if (catchBlock == null && _currentBlock != null) {
+ catchBlock = _currentBlock.catchBlock;
+ }
+ Block block = new Block(catchBlock);
+ blocks.add(block);
+ return block;
+ }
+
+ /// Starts a new block after the end of [block].
+ void branchFrom(Block block, {Block catchBlock}) {
+ _currentBlock = newBlock(catchBlock: catchBlock)..predecessors.add(block);
+ }
+
+ /// Called when reading from [variable].
+ ///
+ /// Appends a read operation to the current basic block.
+ void read(Variable variable) {
+ if (variable.isCaptured) return;
+ if (_ignoredVariables.contains(variable)) return;
+ _currentBlock.addRead(variable);
+ }
+
+ /// Called when writing to [variable].
+ ///
+ /// Appends a write operation to the current basic block.
+ void write(Variable variable) {
+ if (variable.isCaptured) return;
+ if (_ignoredVariables.contains(variable)) return;
+ _currentBlock.addWrite(variable);
+ }
+
+ /// Called to indicate that [variable] should not be merged, and therefore
+ /// be excluded from the control-flow graph.
+ /// Subsequent calls to [read] and [write] will ignore it.
+ void ignoreVariable(Variable variable) {
+ _ignoredVariables.add(variable);
+ }
+
+ visitVariableUse(VariableUse node) {
+ read(node.variable);
+ }
+
+ visitAssign(Assign node) {
+ visitExpression(node.value);
+ write(node.variable);
+ visitStatement(node.next);
+ }
+
+ visitIf(If node) {
+ visitExpression(node.condition);
+ Block afterCondition = _currentBlock;
+ branchFrom(afterCondition);
+ visitStatement(node.thenStatement);
+ branchFrom(afterCondition);
+ visitStatement(node.elseStatement);
+ }
+
+ visitLabeledStatement(LabeledStatement node) {
+ Block join = _jumpTarget[node.label] = newBlock();
+ visitStatement(node.body); // visitBreak will add predecessors to join.
+ _currentBlock = join;
+ visitStatement(node.next);
+ }
+
+ visitBreak(Break node) {
+ _jumpTarget[node.target].predecessors.add(_currentBlock);
+ }
+
+ visitContinue(Continue node) {
+ _jumpTarget[node.target].predecessors.add(_currentBlock);
+ }
+
+ visitWhileTrue(WhileTrue node) {
+ Block join = _jumpTarget[node.label] = newBlock();
+ join.predecessors.add(_currentBlock);
+ _currentBlock = join;
+ visitStatement(node.body); // visitContinue will add predecessors to join.
+ }
+
+ visitWhileCondition(WhileCondition node) {
+ Block join = _jumpTarget[node.label] = newBlock();
+ join.predecessors.add(_currentBlock);
+ _currentBlock = join;
+ visitExpression(node.condition);
+ Block afterCondition = _currentBlock;
+ branchFrom(afterCondition);
+ visitStatement(node.body); // visitContinue will add predecessors to join.
+ branchFrom(afterCondition);
+ visitStatement(node.next);
+ }
+
+ visitTry(Try node) {
+ Block catchBlock = newBlock();
+ branchFrom(_currentBlock, catchBlock: catchBlock);
+ visitStatement(node.tryBody);
+ _currentBlock = catchBlock;
+ // Catch parameters cannot be hoisted to the top of the function, so to
+ // avoid complications with scoping, we do not attempt to merge them.
+ node.catchParameters.forEach(ignoreVariable);
+ visitStatement(node.catchBody);
+ }
+
+ visitConditional(Conditional node) {
+ visitExpression(node.condition);
+ // TODO(asgerf): When assignment expressions are added, this is no longer
+ // sound; then we need to handle as a branch.
+ visitExpression(node.thenExpression);
+ visitExpression(node.elseExpression);
+ }
+
+ visitLogicalOperator(LogicalOperator node) {
+ visitExpression(node.left);
+ // TODO(asgerf): When assignment expressions are added, this is no longer
+ // sound; then we need to handle as a branch.
+ visitExpression(node.right);
+ }
+
+ visitFunctionDeclaration(FunctionDeclaration node) {
+ // The function variable is final, hence cannot be merged.
+ ignoreVariable(node.variable);
+ visitStatement(node.next);
+ }
+}
+
+/// Computes liveness information of the given control-flow graph.
+///
+/// The results are stored in [Block.liveIn] and [Block.liveOut].
+void _computeLiveness(List<Block> blocks) {
+ // We use a LIFO queue as worklist. Blocks are given in AST order, so by
+ // inserting them in this order, we initially visit them backwards, which
+ // is a good ordering.
+ // The choice of LIFO for re-inserted blocks is currently arbitrary,
+ List<Block> worklist = new List<Block>.from(blocks);
+ while (!worklist.isEmpty) {
+ Block block = worklist.removeLast();
+ block.inWorklist = false;
+
+ bool changed = false;
+
+ // The liveIn set is computed as:
+ //
+ // liveIn = (liveOut - kill) + gen
+ //
+ // We do the computation in two steps:
+ //
+ // 1. liveIn = gen
+ // 2. liveIn += (liveOut - kill)
+ //
+ // However, since liveIn only grows, and gen never changes, we only have
+ // to do the first step at the first iteration. Moreover, the gen set is
+ // not needed anywhere else, so we don't even need to copy it.
+ if (block.liveIn == null) {
+ block.liveIn = block.gen;
+ block.gen = null;
+ changed = true;
+ }
+
+ // liveIn += (liveOut - kill)
+ for (Variable variable in block.liveOut) {
+ if (!block.kill.contains(variable)) {
+ if (block.liveIn.add(variable)) {
+ changed = true;
+ }
+ }
+ }
+
+ // If anything changed, propagate liveness backwards.
+ if (changed) {
+ // Propagate live variables to predecessors.
+ for (Block predecessor in block.predecessors) {
+ int lengthBeforeChange = predecessor.liveOut.length;
+ predecessor.liveOut.addAll(block.liveIn);
+ if (!predecessor.inWorklist &&
+ predecessor.liveOut.length != lengthBeforeChange) {
+ worklist.add(predecessor);
+ predecessor.inWorklist = true;
+ }
+ }
+
+ // Propagate live variables to catch predecessors.
+ for (Block pred in block.catchPredecessors) {
+ bool changed = false;
+ int lengthBeforeChange = pred.liveOut.length;
+ pred.liveOut.addAll(block.liveIn);
+ if (pred.liveOut.length != lengthBeforeChange) {
+ changed = true;
+ }
+ // Assigning to a variable that is live in the catch block, does not
+ // kill the variable, because we conservatively assume that an exception
+ // could be thrown immediately before the assignment.
+ // Therefore remove live variables from all kill sets inside the try.
+ // Since the kill set is only used to subtract live variables from a
+ // set, the analysis remains monotone.
+ lengthBeforeChange = pred.kill.length;
+ pred.kill.removeAll(block.liveIn);
+ if (pred.kill.length != lengthBeforeChange) {
+ changed = true;
+ }
+ if (changed && !pred.inWorklist) {
+ worklist.add(pred);
+ pred.inWorklist = true;
+ }
+ }
+ }
+ }
+}
+
+/// For testing purposes, this flag can be passed to merge variables that
+/// originated from different source variables.
+///
+/// Correctness should not depend on the fact that we only merge variable
+/// originating from the same source variable. Setting this flag makes a bug
+/// more likely to provoke a test case failure.
+const bool NO_PRESERVE_VARS = const bool.fromEnvironment('NO_PRESERVE_VARS');
+
+/// Based on liveness information, computes a map of variable substitutions to
+/// merge variables.
+///
+/// Constructs a register interference graph. This is an undirected graph of
+/// variables, with an edge between two variables if they cannot be merged
+/// (because they are live simultaneously).
+///
+/// We then compute a graph coloring, where the color of a node denotes which
+/// variable it will be substituted by.
+///
+/// We never merge variables that originated from distinct source variables,
+/// so we build a separate register interference graph for each source variable.
+Map<Variable, Variable> _computeRegisterAllocation(List<Block> blocks) {
+ Map<Variable, Set<Variable>> interference = <Variable, Set<Variable>>{};
+
+ /// Group for the given variable. We attempt to merge variables in the same
+ /// group.
+ /// By default, variables are grouped based on their source variable, but
+ /// this can be disabled for testing purposes.
+ Local group(Variable variable) {
+ if (NO_PRESERVE_VARS) {
+ // Parameters may not occur more than once in a parameter list,
+ // so except for parameters, we try to merge all variables.
+ return variable.element is ParameterElement ? variable.element : null;
+ }
+ return variable.element;
+ }
+
+ Set<Variable> empty = new Set<Variable>();
+
+ // At the assignment to a variable x, add an edge to every variable that is
+ // live after the assignment (if it came from the same source variable).
+ for (Block block in blocks) {
+ // Group the liveOut set by source variable.
+ Map<Local, Set<Variable>> liveOut = <Local, Set<Variable>>{};
+ for (Variable variable in block.liveOut) {
+ liveOut.putIfAbsent(
+ group(variable),
+ () => new Set<Variable>()).add(variable);
+ interference.putIfAbsent(variable, () => new Set<Variable>());
+ }
+ // Get variables that are live at the catch block.
+ Set<Variable> liveCatch = block.catchBlock != null
+ ? block.catchBlock.liveIn
+ : empty;
+ // Add edges for each variable being assigned here.
+ for (VariableAccess access in block.accesses.reversed) {
+ Variable variable = access.variable;
+ interference.putIfAbsent(variable, () => new Set<Variable>());
+ Set<Variable> live =
+ liveOut.putIfAbsent(group(variable), () => new Set<Variable>());
+ if (access.isRead) {
+ live.add(variable);
+ } else {
+ if (!liveCatch.contains(variable)) {
+ // Assignment to a variable that is not live in the catch block.
+ live.remove(variable);
+ }
+ for (Variable other in live) {
+ interference[variable].add(other);
+ interference[other].add(variable);
+ }
+ }
+ }
+ }
+
+ // Sort the variables by descending degree.
+ // The most constrained variables will be assigned a color first.
+ List<Variable> variables = interference.keys.toList();
+ variables.sort((x, y) => interference[y].length - interference[x].length);
+
+ Map<Local, List<Variable>> registers = <Local, List<Variable>>{};
+ Map<Variable, Variable> subst = <Variable, Variable>{};
+
+ for (Variable v1 in variables) {
+ List<Variable> register = registers[group(v1)];
+
+ // Optimization: For the first variable in a group, allocate a new color
+ // without iterating over its interference edges.
+ if (register == null) {
+ registers[group(v1)] = <Variable>[v1];
+ subst[v1] = v1;
+ continue;
+ }
+
+ // Optimization: If there are no inteference edges for this variable,
+ // assign it the first color without copying the register list.
+ Set<Variable> interferenceSet = interference[v1];
+ if (interferenceSet.isEmpty) {
+ subst[v1] = register[0];
+ continue;
+ }
+
+ // Find an unused color.
+ Set<Variable> potential = new Set<Variable>.from(register);
+ for (Variable v2 in interferenceSet) {
+ Variable v2subst = subst[v2];
+ if (v2subst != null) {
+ potential.remove(v2subst);
+ if (potential.isEmpty) break;
+ }
+ }
+
+ if (potential.isEmpty) {
+ // If no free color was found, add this variable as a new color.
+ register.add(v1);
+ subst[v1] = v1;
+ } else {
+ subst[v1] = potential.first;
+ }
+ }
+
+ return subst;
+}
+
+/// Performs variable substitution and removes redundant assignments.
+class SubstituteVariables extends RecursiveTransformer {
+
+ Map<Variable, Variable> mapping;
+
+ SubstituteVariables(this.mapping);
+
+ Variable replaceRead(Variable variable) {
+ Variable w = mapping[variable];
+ if (w == null) return variable; // Skip ignored variables.
+ w.readCount++;
+ variable.readCount--;
+ return w;
+ }
+
+ Variable replaceWrite(Variable variable) {
+ Variable w = mapping[variable];
+ if (w == null) return variable; // Skip ignored variables.
+ w.writeCount++;
+ variable.writeCount--;
+ return w;
+ }
+
+ void apply(RootNode node) {
+ for (int i = 0; i < node.parameters.length; ++i) {
+ node.parameters[i] = replaceWrite(node.parameters[i]);
+ }
+ node.replaceEachBody(visitStatement);
+ }
+
+ @override
+ void visitInnerFunction(FunctionDefinition node) {
+ // Do nothing. Inner functions are traversed in VariableMerger.
+ }
+
+ Expression visitVariableUse(VariableUse node) {
+ node.variable = replaceRead(node.variable);
+ return node;
+ }
+
+ Statement visitAssign(Assign node) {
+ node.variable = replaceWrite(node.variable);
+
+ visitExpression(node.value);
+ node.next = visitStatement(node.next);
+
+ // Remove assignments of form "x := x"
+ if (node.value is VariableUse) {
+ VariableUse value = node.value;
+ if (value.variable == node.variable) {
+ value.variable.readCount--;
+ node.variable.writeCount--;
+ return node.next;
+ }
+ }
+
+ return node;
+ }
+}
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
index f61630c..fda5ca6 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
@@ -46,11 +46,9 @@
class Builder implements cps_ir.Visitor<Node> {
final dart2js.InternalErrorFunction internalError;
- /// Maps variable/parameter elements to the Tree variables that represent it.
- final Map<Local, List<Variable>> local2variables = <Local, List<Variable>>{};
-
- /// Like [local2variables], except for mutable variables.
- final Map<cps_ir.MutableVariable, Variable> local2mutable =
+ final Map<cps_ir.Primitive, Variable> primitive2variable =
+ <cps_ir.Primitive, Variable>{};
+ final Map<cps_ir.MutableVariable, Variable> mutable2variable =
<cps_ir.MutableVariable, Variable>{};
// Continuations with more than one use are replaced with Tree labels. This
@@ -85,9 +83,9 @@
Variable addMutableVariable(cps_ir.MutableVariable irVariable) {
assert(irVariable.host == currentElement);
- assert(!local2mutable.containsKey(irVariable));
+ assert(!mutable2variable.containsKey(irVariable));
Variable variable = new Variable(currentElement, irVariable.hint);
- local2mutable[irVariable] = variable;
+ mutable2variable[irVariable] = variable;
return variable;
}
@@ -95,7 +93,7 @@
if (mutableVariable.host != currentElement) {
return parent.getMutableVariable(mutableVariable)..isCaptured = true;
}
- return local2mutable[mutableVariable];
+ return mutable2variable[mutableVariable];
}
VariableUse getMutableVariableUse(
@@ -107,15 +105,8 @@
/// Obtains the variable representing the given primitive. Returns null for
/// primitives that have no reference and do not need a variable.
Variable getVariable(cps_ir.Primitive primitive) {
- if (primitive.registerIndex == null) {
- return null; // variable is unused
- }
- List<Variable> variables = local2variables.putIfAbsent(primitive.hint,
- () => <Variable>[]);
- while (variables.length <= primitive.registerIndex) {
- variables.add(new Variable(currentElement, primitive.hint));
- }
- return variables[primitive.registerIndex];
+ return primitive2variable.putIfAbsent(primitive,
+ () => new Variable(currentElement, primitive.hint));
}
/// Obtains a reference to the tree Variable corresponding to the IR primitive
@@ -126,18 +117,11 @@
if (thisParameter != null && reference.definition == thisParameter) {
return new This();
}
- Variable variable = getVariable(reference.definition);
- if (variable == null) {
- // Note: this may fail because you forgot to implement a visit-function
- // in the RegisterAllocator.
- internalError(
- CURRENT_ELEMENT_SPANNABLE,
- "Reference to ${reference.definition} has no register");
- }
- return new VariableUse(variable);
+ return new VariableUse(getVariable(reference.definition));
}
- ExecutableDefinition build(cps_ir.ExecutableDefinition node) {
+ RootNode build(cps_ir.RootNode node) {
+ // TODO(asgerf): Don't have build AND buildXXX as public API.
if (node is cps_ir.FieldDefinition) {
return buildField(node);
} else if (node is cps_ir.ConstructorDefinition) {
@@ -154,7 +138,7 @@
FieldDefinition buildField(cps_ir.FieldDefinition node) {
Statement body;
- if (node.hasInitializer) {
+ if (!node.isEmpty) {
currentElement = node.element;
returnContinuation = node.body.returnContinuation;
@@ -184,7 +168,7 @@
List<Variable> parameters =
node.parameters.map(addFunctionParameter).toList();
Statement body;
- if (!node.isAbstract) {
+ if (!node.isEmpty) {
returnContinuation = node.body.returnContinuation;
phiTempVar = new Variable(node.element, null);
body = visit(node.body);
@@ -201,7 +185,7 @@
node.parameters.map(addFunctionParameter).toList();
List<Initializer> initializers;
Statement body;
- if (!node.isAbstract) {
+ if (!node.isEmpty) {
initializers = node.initializers.map(visit).toList();
returnContinuation = node.body.returnContinuation;
@@ -230,12 +214,12 @@
cps_ir.Parameter parameter,
Expression argument,
Statement buildRest()) {
- Variable variable = getVariable(parameter);
Statement assignment;
- if (variable == null) {
- assignment = new ExpressionStatement(argument, null);
- } else {
+ if (parameter.hasAtLeastOneUse) {
+ Variable variable = getVariable(parameter);
assignment = new Assign(variable, argument, null);
+ } else {
+ assignment = new ExpressionStatement(argument, null);
}
assignment.next = buildRest();
return assignment;
@@ -366,7 +350,7 @@
Initializer visitSuperInitializer(cps_ir.SuperInitializer node) {
List<Statement> arguments =
- node.arguments.map((cps_ir.RunnableBody argument) {
+ node.arguments.map((cps_ir.Body argument) {
returnContinuation = argument.returnContinuation;
return visit(argument.body);
}).toList();
@@ -391,7 +375,7 @@
}
}
- Statement visitRunnableBody(cps_ir.RunnableBody node) {
+ Statement visitBody(cps_ir.Body node) {
return visit(node.body);
}
@@ -519,8 +503,11 @@
Statement visitInvokeConstructor(cps_ir.InvokeConstructor node) {
List<Expression> arguments = translateArguments(node.arguments);
- Expression invoke =
- new InvokeConstructor(node.type, node.target, node.selector, arguments);
+ Expression invoke = new InvokeConstructor(
+ node.type,
+ node.target,
+ node.selector,
+ arguments);
return continueWithExpression(node.continuation, invoke);
}
@@ -651,4 +638,12 @@
Expression visitReadTypeVariable(cps_ir.ReadTypeVariable node) {
return new ReadTypeVariable(node.variable, getVariableUse(node.target));
}
+
+ @override
+ Node visitTypeExpression(cps_ir.TypeExpression node) {
+ return new TypeExpression(
+ node.dartType,
+ node.arguments.map(getVariableUse).toList());
+ }
}
+
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
index 01eaa9c..8829e70 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
@@ -16,7 +16,7 @@
/// - Variables must not have more than one declaration.
///
class CheckTreeIntegrity extends RecursiveVisitor {
- ExecutableDefinition topLevelNode;
+ RootNode topLevelNode;
Map<Variable, int> varReads = <Variable, int>{};
Map<Variable, int> varWrites = <Variable, int>{};
@@ -85,22 +85,9 @@
node.catchParameters.forEach(undeclare);
}
- visitFunctionDefinition(FunctionDefinition node) {
- node.parameters.forEach(declare);
- if (node.body != null) visitStatement(node.body);
- node.parameters.forEach(undeclare);
- }
-
- visitConstructorDefinition(ConstructorDefinition node) {
- node.parameters.forEach(declare);
- if (node.initializers != null) node.initializers.forEach(visitInitializer);
- if (node.body != null) visitStatement(node.body);
- node.parameters.forEach(undeclare);
- }
-
visitFunctionDeclaration(FunctionDeclaration node) {
declare(node.variable);
- visitFunctionDefinition(node.definition);
+ checkBody(node.definition);
visitStatement(node.next);
undeclare(node.variable);
if (varWrites[node.variable] > 1) {
@@ -159,13 +146,23 @@
labelUses[node.target]++;
}
+ visitInnerFunction(FunctionDefinition node) {
+ checkBody(node);
+ }
+
+ void checkBody(RootNode node) {
+ node.parameters.forEach(declare);
+ node.forEachBody(visitStatement);
+ node.parameters.forEach(undeclare);
+ }
+
dynamic error(String message) {
throw 'Tree IR integrity violation in ${topLevelNode.element}:\n$message';
}
- void check(ExecutableDefinition node) {
+ void check(RootNode node) {
topLevelNode = node;
- visitExecutableDefinition(node);
+ checkBody(node);
// Verify reference counters for all variables.
List<Variable> seenVariables = new List<Variable>();
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
index 005d082..92abcc8 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -6,12 +6,11 @@
import '../constants/expressions.dart';
import '../constants/values.dart' as values;
-import '../dart_types.dart' show DartType, GenericType, TypeVariableType;
+import '../dart_types.dart' show DartType, GenericType, InterfaceType, TypeVariableType;
import '../elements/elements.dart';
import '../io/source_information.dart' show SourceInformation;
import '../universe/universe.dart';
import '../universe/universe.dart' show Selector;
-import 'optimization/optimization.dart';
// The Tree language is the target of translation out of the CPS-based IR.
//
@@ -222,11 +221,14 @@
final values.ConstantValue constant;
InvokeConstructor(this.type, this.target, this.selector, this.arguments,
- [this.constant]);
+ [this.constant]);
ClassElement get targetClass => target.enclosingElement;
- accept(ExpressionVisitor visitor) => visitor.visitInvokeConstructor(this);
+ accept(ExpressionVisitor visitor) {
+ return visitor.visitInvokeConstructor(this);
+ }
+
accept1(ExpressionVisitor1 visitor, arg) {
return visitor.visitInvokeConstructor(this, arg);
}
@@ -597,9 +599,6 @@
}
}
-// TODO(kmillikin): Do we want this 'TryStatement'? Other than
-// LabeledStatement and EmptyStatement, the statement class names are not
-// suffixed with 'Statement'.
class Try extends Statement {
Statement tryBody;
List<Variable> catchParameters;
@@ -620,42 +619,49 @@
}
}
-abstract class ExecutableDefinition {
+abstract class RootNode extends Node {
ExecutableElement get element;
- Statement body;
+ List<Variable> get parameters;
- applyPass(Pass pass);
+ /// True if there is no body for this root node.
+ ///
+ /// In some parts of the compiler, empty root nodes are used as placeholders
+ /// for abstract methods, external constructors, fields without initializers,
+ /// etc.
+ bool get isEmpty;
+
+ void forEachBody(void action(Statement node));
+ void replaceEachBody(Statement transform(Statement node));
+
+ accept(RootVisitor v);
+ accept1(RootVisitor1 v, arg);
}
-class FieldDefinition extends Node implements ExecutableDefinition {
+class FieldDefinition extends RootNode implements DartSpecificNode {
final FieldElement element;
// The `body` of a field is its initializer.
Statement body;
+ List<Variable> get parameters => const <Variable>[];
FieldDefinition(this.element, this.body);
- applyPass(Pass pass) => pass.rewriteFieldDefinition(this);
- /// `true` if this field has no initializer.
- ///
- /// If `true` [body] is `null`.
- ///
- /// This is different from a initializer that is `null`. Consider this class:
- ///
- /// class Class {
- /// final field;
- /// Class.a(this.field);
- /// Class.b() : this.field = null;
- /// Class.c();
- /// }
- ///
- /// If `field` had an initializer, possibly `null`, constructors `Class.a` and
- /// `Class.b` would be invalid, and since `field` has no initializer
- /// constructor `Class.c` is invalid. We therefore need to distinguish the two
- /// cases.
- bool get hasInitializer => body != null;
+ bool get isEmpty => body == null;
+
+ accept(RootVisitor v) => v.visitFieldDefinition(this);
+ accept1(RootVisitor1 v, arg) => v.visitFieldDefinition(this, arg);
+
+ void forEachBody(void action(Statement node)) {
+ if (isEmpty) return;
+ action(body);
+ }
+
+ void replaceEachBody(Statement transform(Statement node)) {
+ if (isEmpty) return;
+ body = transform(body);
+ }
}
-class FunctionDefinition extends Node implements ExecutableDefinition {
+class FunctionDefinition extends RootNode {
final FunctionElement element;
final List<Variable> parameters;
Statement body;
@@ -670,14 +676,29 @@
}
}
- /// Returns `true` if this function is abstract.
- ///
- /// If `true` [body] is `null` and [localConstants] is empty.
- bool get isAbstract => body == null;
- applyPass(Pass pass) => pass.rewriteFunctionDefinition(this);
+ bool get isEmpty => body == null;
+
+ accept(RootVisitor v) => v.visitFunctionDefinition(this);
+ accept1(RootVisitor1 v, arg) => v.visitFunctionDefinition(this, arg);
+
+ void forEachBody(void action(Statement node)) {
+ if (isEmpty) return;
+ action(body);
+ }
+
+ void replaceEachBody(Statement transform(Statement node)) {
+ if (isEmpty) return;
+ body = transform(body);
+ }
}
-abstract class Initializer implements Expression, DartSpecificNode {}
+abstract class Initializer implements DartSpecificNode {
+ accept(InitializerVisitor v);
+ accept1(InitializerVisitor1 v, arg);
+
+ void forEachBody(void action(Statement node));
+ void replaceEachBody(Statement transform(Statement node));
+}
class FieldInitializer extends Initializer {
final FieldElement element;
@@ -686,10 +707,18 @@
FieldInitializer(this.element, this.body);
- accept(ExpressionVisitor visitor) => visitor.visitFieldInitializer(this);
- accept1(ExpressionVisitor1 visitor, arg) {
+ accept(InitializerVisitor visitor) => visitor.visitFieldInitializer(this);
+ accept1(InitializerVisitor1 visitor, arg) {
return visitor.visitFieldInitializer(this, arg);
}
+
+ void forEachBody(void action(Statement node)) {
+ action(body);
+ }
+
+ void replaceEachBody(Statement transform(Statement node)) {
+ body = transform(body);
+ }
}
class SuperInitializer extends Initializer {
@@ -699,25 +728,62 @@
bool processed = false;
SuperInitializer(this.target, this.selector, this.arguments);
- accept(ExpressionVisitor visitor) => visitor.visitSuperInitializer(this);
- accept1(ExpressionVisitor1 visitor, arg) {
+ accept(InitializerVisitor visitor) => visitor.visitSuperInitializer(this);
+ accept1(InitializerVisitor1 visitor, arg) {
return visitor.visitSuperInitializer(this, arg);
}
+
+ void forEachBody(void action(Statement node)) {
+ arguments.forEach(action);
+ }
+
+ void replaceEachBody(Statement transform(Statement node)) {
+ for (int i = 0; i < arguments.length; i++) {
+ arguments[i] = transform(arguments[i]);
+ }
+ }
}
-class ConstructorDefinition extends FunctionDefinition {
+class ConstructorDefinition extends RootNode
+ implements DartSpecificNode {
+ final ConstructorElement element;
+ final List<Variable> parameters;
+ Statement body;
+ final List<ConstDeclaration> localConstants;
+ final List<ConstantExpression> defaultParameterValues;
final List<Initializer> initializers;
- ConstructorDefinition(ConstructorElement element,
- List<Variable> parameters,
- Statement body,
+ ConstructorDefinition(this.element,
+ this.parameters,
+ this.body,
this.initializers,
- List<ConstDeclaration> localConstants,
- List<ConstantExpression> defaultParameterValues)
- : super(element, parameters, body, localConstants,
- defaultParameterValues);
+ this.localConstants,
+ this.defaultParameterValues) {
+ for (Variable param in parameters) {
+ param.writeCount++; // Being a parameter counts as a write.
+ }
+ }
- applyPass(Pass pass) => pass.rewriteConstructorDefinition(this);
+ bool get isEmpty => body == null;
+
+ accept(RootVisitor v) => v.visitConstructorDefinition(this);
+ accept1(RootVisitor1 v, arg) => v.visitConstructorDefinition(this, arg);
+
+ void forEachBody(void action(Statement node)) {
+ if (isEmpty) return;
+ for (Initializer init in initializers) {
+ init.forEachBody(action);
+ }
+ action(body);
+ }
+
+ void replaceEachBody(Statement transform(Statement node)) {
+ if (isEmpty) return;
+ for (Initializer init in initializers) {
+ init.replaceEachBody(transform);
+ }
+ body = transform(body);
+ }
}
abstract class JsSpecificNode implements Node {}
@@ -732,8 +798,9 @@
class CreateInstance extends Expression implements JsSpecificNode {
ClassElement classElement;
List<Expression> arguments;
+ List<Expression> typeInformation;
- CreateInstance(this.classElement, this.arguments);
+ CreateInstance(this.classElement, this.arguments, this.typeInformation);
accept(ExpressionVisitor visitor) => visitor.visitCreateInstance(this);
accept1(ExpressionVisitor1 visitor, arg) {
@@ -792,8 +859,26 @@
}
}
+/// Denotes the internal representation of [dartType], where all type variables
+/// are replaced by the values in [arguments].
+/// (See documentation on the TypeExpression CPS node for more details.)
+class TypeExpression extends Expression {
+ final DartType dartType;
+ final List<Expression> arguments;
+
+ TypeExpression(this.dartType, this.arguments);
+
+ accept(ExpressionVisitor visitor) {
+ return visitor.visitTypeExpression(this);
+ }
+
+ accept1(ExpressionVisitor1 visitor, arg) {
+ return visitor.visitTypeExpression(this, arg);
+ }
+}
+
abstract class ExpressionVisitor<E> {
- E visitExpression(Expression e) => e.accept(this);
+ E visitExpression(Expression node) => node.accept(this);
E visitVariableUse(VariableUse node);
E visitInvokeStatic(InvokeStatic node);
E visitInvokeMethod(InvokeMethod node);
@@ -810,17 +895,16 @@
E visitLiteralMap(LiteralMap node);
E visitTypeOperator(TypeOperator node);
E visitFunctionExpression(FunctionExpression node);
- E visitFieldInitializer(FieldInitializer node);
- E visitSuperInitializer(SuperInitializer node);
E visitGetField(GetField node);
E visitCreateBox(CreateBox node);
E visitCreateInstance(CreateInstance node);
E visitReifyRuntimeType(ReifyRuntimeType node);
E visitReadTypeVariable(ReadTypeVariable node);
+ E visitTypeExpression(TypeExpression node);
}
abstract class ExpressionVisitor1<E, A> {
- E visitExpression(Expression e, A arg) => e.accept1(this, arg);
+ E visitExpression(Expression node, A arg) => node.accept1(this, arg);
E visitVariableUse(VariableUse node, A arg);
E visitInvokeStatic(InvokeStatic node, A arg);
E visitInvokeMethod(InvokeMethod node, A arg);
@@ -837,17 +921,16 @@
E visitLiteralMap(LiteralMap node, A arg);
E visitTypeOperator(TypeOperator node, A arg);
E visitFunctionExpression(FunctionExpression node, A arg);
- E visitFieldInitializer(FieldInitializer node, A arg);
- E visitSuperInitializer(SuperInitializer node, A arg);
E visitGetField(GetField node, A arg);
E visitCreateBox(CreateBox node, A arg);
E visitCreateInstance(CreateInstance node, A arg);
- E visitReifyRuntimeType(ReifyRuntimeType reifyRuntimeType, A arg);
- E visitReadTypeVariable(ReadTypeVariable readTypeVariable, A arg);
+ E visitReifyRuntimeType(ReifyRuntimeType node, A arg);
+ E visitReadTypeVariable(ReadTypeVariable node, A arg);
+ E visitTypeExpression(TypeExpression node, A arg);
}
abstract class StatementVisitor<S> {
- S visitStatement(Statement s) => s.accept(this);
+ S visitStatement(Statement node) => node.accept(this);
S visitLabeledStatement(LabeledStatement node);
S visitAssign(Assign node);
S visitReturn(Return node);
@@ -863,7 +946,7 @@
}
abstract class StatementVisitor1<S, A> {
- S visitStatement(Statement s, A arg) => s.accept1(this, arg);
+ S visitStatement(Statement node, A arg) => node.accept1(this, arg);
S visitLabeledStatement(LabeledStatement node, A arg);
S visitAssign(Assign node, A arg);
S visitReturn(Return node, A arg);
@@ -878,59 +961,37 @@
S visitSetField(SetField node, A arg);
}
-abstract class Visitor<S, E> implements ExpressionVisitor<E>,
- StatementVisitor<S> {
- E visitExpression(Expression e) => e.accept(this);
- S visitStatement(Statement s) => s.accept(this);
+abstract class RootVisitor<T> {
+ T visitRootNode(RootNode node) => node.accept(this);
+ T visitFunctionDefinition(FunctionDefinition node);
+ T visitConstructorDefinition(ConstructorDefinition node);
+ T visitFieldDefinition(FieldDefinition node);
}
-abstract class Visitor1<S, E, A> implements ExpressionVisitor1<E, A>,
- StatementVisitor1<S, A> {
- E visitExpression(Expression e, A arg) => e.accept1(this, arg);
- S visitStatement(Statement s, A arg) => s.accept1(this, arg);
+abstract class RootVisitor1<T, A> {
+ T visitRootNode(RootNode node, A arg) => node.accept1(this, arg);
+ T visitFunctionDefinition(FunctionDefinition node, A arg);
+ T visitConstructorDefinition(ConstructorDefinition node, A arg);
+ T visitFieldDefinition(FieldDefinition node, A arg);
}
-class RecursiveVisitor extends Visitor {
- // TODO(asgerf): Clean up the tree visitor.
-
- visitExecutableDefinition(ExecutableDefinition node) {
- if (node is ConstructorDefinition) return visitConstructorDefinition(node);
- if (node is FunctionDefinition) return visitFunctionDefinition(node);
- if (node is FieldDefinition) return visitFieldDefinition(node);
- throw 'Unexpected ExecutableDefinition: $node';
- }
+abstract class InitializerVisitor<T> {
+ T visitInitializer(Initializer node) => node.accept(this);
+ T visitFieldInitializer(FieldInitializer node);
+ T visitSuperInitializer(SuperInitializer node);
+}
- visitFunctionDefinition(FunctionDefinition node) {
- node.parameters.forEach(visitVariable);
- if (node.body != null) visitStatement(node.body);
- }
+abstract class InitializerVisitor1<T, A> {
+ T visitInitializer(Initializer node, A arg) => node.accept1(this, arg);
+ T visitFieldInitializer(FieldInitializer node, A arg);
+ T visitSuperInitializer(SuperInitializer node, A arg);
+}
- visitConstructorDefinition(ConstructorDefinition node) {
- if (node.initializers != null) node.initializers.forEach(visitInitializer);
- visitFunctionDefinition(node);
- }
+abstract class RecursiveVisitor implements StatementVisitor, ExpressionVisitor {
+ visitExpression(Expression e) => e.accept(this);
+ visitStatement(Statement s) => s.accept(this);
- visitFieldDefinition(FieldDefinition node) {
- if (node.body != null) {
- visitStatement(node.body);
- }
- }
-
- visitInitializer(Initializer node) {
- if (node is FieldInitializer) {
- return visitFieldInitializer(node);
- } else {
- return visitSuperInitializer(node);
- }
- }
-
- visitFieldInitializer(FieldInitializer node) {
- visitStatement(node.body);
- }
-
- visitSuperInitializer(SuperInitializer node) {
- node.arguments.forEach(visitStatement);
- }
+ visitInnerFunction(FunctionDefinition node);
visitVariable(Variable node) {}
@@ -997,7 +1058,7 @@
}
visitFunctionExpression(FunctionExpression node) {
- visitFunctionDefinition(node.definition);
+ visitInnerFunction(node.definition);
}
visitLabeledStatement(LabeledStatement node) {
@@ -1036,7 +1097,7 @@
}
visitFunctionDeclaration(FunctionDeclaration node) {
- visitFunctionDefinition(node.definition);
+ visitInnerFunction(node.definition);
visitStatement(node.next);
}
@@ -1065,6 +1126,7 @@
visitCreateInstance(CreateInstance node) {
node.arguments.forEach(visitExpression);
+ node.typeInformation.forEach(visitExpression);
}
visitReifyRuntimeType(ReifyRuntimeType node) {
@@ -1074,4 +1136,194 @@
visitReadTypeVariable(ReadTypeVariable node) {
visitExpression(node.target);
}
+
+ visitTypeExpression(TypeExpression node) {
+ node.arguments.forEach(visitExpression);
+ }
+}
+
+abstract class Transformer implements ExpressionVisitor<Expression>,
+ StatementVisitor<Statement> {
+ Expression visitExpression(Expression e) => e.accept(this);
+ Statement visitStatement(Statement s) => s.accept(this);
+}
+
+class RecursiveTransformer extends Transformer {
+ void visitInnerFunction(FunctionDefinition node) {
+ node.body = visitStatement(node.body);
+ }
+
+ void _replaceExpressions(List<Expression> list) {
+ for (int i = 0; i < list.length; i++) {
+ list[i] = visitExpression(list[i]);
+ }
+ }
+
+ visitVariableUse(VariableUse node) => node;
+
+ visitInvokeStatic(InvokeStatic node) {
+ _replaceExpressions(node.arguments);
+ return node;
+ }
+
+ visitInvokeMethod(InvokeMethod node) {
+ node.receiver = visitExpression(node.receiver);
+ _replaceExpressions(node.arguments);
+ return node;
+ }
+
+ visitInvokeMethodDirectly(InvokeMethodDirectly node) {
+ node.receiver = visitExpression(node.receiver);
+ _replaceExpressions(node.arguments);
+ return node;
+ }
+
+ visitInvokeConstructor(InvokeConstructor node) {
+ _replaceExpressions(node.arguments);
+ return node;
+ }
+
+ visitConcatenateStrings(ConcatenateStrings node) {
+ _replaceExpressions(node.arguments);
+ return node;
+ }
+
+ visitConstant(Constant node) => node;
+
+ visitThis(This node) => node;
+
+ visitReifyTypeVar(ReifyTypeVar node) => node;
+
+ visitConditional(Conditional node) {
+ node.condition = visitExpression(node.condition);
+ node.thenExpression = visitExpression(node.thenExpression);
+ node.elseExpression = visitExpression(node.elseExpression);
+ return node;
+ }
+
+ visitLogicalOperator(LogicalOperator node) {
+ node.left = visitExpression(node.left);
+ node.right = visitExpression(node.right);
+ return node;
+ }
+
+ visitNot(Not node) {
+ node.operand = visitExpression(node.operand);
+ return node;
+ }
+
+ visitLiteralList(LiteralList node) {
+ _replaceExpressions(node.values);
+ return node;
+ }
+
+ visitLiteralMap(LiteralMap node) {
+ node.entries.forEach((LiteralMapEntry entry) {
+ entry.key = visitExpression(entry.key);
+ entry.value = visitExpression(entry.value);
+ });
+ return node;
+ }
+
+ visitTypeOperator(TypeOperator node) {
+ node.receiver = visitExpression(node.receiver);
+ return node;
+ }
+
+ visitFunctionExpression(FunctionExpression node) {
+ visitInnerFunction(node.definition);
+ return node;
+ }
+
+ visitLabeledStatement(LabeledStatement node) {
+ node.body = visitStatement(node.body);
+ node.next = visitStatement(node.next);
+ return node;
+ }
+
+ visitAssign(Assign node) {
+ node.value = visitExpression(node.value);
+ node.next = visitStatement(node.next);
+ return node;
+ }
+
+ visitReturn(Return node) {
+ node.value = visitExpression(node.value);
+ return node;
+ }
+
+ visitBreak(Break node) => node;
+
+ visitContinue(Continue node) => node;
+
+ visitIf(If node) {
+ node.condition = visitExpression(node.condition);
+ node.thenStatement = visitStatement(node.thenStatement);
+ node.elseStatement = visitStatement(node.elseStatement);
+ return node;
+ }
+
+ visitWhileTrue(WhileTrue node) {
+ node.body = visitStatement(node.body);
+ return node;
+ }
+
+ visitWhileCondition(WhileCondition node) {
+ node.condition = visitExpression(node.condition);
+ node.body = visitStatement(node.body);
+ node.next = visitStatement(node.next);
+ return node;
+ }
+
+ visitFunctionDeclaration(FunctionDeclaration node) {
+ visitInnerFunction(node.definition);
+ node.next = visitStatement(node.next);
+ return node;
+ }
+
+ visitExpressionStatement(ExpressionStatement node) {
+ node.expression = visitExpression(node.expression);
+ node.next = visitStatement(node.next);
+ return node;
+ }
+
+ visitTry(Try node) {
+ node.tryBody = visitStatement(node.tryBody);
+ node.catchBody = visitStatement(node.catchBody);
+ return node;
+ }
+
+ visitGetField(GetField node) {
+ node.object = visitExpression(node.object);
+ return node;
+ }
+
+ visitSetField(SetField node) {
+ node.object = visitExpression(node.object);
+ node.value = visitExpression(node.value);
+ node.next = visitStatement(node.next);
+ return node;
+ }
+
+ visitCreateBox(CreateBox node) => node;
+
+ visitCreateInstance(CreateInstance node) {
+ _replaceExpressions(node.arguments);
+ return node;
+ }
+
+ visitReifyRuntimeType(ReifyRuntimeType node) {
+ node.value = visitExpression(node.value);
+ return node;
+ }
+
+ visitReadTypeVariable(ReadTypeVariable node) {
+ node.target = visitExpression(node.target);
+ return node;
+ }
+
+ visitTypeExpression(TypeExpression node) {
+ _replaceExpressions(node.arguments);
+ return node;
+ }
}
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
index 5bea4f5..a6423f3 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
@@ -7,7 +7,6 @@
import 'dart:async' show EventSink;
import '../tracer.dart';
import 'tree_ir_nodes.dart';
-import 'optimization/optimization.dart';
class Block {
Label label;
@@ -22,6 +21,10 @@
/// `null` if not inside a try block.
Block catcher;
+ /// True if this block is the entry point to one of the bodies
+ /// (constructors can have multiple bodies).
+ bool isEntryPoint = false;
+
String get name => 'B$index';
Block([this.label]);
@@ -35,7 +38,7 @@
class BlockCollector extends StatementVisitor {
// Accumulate a list of blocks. The current block is the last block in
// the list.
- final List<Block> blocks = [new Block()..index = 0];
+ final List<Block> blocks = [];
// Map tree [Label]s (break or continue targets) and [Statement]s
// (if targets) to blocks.
@@ -58,17 +61,11 @@
blocks.add(block);
}
- void collect(ExecutableDefinition node) {
- if (node.body != null) {
- if (node is ConstructorDefinition) {
- for (Initializer initializer in node.initializers) {
- if (initializer is FieldInitializer) {
- visitStatement(initializer.body);
- }
- }
- }
- visitStatement(node.body);
- }
+ void collect(RootNode node) {
+ node.forEachBody((Statement body) {
+ _addBlock(new Block()..isEntryPoint = true);
+ visitStatement(body);
+ });
}
visitLabeledStatement(LabeledStatement node) {
@@ -183,30 +180,29 @@
}
-class TreeTracer extends TracerUtil with StatementVisitor, PassMixin {
- // TODO(asgerf): Fix visitors so we don't have to use PassMixin here.
+class TreeTracer extends TracerUtil with StatementVisitor {
String get passName => null;
final EventSink<String> output;
TreeTracer(this.output);
+ List<Variable> parameters;
Names names;
BlockCollector collector;
int statementCounter;
- void traceGraph(String name, ExecutableDefinition node) {
- if (node is FunctionDefinition && node.isAbstract) return;
- if (node is FieldDefinition && node.body == null) return;
+ void traceGraph(String name, RootNode node) {
+ if (node.isEmpty) return;
+ parameters = node.parameters;
tag("cfg", () {
printProperty("name", name);
- rewrite(node);
+ printRootNode(node);
collector.blocks.forEach(printBlock);
});
}
- @override
- void rewriteExecutableDefinition(ExecutableDefinition node) {
+ void printRootNode(RootNode node) {
collector = new BlockCollector();
names = new Names();
statementCounter = 0;
@@ -231,6 +227,10 @@
});
});
tag("HIR", () {
+ if (block.isEntryPoint) {
+ String params = parameters.map(names.varName).join(', ');
+ printStatement(null, 'Entry ($params)');
+ }
if (block.label != null) {
printStatement(null,
"Label ${block.name}, useCount=${block.label.useCount}");
@@ -381,11 +381,12 @@
}
String visitInvokeConstructor(InvokeConstructor node) {
+ String className = node.target.enclosingClass.name;
String callName;
if (node.target.name.isEmpty) {
- callName = '${node.type}';
+ callName = '${className}';
} else {
- callName = '${node.type}.${node.target.name}';
+ callName = '${className}.${node.target.name}';
}
String args = formatArguments(node);
String keyword = node.constant != null ? 'const' : 'new';
@@ -495,12 +496,17 @@
@override
String visitReadTypeVariable(ReadTypeVariable node) {
- return 'read ${node.variable.element} ${visitExpression(node.target)}';
+ return 'Read ${node.variable.element} ${visitExpression(node.target)}';
}
@override
String visitReifyRuntimeType(ReifyRuntimeType node) {
- return 'reify ${node.value}';
+ return 'Reify ${node.value}';
+ }
+
+ @override
+ String visitTypeExpression(TypeExpression node) {
+ return node.dartType.toString();
}
}
diff --git a/pkg/compiler/lib/src/types/type_mask.dart b/pkg/compiler/lib/src/types/type_mask.dart
index bb97a15..a6ac402 100644
--- a/pkg/compiler/lib/src/types/type_mask.dart
+++ b/pkg/compiler/lib/src/types/type_mask.dart
@@ -200,14 +200,18 @@
bool operator==(other);
/**
- * Returns `true` if [other] is a supertype of this mask, i.e., if
- * this mask is in [other].
+ * If this returns `true`, [other] is guaranteed to be a supertype of this
+ * mask, i.e., this mask is in [other]. However, the inverse does not hold.
+ * Enable [UnionTypeMask.PERFORM_EXTRA_CONTAINS_CHECK] to be notified of
+ * false negatives.
*/
bool isInMask(TypeMask other, ClassWorld classWorld);
/**
- * Returns `true` if [other] is a subtype of this mask, i.e., if
- * this mask contains [other].
+ * If this returns `true`, [other] is guaranteed to be a subtype of this mask,
+ * i.e., this mask contains [other]. However, the inverse does not hold.
+ * Enable [UnionTypeMask.PERFORM_EXTRA_CONTAINS_CHECK] to be notified of
+ * false negatives.
*/
bool containsMask(TypeMask other, ClassWorld classWorld);
diff --git a/pkg/compiler/lib/src/types/union_type_mask.dart b/pkg/compiler/lib/src/types/union_type_mask.dart
index 0ad1cc6..3b0f139 100644
--- a/pkg/compiler/lib/src/types/union_type_mask.dart
+++ b/pkg/compiler/lib/src/types/union_type_mask.dart
@@ -9,6 +9,11 @@
static const int MAX_UNION_LENGTH = 4;
+ // Set this flag to `true` to perform a set-membership based containment check
+ // instead of relying on normalized types. This is quite slow but can be
+ // helpful in debugging.
+ static const bool PERFORM_EXTRA_CONTAINS_CHECK = false;
+
UnionTypeMask._internal(this.disjointMasks) {
assert(disjointMasks.length > 1);
assert(disjointMasks.every((TypeMask mask) => !mask.isUnion));
@@ -231,7 +236,11 @@
}
return disjointMasks.every((FlatTypeMask disjointMask) {
bool contained = containedInAnyOf(disjointMask, union.disjointMasks);
- assert(contained || !union.slowContainsCheck(disjointMask, classWorld));
+ if (PERFORM_EXTRA_CONTAINS_CHECK &&
+ !contained &&
+ union.slowContainsCheck(disjointMask, classWorld)) {
+ throw "TypeMask based containment check failed for $this and $other.";
+ }
return contained;
});
}
@@ -245,7 +254,11 @@
other = other.nonNullable(); // nullable is not canonicalized, so drop it.
bool contained =
disjointMasks.any((mask) => mask.containsMask(other, classWorld));
- assert(contained || !slowContainsCheck(other, classWorld));
+ if (PERFORM_EXTRA_CONTAINS_CHECK &&
+ !contained &&
+ slowContainsCheck(other, classWorld)) {
+ throw "TypeMask based containment check failed for $this and $other.";
+ }
return contained;
}
diff --git a/pkg/compiler/lib/src/universe/universe.dart b/pkg/compiler/lib/src/universe/universe.dart
index 3deffcb..590bb54 100644
--- a/pkg/compiler/lib/src/universe/universe.dart
+++ b/pkg/compiler/lib/src/universe/universe.dart
@@ -228,230 +228,78 @@
String toString() => name;
}
-class Selector {
- final SelectorKind kind;
- final String name;
- final LibraryElement library; // Library is null for non-private selectors.
+/// The structure of the arguments at a call-site.
+// TODO(johnniwinther): Should these be cached?
+// TODO(johnniwinther): Should isGetter/isSetter be part of the call structure
+// instead of the selector?
+class CallStructure {
+ static const CallStructure NO_ARGS = const CallStructure.unnamed(0);
+ static const CallStructure ONE_ARG = const CallStructure.unnamed(1);
+ static const CallStructure TWO_ARGS = const CallStructure.unnamed(2);
- // The numbers of arguments of the selector. Includes named arguments.
+ /// The numbers of arguments of the call. Includes named arguments.
final int argumentCount;
- final List<String> namedArguments;
- final List<String> _orderedNamedArguments;
- final int hashCode;
- static const String INDEX_NAME ="[]";
- static const String INDEX_SET_NAME = "[]=";
- static const String CALL_NAME = Compiler.CALL_OPERATOR_NAME;
+ /// The number of named arguments of the call.
+ int get namedArgumentCount => 0;
- Selector.internal(this.kind,
- this.name,
- this.library,
- this.argumentCount,
- this.namedArguments,
- this._orderedNamedArguments,
- this.hashCode) {
- assert(kind == SelectorKind.INDEX
- || (name != INDEX_NAME && name != INDEX_SET_NAME));
- assert(kind == SelectorKind.OPERATOR
- || kind == SelectorKind.INDEX
- || !Elements.isOperatorName(name));
- assert(kind == SelectorKind.CALL
- || kind == SelectorKind.GETTER
- || kind == SelectorKind.SETTER
- || Elements.isOperatorName(name));
- assert(!isPrivateName(name) || library != null);
- }
+ /// The number of positional argument of the call.
+ int get positionalArgumentCount => argumentCount;
- static Map<int, List<Selector>> canonicalizedValues =
- new Map<int, List<Selector>>();
+ const CallStructure.unnamed(this.argumentCount);
- factory Selector(SelectorKind kind,
- String name,
- LibraryElement library,
- int argumentCount,
- [List<String> namedArguments]) {
- if (!isPrivateName(name)) library = null;
- if (namedArguments == null) namedArguments = const <String>[];
- int hashCode = computeHashCode(
- kind, name, library, argumentCount, namedArguments);
- List<Selector> list = canonicalizedValues.putIfAbsent(hashCode,
- () => <Selector>[]);
- for (int i = 0; i < list.length; i++) {
- Selector existing = list[i];
- if (existing.match(kind, name, library, argumentCount, namedArguments)) {
- assert(existing.hashCode == hashCode);
- assert(existing.mask == null);
- return existing;
- }
+ factory CallStructure(int argumentCount, [List<String> namedArguments]) {
+ if (namedArguments == null || namedArguments.isEmpty) {
+ return new CallStructure.unnamed(argumentCount);
}
- List<String> orderedNamedArguments = namedArguments.isEmpty
- ? const <String>[]
- : <String>[];
- Selector result = new Selector.internal(
- kind, name, library, argumentCount,
- namedArguments, orderedNamedArguments,
- hashCode);
- list.add(result);
- return result;
+ return new NamedCallStructure(argumentCount, namedArguments);
}
- factory Selector.fromElement(Element element) {
- String name = element.name;
- if (element.isFunction) {
- if (name == '[]') {
- return new Selector.index();
- } else if (name == '[]=') {
- return new Selector.indexSet();
- }
- FunctionSignature signature =
- element.asFunctionElement().functionSignature;
- int arity = signature.parameterCount;
- List<String> namedArguments = null;
- if (signature.optionalParametersAreNamed) {
- namedArguments =
- signature.orderedOptionalParameters.map((e) => e.name).toList();
- }
- if (element.isOperator) {
- // Operators cannot have named arguments, however, that doesn't prevent
- // a user from declaring such an operator.
- return new Selector(
- SelectorKind.OPERATOR, name, null, arity, namedArguments);
- } else {
- return new Selector.call(
- name, element.library, arity, namedArguments);
- }
- } else if (element.isSetter) {
- return new Selector.setter(name, element.library);
- } else if (element.isGetter) {
- return new Selector.getter(name, element.library);
- } else if (element.isField) {
- return new Selector.getter(name, element.library);
- } else if (element.isConstructor) {
- return new Selector.callConstructor(name, element.library);
- } else {
- throw new SpannableAssertionFailure(
- element, "Can't get selector from $element");
+ /// `true` if this call has named arguments.
+ bool get isNamed => false;
+
+ /// `true` if this call has no named arguments.
+ bool get isUnnamed => true;
+
+ /// The names of the named arguments in call-site order.
+ List<String> get namedArguments => const <String>[];
+
+ /// The names of the named arguments in canonicalized order.
+ List<String> getOrderedNamedArguments() => const <String>[];
+
+ /// A description of the argument structure.
+ String structureToString() => 'arity=$argumentCount';
+
+ String toString() => 'CallStructure(${structureToString()})';
+
+ Selector get callSelector {
+ return new Selector(SelectorKind.CALL, Selector.CALL_NAME, this);
+ }
+
+ bool match(CallStructure other) {
+ if (identical(this, other)) return true;
+ return this.argumentCount == other.argumentCount
+ && this.namedArgumentCount == other.namedArgumentCount
+ && sameNames(this.namedArguments, other.namedArguments);
+ }
+
+ // TODO(johnniwinther): Cache hash code?
+ int get hashCode {
+ int named = namedArguments.length;
+ int hash = mixHashCodeBits(argumentCount, named);
+ for (int i = 0; i < named; i++) {
+ hash = mixHashCodeBits(hash, namedArguments[i].hashCode);
}
+ return hash;
}
- factory Selector.getter(String name, LibraryElement library)
- => new Selector(SelectorKind.GETTER, name, library, 0);
-
- factory Selector.getterFrom(Selector selector)
- => new Selector(SelectorKind.GETTER, selector.name, selector.library, 0);
-
- factory Selector.setter(String name, LibraryElement library)
- => new Selector(SelectorKind.SETTER, name, library, 1);
-
- factory Selector.unaryOperator(String name)
- => new Selector(SelectorKind.OPERATOR,
- Elements.constructOperatorName(name, true),
- null, 0);
-
- factory Selector.binaryOperator(String name)
- => new Selector(SelectorKind.OPERATOR,
- Elements.constructOperatorName(name, false),
- null, 1);
-
- factory Selector.index()
- => new Selector(SelectorKind.INDEX,
- Elements.constructOperatorName(INDEX_NAME, false),
- null, 1);
-
- factory Selector.indexSet()
- => new Selector(SelectorKind.INDEX,
- Elements.constructOperatorName(INDEX_SET_NAME, false),
- null, 2);
-
- factory Selector.call(String name,
- LibraryElement library,
- int arity,
- [List<String> namedArguments])
- => new Selector(SelectorKind.CALL, name, library, arity, namedArguments);
-
- factory Selector.callClosure(int arity, [List<String> namedArguments])
- => new Selector(SelectorKind.CALL, CALL_NAME, null,
- arity, namedArguments);
-
- factory Selector.callClosureFrom(Selector selector)
- => new Selector(SelectorKind.CALL, CALL_NAME, null,
- selector.argumentCount, selector.namedArguments);
-
- factory Selector.callConstructor(String name, LibraryElement library,
- [int arity = 0,
- List<String> namedArguments])
- => new Selector(SelectorKind.CALL, name, library,
- arity, namedArguments);
-
- factory Selector.callDefaultConstructor()
- => new Selector(SelectorKind.CALL, "", null, 0);
-
- bool get isGetter => identical(kind, SelectorKind.GETTER);
- bool get isSetter => identical(kind, SelectorKind.SETTER);
- bool get isCall => identical(kind, SelectorKind.CALL);
- bool get isClosureCall {
- String callName = Compiler.CALL_OPERATOR_NAME;
- return isCall && name == callName;
- }
-
- bool get isIndex => identical(kind, SelectorKind.INDEX) && argumentCount == 1;
- bool get isIndexSet => identical(kind, SelectorKind.INDEX) && argumentCount == 2;
-
- bool get isOperator => identical(kind, SelectorKind.OPERATOR);
- bool get isUnaryOperator => isOperator && argumentCount == 0;
-
- /** Check whether this is a call to 'assert'. */
- bool get isAssert => isCall && identical(name, "assert");
-
- int get namedArgumentCount => namedArguments.length;
- int get positionalArgumentCount => argumentCount - namedArgumentCount;
-
- bool get hasExactMask => false;
- TypeMask get mask => null;
- Selector get asUntyped => this;
-
- /**
- * The member name for invocation mirrors created from this selector.
- */
- String get invocationMirrorMemberName =>
- isSetter ? '$name=' : name;
-
- int get invocationMirrorKind {
- const int METHOD = 0;
- const int GETTER = 1;
- const int SETTER = 2;
- int kind = METHOD;
- if (isGetter) {
- kind = GETTER;
- } else if (isSetter) {
- kind = SETTER;
- }
- return kind;
- }
-
- bool appliesUnnamed(Element element, World world) {
- assert(sameNameHack(element, world));
- return appliesUntyped(element, world);
- }
-
- bool appliesUntyped(Element element, World world) {
- assert(sameNameHack(element, world));
- if (Elements.isUnresolved(element)) return false;
- if (isPrivateName(name) && library != element.library) return false;
- if (world.isForeign(element)) return true;
- if (element.isSetter) return isSetter;
- if (element.isGetter) return isGetter || isCall;
- if (element.isField) {
- return isSetter
- ? !element.isFinal && !element.isConst
- : isGetter || isCall;
- }
- if (isGetter) return true;
- if (isSetter) return false;
- return signatureApplies(element);
+ bool operator ==(other) {
+ if (other is! CallStructure) return false;
+ return match(other);
}
bool signatureApplies(FunctionElement function) {
+ if (Elements.isUnresolved(function)) return false;
FunctionSignature parameters = function.functionSignature;
if (argumentCount > parameters.parameterCount) return false;
int requiredParameterCount = parameters.requiredParameterCount;
@@ -484,18 +332,6 @@
}
}
- bool sameNameHack(Element element, World world) {
- // TODO(ngeoffray): Remove workaround checks.
- return element.isConstructor ||
- name == element.name ||
- name == 'assert' && world.isAssertMethod(element);
- }
-
- bool applies(Element element, World world) {
- if (!sameNameHack(element, world)) return false;
- return appliesUnnamed(element, world);
- }
-
/**
* Returns a `List` with the evaluated arguments in the normalized order.
*
@@ -564,21 +400,20 @@
* Returns [:true:] if the signature of the [caller] matches the
* signature of the [callee], [:false:] otherwise.
*/
- static bool addForwardingElementArgumentsToList(
- FunctionElement caller,
- List list,
- FunctionElement callee,
- compileArgument(Element element),
- compileConstant(Element element),
- World world) {
+ static /*<T>*/ bool addForwardingElementArgumentsToList(
+ ConstructorElement caller,
+ List/*<T>*/ list,
+ ConstructorElement callee,
+ /*T*/ compileArgument(ParameterElement element),
+ /*T*/ compileConstant(ParameterElement element)) {
FunctionSignature signature = caller.functionSignature;
- Map mapping = new Map();
+ Map<Node, ParameterElement> mapping = <Node, ParameterElement>{};
// TODO(ngeoffray): This is a hack that fakes up AST nodes, so
// that we can call [addArgumentsToList].
- Link computeCallNodesFromParameters() {
- LinkBuilder builder = new LinkBuilder();
+ Link<Node> computeCallNodesFromParameters() {
+ LinkBuilder<Node> builder = new LinkBuilder<Node>();
signature.forEachRequiredParameter((ParameterElement element) {
Node node = element.node;
mapping[node] = element;
@@ -599,29 +434,28 @@
return builder.toLink();
}
- internalCompileArgument(Node node) {
+ /*T*/ internalCompileArgument(Node node) {
return compileArgument(mapping[node]);
}
Link<Node> nodes = computeCallNodesFromParameters();
- // Synthesize a selector for the call.
+ // Synthesize a structure for the call.
// TODO(ngeoffray): Should the resolver do it instead?
List<String> namedParameters;
if (signature.optionalParametersAreNamed) {
- namedParameters =
- signature.optionalParameters.mapToList((e) => e.name);
+ namedParameters = signature.optionalParameters.mapToList((e) => e.name);
}
- Selector selector = new Selector.call(callee.name,
- caller.library,
- signature.parameterCount,
- namedParameters);
-
- if (!selector.applies(callee, world)) return false;
- list.addAll(selector.makeArgumentsList(nodes,
- callee,
- internalCompileArgument,
- compileConstant));
+ CallStructure callStructure =
+ new CallStructure(signature.parameterCount, namedParameters);
+ if (!callStructure.signatureApplies(callee)) {
+ return false;
+ }
+ list.addAll(callStructure.makeArgumentsList(
+ nodes,
+ callee,
+ internalCompileArgument,
+ compileConstant));
return true;
}
@@ -632,59 +466,32 @@
}
return true;
}
+}
- bool match(SelectorKind kind,
- String name,
- LibraryElement library,
- int argumentCount,
- List<String> namedArguments) {
- return this.kind == kind
- && this.name == name
- && identical(this.library, library)
- && this.argumentCount == argumentCount
- && this.namedArguments.length == namedArguments.length
- && sameNames(this.namedArguments, namedArguments);
+///
+class NamedCallStructure extends CallStructure {
+ final List<String> namedArguments;
+ final List<String> _orderedNamedArguments = <String>[];
+
+ NamedCallStructure(int argumentCount, this.namedArguments)
+ : super.unnamed(argumentCount) {
+ assert(namedArguments.isNotEmpty);
}
- static int computeHashCode(SelectorKind kind,
- String name,
- LibraryElement library,
- int argumentCount,
- List<String> namedArguments) {
- // Add bits from name and kind.
- int hash = mixHashCodeBits(name.hashCode, kind.hashCode);
- // Add bits from the library.
- if (library != null) hash = mixHashCodeBits(hash, library.hashCode);
- // Add bits from the unnamed arguments.
- hash = mixHashCodeBits(hash, argumentCount);
- // Add bits from the named arguments.
- int named = namedArguments.length;
- hash = mixHashCodeBits(hash, named);
- for (int i = 0; i < named; i++) {
- hash = mixHashCodeBits(hash, namedArguments[i].hashCode);
- }
- return hash;
- }
+ @override
+ bool get isNamed => true;
- // TODO(kasperl): Move this out so it becomes useful in other places too?
- static int mixHashCodeBits(int existing, int value) {
- // Spread the bits of value. Try to stay in the 30-bit range to
- // avoid overflowing into a more expensive integer representation.
- int h = value & 0x1fffffff;
- h += ((h & 0x3fff) << 15) ^ 0x1fffcd7d;
- h ^= (h >> 10);
- h += ((h & 0x3ffffff) << 3);
- h ^= (h >> 6);
- h += ((h & 0x7ffffff) << 2) + ((h & 0x7fff) << 14);
- h ^= (h >> 16);
- // Combine the two hash values.
- int high = existing >> 15;
- int low = existing & 0x7fff;
- return ((high * 13) ^ (low * 997) ^ h) & SMI_MASK;
- }
+ @override
+ bool get isUnnamed => false;
+ @override
+ int get namedArgumentCount => namedArguments.length;
+
+ @override
+ int get positionalArgumentCount => argumentCount - namedArgumentCount;
+
+ @override
List<String> getOrderedNamedArguments() {
- if (namedArguments.isEmpty) return namedArguments;
if (!_orderedNamedArguments.isEmpty) return _orderedNamedArguments;
_orderedNamedArguments.addAll(namedArguments);
@@ -694,25 +501,273 @@
return _orderedNamedArguments;
}
- String namedArgumentsToString() {
- if (namedArgumentCount > 0) {
- StringBuffer result = new StringBuffer();
- for (int i = 0; i < namedArgumentCount; i++) {
- if (i != 0) result.write(', ');
- result.write(namedArguments[i]);
+ @override
+ String structureToString() {
+ return 'arity=$argumentCount, named=[${namedArguments.join(', ')}]';
+ }
+}
+
+class Selector {
+ final SelectorKind kind;
+ final Name memberName;
+ final CallStructure callStructure;
+
+ final int hashCode;
+
+ int get argumentCount => callStructure.argumentCount;
+ int get namedArgumentCount => callStructure.namedArgumentCount;
+ int get positionalArgumentCount => callStructure.positionalArgumentCount;
+ List<String> get namedArguments => callStructure.namedArguments;
+
+ String get name => memberName.text;
+
+ LibraryElement get library => memberName.library;
+
+ static const Name INDEX_NAME = const PublicName("[]");
+ static const Name INDEX_SET_NAME = const PublicName("[]=");
+ static const Name CALL_NAME = const PublicName(Compiler.CALL_OPERATOR_NAME);
+
+ Selector.internal(this.kind,
+ this.memberName,
+ this.callStructure,
+ this.hashCode) {
+ assert(kind == SelectorKind.INDEX ||
+ (memberName != INDEX_NAME && memberName != INDEX_SET_NAME));
+ assert(kind == SelectorKind.OPERATOR ||
+ kind == SelectorKind.INDEX ||
+ !Elements.isOperatorName(memberName.text));
+ assert(kind == SelectorKind.CALL ||
+ kind == SelectorKind.GETTER ||
+ kind == SelectorKind.SETTER ||
+ Elements.isOperatorName(memberName.text));
+ }
+
+ // TODO(johnniwinther): Extract caching.
+ static Map<int, List<Selector>> canonicalizedValues =
+ new Map<int, List<Selector>>();
+
+ factory Selector(SelectorKind kind,
+ Name name,
+ CallStructure callStructure) {
+ // TODO(johnniwinther): Maybe use equality instead of implicit hashing.
+ int hashCode = computeHashCode(kind, name, callStructure);
+ List<Selector> list = canonicalizedValues.putIfAbsent(hashCode,
+ () => <Selector>[]);
+ for (int i = 0; i < list.length; i++) {
+ Selector existing = list[i];
+ if (existing.match(kind, name, callStructure)) {
+ assert(existing.hashCode == hashCode);
+ assert(existing.mask == null);
+ return existing;
}
- return "[$result]";
}
- return '';
+ Selector result = new Selector.internal(
+ kind, name, callStructure, hashCode);
+ list.add(result);
+ return result;
+ }
+
+ factory Selector.fromElement(Element element) {
+ String name = element.name;
+ if (element.isFunction) {
+ if (name == '[]') {
+ return new Selector.index();
+ } else if (name == '[]=') {
+ return new Selector.indexSet();
+ }
+ FunctionSignature signature =
+ element.asFunctionElement().functionSignature;
+ int arity = signature.parameterCount;
+ List<String> namedArguments = null;
+ if (signature.optionalParametersAreNamed) {
+ namedArguments =
+ signature.orderedOptionalParameters.map((e) => e.name).toList();
+ }
+ if (element.isOperator) {
+ // Operators cannot have named arguments, however, that doesn't prevent
+ // a user from declaring such an operator.
+ return new Selector(
+ SelectorKind.OPERATOR,
+ new PublicName(name),
+ new CallStructure(arity, namedArguments));
+ } else {
+ return new Selector.call(
+ name, element.library, arity, namedArguments);
+ }
+ } else if (element.isSetter) {
+ return new Selector.setter(name, element.library);
+ } else if (element.isGetter) {
+ return new Selector.getter(name, element.library);
+ } else if (element.isField) {
+ return new Selector.getter(name, element.library);
+ } else if (element.isConstructor) {
+ return new Selector.callConstructor(name, element.library);
+ } else {
+ throw new SpannableAssertionFailure(
+ element, "Can't get selector from $element");
+ }
+ }
+
+ factory Selector.getter(String name, LibraryElement library)
+ => new Selector(SelectorKind.GETTER,
+ new Name(name, library),
+ CallStructure.NO_ARGS);
+
+ factory Selector.getterFrom(Selector selector)
+ => new Selector(SelectorKind.GETTER,
+ selector.memberName,
+ CallStructure.NO_ARGS);
+
+ factory Selector.setter(String name, LibraryElement library)
+ => new Selector(SelectorKind.SETTER,
+ new Name(name, library, isSetter: true),
+ CallStructure.ONE_ARG);
+
+ factory Selector.unaryOperator(String name) => new Selector(
+ SelectorKind.OPERATOR,
+ new PublicName(Elements.constructOperatorName(name, true)),
+ CallStructure.NO_ARGS);
+
+ factory Selector.binaryOperator(String name) => new Selector(
+ SelectorKind.OPERATOR,
+ new PublicName(Elements.constructOperatorName(name, false)),
+ CallStructure.ONE_ARG);
+
+ factory Selector.index()
+ => new Selector(SelectorKind.INDEX, INDEX_NAME,
+ CallStructure.ONE_ARG);
+
+ factory Selector.indexSet()
+ => new Selector(SelectorKind.INDEX, INDEX_SET_NAME,
+ CallStructure.TWO_ARGS);
+
+ factory Selector.call(String name,
+ LibraryElement library,
+ int arity,
+ [List<String> namedArguments])
+ => new Selector(SelectorKind.CALL,
+ new Name(name, library),
+ new CallStructure(arity, namedArguments));
+
+ factory Selector.callClosure(int arity, [List<String> namedArguments])
+ => new Selector(SelectorKind.CALL, CALL_NAME,
+ new CallStructure(arity, namedArguments));
+
+ factory Selector.callClosureFrom(Selector selector)
+ => new Selector(SelectorKind.CALL, CALL_NAME, selector.callStructure);
+
+ factory Selector.callConstructor(String name, LibraryElement library,
+ [int arity = 0,
+ List<String> namedArguments])
+ => new Selector(SelectorKind.CALL, new Name(name, library),
+ new CallStructure(arity, namedArguments));
+
+ factory Selector.callDefaultConstructor()
+ => new Selector(
+ SelectorKind.CALL,
+ const PublicName(''),
+ CallStructure.NO_ARGS);
+
+ bool get isGetter => kind == SelectorKind.GETTER;
+ bool get isSetter => kind == SelectorKind.SETTER;
+ bool get isCall => kind == SelectorKind.CALL;
+ bool get isClosureCall => isCall && memberName == CALL_NAME;
+
+ bool get isIndex => kind == SelectorKind.INDEX && argumentCount == 1;
+ bool get isIndexSet => kind == SelectorKind.INDEX && argumentCount == 2;
+
+ bool get isOperator => kind == SelectorKind.OPERATOR;
+ bool get isUnaryOperator => isOperator && argumentCount == 0;
+
+ /** Check whether this is a call to 'assert'. */
+ bool get isAssert => isCall && identical(name, "assert");
+
+ bool get hasExactMask => false;
+ TypeMask get mask => null;
+ Selector get asUntyped => this;
+
+ /**
+ * The member name for invocation mirrors created from this selector.
+ */
+ String get invocationMirrorMemberName =>
+ isSetter ? '$name=' : name;
+
+ int get invocationMirrorKind {
+ const int METHOD = 0;
+ const int GETTER = 1;
+ const int SETTER = 2;
+ int kind = METHOD;
+ if (isGetter) {
+ kind = GETTER;
+ } else if (isSetter) {
+ kind = SETTER;
+ }
+ return kind;
+ }
+
+ bool appliesUnnamed(Element element, World world) {
+ assert(sameNameHack(element, world));
+ return appliesUntyped(element, world);
+ }
+
+ bool appliesUntyped(Element element, World world) {
+ assert(sameNameHack(element, world));
+ if (Elements.isUnresolved(element)) return false;
+ if (memberName.isPrivate && memberName.library != element.library) {
+ // TODO(johnniwinther): Maybe this should be
+ // `memberName != element.memberName`.
+ return false;
+ }
+ if (world.isForeign(element)) return true;
+ if (element.isSetter) return isSetter;
+ if (element.isGetter) return isGetter || isCall;
+ if (element.isField) {
+ return isSetter
+ ? !element.isFinal && !element.isConst
+ : isGetter || isCall;
+ }
+ if (isGetter) return true;
+ if (isSetter) return false;
+ return signatureApplies(element);
+ }
+
+ bool signatureApplies(FunctionElement function) {
+ return callStructure.signatureApplies(function);
+ }
+
+ bool sameNameHack(Element element, World world) {
+ // TODO(ngeoffray): Remove workaround checks.
+ return element.isConstructor ||
+ name == element.name ||
+ name == 'assert' && world.isAssertMethod(element);
+ }
+
+ bool applies(Element element, World world) {
+ if (!sameNameHack(element, world)) return false;
+ return appliesUnnamed(element, world);
+ }
+
+ bool match(SelectorKind kind,
+ Name memberName,
+ CallStructure callStructure) {
+ return this.kind == kind
+ && this.memberName == memberName
+ && this.callStructure.match(callStructure);
+ }
+
+ static int computeHashCode(SelectorKind kind,
+ Name name,
+ CallStructure callStructure) {
+ // Add bits from name and kind.
+ int hash = mixHashCodeBits(name.hashCode, kind.hashCode);
+ // Add bits from the call structure.
+ return mixHashCodeBits(hash, callStructure.hashCode);
}
String toString() {
- String named = '';
String type = '';
- if (namedArgumentCount > 0) named = ', named=${namedArgumentsToString()}';
if (mask != null) type = ', mask=$mask';
- return 'Selector($kind, $name, '
- 'arity=$argumentCount$named$type)';
+ return 'Selector($kind, $name, ${callStructure.structureToString()}$type)';
}
Selector extendIfReachesAll(Compiler compiler) {
@@ -730,11 +785,8 @@
TypedSelector.internal(this.mask, Selector selector, int hashCode)
: asUntyped = selector,
super.internal(selector.kind,
- selector.name,
- selector.library,
- selector.argumentCount,
- selector.namedArguments,
- selector._orderedNamedArguments,
+ selector.memberName,
+ selector.callStructure,
hashCode) {
assert(mask != null);
assert(asUntyped.mask == null);
@@ -758,7 +810,7 @@
.putIfAbsent(untyped, () => new Map<TypeMask, TypedSelector>());
TypedSelector result = map[mask];
if (result == null) {
- int hashCode = Selector.mixHashCodeBits(untyped.hashCode, mask.hashCode);
+ int hashCode = mixHashCodeBits(untyped.hashCode, mask.hashCode);
result = map[mask] = new TypedSelector.internal(mask, untyped, hashCode);
}
return result;
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index aee8529..8edad0b 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -15,6 +15,7 @@
import 'cps_ir/cps_ir_builder.dart' as ir_builder;
import 'cps_ir/cps_ir_builder_task.dart' as ir_builder;
import 'cps_ir/cps_ir_nodes_sexpr.dart' as cps_ir_nodes_sexpr;
+import 'tree_ir/tree_ir_nodes.dart' as tree_ir;
import 'dart_types.dart' as dart_types;
import 'dart2js.dart' as dart2js;
import 'dart2jslib.dart' as dart2jslib;
@@ -47,6 +48,7 @@
void main(List<String> arguments) {
useApi();
dart2js.main(arguments);
+ dart2jslib.isPublicName(null);
useConstant(null, null);
useNode(null);
useUtil(null);
@@ -72,6 +74,7 @@
useScript(null);
useProgramBuilder(null);
useSemanticVisitor();
+ useTreeVisitors();
}
useApi() {
@@ -269,6 +272,8 @@
useCodeEmitterTask(js_emitter.CodeEmitterTask codeEmitterTask) {
codeEmitterTask.oldEmitter.clearCspPrecompiledNodes();
+ codeEmitterTask.oldEmitter.
+ buildLazilyInitializedStaticField(null, isolateProperties: null);
}
useScript(dart2jslib.Script script) {
@@ -284,3 +289,18 @@
new semantic_visitor.BulkVisitor().apply(null, null);
new semantic_visitor.TraversalVisitor(null).apply(null, null);
}
+
+class DummyTreeVisitor extends tree_ir.RootVisitor
+ with tree_ir.InitializerVisitor {
+ visitFunctionDefinition(tree_ir.FunctionDefinition node) {}
+ visitConstructorDefinition(tree_ir.ConstructorDefinition node) {}
+ visitFieldDefinition(tree_ir.FieldDefinition node) {}
+
+ visitFieldInitializer(tree_ir.FieldInitializer node) {}
+ visitSuperInitializer(tree_ir.SuperInitializer node) {}
+}
+
+useTreeVisitors() {
+ new DummyTreeVisitor().visitRootNode(null);
+ new DummyTreeVisitor().visitInitializer(null);
+}
diff --git a/pkg/compiler/lib/src/util/util.dart b/pkg/compiler/lib/src/util/util.dart
index 7c75819..b825d18 100644
--- a/pkg/compiler/lib/src/util/util.dart
+++ b/pkg/compiler/lib/src/util/util.dart
@@ -18,6 +18,23 @@
/// Smi range.
const int SMI_MASK = 0x3fffffff;
+/// Mix the bits of [value] and merge them with [existing].
+int mixHashCodeBits(int existing, int value) {
+ // Spread the bits of value. Try to stay in the 30-bit range to
+ // avoid overflowing into a more expensive integer representation.
+ int h = value & 0x1fffffff;
+ h += ((h & 0x3fff) << 15) ^ 0x1fffcd7d;
+ h ^= (h >> 10);
+ h += ((h & 0x3ffffff) << 3);
+ h ^= (h >> 6);
+ h += ((h & 0x7ffffff) << 2) + ((h & 0x7fff) << 14);
+ h ^= (h >> 16);
+ // Combine the two hash values.
+ int high = existing >> 15;
+ int low = existing & 0x7fff;
+ return ((high * 13) ^ (low * 997) ^ h) & SMI_MASK;
+}
+
/**
* Tagging interface for classes from which source spans can be generated.
*/
diff --git a/pkg/compiler/lib/src/warnings.dart b/pkg/compiler/lib/src/warnings.dart
index 40b04ed..94714195 100644
--- a/pkg/compiler/lib/src/warnings.dart
+++ b/pkg/compiler/lib/src/warnings.dart
@@ -2410,6 +2410,28 @@
"Non-supported 'call' member on a native class, or a "
"subclass of a native class.");
+ static const MessageKind DIRECTLY_THROWING_NSM =
+ const MessageKind(
+ "This 'noSuchMethod' implementation is guaranteed to throw an "
+ "exception. The generated code will be smaller if it is "
+ "rewritten.",
+ howToFix: "Rewrite to "
+ "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'.");
+
+ static const MessageKind COMPLEX_THROWING_NSM =
+ const MessageKind(
+ "This 'noSuchMethod' implementation is guaranteed to throw an "
+ "exception. The generated code will be smaller and the compiler "
+ "will be able to perform more optimizations if it is rewritten.",
+ howToFix: "Rewrite to "
+ "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'.");
+
+ static const MessageKind COMPLEX_RETURNING_NSM =
+ const MessageKind(
+ "Overriding 'noSuchMethod' causes the compiler to generate "
+ "more code and prevents the compiler from doing some optimizations.",
+ howToFix: "Consider removing this 'noSuchMethod' implementation.");
+
toString() => template;
Message message([Map arguments = const {}, bool terse = false]) {
diff --git a/pkg/dart2js_incremental/lib/library_updater.dart b/pkg/dart2js_incremental/lib/library_updater.dart
index 57d4142..6b08832 100644
--- a/pkg/dart2js_incremental/lib/library_updater.dart
+++ b/pkg/dart2js_incremental/lib/library_updater.dart
@@ -978,7 +978,7 @@
if (backend.constants.lazyStatics.contains(element)) {
jsAst.Expression init =
emitter.oldEmitter.buildLazilyInitializedStaticField(
- element, namer.currentIsolate);
+ element, isolateProperties: namer.currentIsolate);
if (init == null) {
throw new StateError("Initializer optimized away for $element");
}
diff --git a/pkg/docgen/lib/src/models/model_helpers.dart b/pkg/docgen/lib/src/models/model_helpers.dart
index f962e75..d587681 100644
--- a/pkg/docgen/lib/src/models/model_helpers.dart
+++ b/pkg/docgen/lib/src/models/model_helpers.dart
@@ -113,7 +113,7 @@
}
@override
- Annotation visitConstructed(ConstructedConstantExpresssion exp,
+ Annotation visitConstructed(ConstructedConstantExpression exp,
AnnotationInfo context) {
return createAnnotation(exp.target, context,
exp.arguments.map((a) => a.getText()).toList());
diff --git a/pkg/pkg.status b/pkg/pkg.status
index b24c089..a38d8eb 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -163,9 +163,9 @@
third_party/html5lib/test/selectors/*: SkipByDesign # Uses dart:io.
third_party/html5lib/test/tokenizer_test: SkipByDesign # Uses dart:io.
-[ $arch == simarm64 ]
+[ $arch == simarm64 || $arch == armv5te ]
# Timeout. These are not unit tests. They do not run efficiently on our
-# simulator.
+# simulator or low-end devices.
*: Skip
[ $runtime == vm ]
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index fb02b45..beaf048 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -60,7 +60,6 @@
deps = [
"vm:libdart_lib",
"vm:libdart_vm",
- "third_party/jscre:libjscre",
"third_party/double-conversion/src:libdouble_conversion",
":generate_version_cc_file",
]
@@ -116,7 +115,6 @@
"vm:libdart_lib",
"vm:libdart_vm",
"vm:libdart_platform",
- "third_party/jscre:libjscre",
"third_party/double-conversion/src:libdouble_conversion",
]
sources = [
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 7ddfa0c..576a0ef 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -114,7 +114,6 @@
"../vm:libdart_lib_withcore",
"../vm:libdart_vm",
"../vm:libdart_platform",
- "../third_party/jscre:libjscre",
"../third_party/double-conversion/src:libdouble_conversion",
"..:generate_version_cc_file",
]
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index c626805..08413e4 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -11,7 +11,8 @@
'builtin_in_cc_file': 'builtin_in.cc',
'builtin_cc_file': '<(gen_source_dir)/builtin_gen.cc',
'snapshot_in_cc_file': 'snapshot_in.cc',
- 'snapshot_bin_file': '<(gen_source_dir)/snapshot_gen.bin',
+ 'vm_isolate_snapshot_bin_file': '<(gen_source_dir)/vm_isolate_snapshot_gen.bin',
+ 'isolate_snapshot_bin_file': '<(gen_source_dir)/isolate_snapshot_gen.bin',
'resources_cc_file': '<(gen_source_dir)/resources_gen.cc',
'bootstrap_resources_cc_file':
'<(gen_source_dir)/bootstrap_resources_gen.cc',
@@ -352,7 +353,6 @@
'dependencies': [
'libdart_lib_withcore',
'libdart_vm',
- 'libjscre',
'libdouble_conversion',
'generate_version_cc_file#host',
],
@@ -431,17 +431,19 @@
'<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)gen_snapshot<(EXECUTABLE_SUFFIX)',
],
'outputs': [
- '<(snapshot_bin_file)',
+ '<(vm_isolate_snapshot_bin_file)',
+ '<(isolate_snapshot_bin_file)',
],
'action': [
'python',
'tools/create_snapshot_bin.py',
'--executable',
'<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)gen_snapshot<(EXECUTABLE_SUFFIX)',
- '--output_bin', '<(snapshot_bin_file)',
+ '--vm_output_bin', '<(vm_isolate_snapshot_bin_file)',
+ '--output_bin', '<(isolate_snapshot_bin_file)',
'--target_os', '<(OS)'
],
- 'message': 'Generating ''<(snapshot_bin_file)'' file.'
+ 'message': 'Generating ''<(vm_isolate_snapshot_bin_file)'' ''<(isolate_snapshot_bin_file)'' files.'
},
],
},
@@ -459,7 +461,8 @@
'inputs': [
'../tools/create_snapshot_file.py',
'<(snapshot_in_cc_file)',
- '<(snapshot_bin_file)'
+ '<(vm_isolate_snapshot_bin_file)',
+ '<(isolate_snapshot_bin_file)',
],
'outputs': [
'<(snapshot_cc_file)',
@@ -467,7 +470,8 @@
'action': [
'python',
'tools/create_snapshot_file.py',
- '--input_bin', '<(snapshot_bin_file)',
+ '--vm_input_bin', '<(vm_isolate_snapshot_bin_file)',
+ '--input_bin', '<(isolate_snapshot_bin_file)',
'--input_cc', '<(snapshot_in_cc_file)',
'--output', '<(snapshot_cc_file)',
],
diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
index 59338260..1f9584d 100644
--- a/runtime/bin/builtin.dart
+++ b/runtime/bin/builtin.dart
@@ -353,6 +353,7 @@
case 'package':
return _filePathFromUri(_resolvePackageUri(uri).toString());
case 'data':
+ case 'embedder-package':
case 'http':
case 'https':
return uri.toString();
diff --git a/runtime/bin/dbg_connection.cc b/runtime/bin/dbg_connection.cc
index 0b0b217..2cc4cd8 100644
--- a/runtime/bin/dbg_connection.cc
+++ b/runtime/bin/dbg_connection.cc
@@ -21,7 +21,7 @@
namespace dart {
namespace bin {
-extern bool trace_debug_protocol;
+bool trace_debug_protocol = false;
intptr_t DebuggerConnectionHandler::listener_fd_ = -1;
Monitor* DebuggerConnectionHandler::handler_lock_ = new Monitor();
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 719b2b5..06d8a02 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -25,7 +25,6 @@
#define CHECK_RESULT(result) \
if (Dart_IsError(result)) { \
- free(snapshot_buffer); \
Log::PrintErr("Error: %s", Dart_GetError(result)); \
Dart_ExitScope(); \
Dart_ShutdownIsolate(); \
@@ -35,9 +34,9 @@
// Global state that indicates whether a snapshot is to be created and
// if so which file to write the snapshot into.
-static const char* snapshot_filename = NULL;
+static const char* vm_isolate_snapshot_filename = NULL;
+static const char* isolate_snapshot_filename = NULL;
static const char* package_root = NULL;
-static uint8_t* snapshot_buffer = NULL;
// Global state which contains a pointer to the script name for which
@@ -67,10 +66,20 @@
}
-static bool ProcessSnapshotOption(const char* option) {
- const char* name = ProcessOption(option, "--snapshot=");
+static bool ProcessVmIsolateSnapshotOption(const char* option) {
+ const char* name = ProcessOption(option, "--vm_isolate_snapshot=");
if (name != NULL) {
- snapshot_filename = name;
+ vm_isolate_snapshot_filename = name;
+ return true;
+ }
+ return false;
+}
+
+
+static bool ProcessIsolateSnapshotOption(const char* option) {
+ const char* name = ProcessOption(option, "--isolate_snapshot=");
+ if (name != NULL) {
+ isolate_snapshot_filename = name;
return true;
}
return false;
@@ -114,7 +123,8 @@
// Parse out the vm options.
while ((i < argc) && IsValidFlag(argv[i], kPrefix, kPrefixLen)) {
- if (ProcessSnapshotOption(argv[i]) ||
+ if (ProcessVmIsolateSnapshotOption(argv[i]) ||
+ ProcessIsolateSnapshotOption(argv[i]) ||
ProcessURLmappingOption(argv[i]) ||
ProcessPackageRootOption(argv[i])) {
i += 1;
@@ -132,8 +142,13 @@
*script_name = NULL;
}
- if (snapshot_filename == NULL) {
- Log::PrintErr("No snapshot output file specified.\n\n");
+ if (vm_isolate_snapshot_filename == NULL) {
+ Log::PrintErr("No vm isolate snapshot output file specified.\n\n");
+ return -1;
+ }
+
+ if (isolate_snapshot_filename == NULL) {
+ Log::PrintErr("No isolate snapshot output file specified.\n\n");
return -1;
}
@@ -141,11 +156,13 @@
}
-static void WriteSnapshotFile(const uint8_t* buffer, const intptr_t size) {
- File* file = File::Open(snapshot_filename, File::kWriteTruncate);
+static void WriteSnapshotFile(const char* filename,
+ const uint8_t* buffer,
+ const intptr_t size) {
+ File* file = File::Open(filename, File::kWriteTruncate);
ASSERT(file != NULL);
if (!file->WriteFully(buffer, size)) {
- Log::PrintErr("Error: Failed to write full snapshot.\n\n");
+ Log::PrintErr("Error: Failed to write snapshot file.\n\n");
}
delete file;
}
@@ -438,15 +455,26 @@
static void CreateAndWriteSnapshot() {
Dart_Handle result;
- uint8_t* buffer = NULL;
- intptr_t size = 0;
+ uint8_t* vm_isolate_buffer = NULL;
+ intptr_t vm_isolate_size = 0;
+ uint8_t* isolate_buffer = NULL;
+ intptr_t isolate_size = 0;
// First create a snapshot.
- result = Dart_CreateSnapshot(&buffer, &size);
+ result = Dart_CreateSnapshot(&vm_isolate_buffer,
+ &vm_isolate_size,
+ &isolate_buffer,
+ &isolate_size);
CHECK_RESULT(result);
- // Now write the snapshot out to specified file and exit.
- WriteSnapshotFile(buffer, size);
+ // Now write the vm isolate and isolate snapshots out to the
+ // specified file and exit.
+ WriteSnapshotFile(vm_isolate_snapshot_filename,
+ vm_isolate_buffer,
+ vm_isolate_size);
+ WriteSnapshotFile(isolate_snapshot_filename,
+ isolate_buffer,
+ isolate_size);
Dart_ExitScope();
// Shutdown the isolate.
@@ -510,7 +538,8 @@
// Initialize the Dart VM.
// Note: We don't expect isolates to be created from dart code during
// snapshot generation.
- if (!Dart_Initialize(NULL, NULL, NULL, NULL,
+ if (!Dart_Initialize(NULL,
+ NULL, NULL, NULL, NULL,
DartUtils::OpenFile,
DartUtils::ReadFile,
DartUtils::WriteFile,
@@ -532,7 +561,8 @@
Dart_Handle library;
Dart_EnterScope();
- ASSERT(snapshot_filename != NULL);
+ ASSERT(vm_isolate_snapshot_filename != NULL);
+ ASSERT(isolate_snapshot_filename != NULL);
// Load up the script before a snapshot is created.
if (app_script_name != NULL) {
// This is the case of a custom embedder (e.g: dartium) trying to
@@ -557,6 +587,7 @@
DartUtils::PrepareForScriptLoading(package_root, false, builtin_lib);
CHECK_RESULT(result);
Dart_ExitScope();
+ Dart_ExitIsolate();
UriResolverIsolateScope::isolate = isolate;
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 693ab90..9fa8de9 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -28,9 +28,13 @@
namespace dart {
namespace bin {
-// snapshot_buffer points to a snapshot if we link in a snapshot otherwise
-// it is initialized to NULL.
-extern const uint8_t* snapshot_buffer;
+// vm_isolate_snapshot_buffer points to a snapshot for the vm isolate if we
+// link in a snapshot otherwise it is initialized to NULL.
+extern const uint8_t* vm_isolate_snapshot_buffer;
+
+// isolate_snapshot_buffer points to a snapshot for an isolate if we link in a
+// snapshot otherwise it is initialized to NULL.
+extern const uint8_t* isolate_snapshot_buffer;
// Global state that stores a pointer to the application script snapshot.
static bool generate_script_snapshot = false;
@@ -293,7 +297,7 @@
CommandLineOptions* vm_options) {
if (filename != NULL && strlen(filename) != 0) {
// Ensure that are already running using a full snapshot.
- if (snapshot_buffer == NULL) {
+ if (isolate_snapshot_buffer == NULL) {
Log::PrintErr("Script snapshots cannot be generated in this version of"
" dart\n");
return false;
@@ -346,7 +350,7 @@
}
-bool trace_debug_protocol = false;
+extern bool trace_debug_protocol;
static bool ProcessTraceDebugProtocolOption(const char* arg,
CommandLineOptions* vm_options) {
if (*arg != '\0') {
@@ -584,7 +588,7 @@
isolate = Dart_CreateIsolate(script_uri,
main,
- snapshot_buffer,
+ isolate_snapshot_buffer,
isolate_data,
error);
@@ -594,7 +598,7 @@
Dart_EnterScope();
- if (snapshot_buffer != NULL) {
+ if (isolate_snapshot_buffer != NULL) {
// Setup the native resolver as the snapshot does not carry it.
Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
Builtin::SetNativeResolver(Builtin::kIOLibrary);
@@ -610,6 +614,10 @@
*error = strdup(VmService::GetErrorMessage());
return NULL;
}
+ if (has_compile_all) {
+ result = Dart_CompileAll();
+ CHECK_RESULT(result);
+ }
Dart_ExitScope();
Dart_ExitIsolate();
return isolate;
@@ -960,7 +968,8 @@
}
// Initialize the Dart VM.
- if (!Dart_Initialize(CreateIsolateAndSetup, NULL, NULL, ShutdownIsolate,
+ if (!Dart_Initialize(vm_isolate_snapshot_buffer,
+ CreateIsolateAndSetup, NULL, NULL, ShutdownIsolate,
DartUtils::OpenFile,
DartUtils::ReadFile,
DartUtils::WriteFile,
diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
index 0cffb5a..b6d40ee 100644
--- a/runtime/bin/process_patch.dart
+++ b/runtime/bin/process_patch.dart
@@ -490,7 +490,7 @@
_processes.remove(_serviceId);
- return new _ProcessResult(
+ return new ProcessResult(
result[0],
result[1],
getOutput(result[2], stdoutEncoding),
@@ -602,7 +602,7 @@
Future stderr = foldStream(p.stderr, stderrEncoding);
return Future.wait([p.exitCode, stdout, stderr]).then((result) {
- return new _ProcessResult(pid, result[0], result[1], result[2]);
+ return new ProcessResult(pid, result[0], result[1], result[2]);
});
});
}
@@ -625,16 +625,3 @@
ProcessStartMode.NORMAL);
return process._runAndWait(stdoutEncoding, stderrEncoding);
}
-
-
-class _ProcessResult implements ProcessResult {
- const _ProcessResult(int this.pid,
- int this.exitCode,
- this.stdout,
- this.stderr);
-
- final int pid;
- final int exitCode;
- final stdout;
- final stderr;
-}
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index 9688457..f6bffe8 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -97,7 +97,8 @@
bool set_vm_flags_success = Flags::ProcessCommandLineFlags(dart_argc,
dart_argv);
ASSERT(set_vm_flags_success);
- const char* err_msg = Dart::InitOnce(NULL, NULL, NULL, NULL,
+ const char* err_msg = Dart::InitOnce(NULL,
+ NULL, NULL, NULL, NULL,
dart::bin::DartUtils::OpenFile,
dart::bin::DartUtils::ReadFile,
dart::bin::DartUtils::WriteFile,
diff --git a/runtime/bin/snapshot_empty.cc b/runtime/bin/snapshot_empty.cc
index f8c3f95..4fd42b3 100644
--- a/runtime/bin/snapshot_empty.cc
+++ b/runtime/bin/snapshot_empty.cc
@@ -17,7 +17,8 @@
namespace dart {
namespace bin {
-const uint8_t* snapshot_buffer = NULL;
+const uint8_t* vm_isolate_snapshot_buffer = NULL;
+const uint8_t* isolate_snapshot_buffer = NULL;
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/snapshot_in.cc b/runtime/bin/snapshot_in.cc
index 2e2a497..1f57a55 100644
--- a/runtime/bin/snapshot_in.cc
+++ b/runtime/bin/snapshot_in.cc
@@ -18,12 +18,24 @@
namespace bin {
// The string on the next line will be filled in with the contents of the
-// generated snapshot binary file.
-// This string forms the content of a snapshot which is loaded in by dart.
-static const uint8_t snapshot_buffer_[] = {
+// generated snapshot binary file for the vm isolate.
+// This string forms the content of a vm isolate snapshot which is loaded
+// into the vm isolate.
+static const uint8_t vm_isolate_snapshot_buffer_[] = {
+ 0,
%s
};
-const uint8_t* snapshot_buffer = snapshot_buffer_;
+const uint8_t* vm_isolate_snapshot_buffer = vm_isolate_snapshot_buffer_;
+
+
+// The string on the next line will be filled in with the contents of the
+// generated snapshot binary file for a regular dart isolate.
+// This string forms the content of a regular dart isolate snapshot which is
+// loaded into an isolate when it is created.
+static const uint8_t isolate_snapshot_buffer_[] = {
+ %s
+};
+const uint8_t* isolate_snapshot_buffer = isolate_snapshot_buffer_;
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/vmservice/server.dart b/runtime/bin/vmservice/server.dart
index a847828..2530f37 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/runtime/bin/vmservice/server.dart
@@ -10,11 +10,9 @@
static const int NOT_MAP_ERROR_CODE = 4002;
final WebSocket socket;
- WebSocketClient(this.socket, service) : super(service) {
+ WebSocketClient(this.socket, VMService service) : super(service) {
socket.listen((message) => onWebSocketMessage(message));
socket.done.then((_) => close());
- service.subscribe('debug', this);
- service.subscribe('gc', this);
}
void onWebSocketMessage(message) {
@@ -37,15 +35,15 @@
}
}
- void post(var serial, dynamic response) {
+ void post(var serial, dynamic result) {
try {
- Map map = {
- 'id': serial,
- 'response': response
- };
- if (serial == null && response is! String) {
- socket.add(response);
+ if (serial == null && result is! String) {
+ socket.add(result);
} else {
+ Map map = {
+ 'id': serial,
+ 'result': result
+ };
socket.add(JSON.encode(map));
}
} catch (_) {
@@ -67,11 +65,12 @@
new ContentType("application", "json", charset: "utf-8");
final HttpRequest request;
- HttpRequestClient(this.request, service) : super(service);
+ HttpRequestClient(this.request, VMService service)
+ : super(service, sendEvents:false);
- void post(var serial, String response) {
+ void post(var serial, String result) {
request.response..headers.contentType = jsonContentType
- ..write(response)
+ ..write(result)
..close();
close();
}
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index 75aa56c..409bc59 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.dart
@@ -31,7 +31,9 @@
_onShutdown() {
if (server != null) {
- server.close(true).catchError((e, st) { assert(e); });
+ server.close(true).catchError((e, st) {
+ print("Error in vm-service shutdown: $e\n$st\n");
+ });
}
if (_signalSubscription != null) {
_signalSubscription.cancel();
diff --git a/runtime/bin/vmservice_dartium.cc b/runtime/bin/vmservice_dartium.cc
index 986aa92..725d204 100644
--- a/runtime/bin/vmservice_dartium.cc
+++ b/runtime/bin/vmservice_dartium.cc
@@ -24,9 +24,9 @@
-// snapshot_buffer points to a snapshot if we link in a snapshot otherwise
-// it is initialized to NULL.
-extern const uint8_t* snapshot_buffer;
+// isolate_snapshot_buffer points to a snapshot if we link in a snapshot
+// otherwise it is initialized to NULL.
+extern const uint8_t* isolate_snapshot_buffer;
static const char* DEFAULT_VM_SERVICE_SERVER_IP = "127.0.0.1";
static const int DEFAULT_VM_SERVICE_SERVER_PORT = 0;
@@ -42,12 +42,12 @@
Dart_Isolate VmServiceServer::CreateIsolate() {
- ASSERT(snapshot_buffer != NULL);
+ ASSERT(isolate_snapshot_buffer != NULL);
// Create the isolate.
char* error = 0;
Dart_Isolate isolate = Dart_CreateIsolate(DART_VM_SERVICE_ISOLATE_NAME,
"main",
- dart::bin::snapshot_buffer,
+ dart::bin::isolate_snapshot_buffer,
NULL,
&error);
if (!isolate) {
diff --git a/runtime/dart-runtime.gyp b/runtime/dart-runtime.gyp
index 5e7c5d5..d64b9a9 100644
--- a/runtime/dart-runtime.gyp
+++ b/runtime/dart-runtime.gyp
@@ -9,7 +9,6 @@
'observatory/observatory.gypi',
'bin/bin.gypi',
'third_party/double-conversion/src/double-conversion.gypi',
- 'third_party/jscre/jscre.gypi',
],
'variables': {
'gen_source_dir': '<(SHARED_INTERMEDIATE_DIR)',
@@ -17,7 +16,7 @@
'version_cc_file': '<(gen_source_dir)/version.cc',
'libdart_deps': ['libdart_lib_withcore', 'libdart_lib', 'libdart_vm',
- 'libjscre', 'libdouble_conversion',],
+ 'libdouble_conversion',],
},
'targets': [
{
@@ -26,7 +25,6 @@
'dependencies': [
'libdart_lib',
'libdart_vm',
- 'libjscre',
'libdouble_conversion',
'generate_version_cc_file#host',
],
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 2d2dbc3..af5f977 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -825,6 +825,8 @@
/**
* Initializes the VM.
*
+ * \param vm_isolate_snapshot A buffer containing a snapshot of the VM isolate
+ * or NULL if no snapshot is provided.
* \param create A function to be called during isolate creation.
* See Dart_IsolateCreateCallback.
* \param interrupt A function to be called when an isolate is interrupted.
@@ -837,6 +839,7 @@
* \return True if initialization is successful.
*/
DART_EXPORT bool Dart_Initialize(
+ const uint8_t* vm_isolate_snapshot,
Dart_IsolateCreateCallback create,
Dart_IsolateInterruptCallback interrupt,
Dart_IsolateUnhandledExceptionCallback unhandled_exception,
@@ -889,8 +892,8 @@
* Provided only for advisory purposes to improve debugging messages.
* \param main The name of the main entry point this isolate will run.
* Provided only for advisory purposes to improve debugging messages.
- * \param snapshot A buffer containing a VM snapshot or NULL if no
- * snapshot is provided.
+ * \param snapshot A buffer containing a snapshot of the isolate or
+ * NULL if no snapshot is provided.
* \param callback_data Embedder data. This data will be passed to
* the Dart_IsolateCreateCallback when new isolates are spawned from
* this parent isolate.
@@ -949,12 +952,10 @@
* Enters an isolate. After calling this function,
* the current isolate will be set to the provided isolate.
*
- * Requires there to be no current isolate.
+ * Requires there to be no current isolate. Multiple threads may not be in
+ * the same isolate at once.
*/
DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate);
-/* TODO(turnidge): Describe what happens if two threads attempt to
- * enter the same isolate simultaneously. Check for this in the code.
- * Describe whether isolates are allowed to migrate. */
/**
* Notifies the VM that the current isolate is about to make a blocking call.
@@ -992,9 +993,10 @@
/**
* Creates a full snapshot of the current isolate heap.
*
- * A full snapshot is a compact representation of the dart heap state and
- * can be used for fast initialization of an isolate. A Snapshot of the heap
- * can only be created before any dart code has executed.
+ * A full snapshot is a compact representation of the dart vm isolate heap
+ * and dart isolate heap states. These snapshots are used to initialize
+ * the vm isolate on startup and fast initialization of an isolate.
+ * A Snapshot of the heap is created before any dart code has executed.
*
* Requires there to be a current isolate.
*
@@ -1005,8 +1007,11 @@
*
* \return A valid handle if no error occurs during the operation.
*/
-DART_EXPORT Dart_Handle Dart_CreateSnapshot(uint8_t** buffer,
- intptr_t* size);
+DART_EXPORT Dart_Handle Dart_CreateSnapshot(
+ uint8_t** vm_isolate_snapshot_buffer,
+ intptr_t* vm_isolate_snapshot_size,
+ uint8_t** isolate_snapshot_buffer,
+ intptr_t* isolate_snapshot_size);
/**
* Creates a snapshot of the application script loaded in the isolate.
@@ -1169,6 +1174,11 @@
/**
* Returns a new SendPort with the provided port id.
+ *
+ * \param port_id The destination port.
+ *
+ * \return A new SendPort if no errors occurs. Otherwise returns
+ * an error handle.
*/
DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id);
diff --git a/runtime/lib/bigint.dart b/runtime/lib/bigint.dart
index cad1562..78b5cc5 100644
--- a/runtime/lib/bigint.dart
+++ b/runtime/lib/bigint.dart
@@ -65,6 +65,16 @@
static _Bigint _ZERO = new _Bigint._fromInt(0);
static _Bigint _ONE = new _Bigint._fromInt(1);
+ // Result cache for last _divRem call.
+ static Uint32List _lastDividend_digits;
+ static int _lastDividend_used;
+ static Uint32List _lastDivisor_digits;
+ static int _lastDivisor_used;
+ static Uint32List _lastQuoRem_digits;
+ static int _lastQuoRem_used;
+ static int _lastRem_used;
+ static int _lastRem_nsh;
+
// Internal data structure.
bool get _neg native "Bigint_getNeg";
int get _used native "Bigint_getUsed";
@@ -171,13 +181,13 @@
// Return this << n*_DIGIT_BITS.
_Bigint _dlShift(int n) {
- var used = _used;
+ final used = _used;
if (used == 0) {
return _ZERO;
}
- var r_used = used + n;
- var digits = _digits;
- var r_digits = new Uint32List(r_used + (r_used & 1));
+ final r_used = used + n;
+ final digits = _digits;
+ final r_digits = new Uint32List(r_used + (r_used & 1));
var i = used;
while (--i >= 0) {
r_digits[i + n] = digits[i];
@@ -192,10 +202,10 @@
if (x_used == 0) {
return 0;
}
- if (n == 0 && r_digits == x_digits) {
+ if (n == 0 && identical(r_digits, x_digits)) {
return x_used;
}
- var r_used = x_used + n;
+ final r_used = x_used + n;
assert(r_digits.length >= r_used + (r_used & 1));
var i = x_used;
while (--i >= 0) {
@@ -213,20 +223,20 @@
// Return this >> n*_DIGIT_BITS.
_Bigint _drShift(int n) {
- var used = _used;
+ final used = _used;
if (used == 0) {
return _ZERO;
}
- var r_used = used - n;
+ final r_used = used - n;
if (r_used <= 0) {
return _neg ? _MINUS_ONE : _ZERO;
}
- var digits = _digits;
- var r_digits = new Uint32List(r_used + (r_used & 1));
+ final digits = _digits;
+ final r_digits = new Uint32List(r_used + (r_used & 1));
for (var i = n; i < used; i++) {
r_digits[i - n] = digits[i];
}
- var r = new _Bigint(_neg, r_used, r_digits);
+ final r = new _Bigint(_neg, r_used, r_digits);
if (_neg) {
// Round down if any bit was shifted out.
for (var i = 0; i < n; i++) {
@@ -242,7 +252,7 @@
// Return r_used.
static int _drShiftDigits(Uint32List x_digits, int x_used, int n,
Uint32List r_digits) {
- var r_used = x_used - n;
+ final r_used = x_used - n;
if (r_used <= 0) {
return 0;
}
@@ -256,25 +266,33 @@
return r_used;
}
+ // r_digits[0..r_used-1] = x_digits[0..x_used-1] << n.
+ static void _lsh(Uint32List x_digits, int x_used, int n,
+ Uint32List r_digits) {
+ final ds = n ~/ _DIGIT_BITS;
+ final bs = n % _DIGIT_BITS;
+ final cbs = _DIGIT_BITS - bs;
+ final bm = (1 << cbs) - 1;
+ var c = 0;
+ var i = x_used;
+ while (--i >= 0) {
+ final d = x_digits[i];
+ r_digits[i + ds + 1] = (d >> cbs) | c;
+ c = (d & bm) << bs;
+ }
+ r_digits[ds] = c;
+ }
+
// Return this << n.
_Bigint _lShift(int n) {
- var ds = n ~/ _DIGIT_BITS;
- var bs = n % _DIGIT_BITS;
+ final ds = n ~/ _DIGIT_BITS;
+ final bs = n % _DIGIT_BITS;
if (bs == 0) {
return _dlShift(ds);
}
- var cbs = _DIGIT_BITS - bs;
- var bm = (1 << cbs) - 1;
var r_used = _used + ds + 1;
- var digits = _digits;
- var r_digits = new Uint32List(r_used + (r_used & 1));
- var c = 0;
- var i = _used;
- while (--i >= 0) {
- r_digits[i + ds + 1] = (digits[i] >> cbs) | c;
- c = (digits[i] & bm) << bs;
- }
- r_digits[ds] = c;
+ var r_digits = new Uint32List(r_used + 2 + (r_used & 1)); // +2 for 64-bit.
+ _lsh(_digits, _used, n, r_digits);
return new _Bigint(_neg, r_used, r_digits);
}
@@ -282,57 +300,62 @@
// Return r_used.
static int _lShiftDigits(Uint32List x_digits, int x_used, int n,
Uint32List r_digits) {
- var ds = n ~/ _DIGIT_BITS;
- var bs = n % _DIGIT_BITS;
+ final ds = n ~/ _DIGIT_BITS;
+ final bs = n % _DIGIT_BITS;
if (bs == 0) {
return _dlShiftDigits(x_digits, x_used, ds, r_digits);
}
- var cbs = _DIGIT_BITS - bs;
- var bm = (1 << cbs) - 1;
var r_used = x_used + ds + 1;
- assert(r_digits.length >= r_used + (r_used & 1));
- var c = 0;
- var i = x_used;
- while (--i >= 0) {
- r_digits[i + ds + 1] = (x_digits[i] >> cbs) | c;
- c = (x_digits[i] & bm) << bs;
- }
- r_digits[ds] = c;
- i = ds;
+ assert(r_digits.length >= r_used + 2 + (r_used & 1)); // +2 for 64-bit.
+ _lsh(x_digits, x_used, n, r_digits);
+ var i = ds;
while (--i >= 0) {
r_digits[i] = 0;
}
- if (r_used.isOdd) {
+ if (r_digits[r_used - 1] == 0) {
+ r_used--; // Clamp result.
+ } else if (r_used.isOdd) {
r_digits[r_used] = 0;
}
return r_used;
}
+ // r_digits[0..r_used-1] = x_digits[0..x_used-1] >> n.
+ static void _rsh(Uint32List x_digits, int x_used, int n,
+ Uint32List r_digits) {
+ final ds = n ~/ _DIGIT_BITS;
+ final bs = n % _DIGIT_BITS;
+ final cbs = _DIGIT_BITS - bs;
+ final bm = (1 << bs) - 1;
+ var c = x_digits[ds] >> bs;
+ final last = x_used - ds - 1;
+ for (var i = 0; i < last; i++) {
+ final d = x_digits[i + ds + 1];
+ r_digits[i] = ((d & bm) << cbs) | c;
+ c = d >> bs;
+ }
+ r_digits[last] = c;
+ }
+
// Return this >> n.
_Bigint _rShift(int n) {
- var ds = n ~/ _DIGIT_BITS;
- var bs = n % _DIGIT_BITS;
+ final ds = n ~/ _DIGIT_BITS;
+ final bs = n % _DIGIT_BITS;
if (bs == 0) {
return _drShift(ds);
}
- var r_used = _used - ds;
+ final used = _used;
+ final r_used = used - ds;
if (r_used <= 0) {
return _neg ? _MINUS_ONE : _ZERO;
}
- var cbs = _DIGIT_BITS - bs;
- var bm = (1 << bs) - 1;
- var digits = _digits;
- var r_digits = new Uint32List(r_used + (r_used & 1));
- r_digits[0] = digits[ds] >> bs;
- var used = _used;
- for (var i = ds + 1; i < used; i++) {
- r_digits[i - ds - 1] |= (digits[i] & bm) << cbs;
- r_digits[i - ds] = digits[i] >> bs;
- }
- var r = new _Bigint(_neg, r_used, r_digits);
+ final digits = _digits;
+ final r_digits = new Uint32List(r_used + (r_used & 1));
+ _rsh(digits, used, n, r_digits);
+ final r = new _Bigint(_neg, r_used, r_digits);
if (_neg) {
// Round down if any bit was shifted out.
- if ((digits[ds] & bm) != 0) {
+ if ((digits[ds] & ((1 << bs) - 1)) != 0) {
return r._sub(_ONE);
}
for (var i = 0; i < ds; i++) {
@@ -348,8 +371,8 @@
// Return r_used.
static int _rShiftDigits(Uint32List x_digits, int x_used, int n,
Uint32List r_digits) {
- var ds = n ~/ _DIGIT_BITS;
- var bs = n % _DIGIT_BITS;
+ final ds = n ~/ _DIGIT_BITS;
+ final bs = n % _DIGIT_BITS;
if (bs == 0) {
return _drShiftDigits(x_digits, x_used, ds, r_digits);
}
@@ -357,15 +380,11 @@
if (r_used <= 0) {
return 0;
}
- var cbs = _DIGIT_BITS - bs;
- var bm = (1 << bs) - 1;
assert(r_digits.length >= r_used + (r_used & 1));
- r_digits[0] = x_digits[ds] >> bs;
- for (var i = ds + 1; i < x_used; i++) {
- r_digits[i - ds - 1] |= (x_digits[i] & bm) << cbs;
- r_digits[i - ds] = x_digits[i] >> bs;
- }
- if (r_used.isOdd) {
+ _rsh(x_digits, x_used, n, r_digits);
+ if (r_digits[r_used - 1] == 0) {
+ r_used--; // Clamp result.
+ } else if (r_used.isOdd) {
r_digits[r_used] = 0;
}
return r_used;
@@ -935,128 +954,156 @@
// Return trunc(this / a), a != 0.
_Bigint _div(_Bigint a) {
- return _divRem(a, true);
+ assert(a._used > 0);
+ if (_used < a._used) {
+ return _ZERO;
+ }
+ _divRem(a);
+ // Return quotient, i.e.
+ // _lastQuoRem_digits[_lastRem_used.._lastQuoRem_used-1] with proper sign.
+ var lastQuo_used = _lastQuoRem_used - _lastRem_used;
+ var quo_digits = _cloneDigits(_lastQuoRem_digits,
+ _lastRem_used,
+ _lastQuoRem_used,
+ lastQuo_used);
+ var quo = new _Bigint(false, lastQuo_used, quo_digits);
+ if ((_neg != a._neg) && (quo._used > 0)) {
+ quo = quo._negate();
+ }
+ return quo;
}
// Return this - a * trunc(this / a), a != 0.
_Bigint _rem(_Bigint a) {
- return _divRem(a, false);
- }
-
- // Return trunc(this / a), a != 0, if div == true.
- // Return this - a * trunc(this / a), a != 0, if div == false.
- _Bigint _divRem(_Bigint a, bool div) {
assert(a._used > 0);
if (_used < a._used) {
- return div ? _ZERO : this;
+ return this;
+ }
+ _divRem(a);
+ // Return remainder, i.e.
+ // denormalized _lastQuoRem_digits[0.._lastRem_used-1] with proper sign.
+ var rem_digits = _cloneDigits(_lastQuoRem_digits,
+ 0,
+ _lastRem_used,
+ _lastRem_used);
+ var rem = new _Bigint(false, _lastRem_used, rem_digits);
+ if (_lastRem_nsh > 0) {
+ rem = rem._rShift(_lastRem_nsh); // Denormalize remainder.
+ }
+ if (_neg && (rem._used > 0)) {
+ rem = rem._negate();
+ }
+ return rem;
+ }
+
+ // Cache concatenated positive quotient and normalized positive remainder.
+ void _divRem(_Bigint a) {
+ // Check if result is already cached (identical on Bigint is too expensive).
+ if ((this._used == _lastDividend_used) &&
+ (a._used == _lastDivisor_used) &&
+ identical(this._digits, _lastDividend_digits) &&
+ identical(a._digits, _lastDivisor_digits)) {
+ return;
}
var nsh = _DIGIT_BITS - _nbits(a._digits[a._used - 1]);
// For 64-bit processing, make sure y has an even number of digits.
if (a._used.isOdd) {
nsh += _DIGIT_BITS;
}
- var y; // Normalized positive divisor.
- var r; // Concatenated positive quotient and normalized positive remainder.
+ // Concatenated positive quotient and normalized positive remainder.
+ var r_digits;
+ var r_used;
+ // Normalized positive divisor.
+ var y_digits;
+ var y_used;
if (nsh > 0) {
- y = a._lShift(nsh)._abs();
- r = _lShift(nsh)._abs();
+ y_digits = new Uint32List(a._used + 5); // +5 for norm. and 64-bit.
+ y_used = _lShiftDigits(a._digits, a._used, nsh, y_digits);
+ r_digits = new Uint32List(_used + 5); // +5 for normalization and 64-bit.
+ r_used = _lShiftDigits(_digits, _used, nsh, r_digits);
+ } else {
+ y_digits = a._digits;
+ y_used = a._used;
+ r_digits = _cloneDigits(_digits, 0, _used, _used + 2);
+ r_used = _used;
}
- else {
- y = a._abs();
- r = _abs();
- }
- var y_used = y._used;
- var y_digits = y._digits;
- Uint32List args = new Uint32List(4);
- args[_YT_LO] = y_digits[y_used - 2];
- args[_YT] = y_digits[y_used - 1];
- var r_used = r._used;
+ Uint32List yt_qd = new Uint32List(4);
+ yt_qd[_YT_LO] = y_digits[y_used - 2];
+ yt_qd[_YT] = y_digits[y_used - 1];
// For 64-bit processing, make sure y_used, i, and j are even.
assert(y_used.isEven);
var i = r_used + (r_used & 1);
var j = i - y_used;
- var t = y._dlShift(j);
- if (r._compare(t) >= 0) {
+ // t_digits is a temporary array of i digits.
+ var t_digits = new Uint32List(i);
+ var t_used = _dlShiftDigits(y_digits, y_used, j, t_digits);
+ // Explicit first division step in case normalized dividend is larger or
+ // equal to shifted normalized divisor.
+ if (_compareDigits(r_digits, r_used, t_digits, t_used) >= 0) {
assert(i == r_used);
- r = r._or(_ONE._dlShift(r_used++))._sub(t);
- assert(r._used == r_used && (i + 1) == r_used);
+ r_digits[r_used++] = 1; // Quotient = 1.
+ r_digits[r_used] = 0; // Leading zero.
+ // Subtract divisor from remainder.
+ _absSub(r_digits, r_used, t_digits, t_used, r_digits);
}
// Negate y so we can later use _mulAdd instead of non-existent _mulSub.
- y = _ONE._dlShift(y_used)._sub(y);
- if (y._used < y_used) {
- y_digits = _cloneDigits(y._digits, 0, y._used, y_used);
- } else {
- y_digits = y._digits;
- }
- // y_digits is read-only and has y_used digits (possibly including several
+ var ny_digits = new Uint32List(y_used + 2);
+ ny_digits[y_used] = 1;
+ _absSub(ny_digits, y_used + 1, y_digits, y_used, ny_digits);
+ // ny_digits is read-only and has y_used digits (possibly including several
// leading zeros) plus a leading zero for 64-bit processing.
- var r_digits = _cloneDigits(r._digits, 0, r._used, i + 1);
// r_digits is modified during iteration.
// r_digits[0..y_used-1] is the current remainder.
// r_digits[y_used..r_used-1] is the current quotient.
--i;
while (j > 0) {
- var d0 = _estQuotientDigit(args, r_digits, i);
+ var d0 = _estQuotientDigit(yt_qd, r_digits, i);
j -= d0;
- var d1 = _mulAdd(args, _QD, y_digits, 0, r_digits, j, y_used);
+ var d1 = _mulAdd(yt_qd, _QD, ny_digits, 0, r_digits, j, y_used);
// _estQuotientDigit and _mulAdd must agree on the number of digits to
// process.
assert(d0 == d1);
if (d0 == 1) {
- if (r_digits[i] < args[_QD]) {
- var t = y._dlShift(j);
- var t_digits = t._digits;
- var t_used = t._used;
+ if (r_digits[i] < yt_qd[_QD]) {
+ var t_used = _dlShiftDigits(ny_digits, y_used, j, t_digits);
_absSub(r_digits, r_used, t_digits, t_used, r_digits);
- while (r_digits[i] < --args[_QD]) {
+ while (r_digits[i] < --yt_qd[_QD]) {
_absSub(r_digits, r_used, t_digits, t_used, r_digits);
}
}
} else {
assert(d0 == 2);
- assert(r_digits[i] <= args[_QD_HI]);
- if ((r_digits[i] < args[_QD_HI]) || (r_digits[i-1] < args[_QD])) {
- var t = y._dlShift(j);
- var t_digits = t._digits;
- var t_used = t._used;
+ assert(r_digits[i] <= yt_qd[_QD_HI]);
+ if ((r_digits[i] < yt_qd[_QD_HI]) || (r_digits[i-1] < yt_qd[_QD])) {
+ var t_used = _dlShiftDigits(ny_digits, y_used, j, t_digits);
_absSub(r_digits, r_used, t_digits, t_used, r_digits);
- if (args[_QD] == 0) {
- --args[_QD_HI];
+ if (yt_qd[_QD] == 0) {
+ --yt_qd[_QD_HI];
}
- --args[_QD];
- assert(r_digits[i] <= args[_QD_HI]);
- while ((r_digits[i] < args[_QD_HI]) || (r_digits[i-1] < args[_QD])) {
+ --yt_qd[_QD];
+ assert(r_digits[i] <= yt_qd[_QD_HI]);
+ while ((r_digits[i] < yt_qd[_QD_HI]) ||
+ (r_digits[i-1] < yt_qd[_QD])) {
_absSub(r_digits, r_used, t_digits, t_used, r_digits);
- if (args[_QD] == 0) {
- --args[_QD_HI];
+ if (yt_qd[_QD] == 0) {
+ --yt_qd[_QD_HI];
}
- --args[_QD];
- assert(r_digits[i] <= args[_QD_HI]);
+ --yt_qd[_QD];
+ assert(r_digits[i] <= yt_qd[_QD_HI]);
}
}
}
i -= d0;
}
- if (div) {
- // Return quotient, i.e. r_digits[y_used..r_used-1] with proper sign.
- r_digits = _cloneDigits(r_digits, y_used, r_used, r_used - y_used);
- r = new _Bigint(false, r_used - y_used, r_digits);
- if (_neg != a._neg && r._used > 0) {
- r = r._negate();
- }
- return r;
- }
- // Return remainder, i.e. denormalized r_digits[0..y_used-1] with
- // proper sign.
- r_digits = _cloneDigits(r_digits, 0, y_used, y_used);
- r = new _Bigint(false, y_used, r_digits);
- if (nsh > 0) {
- r = r._rShift(nsh); // Denormalize remainder.
- }
- if (_neg && r._used > 0) {
- r = r._negate();
- }
- return r;
+ // Cache result.
+ _lastDividend_digits = _digits;
+ _lastDividend_used = _used;
+ _lastDivisor_digits = a._digits;
+ _lastDivisor_used = a._used;
+ _lastQuoRem_digits = r_digits;
+ _lastQuoRem_used = r_used;
+ _lastRem_used = y_used;
+ _lastRem_nsh = nsh;
}
// Customized version of _rem() minimizing allocations for use in reduction.
@@ -1189,6 +1236,7 @@
assert(_DIGIT_BITS == 32); // Otherwise this code needs to be revised.
var shift;
if (_used > 2 || (_used == 2 && _digits[1] > 0x10000000)) {
+ if (other == 0) return 0; // Shifted value is zero.
throw new OutOfMemoryError();
} else {
shift = ((_used == 2) ? (_digits[1] << _DIGIT_BITS) : 0) + _digits[0];
@@ -1346,7 +1394,7 @@
if (e == 0) return 1;
m = m._toBigint();
final m_used = m._used;
- final m_used2p2 = 2*m_used + 2;
+ final m_used2p4 = 2*m_used + 4;
final e_bitlen = e.bitLength;
if (e_bitlen <= 0) return 1;
final bool cannotUseMontgomery = m.isEven || _abs() >= m;
@@ -1355,8 +1403,8 @@
new _Classic(m) : new _Montgomery(m);
// TODO(regis): Should we use Barrett reduction for an even modulus and a
// large exponent?
- var r_digits = new Uint32List(m_used2p2);
- var r2_digits = new Uint32List(m_used2p2);
+ var r_digits = new Uint32List(m_used2p4);
+ var r2_digits = new Uint32List(m_used2p4);
var g_digits = new Uint32List(m_used + (m_used & 1));
var g_used = z._convert(this, g_digits);
// Initialize r with g.
@@ -1398,10 +1446,10 @@
g_digits[1] = new Uint32List(m_used + (m_used & 1));
g_used[1] = z._convert(this, g_digits[1]);
if (k > 1) {
- var g2_digits = new Uint32List(m_used2p2);
+ var g2_digits = new Uint32List(m_used2p4);
var g2_used = z._sqr(g_digits[1], g_used[1], g2_digits);
while (n <= km) {
- g_digits[n] = new Uint32List(m_used2p2);
+ g_digits[n] = new Uint32List(m_used2p4);
g_used[n] = z._mul(g2_digits, g2_used,
g_digits[n - 2], g_used[n - 2],
g_digits[n]);
@@ -1412,7 +1460,7 @@
var is1 = true;
var r_digits = _ONE._digits;
var r_used = _ONE._used;
- var r2_digits = new Uint32List(m_used2p2);
+ var r2_digits = new Uint32List(m_used2p4);
var r2_used;
var e_digits = e._digits;
var j = e._used - 1;
@@ -1436,7 +1484,7 @@
--j;
}
if (is1) { // r == 1, don't bother squaring or multiplying it.
- r_digits = new Uint32List(m_used2p2);
+ r_digits = new Uint32List(m_used2p4);
r_used = g_used[w];
var gw_digits = g_digits[w];
var ri = r_used + (r_used & 1); // Copy leading zero if any.
@@ -1698,7 +1746,7 @@
// _neg_norm_m_digits is read-only and has nm_used digits (possibly
// including several leading zeros) plus a leading zero for 64-bit
// processing.
- _t_digits = new Uint32List(2*nm_used + 2);
+ _t_digits = new Uint32List(2*nm_used);
}
int _convert(_Bigint x, Uint32List r_digits) {
@@ -1728,6 +1776,9 @@
}
int _reduce(Uint32List x_digits, int x_used) {
+ if (x_used < _m._used) {
+ return x_used;
+ }
// The function _remDigits(...) is optimized for reduction and equivalent to
// calling _convert(_revert(x_digits, x_used)._rem(_m), x_digits);
return _Bigint._remDigits(x_digits, x_used,
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index f3f9da3..5ff7676 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -36,12 +36,14 @@
bool isAdding = false;
bool onListenReceived = false;
bool isScheduled = false;
+ bool isSuspendedAtYield = false;
Completer cancellationCompleter = null;
Stream get stream => controller.stream;
void runBody() {
isScheduled = false;
+ isSuspendedAtYield = false;
asyncStarBody();
}
@@ -62,15 +64,17 @@
// The generator would translate a 'yield e' statement to
// controller.add(e);
// suspend;
- // if (controller.isCanelled) return;
+ // if (controller.isCancelled) return;
bool add(event) {
if (!onListenReceived) _fatal("yield before stream is listened to!");
+ if (isSuspendedAtYield) _fatal("unexpected yield");
// If stream is cancelled, tell caller to exit the async generator.
if (!controller.hasListener) {
return true;
}
controller.add(event);
scheduleGenerator();
+ isSuspendedAtYield = true;
return false;
}
@@ -131,7 +135,9 @@
}
onResume() {
- scheduleGenerator();
+ if (isSuspendedAtYield) {
+ scheduleGenerator();
+ }
}
onCancel() {
diff --git a/runtime/lib/core_sources.gypi b/runtime/lib/core_sources.gypi
index d5be47e..8bab528 100644
--- a/runtime/lib/core_sources.gypi
+++ b/runtime/lib/core_sources.gypi
@@ -43,8 +43,6 @@
'object.cc',
'object_patch.dart',
'regexp.cc',
- 'regexp_jsc.cc',
- 'regexp_jsc.h',
'regexp_patch.dart',
'stacktrace.cc',
'stacktrace.dart',
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 9f78df3..1f72dc2 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -168,7 +168,6 @@
Dart_IsolateCreateCallback callback = Isolate::CreateCallback();
if (callback == NULL) {
*error = strdup("Null callback specified for isolate creation\n");
- Isolate::SetCurrent(parent_isolate);
return false;
}
@@ -180,7 +179,6 @@
init_data,
error));
if (child_isolate == NULL) {
- Isolate::SetCurrent(parent_isolate);
return false;
}
if (!state->is_spawn_uri()) {
@@ -189,22 +187,22 @@
child_isolate->set_origin_id(parent_isolate->origin_id());
}
state->set_isolate(reinterpret_cast<Isolate*>(child_isolate));
-
- Isolate::SetCurrent(parent_isolate);
return true;
}
static void Spawn(Isolate* parent_isolate, IsolateSpawnState* state) {
+ Thread::ExitIsolate();
// Create a new isolate.
char* error = NULL;
if (!CreateIsolate(parent_isolate, state, &error)) {
+ Thread::EnterIsolate(parent_isolate);
delete state;
const String& msg = String::Handle(String::New(error));
free(error);
ThrowIsolateSpawnException(msg);
}
-
+ Thread::EnterIsolate(parent_isolate);
// Start the new isolate if it is already marked as runnable.
Isolate* spawned_isolate = state->isolate();
MutexLocker ml(spawned_isolate->mutex());
@@ -229,6 +227,8 @@
ctx = Closure::context(closure);
ASSERT(ctx.num_variables() == 0);
#endif
+ // Get the parent function so that we get the right function name.
+ func = func.parent_function();
Spawn(isolate, new IsolateSpawnState(port.Id(),
func,
message,
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 7fb8fd0..cfa2e8c 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -240,8 +240,9 @@
static RawInstance* CreateMethodMirror(const Function& func,
- const Instance& owner_mirror) {
- const Array& args = Array::Handle(Array::New(12));
+ const Instance& owner_mirror,
+ const AbstractType& instantiator) {
+ const Array& args = Array::Handle(Array::New(13));
args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func)));
String& name = String::Handle(func.name());
@@ -249,17 +250,18 @@
args.SetAt(1, name);
args.SetAt(2, owner_mirror);
- args.SetAt(3, Bool::Get(func.is_static()));
- args.SetAt(4, Bool::Get(func.is_abstract()));
- args.SetAt(5, Bool::Get(func.IsGetterFunction()));
- args.SetAt(6, Bool::Get(func.IsSetterFunction()));
+ args.SetAt(3, instantiator);
+ args.SetAt(4, Bool::Get(func.is_static()));
+ args.SetAt(5, Bool::Get(func.is_abstract()));
+ args.SetAt(6, Bool::Get(func.IsGetterFunction()));
+ args.SetAt(7, Bool::Get(func.IsSetterFunction()));
bool isConstructor = (func.kind() == RawFunction::kConstructor);
- args.SetAt(7, Bool::Get(isConstructor));
- args.SetAt(8, Bool::Get(isConstructor && func.is_const()));
- args.SetAt(9, Bool::Get(isConstructor && func.IsGenerativeConstructor()));
- args.SetAt(10, Bool::Get(isConstructor && func.is_redirecting()));
- args.SetAt(11, Bool::Get(isConstructor && func.IsFactory()));
+ args.SetAt(8, Bool::Get(isConstructor));
+ args.SetAt(9, Bool::Get(isConstructor && func.is_const()));
+ args.SetAt(10, Bool::Get(isConstructor && func.IsGenerativeConstructor()));
+ args.SetAt(11, Bool::Get(isConstructor && func.is_redirecting()));
+ args.SetAt(12, Bool::Get(isConstructor && func.IsFactory()));
return CreateMirror(Symbols::_LocalMethodMirror(), args);
}
@@ -747,7 +749,7 @@
ASSERT(type.IsFinalized());
ASSERT(!type.IsMalformed());
- if (type.IsInstantiated()) {
+ if (type.IsInstantiated() || instantiator.IsNull()) {
return type.Canonicalize();
}
@@ -864,7 +866,7 @@
const Class& cls = Class::Handle(ref.GetClassReferent());
const Function& func = Function::Handle(CallMethod(cls));
ASSERT(!func.IsNull());
- return CreateMethodMirror(func, owner_mirror);
+ return CreateMethodMirror(func, owner_mirror, AbstractType::Handle());
}
@@ -1009,11 +1011,14 @@
}
-DEFINE_NATIVE_ENTRY(ClassMirror_members, 2) {
+DEFINE_NATIVE_ENTRY(ClassMirror_members, 3) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance,
owner_mirror,
arguments->NativeArgAt(0));
- GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
+ GET_NATIVE_ARGUMENT(AbstractType,
+ owner_instantiator,
+ arguments->NativeArgAt(1));
+ GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(2));
const Class& klass = Class::Handle(ref.GetClassReferent());
const Error& error = Error::Handle(klass.EnsureIsFinalized(isolate));
@@ -1047,7 +1052,8 @@
(func.kind() == RawFunction::kRegularFunction ||
func.kind() == RawFunction::kGetterFunction ||
func.kind() == RawFunction::kSetterFunction)) {
- member_mirror = CreateMethodMirror(func, owner_mirror);
+ member_mirror = CreateMethodMirror(func, owner_mirror,
+ owner_instantiator);
member_mirrors.Add(member_mirror);
}
}
@@ -1056,11 +1062,14 @@
}
-DEFINE_NATIVE_ENTRY(ClassMirror_constructors, 2) {
+DEFINE_NATIVE_ENTRY(ClassMirror_constructors, 3) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance,
owner_mirror,
arguments->NativeArgAt(0));
- GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
+ GET_NATIVE_ARGUMENT(AbstractType,
+ owner_instantiator,
+ arguments->NativeArgAt(1));
+ GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(2));
const Class& klass = Class::Handle(ref.GetClassReferent());
const Error& error = Error::Handle(klass.EnsureIsFinalized(isolate));
@@ -1079,7 +1088,8 @@
for (intptr_t i = 0; i < num_functions; i++) {
func ^= functions.At(i);
if (func.is_reflectable() && func.kind() == RawFunction::kConstructor) {
- constructor_mirror = CreateMethodMirror(func, owner_mirror);
+ constructor_mirror = CreateMethodMirror(func, owner_mirror,
+ owner_instantiator);
constructor_mirrors.Add(constructor_mirror);
}
}
@@ -1134,7 +1144,8 @@
(func.kind() == RawFunction::kRegularFunction ||
func.kind() == RawFunction::kGetterFunction ||
func.kind() == RawFunction::kSetterFunction)) {
- member_mirror = CreateMethodMirror(func, owner_mirror);
+ member_mirror = CreateMethodMirror(func, owner_mirror,
+ AbstractType::Handle());
member_mirrors.Add(member_mirror);
}
}
@@ -1238,6 +1249,17 @@
Exceptions::PropagateError(Error::Cast(result));
UNREACHABLE();
}
+
+ // Because we currently only use this native for building field extractors and
+ // setters, assume the result is a closure and mark its function as invisible,
+ // so it will not appear in stack traces. Whenever we support
+ // ObjectMirror.evaluate this will need to be separated.
+ ASSERT(Instance::Cast(result).IsClosure());
+ const Function& func =
+ Function::Handle(Closure::function(Instance::Cast(result)));
+ func.set_is_visible(false);
+ func.set_is_debuggable(false);
+
return result.raw();
}
@@ -1373,7 +1395,19 @@
// the equality test.
function = function.parent_function();
}
- return CreateMethodMirror(function, Instance::null_instance());
+
+ Type& instantiator = Type::Handle();
+ if (closure.IsClosure()) {
+ const TypeArguments& arguments =
+ TypeArguments::Handle(Closure::GetTypeArguments(closure));
+ const Class& cls =
+ Class::Handle(Isolate::Current()->object_store()->object_class());
+ instantiator = Type::New(cls, arguments, Scanner::kNoSourcePos);
+ instantiator.SetIsFinalized();
+ }
+ return CreateMethodMirror(function,
+ Instance::null_instance(),
+ instantiator);
}
return Instance::null();
}
@@ -1818,12 +1852,13 @@
}
-DEFINE_NATIVE_ENTRY(MethodMirror_owner, 1) {
+DEFINE_NATIVE_ENTRY(MethodMirror_owner, 2) {
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
+ GET_NATIVE_ARGUMENT(AbstractType, instantiator, arguments->NativeArgAt(1));
const Function& func = Function::Handle(ref.GetFunctionReferent());
if (func.IsNonImplicitClosureFunction()) {
return CreateMethodMirror(Function::Handle(
- func.parent_function()), Object::null_instance());
+ func.parent_function()), Object::null_instance(), instantiator);
}
const Class& owner = Class::Handle(func.Owner());
if (owner.IsTopLevel()) {
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 2cbb083..e3f87ba 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -15,16 +15,6 @@
String toString() => _msg;
}
-Map _filterMap(Map<Symbol, dynamic> old_map, bool filter(Symbol key, value)) {
- Map new_map = new Map<Symbol, dynamic>();
- old_map.forEach((key, value) {
- if (filter(key, value)) {
- new_map[key] = value;
- }
- });
- return new UnmodifiableMapView(new_map);
-}
-
Map _makeMemberMap(List mirrors) {
return new UnmodifiableMapView<Symbol, DeclarationMirror>(
new Map<Symbol, DeclarationMirror>.fromIterable(
@@ -693,11 +683,12 @@
ClassMirror get mixin {
if (_mixin == null) {
if (_isMixinAlias) {
- Type mixinType = _nativeMixinInstantiated(_trueSuperclass._reflectedType,
- _instantiator);
+ Type mixinType = _nativeMixinInstantiated(
+ _trueSuperclass._reflectedType, _instantiator);
_mixin = reflectType(mixinType);
} else {
- Type mixinType = _nativeMixinInstantiated(_reflectedType, _instantiator);
+ Type mixinType = _nativeMixinInstantiated(_reflectedType,
+ _instantiator);
if (mixinType == null) {
// The reflectee is not a mixin application.
_mixin = this;
@@ -778,25 +769,16 @@
Map<Symbol, Mirror> get _members {
if (_cachedMembers == null) {
var whoseMembers = _isMixinAlias ? _trueSuperclass : this;
- _cachedMembers = _makeMemberMap(mixin._computeMembers(whoseMembers.mixin._reflectee));
+ _cachedMembers = _makeMemberMap(mixin._computeMembers(
+ _instantiator, whoseMembers.mixin._reflectee));
}
return _cachedMembers;
}
- Map<Symbol, MethodMirror> _cachedMethods;
- Map<Symbol, MethodMirror> get _methods {
- if (_cachedMethods == null) {
- _cachedMethods = _filterMap(
- _members,
- (key, value) => (value is MethodMirror && value.isRegularMethod));
- }
- return _cachedMethods;
- }
-
Map<Symbol, MethodMirror> _cachedConstructors;
Map<Symbol, MethodMirror> get _constructors {
if (_cachedConstructors == null) {
- var constructorsList = _computeConstructors(_reflectee);
+ var constructorsList = _computeConstructors(_instantiator, _reflectee);
var stringName = _n(simpleName);
constructorsList.forEach((c) => c._patchConstructorName(stringName));
_cachedConstructors =
@@ -943,10 +925,10 @@
static _nativeMixinInstantiated(reflectedType, instantiator)
native "ClassMirror_mixin_instantiated";
- _computeMembers(reflectee)
+ _computeMembers(reflectee, instantiator)
native "ClassMirror_members";
- _computeConstructors(reflectee)
+ _computeConstructors(reflectee, instantiator)
native "ClassMirror_constructors";
_invoke(reflectee, memberName, arguments, argumentNames)
@@ -1015,8 +997,6 @@
get typeVariables => emptyList;
get typeArguments => emptyList;
get metadata => emptyList;
- Map<Symbol, Mirror> get members => emptyMap;
- Map<Symbol, MethodMirror> get constructors => emptyMap;
String toString() => "FunctionTypeMirror on '${_n(simpleName)}'";
@@ -1357,6 +1337,7 @@
class _LocalMethodMirror extends _LocalDeclarationMirror
implements MethodMirror {
+ final Type _instantiator;
final bool isStatic;
final bool isAbstract;
final bool isGetter;
@@ -1374,6 +1355,7 @@
_LocalMethodMirror(reflectee,
String simpleName,
this._owner,
+ this._instantiator,
this.isStatic,
this.isAbstract,
this.isGetter,
@@ -1391,7 +1373,7 @@
// For nested closures it is possible, that the mirror for the owner has not
// been created yet.
if (_owner == null) {
- _owner = _MethodMirror_owner(_reflectee);
+ _owner = _MethodMirror_owner(_reflectee, _instantiator);
}
return _owner;
}
@@ -1402,12 +1384,6 @@
bool get isTopLevel => owner is LibraryMirror;
bool get isSynthetic => false;
- Type get _instantiator {
- var o = owner;
- while (o is MethodMirror) o = o.owner;
- return o._instantiator;
- }
-
TypeMirror _returnType = null;
TypeMirror get returnType {
if (_returnType == null) {
@@ -1473,7 +1449,7 @@
String toString() => "MethodMirror on '${MirrorSystem.getName(simpleName)}'";
- static dynamic _MethodMirror_owner(reflectee)
+ static dynamic _MethodMirror_owner(reflectee, instantiator)
native "MethodMirror_owner";
static dynamic _MethodMirror_return_type(reflectee, instantiator)
@@ -1571,9 +1547,7 @@
}
Type get _instantiator {
- var o = owner;
- while (o is MethodMirror) o = o.owner;
- return o._instantiator;
+ return owner._instantiator;
}
TypeMirror _type = null;
diff --git a/runtime/lib/regexp.cc b/runtime/lib/regexp.cc
index 0adb8d2..6ffeb6d 100644
--- a/runtime/lib/regexp.cc
+++ b/runtime/lib/regexp.cc
@@ -10,12 +10,9 @@
#include "vm/regexp_parser.h"
#include "vm/thread.h"
-#include "lib/regexp_jsc.h"
-
namespace dart {
DECLARE_FLAG(bool, trace_irregexp);
-DEFINE_FLAG(bool, use_jscre, false, "Use the JSCRE regular expression engine");
DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_factory, 4) {
@@ -28,9 +25,6 @@
bool ignore_case = handle_case_sensitive.raw() != Bool::True().raw();
bool multi_line = handle_multi_line.raw() == Bool::True().raw();
- if (FLAG_use_jscre) {
- return Jscre::Compile(pattern, multi_line, ignore_case);
- }
// Parse the pattern once in order to throw any format exceptions within
// the factory constructor. It is parsed again upon compilation.
RegExpCompileData compileData;
@@ -91,10 +85,6 @@
GET_NON_NULL_NATIVE_ARGUMENT(String, str, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_index, arguments->NativeArgAt(2));
- if (FLAG_use_jscre) {
- return Jscre::Execute(regexp, str, start_index.Value());
- }
-
// This function is intrinsified. See Intrinsifier::JSRegExp_ExecuteMatch.
const intptr_t cid = str.GetClassId();
diff --git a/runtime/lib/regexp_jsc.cc b/runtime/lib/regexp_jsc.cc
deleted file mode 100644
index 158579f..0000000
--- a/runtime/lib/regexp_jsc.cc
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-// This file encapsulates all the interaction with the
-// JSC regular expression library also referred to as pcre
-
-#include "lib/regexp_jsc.h"
-
-#include "platform/assert.h"
-#include "vm/allocation.h"
-#include "vm/exceptions.h"
-#include "vm/globals.h"
-#include "vm/isolate.h"
-#include "third_party/jscre/pcre.h"
-
-namespace dart {
-
-static uint16_t* GetTwoByteData(const String& str) {
- Zone* zone = Isolate::Current()->current_zone();
- uint16_t* two_byte_str = zone->Alloc<uint16_t>(str.Length());
- for (intptr_t i = 0; i < str.Length(); i++) {
- two_byte_str[i] = str.CharAt(i);
- }
- return two_byte_str;
-}
-
-
-static void* JSREMalloc(size_t size) {
- intptr_t regexp_size = static_cast<intptr_t>(size);
- ASSERT(regexp_size > 0);
- const JSRegExp& new_regex = JSRegExp::Handle(JSRegExp::New(size));
- return new_regex.GetDataStartAddress();
-}
-
-
-static void JSREFree(void* ptr) {
- USE(ptr); // Do nothing, memory is garbage collected.
-}
-
-
-static void ThrowExceptionOnError(const String& pattern,
- const char* error_msg) {
- if (error_msg == NULL) {
- error_msg = "Unknown regexp compile error. ";
- }
- const String& errmsg = String::Handle(String::New(error_msg));
- const String& message = String::Handle(String::Concat(errmsg, pattern));
- const Array& args = Array::Handle(Array::New(1));
- args.SetAt(0, message);
- Exceptions::ThrowByType(Exceptions::kFormat, args);
-}
-
-
-RawJSRegExp* Jscre::Compile(const String& pattern,
- bool multi_line,
- bool ignore_case) {
- // First convert the pattern to UTF16 format as the jscre library expects
- // strings to be in UTF16 encoding.
- uint16_t* two_byte_pattern = GetTwoByteData(pattern);
-
- // A Dart regexp is always global.
- bool is_global = true;
- // Parse the flags.
- jscre::JSRegExpIgnoreCaseOption jscre_ignore_case = ignore_case ?
- jscre::JSRegExpIgnoreCase : jscre::JSRegExpDoNotIgnoreCase;
- jscre::JSRegExpMultilineOption jscre_multi_line = multi_line ?
- jscre::JSRegExpMultiline : jscre::JSRegExpSingleLine;
-
- // Compile the regex by calling into the jscre library.
- uint32_t num_bracket_expressions = 0;
- const char* error_msg = NULL;
- jscre::JSRegExp* jscregexp = jscre::jsRegExpCompile(two_byte_pattern,
- pattern.Length(),
- jscre_ignore_case,
- jscre_multi_line,
- &num_bracket_expressions,
- &error_msg,
- &JSREMalloc,
- &JSREFree);
-
- if (jscregexp == NULL) {
- // There was an error compiling the regex, Throw an exception.
- ThrowExceptionOnError(pattern, error_msg);
- UNREACHABLE();
- return JSRegExp::null();
- } else {
- // Setup the compiled regex object and return it.
- JSRegExp& regexp =
- JSRegExp::Handle(JSRegExp::FromDataStartAddress(jscregexp));
- regexp.set_pattern(pattern);
- if (jscre_multi_line == jscre::JSRegExpMultiline) {
- regexp.set_is_multi_line();
- }
- if (jscre_ignore_case == jscre::JSRegExpIgnoreCase) {
- regexp.set_is_ignore_case();
- }
- if (is_global) {
- regexp.set_is_global();
- }
- regexp.set_is_complex(); // Always use jscre library.
- regexp.set_num_bracket_expressions(num_bracket_expressions);
- return regexp.raw();
- }
-}
-
-
-RawArray* Jscre::Execute(const JSRegExp& regex,
- const String& str,
- intptr_t start_index) {
- // First convert the input str to UTF16 format as the jscre library expects
- // strings to be in UTF16 encoding.
- uint16_t* two_byte_str = GetTwoByteData(str);
-
- // Execute a regex match by calling into the jscre library.
- jscre::JSRegExp* jscregexp =
- reinterpret_cast<jscre::JSRegExp*>(regex.GetDataStartAddress());
- ASSERT(jscregexp != NULL);
- const Smi& num_bracket_exprs = Smi::Handle(regex.num_bracket_expressions());
- intptr_t num_bracket_expressions = num_bracket_exprs.Value();
- Zone* zone = Isolate::Current()->current_zone();
- // The jscre library rounds the passed in size to a multiple of 3 in order
- // to reuse the passed in offsets array as a temporary chunk of working
- // storage during matching, so we just pass in a size which is a multiple
- // of 3.
- const int kJscreMultiple = 3;
- int offsets_length = (num_bracket_expressions + 1) * kJscreMultiple;
- int* offsets = NULL;
- offsets = zone->Alloc<int>(offsets_length);
- int retval = jscre::jsRegExpExecute(jscregexp,
- two_byte_str,
- str.Length(),
- start_index,
- offsets,
- offsets_length);
-
- // The KJS JavaScript engine returns null (ie, a failed match) when
- // JSRE's internal match limit is exceeded. We duplicate that behavior here.
- if (retval == jscre::JSRegExpErrorNoMatch
- || retval == jscre::JSRegExpErrorHitLimit) {
- return Array::null();
- }
-
- // Other JSRE errors:
- if (retval < 0) {
- const String& pattern = String::Handle(regex.pattern());
- const int kErrorLength = 256;
- char error_msg[kErrorLength];
- OS::SNPrint(error_msg, kErrorLength,
- "jscre::jsRegExpExecute error : %d", retval);
- ThrowExceptionOnError(pattern, error_msg);
- UNREACHABLE();
- return Array::null();
- }
-
- const int kMatchPair = 2;
- Array& array =
- Array::Handle(Array::New(kMatchPair * (num_bracket_expressions + 1)));
- // The matches come in (start, end + 1) pairs for each bracketted expression.
- Smi& start = Smi::Handle();
- Smi& end = Smi::Handle();
- for (intptr_t i = 0;
- i < (kMatchPair * (num_bracket_expressions + 1));
- i += kMatchPair) {
- start = Smi::New(offsets[i]);
- end = Smi::New(offsets[i + 1]);
- array.SetAt(i, start);
- array.SetAt(i+1, end);
- }
- return array.raw();
-}
-
-} // namespace dart
diff --git a/runtime/lib/regexp_jsc.h b/runtime/lib/regexp_jsc.h
deleted file mode 100644
index 2dff024..0000000
--- a/runtime/lib/regexp_jsc.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef LIB_REGEXP_JSC_H_
-#define LIB_REGEXP_JSC_H_
-
-#include "vm/object.h"
-
-
-namespace dart {
-
-class Jscre : public AllStatic {
- public:
- static RawJSRegExp* Compile(const String& pattern,
- bool multi_line,
- bool ignore_case);
- static RawArray* Execute(const JSRegExp& regex,
- const String& str,
- intptr_t index);
-};
-
-} // namespace dart
-
-#endif // LIB_REGEXP_JSC_H_
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index 61065ed..4fb7fff 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -3446,11 +3446,11 @@
if (byteOffset < 0 || byteOffset + 3 >= length) {
throw _newRangeError(byteOffset + 3, length);
}
- var result = _typedData._getFloat32(_offset + byteOffset);
if (identical(endian, Endianness.HOST_ENDIAN)) {
- return result;
+ return _typedData._getFloat32(_offset + byteOffset);
}
- return _byteSwapFloat32(result);
+ _convU32[0] = _byteSwap32(_typedData._getUint32(_offset + byteOffset));
+ return _convF32[0];
}
void setFloat32(int byteOffset,
double value,
@@ -3458,9 +3458,12 @@
if (byteOffset < 0 || byteOffset + 3 >= length) {
throw _newRangeError(byteOffset + 3, length);
}
- _typedData._setFloat32(_offset + byteOffset,
- identical(endian, Endianness.HOST_ENDIAN) ? value
- : _byteSwapFloat32(value));
+ if (identical(endian, Endianness.HOST_ENDIAN)) {
+ _typedData._setFloat32(_offset + byteOffset, value);
+ return;
+ }
+ _convF32[0] = value;
+ _typedData._setUint32(_offset + byteOffset, _byteSwap32(_convU32[0]));
}
double getFloat64(int byteOffset,
@@ -3468,11 +3471,11 @@
if (byteOffset < 0 || byteOffset + 7 >= length) {
throw _newRangeError(byteOffset + 7, length);
}
- var result = _typedData._getFloat64(_offset + byteOffset);
if (identical(endian, Endianness.HOST_ENDIAN)) {
- return result;
+ return _typedData._getFloat64(_offset + byteOffset);
}
- return _byteSwapFloat64(result);
+ _convU64[0] = _byteSwap64(_typedData._getUint64(_offset + byteOffset));
+ return _convF64[0];
}
void setFloat64(int byteOffset,
double value,
@@ -3480,9 +3483,12 @@
if (byteOffset < 0 || byteOffset + 7 >= length) {
throw _newRangeError(byteOffset + 7, length);
}
- _typedData._setFloat64(_offset + byteOffset,
- identical(endian, Endianness.HOST_ENDIAN) ? value
- : _byteSwapFloat64(value));
+ if (identical(endian, Endianness.HOST_ENDIAN)) {
+ _typedData._setFloat64(_offset + byteOffset, value);
+ return;
+ }
+ _convF64[0] = value;
+ _typedData._setUint64(_offset + byteOffset, _byteSwap64(_convU64[0]));
}
Float32x4 getFloat32x4(int byteOffset,
@@ -3525,23 +3531,10 @@
}
final _convU32 = new Uint32List(2);
+final _convU64 = new Uint64List.view(_convU32.buffer);
final _convF32 = new Float32List.view(_convU32.buffer);
final _convF64 = new Float64List.view(_convU32.buffer);
-double _byteSwapFloat32(double value) {
- _convF32[0] = value;
- _convU32[0] = _byteSwap32(_convU32[0]);
- return _convF32[0];
-}
-
-double _byteSwapFloat64(double value) {
- _convF64[0] = value;
- var lo = _convU32[0];
- _convU32[0] = _byteSwap32(_convU32[1]);
- _convU32[1] = _byteSwap32(lo);
- return _convF64[0];
-}
-
// Top level utility methods.
int _toInt(int value, int mask) {
value &= mask;
diff --git a/runtime/observatory/lib/service_common.dart b/runtime/observatory/lib/service_common.dart
index 3add115..c47d2b3 100644
--- a/runtime/observatory/lib/service_common.dart
+++ b/runtime/observatory/lib/service_common.dart
@@ -186,15 +186,15 @@
Logger.root.severe('WebSocketVM got empty message');
return;
}
- // Extract serial and response.
+ // Extract serial and result.
var serial;
- var response;
+ var result;
serial = map['id'];
- response = map['response'];
+ result = map['result'];
if (serial == null) {
// Messages without serial numbers are asynchronous events
// from the vm.
- postServiceEvent(response, null);
+ postServiceEvent(result, null);
return;
}
// Complete request.
@@ -209,7 +209,7 @@
Logger.root.info(
'RESPONSE [${serial}] ${request.method}');
}
- request.completer.complete(response);
+ request.completer.complete(result);
}
// WebSocket message event handler.
diff --git a/runtime/observatory/lib/src/app/application.dart b/runtime/observatory/lib/src/app/application.dart
index d06c6e1..090d300 100644
--- a/runtime/observatory/lib/src/app/application.dart
+++ b/runtime/observatory/lib/src/app/application.dart
@@ -67,6 +67,7 @@
void _onEvent(ServiceEvent event) {
switch(event.eventType) {
case ServiceEvent.kIsolateStart:
+ case ServiceEvent.kIsolateUpdate:
case ServiceEvent.kGraph:
case ServiceEvent.kBreakpointAdded:
case ServiceEvent.kBreakpointResolved:
diff --git a/runtime/observatory/lib/src/app/page.dart b/runtime/observatory/lib/src/app/page.dart
index c777579..e79f3dc 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -58,10 +58,11 @@
}
Future<Isolate> getIsolate(Uri uri) {
- return app.vm.getIsolate(uri.queryParameters['isolateId']).catchError((e) {
- Logger.root.severe('$path visit error: $e');
- return e;
- });
+ return app.vm.getIsolate(uri.queryParameters['isolateId'])
+ .catchError((e, stack) {
+ Logger.root.severe('$path visit error: $e\n$stack');
+ return e;
+ });
}
bool canVisit(Uri uri) => uri.path == path;
@@ -110,8 +111,8 @@
ServiceObjectViewElement serviceElement = element;
serviceElement.object = vm;
}
- }).catchError((e) {
- Logger.root.severe('VMPage visit error: $e');
+ }).catchError((e, stack) {
+ Logger.root.severe('VMPage visit error: $e\n$stack');
});
}
}
@@ -126,8 +127,8 @@
FlagListElement serviceElement = element;
serviceElement.flagList = flags;
}
- }).catchError((e) {
- Logger.root.severe('FlagsPage visit error: $e');
+ }).catchError((e, stack) {
+ Logger.root.severe('FlagsPage visit error: $e\n$stack');
});
}
}
@@ -181,6 +182,7 @@
if (element != null) {
/// Update the page.
DebuggerPageElement page = element;
+ page.app = app;
page.isolate = isolate;
}
});
diff --git a/runtime/observatory/lib/src/cli/command.dart b/runtime/observatory/lib/src/cli/command.dart
index 67b21c2..0f57376 100644
--- a/runtime/observatory/lib/src/cli/command.dart
+++ b/runtime/observatory/lib/src/cli/command.dart
@@ -10,8 +10,6 @@
List<String> _splitLine(String line) {
line = line.trimLeft();
var args = [];
- var codes = line.codeUnits;
-
int pos = 0;
while (pos < line.length) {
int startPos = pos;
@@ -149,11 +147,11 @@
}
// We have found a set of commands which match all of the args.
- // Return the completions strings.
+ // Return the completion strings.
var prefix = _concatArgs(args, args.length - 1);
var completions =
commands.map((command) => '${prefix}${command.name} ').toList();
- if (showAll && matchLen == args.length) {
+ if (matchLen == args.length) {
// If we are showing all possiblities, also include local
// completions for the parent command.
return commands[0]._parent._buildCompletions(args, false)
diff --git a/runtime/observatory/lib/src/debugger/debugger.dart b/runtime/observatory/lib/src/debugger/debugger.dart
index 97a6ff5..b2d5203 100644
--- a/runtime/observatory/lib/src/debugger/debugger.dart
+++ b/runtime/observatory/lib/src/debugger/debugger.dart
@@ -6,6 +6,7 @@
// TODO(turnidge): Move more of ObservatoryDebugger to this class.
abstract class Debugger {
+ VM get vm;
Isolate get isolate;
ServiceMap get stack;
int get currentFrame;
diff --git a/runtime/observatory/lib/src/debugger/source_location.dart b/runtime/observatory/lib/src/debugger/source_location.dart
index f14d87b..91da581 100644
--- a/runtime/observatory/lib/src/debugger/source_location.dart
+++ b/runtime/observatory/lib/src/debugger/source_location.dart
@@ -187,7 +187,6 @@
}
static ServiceFunction _getConstructor(Class cls, String name) {
- var matches = [];
for (var function in cls.functions) {
assert(cls.loaded);
if (name == function.name) {
diff --git a/runtime/observatory/lib/src/elements/class_view.html b/runtime/observatory/lib/src/elements/class_view.html
index 400bc83..3a3253c 100644
--- a/runtime/observatory/lib/src/elements/class_view.html
+++ b/runtime/observatory/lib/src/elements/class_view.html
@@ -77,7 +77,7 @@
<div class="memberName">implements</div>
<div class="memberValue">
<template repeat="{{ interface in cls.interfaces }}">
- <class-ref ref="{{ interface }}"></class-ref>
+ <instance-ref ref="{{ interface }}"></instance-ref>
</template>
</div>
</div>
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile.dart
index 8a69f90..b4406ac 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:html';
import 'observatory_element.dart';
-import 'package:logging/logging.dart';
import 'package:observatory/service.dart';
import 'package:observatory/app.dart';
import 'package:observatory/cpu_profile.dart';
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 4a9bdf8..662ebb8 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -7,6 +7,7 @@
import 'dart:async';
import 'dart:html';
import 'observatory_element.dart';
+import 'package:observatory/app.dart';
import 'package:observatory/cli.dart';
import 'package:observatory/debugger.dart';
import 'package:observatory/service.dart';
@@ -30,9 +31,9 @@
String _nameAndAlias(Command cmd) {
if (cmd.alias == null) {
- return cmd.name;
+ return cmd.fullName;
} else {
- return '${cmd.name}, ${cmd.alias}';
+ return '${cmd.fullName}, ${cmd.alias}';
}
}
@@ -51,7 +52,7 @@
"\nFor more information on a specific command type 'help <command>'\n"
"\n"
"Command prefixes are accepted (e.g. 'h' for 'help')\n"
- "Hit [TAB] to complete a command (try 'i[TAB][TAB]')\n"
+ "Hit [TAB] to complete a command (try 'is[TAB][TAB]')\n"
"Hit [ENTER] to repeat the last command\n"
"Use up/down arrow for command history\n");
return new Future.value(null);
@@ -409,7 +410,7 @@
Future<List<String>> complete(List<String> args) {
if (args.length != 1) {
- return new Future.value([]);
+ return new Future.value([args.join('')]);
}
// TODO - fix SourceLocation complete
return new Future.value(SourceLocation.complete(debugger, args[0]));
@@ -493,7 +494,7 @@
Future<List<String>> complete(List<String> args) {
if (args.length != 1) {
- return new Future.value([]);
+ return new Future.value([args.join('')]);
}
return new Future.value(SourceLocation.complete(debugger, args[0]));
}
@@ -603,32 +604,12 @@
'Syntax: info breakpoints\n';
}
-class InfoIsolatesCommand extends DebuggerCommand {
- InfoIsolatesCommand(Debugger debugger) : super(debugger, 'isolates', []);
-
- Future run(List<String> args) {
- for (var isolate in debugger.isolate.vm.isolates) {
- String current = (isolate == debugger.isolate ? ' *' : '');
- debugger.console.print(
- "Isolate ${isolate.id} '${isolate.name}'${current}");
- }
- return new Future.value(null);
- }
-
- String helpShort = 'List all isolates';
-
- String helpLong =
- 'List all isolates.\n'
- '\n'
- 'Syntax: info isolates\n';
-}
-
class InfoFrameCommand extends DebuggerCommand {
InfoFrameCommand(Debugger debugger) : super(debugger, 'frame', []);
Future run(List<String> args) {
if (args.length > 0) {
- debugger.console.print('info frame expects 1 argument');
+ debugger.console.print('info frame expects no arguments');
return new Future.value(null);
}
debugger.console.print('frame = ${debugger.currentFrame}');
@@ -643,12 +624,131 @@
'Syntax: info frame\n';
}
+class IsolateCommand extends DebuggerCommand {
+ IsolateCommand(Debugger debugger) : super(debugger, 'isolate', [
+ new IsolateListCommand(debugger),
+ new IsolateNameCommand(debugger),
+ ]) {
+ alias = 'i';
+ }
+
+ Future run(List<String> args) {
+ if (args.length != 1) {
+ debugger.console.print('isolate expects one argument');
+ return new Future.value(null);
+ }
+ var arg = args[0].trim();
+ var num = int.parse(arg, onError:(_) => null);
+
+ var candidate;
+ for (var isolate in debugger.vm.isolates) {
+ if (num != null && num == isolate.number) {
+ candidate = isolate;
+ break;
+ } else if (arg == isolate.name) {
+ if (candidate != null) {
+ debugger.console.print(
+ "Isolate identifier '${arg}' is ambiguous: "
+ 'use the isolate number instead');
+ return new Future.value(null);
+ }
+ candidate = isolate;
+ }
+ }
+ if (candidate == null) {
+ debugger.console.print("Invalid isolate identifier '${arg}'");
+ } else {
+ if (candidate == debugger.isolate) {
+ debugger.console.print(
+ "Current isolate is already ${candidate.number} '${candidate.name}'");
+ } else {
+ debugger.console.print(
+ "Switching to isolate ${candidate.number} '${candidate.name}'");
+ debugger.isolate = candidate;
+ }
+ }
+ return new Future.value(null);
+ }
+
+ Future<List<String>> complete(List<String> args) {
+ if (args.length != 1) {
+ return new Future.value([args.join('')]);
+ }
+ var isolates = debugger.vm.isolates.toList();
+ isolates.sort((a, b) => a.startTime.compareTo(b.startTime));
+ var result = [];
+ for (var isolate in isolates) {
+ var str = isolate.number.toString();
+ if (str.startsWith(args[0])) {
+ result.add('$str ');
+ }
+ }
+ for (var isolate in isolates) {
+ if (isolate.name.startsWith(args[0])) {
+ result.add('${isolate.name} ');
+ }
+ }
+ return new Future.value(result);
+ }
+ String helpShort = 'Switch the current isolate';
+
+ String helpLong =
+ 'Switch the current isolate.\n'
+ '\n'
+ 'Syntax: isolate <number>\n'
+ ' isolate <name>\n';
+}
+
+class IsolateListCommand extends DebuggerCommand {
+ IsolateListCommand(Debugger debugger) : super(debugger, 'list', []);
+
+ Future run(List<String> args) {
+ if (debugger.vm == null) {
+ debugger.console.print(
+ "Internal error: vm has not been set");
+ return new Future.value(null);
+ }
+ var isolates = debugger.vm.isolates.toList();
+ isolates.sort((a, b) => a.startTime.compareTo(b.startTime));
+ for (var isolate in isolates) {
+ String current = (isolate == debugger.isolate ? ' *' : '');
+ debugger.console.print(
+ "Isolate ${isolate.number} '${isolate.name}'${current}");
+ }
+ return new Future.value(null);
+ }
+
+ String helpShort = 'List all isolates';
+
+ String helpLong =
+ 'List all isolates.\n'
+ '\n'
+ 'Syntax: isolate list\n';
+}
+
+class IsolateNameCommand extends DebuggerCommand {
+ IsolateNameCommand(Debugger debugger) : super(debugger, 'name', []);
+
+ Future run(List<String> args) {
+ if (args.length != 1) {
+ debugger.console.print('isolate name expects one argument');
+ return new Future.value(null);
+ }
+ return debugger.isolate.setName(args[0]);
+ }
+
+ String helpShort = 'Rename an isolate';
+
+ String helpLong =
+ 'Rename an isolate.\n'
+ '\n'
+ 'Syntax: isolate name <name>\n';
+}
+
class InfoCommand extends DebuggerCommand {
InfoCommand(Debugger debugger) : super(debugger, 'info', [
new InfoBreakpointsCommand(debugger),
- new InfoIsolatesCommand(debugger),
- new InfoFrameCommand(debugger),
- ]);
+ new InfoFrameCommand(debugger)]);
Future run(List<String> args) {
debugger.console.print("'info' expects a subcommand (see 'help info')");
@@ -689,8 +789,6 @@
RefreshStackCommand(Debugger debugger) : super(debugger, 'stack', []);
Future run(List<String> args) {
- Set<Script> scripts = debugger.stackElement.activeScripts();
- List pending = [];
return debugger.refreshStack();
}
@@ -724,6 +822,7 @@
// Tracks the state for an isolate debugging session.
class ObservatoryDebugger extends Debugger {
RootCommand cmd;
+ DebuggerPageElement page;
DebuggerConsoleElement console;
DebuggerStackElement stackElement;
ServiceMap stack;
@@ -758,14 +857,17 @@
new ClearCommand(this),
new DeleteCommand(this),
new InfoCommand(this),
+ new IsolateCommand(this),
new RefreshCommand(this),
]);
}
- void set isolate(Isolate iso) {
+ VM get vm => page.app.vm;
+
+ void updateIsolate(Isolate iso) {
_isolate = iso;
if (_isolate != null) {
- _isolate.reload().then((_) {
+ _isolate.reload().then((response) {
// TODO(turnidge): Currently the debugger relies on all libs
// being loaded. Fix this.
var pending = [];
@@ -775,26 +877,46 @@
}
}
Future.wait(pending).then((_) {
- _isolate.vm.events.stream.listen(_onEvent);
+ if (_subscription == null) {
+ _subscription = vm.events.stream.listen(_onEvent);
+ }
_refreshStack(isolate.pauseEvent).then((_) {
reportStatus();
});
});
});
+ } else {
+ reportStatus();
}
}
+
+ void set isolate(Isolate iso) {
+ // Setting the page's isolate will trigger updateIsolate to be called.
+ //
+ // TODO(turnidge): Rework ownership of the ObservatoryDebugger in another
+ // change.
+ page.isolate = iso;
+ }
Isolate get isolate => _isolate;
Isolate _isolate;
+ var _subscription;
void init() {
console.newline();
console.printBold("Type 'h' for help");
+ // Wait a bit and if polymer still hasn't set up the isolate,
+ // report this to the user.
+ new Timer(const Duration(seconds:1), () {
+ if (isolate == null) {
+ reportStatus();
+ }
+ });
}
Future refreshStack() {
return _refreshStack(isolate.pauseEvent).then((_) {
- reportStatus();
- });
+ reportStatus();
+ });
}
bool isolatePaused() {
@@ -830,7 +952,9 @@
}
void reportStatus() {
- if (_isolate.idle) {
+ if (_isolate == null) {
+ console.print('No current isolate');
+ } else if (_isolate.idle) {
console.print('Isolate is idle');
} else if (_isolate.running) {
console.print("Isolate is running (type 'pause' to interrupt)");
@@ -902,13 +1026,30 @@
}
void _onEvent(ServiceEvent event) {
- if (event.owner != isolate) {
- return;
- }
switch(event.eventType) {
+ case ServiceEvent.kIsolateStart:
+ {
+ var iso = event.owner;
+ console.print(
+ "Isolate ${iso.number} '${iso.name}' has been created");
+ }
+ break;
+
case ServiceEvent.kIsolateExit:
- console.print('Isolate shutdown');
- isolate = null;
+ {
+ var iso = event.owner;
+ if (iso == isolate) {
+ console.print("The current isolate has exited");
+ } else {
+ console.print(
+ "Isolate ${iso.number} '${iso.name}' has exited");
+ }
+ }
+ break;
+
+ case ServiceEvent.kIsolateUpdate:
+ var iso = event.owner;
+ console.print("Isolate ${iso.number} renamed to '${iso.name}'");
break;
case ServiceEvent.kPauseStart:
@@ -916,25 +1057,30 @@
case ServiceEvent.kPauseBreakpoint:
case ServiceEvent.kPauseInterrupted:
case ServiceEvent.kPauseException:
- _refreshStack(event).then((_) {
- _reportPause(event);
- });
+ if (event.owner == isolate) {
+ _refreshStack(event).then((_) {
+ _reportPause(event);
+ });
+ }
break;
case ServiceEvent.kResume:
- console.print('Continuing...');
+ if (event.owner == isolate) {
+ console.print('Continuing...');
+ }
break;
case ServiceEvent.kBreakpointAdded:
case ServiceEvent.kBreakpointResolved:
case ServiceEvent.kBreakpointRemoved:
- _reportBreakpointEvent(event);
+ if (event.owner == isolate) {
+ _reportBreakpointEvent(event);
+ }
break;
case ServiceEvent.kIsolateStart:
case ServiceEvent.kGraph:
case ServiceEvent.kGC:
- // Ignore these events for now.
break;
default:
@@ -1008,16 +1154,19 @@
@CustomTag('debugger-page')
class DebuggerPageElement extends ObservatoryElement {
+ @published ObservatoryApplication app;
@published Isolate isolate;
isolateChanged(oldValue) {
if (isolate != null) {
- debugger.isolate = isolate;
+ debugger.updateIsolate(isolate);
}
}
ObservatoryDebugger debugger = new ObservatoryDebugger();
- DebuggerPageElement.created() : super.created();
+ DebuggerPageElement.created() : super.created() {
+ debugger.page = this;
+ }
@override
void attached() {
@@ -1027,7 +1176,6 @@
var stackDiv = $['stackDiv'];
var splitterDiv = $['splitterDiv'];
var cmdDiv = $['commandDiv'];
- var consoleDiv = $['consoleDiv'];
int navbarHeight = navbarDiv.clientHeight;
int splitterHeight = splitterDiv.clientHeight;
diff --git a/runtime/observatory/lib/src/elements/field_view.html b/runtime/observatory/lib/src/elements/field_view.html
index 2a9d728..cad31aa 100644
--- a/runtime/observatory/lib/src/elements/field_view.html
+++ b/runtime/observatory/lib/src/elements/field_view.html
@@ -12,12 +12,9 @@
<nav-bar>
<top-nav-menu></top-nav-menu>
<isolate-nav-menu isolate="{{ field.isolate }}"></isolate-nav-menu>
- <template if="{{ field.owner.type == 'Class' }}">
- <!-- TODO(turnidge): Add library nav menu here. -->
- <class-nav-menu cls="{{ field.owner }}"></class-nav-menu>
- </template>
- <template if="{{ field.owner.type == 'Library' }}">
- <library-nav-menu library="{{ field.owner }}"></library-nav-menu>
+ <library-nav-menu library="{{ field.library }}"></library-nav-menu>
+ <template if="{{ field.dartOwner is ServiceClass }}">
+ <class-nav-menu cls="{{ field.dartOwner }}"></class-nav-menu>
</template>
<nav-menu link="{{ makeLink('/inspect', field) }}" anchor="{{ field.name }}" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
@@ -42,12 +39,7 @@
<div class="memberItem">
<div class="memberName">owner</div>
<div class="memberValue">
- <template if="{{ field.owner.type == 'Class' }}">
- <class-ref ref="{{ field.owner }}"></class-ref>
- </template>
- <template if="{{ field.owner.type != 'Class' }}">
- <library-ref ref="{{ field.owner }}"></library-ref>
- </template>
+ <any-service-ref ref="{{ function.dartOwner }}"></any-service-ref>
</div>
</div>
<div class="memberItem">
diff --git a/runtime/observatory/lib/src/elements/function_ref.dart b/runtime/observatory/lib/src/elements/function_ref.dart
index 2e92f60..53920b9 100644
--- a/runtime/observatory/lib/src/elements/function_ref.dart
+++ b/runtime/observatory/lib/src/elements/function_ref.dart
@@ -28,18 +28,17 @@
}
if (function.isDart) {
if (qualified) {
- // Add class-name or parent-function-name followed by a dot.
- if ((function.parent == null) && (function.owningClass != null)) {
- var classRef = new Element.tag('class-ref');
- classRef.ref = function.owningClass;
- shadowRoot.children.add(classRef);
- insertTextSpanIntoShadowRoot('.');
- } else if (function.parent != null) {
+ if (function.dartOwner is ServiceFunction) {
var functionRef = new Element.tag('function-ref');
- functionRef.ref = function.parent;
+ functionRef.ref = function.dartOwner;
functionRef.qualified = true;
shadowRoot.children.add(functionRef);
insertTextSpanIntoShadowRoot('.');
+ } else if (function.dartOwner is Class) {
+ var classRef = new Element.tag('class-ref');
+ classRef.ref = function.dartOwner;
+ shadowRoot.children.add(classRef);
+ insertTextSpanIntoShadowRoot('.');
}
}
insertLinkIntoShadowRoot(name, url, hoverText);
diff --git a/runtime/observatory/lib/src/elements/function_view.html b/runtime/observatory/lib/src/elements/function_view.html
index 519cad8..4b75c5c 100644
--- a/runtime/observatory/lib/src/elements/function_view.html
+++ b/runtime/observatory/lib/src/elements/function_view.html
@@ -14,12 +14,9 @@
<nav-bar>
<top-nav-menu></top-nav-menu>
<isolate-nav-menu isolate="{{ function.isolate }}"></isolate-nav-menu>
- <template if="{{ function.owningClass != null }}">
- <!-- TODO(turnidge): Add library nav menu here. -->
- <class-nav-menu cls="{{ function.owningClass }}"></class-nav-menu>
- </template>
- <template if="{{ function.owningLibrary != null }}">
- <library-nav-menu library="{{ function.owningLibrary }}"></library-nav-menu>
+ <library-nav-menu library="{{ function.library }}"></library-nav-menu>
+ <template if="{{ function.dartOwner is ServiceClass }}">
+ <class-nav-menu cls="{{ function.dartOwner }}"></class-nav-menu>
</template>
<nav-menu link="{{ makeLink('/inspect', function) }}" anchor="{{ function.name }}" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
@@ -39,23 +36,10 @@
{{ function.kind.toString() }}
</div>
</div>
- <template if="{{ function.parent != null }}">
- <div class="memberItem">
- <div class="memberName">parent function</div>
- <div class="memberValue">
- <function-ref ref="{{ function.parent }}"></function-ref>
- </div>
- </div>
- </template>
<div class="memberItem">
<div class="memberName">owner</div>
<div class="memberValue">
- <template if="{{ function.owningClass != null }}">
- <class-ref ref="{{ function.owningClass }}"></class-ref>
- </template>
- <template if="{{ function.owningLibrary != null }}">
- <library-ref ref="{{ function.owningLibrary }}"></library-ref>
- </template>
+ <any-service-ref ref="{{ function.dartOwner }}"></any-service-ref>
</div>
</div>
<div class="memberItem">
diff --git a/runtime/observatory/lib/src/elements/heap_profile.dart b/runtime/observatory/lib/src/elements/heap_profile.dart
index 2cac03f..d826a48 100644
--- a/runtime/observatory/lib/src/elements/heap_profile.dart
+++ b/runtime/observatory/lib/src/elements/heap_profile.dart
@@ -102,13 +102,34 @@
_subscription.cancel((){});
super.detached();
}
-
+
+ // Keep at most one outstanding auto-refresh RPC.
+ bool refreshAutoPending = false;
+ bool refreshAutoQueued = false;
+
void _onEvent(ServiceEvent event) {
if (autoRefresh && event.eventType == 'GC') {
- refresh((){});
+ if (!refreshAutoPending) {
+ refreshAuto();
+ } else {
+ // Remember to refresh once more, to ensure latest profile.
+ refreshAutoQueued = true;
+ }
}
}
+ void refreshAuto() {
+ refreshAutoPending = true;
+ refreshAutoQueued = false;
+ refresh(() {
+ refreshAutoPending = false;
+ // Keep refreshing if at least one GC event was received while waiting.
+ if (refreshAutoQueued) {
+ refreshAuto();
+ }
+ });
+ }
+
void _updatePieCharts() {
assert(profile != null);
_newPieDataTable.clearRows();
diff --git a/runtime/observatory/lib/src/elements/heap_profile.html b/runtime/observatory/lib/src/elements/heap_profile.html
index 460a021..3d0bfec 100644
--- a/runtime/observatory/lib/src/elements/heap_profile.html
+++ b/runtime/observatory/lib/src/elements/heap_profile.html
@@ -57,11 +57,9 @@
<nav-refresh callback="{{ resetAccumulator }}" label="Reset Accumulator"></nav-refresh>
<nav-refresh callback="{{ refreshGC }}" label="GC"></nav-refresh>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
- <!-- Disabled dartbug.com/22970
<div class="nav-option">
<input type="checkbox" checked="{{ autoRefresh }}">Auto-refresh on GC
</div>
- -->
<nav-control></nav-control>
</nav-bar>
<div class="content">
diff --git a/runtime/observatory/lib/src/elements/instance_ref.html b/runtime/observatory/lib/src/elements/instance_ref.html
index ab7bb16..2f4fff1 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.html
+++ b/runtime/observatory/lib/src/elements/instance_ref.html
@@ -38,8 +38,7 @@
<template if="{{ ref.isClosure }}">
<a on-click="{{ goto }}" _href="{{ url }}">
- <!-- TODO(turnidge): Switch this to fully-qualified function -->
- {{ ref.closureFunc.name }}
+ {{ ref.closureFunc.qualifiedName }}
</a>
</template>
diff --git a/runtime/observatory/lib/src/elements/instance_view.html b/runtime/observatory/lib/src/elements/instance_view.html
index b9dbb9b..91fa806 100644
--- a/runtime/observatory/lib/src/elements/instance_view.html
+++ b/runtime/observatory/lib/src/elements/instance_view.html
@@ -46,7 +46,9 @@
<template if="{{ instance.valueAsString != null }}">
<div class="memberItem">
<div class="memberName">value</div>
- <div class="memberValue">{{ instance.valueAsString }}</div>
+ <div class="memberValue">
+ <pre>{{ instance.valueAsString }}</pre>
+ </div>
</div>
</template>
diff --git a/runtime/observatory/lib/src/elements/isolate_summary.dart b/runtime/observatory/lib/src/elements/isolate_summary.dart
index cefc373..288a21e 100644
--- a/runtime/observatory/lib/src/elements/isolate_summary.dart
+++ b/runtime/observatory/lib/src/elements/isolate_summary.dart
@@ -4,7 +4,6 @@
library isolate_summary_element;
-import 'dart:async';
import 'observatory_element.dart';
import 'package:observatory/app.dart';
import 'package:observatory/service.dart';
diff --git a/runtime/observatory/lib/src/elements/isolate_summary.html b/runtime/observatory/lib/src/elements/isolate_summary.html
index 89ea848..2af908d 100644
--- a/runtime/observatory/lib/src/elements/isolate_summary.html
+++ b/runtime/observatory/lib/src/elements/isolate_summary.html
@@ -13,12 +13,15 @@
<img src="img/isolate_icon.png">
</div>
<div class="flex-item-10-percent">
+ {{ isolate.number }}
+ </div>
+ <div class="flex-item-20-percent">
<isolate-ref ref="{{ isolate }}"></isolate-ref>
</div>
<div class="flex-item-10-percent">
<isolate-run-state isolate="{{ isolate }}"></isolate-run-state>
</div>
- <div class="flex-item-60-percent">
+ <div class="flex-item-40-percent">
<isolate-location isolate="{{ isolate }}"></isolate-location>
[<a on-click="{{ goto }}" _href="{{ gotoLink('/debugger', isolate) }}">debug</a>]
</div>
diff --git a/runtime/observatory/lib/src/elements/isolate_view.html b/runtime/observatory/lib/src/elements/isolate_view.html
index 615a855..3bd7845 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.html
+++ b/runtime/observatory/lib/src/elements/isolate_view.html
@@ -80,6 +80,14 @@
<div class="flex-item-50-percent">
<div class="memberList">
<div class="memberItem">
+ <div class="memberName">started at</div>
+ <div class="memberValue">{{ isolate.startTime.toString() }}</div>
+ </div>
+ <div class="memberItem">
+ <div class="memberName">uptime</div>
+ <div class="memberValue">{{ isolate.upTime.toString() }}</div>
+ </div>
+ <div class="memberItem">
<div class="memberName">root library</div>
<div class="memberValue">
<library-ref ref="{{ isolate.rootLib }}"></library-ref>
@@ -95,7 +103,7 @@
</div>
<div class="memberItem">
<div class="memberName">isolate id</div>
- <div class="memberValue">{{ isolate.mainPort }}</div>
+ <div class="memberValue">{{ isolate.number }}</div>
</div>
</div>
</div>
diff --git a/runtime/observatory/lib/src/elements/script_inset.dart b/runtime/observatory/lib/src/elements/script_inset.dart
index 2acb390..1f57b2a 100644
--- a/runtime/observatory/lib/src/elements/script_inset.dart
+++ b/runtime/observatory/lib/src/elements/script_inset.dart
@@ -19,17 +19,19 @@
infoBox.style.border = 'solid black 2px';
infoBox.style.zIndex = '10';
infoBox.style.backgroundColor = 'white';
-
+ infoBox.style.cursor = 'auto';
infoBox.style.display = 'none'; // Initially hidden.
var show = false;
content.onClick.listen((event) {
show = !show;
infoBox.style.display = show ? 'block' : 'none';
+ content.style.backgroundColor = show ? 'white' : '';
});
// Causes infoBox to be positioned relative to the bottom-left of content.
content.style.display = 'inline-block';
+ content.style.cursor = 'pointer';
content.append(infoBox);
}
@@ -54,9 +56,10 @@
class CallSiteAnnotation extends Annotation {
CallSite callSite;
- Element row() {
+ Element row([content]) {
var e = new DivElement();
e.style.display = "table-row";
+ if (content is String) e.text = content;
return e;
}
@@ -81,18 +84,22 @@
e.style.color = "#333";
e.style.font = "400 14px 'Montserrat', sans-serif";
- var r = row();
- r.append(cell("Container"));
- r.append(cell("Count"));
- r.append(cell("Target"));
- e.append(r);
-
- for (var entry in callSite.entries) {
+ if (callSite.entries.isEmpty) {
+ e.append(row('Did not execute'));
+ } else {
var r = row();
- r.append(cell(serviceRef(entry.receiverContainer)));
- r.append(cell(entry.count.toString()));
- r.append(cell(serviceRef(entry.target)));
+ r.append(cell("Container"));
+ r.append(cell("Count"));
+ r.append(cell("Target"));
e.append(r);
+
+ for (var entry in callSite.entries) {
+ var r = row();
+ r.append(cell(serviceRef(entry.receiverContainer)));
+ r.append(cell(entry.count.toString()));
+ r.append(cell(serviceRef(entry.target)));
+ e.append(r);
+ }
}
return e;
diff --git a/runtime/observatory/lib/src/elements/script_view.html b/runtime/observatory/lib/src/elements/script_view.html
index 7e376f7..13802d3 100644
--- a/runtime/observatory/lib/src/elements/script_view.html
+++ b/runtime/observatory/lib/src/elements/script_view.html
@@ -10,7 +10,7 @@
<top-nav-menu></top-nav-menu>
<isolate-nav-menu isolate="{{ script.isolate }}">
</isolate-nav-menu>
- <nav-menu link="{{ makeLink('/inspect', script.owningLibrary) }}" anchor="{{ script.owningLibrary.name }}"></nav-menu>
+ <library-nav-menu library="{{ script.library }}"></library-nav-menu>
<nav-menu link="{{ makeLink('/inspect', script) }}" anchor="{{ script.name }}" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
diff --git a/runtime/observatory/lib/src/elements/vm_view.html b/runtime/observatory/lib/src/elements/vm_view.html
index abf4d58..f1485d8 100644
--- a/runtime/observatory/lib/src/elements/vm_view.html
+++ b/runtime/observatory/lib/src/elements/vm_view.html
@@ -26,8 +26,16 @@
<div class="memberValue">{{ vm.version }}</div>
</div>
<div class="memberItem">
+ <div class="memberName">started at</div>
+ <div class="memberValue">{{ vm.startTime.toString() }}</div>
+ </div>
+ <div class="memberItem">
<div class="memberName">uptime</div>
- <div class="memberValue">{{ vm.uptime | formatTime }}</div>
+ <div class="memberValue">{{ vm.upTime.toString() }}</div>
+ </div>
+ <div class="memberItem">
+ <div class="memberName">refreshed at</div>
+ <div class="memberValue">{{ vm.refreshTime.toString() }}</div>
</div>
<div class="memberItem">
<div class="memberName">type checks enabled</div>
@@ -41,10 +49,6 @@
<div class="memberName">pid</div>
<div class="memberValue">{{ vm.pid }}</div>
</div>
- <div class="memberItem">
- <div class="memberName">refreshed at</div>
- <div class="memberValue">{{ vm.lastUpdate }}</div>
- </div>
<br>
<div class="memberItem">
<div class="memberValue">
@@ -68,4 +72,4 @@
</template>
</polymer-element>
-<script type="application/dart" src="vm_view.dart"></script>
\ No newline at end of file
+<script type="application/dart" src="vm_view.dart"></script>
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 4a006d2..cc233f9 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -310,7 +310,7 @@
if (this is! Isolate) {
params['targetId'] = id;
}
- return isolate.invokeRpcNoUpgrade('getCallSiteData', params).then(
+ return isolate.invokeRpcNoUpgrade('_getCallSiteData', params).then(
(ObservableMap map) {
var coverage = new ServiceObject._fromMap(isolate, map);
assert(coverage.type == 'CodeCoverage');
@@ -347,11 +347,13 @@
@observable String version = 'unknown';
@observable String targetCPU;
@observable int architectureBits;
- @observable double uptime = 0.0;
@observable bool assertsEnabled = false;
@observable bool typeChecksEnabled = false;
@observable String pid = '';
- @observable DateTime lastUpdate;
+ @observable DateTime startTime;
+ @observable DateTime refreshTime;
+ @observable Duration get upTime =>
+ (new DateTime.now().difference(startTime));
VM() : super._empty(null) {
name = 'vm';
@@ -367,19 +369,6 @@
final StreamController<ServiceEvent> events =
new StreamController.broadcast();
- bool _isIsolateLifecycleEvent(String eventType) {
- return _isIsolateExitEvent(eventType) ||
- _isIsolateStartEvent(eventType);
- }
-
- bool _isIsolateExitEvent(String eventType) {
- return (eventType == ServiceEvent.kIsolateExit);
- }
-
- bool _isIsolateStartEvent(String eventType) {
- return (eventType == ServiceEvent.kIsolateStart);
- }
-
void postServiceEvent(String response, ByteData data) {
var map;
try {
@@ -388,7 +377,7 @@
if (data != null) {
map['_data'] = data;
}
- } catch (e, st) {
+ } catch (_) {
Logger.root.severe('Ignoring malformed event response: ${response}');
return;
}
@@ -398,98 +387,42 @@
return;
}
- var eventType = map['eventType'];
-
- if (_isIsolateLifecycleEvent(eventType)) {
- String isolateId = map['isolate']['id'];
- var event;
- if (_isIsolateStartEvent(eventType)) {
- _onIsolateStart(map['isolate']);
- // By constructing the event *after* adding the isolate to the
- // isolate cache, the call to getFromMap will use the cached Isolate.
- event = new ServiceObject._fromMap(this, map);
- } else {
- assert(_isIsolateExitEvent(eventType));
- // By constructing the event *before* removing the isolate from the
- // isolate cache, the call to getFromMap will use the cached Isolate.
- event = new ServiceObject._fromMap(this, map);
- _onIsolateExit(isolateId);
- }
- assert(event != null);
+ var eventIsolate = map['isolate'];
+ if (eventIsolate == null) {
+ var event = new ServiceObject._fromMap(vm, map);
events.add(event);
- return;
+ } else {
+ // getFromMap creates the Isolate if it hasn't been seen already.
+ var isolate = getFromMap(map['isolate']);
+ var event = new ServiceObject._fromMap(isolate, map);
+ if (event.eventType == ServiceEvent.kIsolateExit) {
+ _removeIsolate(isolate.id);
+ }
+ isolate._onEvent(event);
+ events.add(event);
}
-
- // Extract the owning isolate from the event itself.
- String owningIsolateId = map['isolate']['id'];
- getIsolate(owningIsolateId).then((owningIsolate) {
- if (owningIsolate == null) {
- // TODO(koda): Do we care about GC events in VM isolate?
- Logger.root.severe('Ignoring event with unknown isolate id: '
- '$owningIsolateId');
- return;
- }
- var event = new ServiceObject._fromMap(owningIsolate, map);
- owningIsolate._onEvent(event);
- events.add(event);
- });
}
- Isolate _onIsolateStart(Map isolateMap) {
- var isolateId = isolateMap['id'];
- assert(!_isolateCache.containsKey(isolateId));
- Isolate isolate = new ServiceObject._fromMap(this, isolateMap);
- _isolateCache[isolateId] = isolate;
- notifyPropertyChange(#isolates, true, false);
- // Eagerly load the isolate.
- isolate.load().catchError((e) {
- Logger.root.info('Eagerly loading an isolate failed: $e');
- });
- return isolate;
- }
-
- void _onIsolateExit(String isolateId) {
+ void _removeIsolate(String isolateId) {
assert(_isolateCache.containsKey(isolateId));
_isolateCache.remove(isolateId);
notifyPropertyChange(#isolates, true, false);
}
- void _updateIsolatesFromList(List isolateList) {
- var shutdownIsolates = <String>[];
- var createdIsolates = <Map>[];
- var isolateStillExists = <String, bool>{};
+ void _removeDeadIsolates(List newIsolates) {
+ // Build a set of new isolates.
+ var newIsolateSet = new Set();
+ newIsolates.forEach((iso) => newIsolateSet.add(iso.id));
- // Start with the assumption that all isolates are gone.
- for (var isolateId in _isolateCache.keys) {
- isolateStillExists[isolateId] = false;
- }
-
- // Find created isolates and mark existing isolates as living.
- for (var isolateMap in isolateList) {
- var isolateId = isolateMap['id'];
- if (!_isolateCache.containsKey(isolateId)) {
- createdIsolates.add(isolateMap);
- } else {
- isolateStillExists[isolateId] = true;
- }
- }
-
- // Find shutdown isolates.
- isolateStillExists.forEach((isolateId, exists) {
- if (!exists) {
- shutdownIsolates.add(isolateId);
+ // Remove any old isolates which no longer exist.
+ List toRemove = [];
+ _isolateCache.forEach((id, _) {
+ if (!newIsolateSet.contains(id)) {
+ toRemove.add(id);
}
});
-
- // Process shutdown.
- for (var isolateId in shutdownIsolates) {
- _onIsolateExit(isolateId);
- }
-
- // Process creation.
- for (var isolateMap in createdIsolates) {
- _onIsolateStart(isolateMap);
- }
+ toRemove.forEach((id) => _removeIsolate(id));
+ notifyPropertyChange(#isolates, true, false);
}
static final String _isolateIdPrefix = 'isolates/';
@@ -507,11 +440,16 @@
// Check cache.
var isolate = _isolateCache[id];
if (isolate == null) {
- // We should never see an unknown isolate here.
- throw new UnimplementedError();
- }
- var mapIsRef = _hasRef(map['type']);
- if (!mapIsRef) {
+ // Add new isolate to the cache.
+ isolate = new ServiceObject._fromMap(this, map);
+ _isolateCache[id] = isolate;
+ notifyPropertyChange(#isolates, true, false);
+
+ // Eagerly load the isolate.
+ isolate.load().catchError((e, stack) {
+ Logger.root.info('Eagerly loading an isolate failed: $e\n$stack');
+ });
+ } else {
isolate.update(map);
}
return isolate;
@@ -624,17 +562,22 @@
if (mapIsRef) {
return;
}
+ // Note that upgrading the collection creates any isolates in the
+ // isolate list which are new.
+ _upgradeCollection(map, vm);
+
_loaded = true;
version = map['version'];
targetCPU = map['targetCPU'];
architectureBits = map['architectureBits'];
- uptime = map['uptime'];
- var dateInMillis = int.parse(map['date']);
- lastUpdate = new DateTime.fromMillisecondsSinceEpoch(dateInMillis);
- assertsEnabled = map['assertsEnabled'];
+ var startTimeMillis = map['startTime'];
+ startTime = new DateTime.fromMillisecondsSinceEpoch(startTimeMillis);
+ refreshTime = new DateTime.now();
+ notifyPropertyChange(#upTime, 0, 1);
pid = map['pid'];
- typeChecksEnabled = map['typeChecksEnabled'];
- _updateIsolatesFromList(map['isolates']);
+ assertsEnabled = map['_assertsEnabled'];
+ typeChecksEnabled = map['_typeChecksEnabled'];
+ _removeDeadIsolates(map['isolates']);
}
// Reload all isolates.
@@ -780,9 +723,12 @@
class Isolate extends ServiceObjectOwner with Coverage {
@reflectable VM get vm => owner;
@reflectable Isolate get isolate => this;
- @observable ObservableMap counters = new ObservableMap();
+ @observable int number;
+ @observable DateTime startTime;
+ @observable Duration get upTime =>
+ (new DateTime.now().difference(startTime));
- @observable ServiceEvent pauseEvent = null;
+ @observable ObservableMap counters = new ObservableMap();
void _updateRunState() {
topFrame = (pauseEvent != null ? pauseEvent.topFrame : null);
@@ -796,6 +742,7 @@
notifyPropertyChange(#idle, 0, 1);
}
+ @observable ServiceEvent pauseEvent = null;
@observable bool paused = false;
@observable bool running = false;
@observable bool idle = false;
@@ -863,13 +810,15 @@
if (map == null) {
return null;
}
+ var mapType = _stripRef(map['type']);
+ if (mapType == 'Isolate') {
+ // There are sometimes isolate refs in ServiceEvents.
+ return vm.getFromMap(map);
+ }
String mapId = map['id'];
var obj = (mapId != null) ? _cache[mapId] : null;
if (obj != null) {
- var mapIsRef = _hasRef(map['type']);
- if (!mapIsRef) {
- obj.update(map);
- }
+ obj.update(map);
return obj;
}
// Build the object from the map directly.
@@ -917,7 +866,6 @@
@observable String name;
@observable String vmName;
- @observable String mainPort;
@observable ServiceFunction entry;
@observable final Map<String, double> timers =
@@ -953,9 +901,9 @@
}
void _update(ObservableMap map, bool mapIsRef) {
- mainPort = map['mainPort'];
name = map['name'];
vmName = map['name'];
+ number = int.parse(map['number'], onError:(_) => null);
if (mapIsRef) {
return;
}
@@ -973,7 +921,9 @@
if (map['entry'] != null) {
entry = map['entry'];
}
-
+ var startTimeInMillis = map['startTime'];
+ startTime = new DateTime.fromMillisecondsSinceEpoch(startTimeInMillis);
+ notifyPropertyChange(#upTime, 0, 1);
var countersMap = map['tagCounters'];
if (countersMap != null) {
var names = countersMap['names'];
@@ -1041,21 +991,21 @@
ObservableMap<int, Breakpoint> breakpoints = new ObservableMap();
void _updateBreakpoints(List newBpts) {
- // Build a map of new breakpoints.
- var newBptMap = {};
- newBpts.forEach((bpt) => (newBptMap[bpt.number] = bpt));
+ // Build a set of new breakpoints.
+ var newBptSet = new Set();
+ newBpts.forEach((bpt) => newBptSet.add(bpt.number));
// Remove any old breakpoints which no longer exist.
List toRemove = [];
breakpoints.forEach((key, _) {
- if (!newBptMap.containsKey(key)) {
+ if (!newBptSet.contains(key)) {
toRemove.add(key);
}
});
toRemove.forEach((key) => breakpoints.remove(key));
// Add all new breakpoints.
- breakpoints.addAll(newBptMap);
+ newBpts.forEach((bpt) => (breakpoints[bpt.number] = bpt));
}
void _addBreakpoint(Breakpoint bpt) {
@@ -1068,13 +1018,17 @@
}
void _onEvent(ServiceEvent event) {
- assert(event.eventType != ServiceEvent.kIsolateStart &&
- event.eventType != ServiceEvent.kIsolateExit);
switch(event.eventType) {
+ case ServiceEvent.kIsolateStart:
+ case ServiceEvent.kIsolateExit:
+ // Handled elsewhere.
+ break;
+
case ServiceEvent.kBreakpointAdded:
_addBreakpoint(event.breakpoint);
break;
+ case ServiceEvent.kIsolateUpdate:
case ServiceEvent.kBreakpointResolved:
// Update occurs as side-effect of caching.
break;
@@ -1145,6 +1099,7 @@
// TODO(turnidge): Handle this more gracefully.
Logger.root.severe(result.message);
}
+ return result;
});
}
@@ -1154,6 +1109,7 @@
// TODO(turnidge): Handle this more gracefully.
Logger.root.severe(result.message);
}
+ return result;
});
}
@@ -1163,6 +1119,7 @@
// TODO(turnidge): Handle this more gracefully.
Logger.root.severe(result.message);
}
+ return result;
});
}
@@ -1172,6 +1129,7 @@
// TODO(turnidge): Handle this more gracefully.
Logger.root.severe(result.message);
}
+ return result;
});
}
@@ -1181,9 +1139,17 @@
// TODO(turnidge): Handle this more gracefully.
Logger.root.severe(result.message);
}
+ return result;
});
}
+ Future setName(String newName) {
+ Map params = {
+ 'name': newName,
+ };
+ return invokeRpc('setName', params);
+ }
+
Future<ServiceMap> getStack() {
return invokeRpc('getStack', {}).then((result) {
if (result is DartError) {
@@ -1426,6 +1392,7 @@
/// The possible 'eventType' values.
static const kIsolateStart = 'IsolateStart';
static const kIsolateExit = 'IsolateExit';
+ static const kIsolateUpdate = 'IsolateUpdate';
static const kPauseStart = 'PauseStart';
static const kPauseExit = 'PauseExit';
static const kPauseBreakpoint = 'PauseBreakpoint';
@@ -1455,6 +1422,7 @@
void _update(ObservableMap map, bool mapIsRef) {
_loaded = true;
_upgradeCollection(map, owner);
+ assert(map['isolate'] == null || owner == map['isolate']);
eventType = map['eventType'];
name = 'ServiceEvent $eventType';
vmName = name;
@@ -1663,7 +1631,7 @@
@reflectable final functions = new ObservableList<ServiceFunction>();
@observable Class superclass;
- @reflectable final interfaces = new ObservableList<Class>();
+ @reflectable final interfaces = new ObservableList<Instance>();
@reflectable final subclasses = new ObservableList<Class>();
bool get canCache => true;
@@ -1710,6 +1678,10 @@
subclasses.addAll(map['subclasses']);
subclasses.sort(ServiceObject.LexicalSortName);
+ interfaces.clear();
+ interfaces.addAll(map['interfaces']);
+ interfaces.sort(ServiceObject.LexicalSortName);
+
fields.clear();
fields.addAll(map['fields']);
fields.sort(ServiceObject.LexicalSortName);
@@ -1850,25 +1822,25 @@
bool hasDartCode() => isDart() || isStub();
static FunctionKind fromJSON(String value) {
switch(value) {
- case 'kRegularFunction': return kRegularFunction;
- case 'kClosureFunction': return kClosureFunction;
- case 'kGetterFunction': return kGetterFunction;
- case 'kSetterFunction': return kSetterFunction;
- case 'kConstructor': return kConstructor;
- case 'kImplicitGetter': return kImplicitGetterFunction;
- case 'kImplicitSetter': return kImplicitSetterFunction;
- case 'kImplicitStaticFinalGetter': return kImplicitStaticFinalGetter;
- case 'kIrregexpFunction': return kIrregexpFunction;
- case 'kStaticInitializer': return kStaticInitializer;
- case 'kMethodExtractor': return kMethodExtractor;
- case 'kNoSuchMethodDispatcher': return kNoSuchMethodDispatcher;
- case 'kInvokeFieldDispatcher': return kInvokeFieldDispatcher;
+ case 'RegularFunction': return kRegularFunction;
+ case 'ClosureFunction': return kClosureFunction;
+ case 'GetterFunction': return kGetterFunction;
+ case 'SetterFunction': return kSetterFunction;
+ case 'Constructor': return kConstructor;
+ case 'ImplicitGetter': return kImplicitGetterFunction;
+ case 'ImplicitSetter': return kImplicitSetterFunction;
+ case 'ImplicitStaticFinalGetter': return kImplicitStaticFinalGetter;
+ case 'IrregexpFunction': return kIrregexpFunction;
+ case 'StaticInitializer': return kStaticInitializer;
+ case 'MethodExtractor': return kMethodExtractor;
+ case 'NoSuchMethodDispatcher': return kNoSuchMethodDispatcher;
+ case 'InvokeFieldDispatcher': return kInvokeFieldDispatcher;
case 'Collected': return kCollected;
case 'Native': return kNative;
case 'Stub': return kStub;
case 'Tag': return kTag;
}
- print('did not understand $value');
+ Logger.root.severe('Unrecognized function kind: $value');
throw new FallThroughError();
}
@@ -1893,11 +1865,11 @@
}
class ServiceFunction extends ServiceObject with Coverage {
- @observable Class owningClass;
- @observable Library owningLibrary;
+ // owner is a Library, Class, or ServiceFunction.
+ @observable ServiceObject dartOwner;
+ @observable Library library;
@observable bool isStatic;
@observable bool isConst;
- @observable ServiceFunction parent;
@observable Script script;
@observable int tokenPos;
@observable int endTokenPos;
@@ -1923,17 +1895,23 @@
_upgradeCollection(map, isolate);
- owningClass = map.containsKey('owningClass') ? map['owningClass'] : null;
- owningLibrary = map.containsKey('owningLibrary') ? map['owningLibrary'] : null;
+ dartOwner = map['owner'];
kind = FunctionKind.fromJSON(map['kind']);
isDart = !kind.isSynthetic();
- if (parent == null) {
- qualifiedName = (owningClass != null) ?
- "${owningClass.name}.${name}" :
- name;
+ if (dartOwner is ServiceFunction) {
+ ServiceFunction ownerFunction = dartOwner;
+ library = ownerFunction.library;
+ qualifiedName = "${ownerFunction.qualifiedName}.${name}";
+
+ } else if (dartOwner is Class) {
+ Class ownerClass = dartOwner;
+ library = ownerClass.library;
+ qualifiedName = "${ownerClass.name}.${name}";
+
} else {
- qualifiedName = "${parent.qualifiedName}.${name}";
+ library = dartOwner;
+ qualifiedName = name;
}
if (mapIsRef) {
@@ -1943,22 +1921,23 @@
_loaded = true;
isStatic = map['static'];
isConst = map['const'];
- parent = map['parent'];
script = map['script'];
tokenPos = map['tokenPos'];
endTokenPos = map['endTokenPos'];
- code = _convertNull(map['code']);
- unoptimizedCode = _convertNull(map['unoptimizedCode']);
- isOptimizable = map['optimizable'];
- isInlinable = map['inlinable'];
- deoptimizations = map['deoptimizations'];
- usageCounter = map['usageCounter'];
+ code = map['code'];
+ isOptimizable = map['_optimizable'];
+ isInlinable = map['_inlinable'];
+ unoptimizedCode = map['_unoptimizedCode'];
+ deoptimizations = map['_deoptimizations'];
+ usageCounter = map['_usageCounter'];
}
}
class Field extends ServiceObject {
- @observable var /* Library or Class */ owner;
+ // Library or Class.
+ @observable ServiceObject dartOwner;
+ @observable Library library;
@observable Instance declaredType;
@observable bool isStatic;
@observable bool isFinal;
@@ -1981,27 +1960,35 @@
name = map['name'];
vmName = (map.containsKey('vmName') ? map['vmName'] : name);
- owner = map['owner'];
+ dartOwner = map['owner'];
declaredType = map['declaredType'];
isStatic = map['static'];
isFinal = map['final'];
isConst = map['const'];
value = map['value'];
+ if (dartOwner is Class) {
+ Class ownerClass = dartOwner;
+ library = ownerClass.library;
+
+ } else {
+ library = dartOwner;
+ }
+
if (mapIsRef) {
return;
}
- guardNullable = map['guardNullable'];
- guardClass = map['guardClass'];
- guardLength = map['guardLength'];
+ guardNullable = map['_guardNullable'];
+ guardClass = map['_guardClass'];
+ guardLength = map['_guardLength'];
script = map['script'];
tokenPos = map['tokenPos'];
_loaded = true;
}
- String toString() => 'Field(${owner.name}.$name)';
+ String toString() => 'Field(${dartOwner.name}.$name)';
}
@@ -2137,7 +2124,7 @@
@observable String kind;
@observable int firstTokenPos;
@observable int lastTokenPos;
- @observable Library owningLibrary;
+ @observable Library library;
bool get canCache => true;
bool get immutable => true;
@@ -2171,7 +2158,7 @@
}
_parseTokenPosTable(map['tokenPosTable']);
_processSource(map['source']);
- owningLibrary = map['owningLibrary'];
+ library = map['library'];
}
void _parseTokenPosTable(List<List<int>> table) {
@@ -2494,7 +2481,7 @@
} else if (s == 'Stub') {
return Stub;
}
- print('do not understand code kind $s');
+ Logger.root.severe('Unrecognized code kind: $s');
throw new FallThroughError();
}
static const Collected = const CodeKind._internal('Collected');
@@ -2582,29 +2569,29 @@
void _update(ObservableMap m, bool mapIsRef) {
name = m['name'];
vmName = (m.containsKey('vmName') ? m['vmName'] : name);
- isOptimized = m['optimized'] != null ? m['optimized'] : false;
+ isOptimized = m['_optimized'];
kind = CodeKind.fromString(m['kind']);
- startAddress = int.parse(m['start'], radix:16);
- endAddress = int.parse(m['end'], radix:16);
- function = isolate.getFromMap(m['function']);
if (mapIsRef) {
return;
}
_loaded = true;
- objectPool = isolate.getFromMap(m['objectPool']);
- var disassembly = m['disassembly'];
+ startAddress = int.parse(m['_startAddress'], radix:16);
+ endAddress = int.parse(m['_endAddress'], radix:16);
+ function = isolate.getFromMap(m['function']);
+ objectPool = isolate.getFromMap(m['_objectPool']);
+ var disassembly = m['_disassembly'];
if (disassembly != null) {
_processDisassembly(disassembly);
}
- var descriptors = m['descriptors'];
+ var descriptors = m['_descriptors'];
if (descriptors != null) {
descriptors = descriptors['members'];
_processDescriptors(descriptors);
}
hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart);
inlinedFunctions.clear();
- var inlinedFunctionsTable = m['inlinedFunctions'];
- var inlinedIntervals = m['inlinedIntervals'];
+ var inlinedFunctionsTable = m['_inlinedFunctions'];
+ var inlinedIntervals = m['_inlinedIntervals'];
if (inlinedFunctionsTable != null) {
// Iterate and upgrade each ServiceFunction.
for (var i = 0; i < inlinedFunctionsTable.length; i++) {
@@ -2913,14 +2900,6 @@
}
}
-// Convert any ServiceMaps representing a null instance into an actual null.
-_convertNull(obj) {
- if (obj.isNull) {
- return null;
- }
- return obj;
-}
-
// Returns true if [map] is a service map. i.e. it has the following keys:
// 'id' and a 'type'.
bool _isServiceMap(ObservableMap m) {
diff --git a/runtime/observatory/observatory.gypi b/runtime/observatory/observatory.gypi
index 46c126c..a53185f 100644
--- a/runtime/observatory/observatory.gypi
+++ b/runtime/observatory/observatory.gypi
@@ -49,132 +49,8 @@
'../pkg/pkg.gyp:pkg_packages#target',
],
'toolsets': ['host'],
- 'sources': [
- 'lib/app.dart',
- 'lib/cpu_profile.dart',
- 'lib/dominator_tree.dart',
- 'lib/elements.dart',
- 'lib/object_graph.dart',
- 'lib/service_common.dart',
- 'lib/service_io.dart',
- 'lib/service_html.dart',
- 'lib/src/app/application.dart',
- 'lib/src/app/chart.dart',
- 'lib/src/app/location_manager.dart',
- 'lib/src/app/page.dart',
- 'lib/src/app/settings.dart',
- 'lib/src/app/target_manager.dart',
- 'lib/src/app/view_model.dart',
- 'lib/src/cpu_profile/cpu_profile.dart',
- 'lib/src/elements/action_link.dart',
- 'lib/src/elements/action_link.html',
- 'lib/src/elements/class_ref.dart',
- 'lib/src/elements/class_ref.html',
- 'lib/src/elements/class_tree.dart',
- 'lib/src/elements/class_tree.html',
- 'lib/src/elements/class_view.dart',
- 'lib/src/elements/class_view.html',
- 'lib/src/elements/code_ref.dart',
- 'lib/src/elements/code_ref.html',
- 'lib/src/elements/code_view.dart',
- 'lib/src/elements/code_view.html',
- 'lib/src/elements/context_ref.dart',
- 'lib/src/elements/context_ref.html',
- 'lib/src/elements/context_view.dart',
- 'lib/src/elements/context_view.html',
- 'lib/src/elements/cpu_profile.dart',
- 'lib/src/elements/cpu_profile.html',
- 'lib/src/elements/curly_block.dart',
- 'lib/src/elements/curly_block.html',
- 'lib/src/elements/debugger.dart',
- 'lib/src/elements/debugger.html',
- 'lib/src/elements/error_ref.dart',
- 'lib/src/elements/error_ref.html',
- 'lib/src/elements/error_view.dart',
- 'lib/src/elements/error_view.html',
- 'lib/src/elements/eval_box.dart',
- 'lib/src/elements/eval_box.html',
- 'lib/src/elements/eval_link.dart',
- 'lib/src/elements/eval_link.html',
- 'lib/src/elements/field_ref.dart',
- 'lib/src/elements/field_ref.html',
- 'lib/src/elements/field_view.dart',
- 'lib/src/elements/field_view.html',
- 'lib/src/elements/flag_list.dart',
- 'lib/src/elements/flag_list.html',
- 'lib/src/elements/function_ref.dart',
- 'lib/src/elements/function_ref.html',
- 'lib/src/elements/function_view.dart',
- 'lib/src/elements/function_view.html',
- 'lib/src/elements/general_error.dart',
- 'lib/src/elements/general_error.html',
- 'lib/src/elements/heap_map.dart',
- 'lib/src/elements/heap_map.html',
- 'lib/src/elements/heap_profile.dart',
- 'lib/src/elements/heap_profile.html',
- 'lib/src/elements/inbound_reference.dart',
- 'lib/src/elements/inbound_reference.html',
- 'lib/src/elements/instance_ref.dart',
- 'lib/src/elements/instance_ref.html',
- 'lib/src/elements/instance_view.dart',
- 'lib/src/elements/instance_view.html',
- 'lib/src/elements/io_view.dart',
- 'lib/src/elements/io_view.html',
- 'lib/src/elements/isolate_ref.dart',
- 'lib/src/elements/isolate_ref.html',
- 'lib/src/elements/isolate_summary.dart',
- 'lib/src/elements/isolate_summary.html',
- 'lib/src/elements/isolate_view.dart',
- 'lib/src/elements/isolate_view.html',
- 'lib/src/elements/json_view.dart',
- 'lib/src/elements/json_view.html',
- 'lib/src/elements/library_ref.dart',
- 'lib/src/elements/library_ref.html',
- 'lib/src/elements/library_view.dart',
- 'lib/src/elements/library_view.html',
- 'lib/src/elements/metrics.dart',
- 'lib/src/elements/metrics.html',
- 'lib/src/elements/nav_bar.dart',
- 'lib/src/elements/nav_bar.html',
- 'lib/src/elements/object_common.dart',
- 'lib/src/elements/object_common.html',
- 'lib/src/elements/object_view.dart',
- 'lib/src/elements/object_view.html',
- 'lib/src/elements/observatory_application.dart',
- 'lib/src/elements/observatory_application.html',
- 'lib/src/elements/observatory_element.dart',
- 'lib/src/elements/observatory_element.html',
- 'lib/src/elements/script_inset.dart',
- 'lib/src/elements/script_inset.html',
- 'lib/src/elements/script_ref.dart',
- 'lib/src/elements/script_ref.html',
- 'lib/src/elements/script_view.dart',
- 'lib/src/elements/script_view.html',
- 'lib/src/elements/service_error_view.dart',
- 'lib/src/elements/service_error_view.html',
- 'lib/src/elements/service_exception_view.dart',
- 'lib/src/elements/service_exception_view.html',
- 'lib/src/elements/service_ref.dart',
- 'lib/src/elements/service_ref.html',
- 'lib/src/elements/service_view.dart',
- 'lib/src/elements/service_view.html',
- 'lib/src/elements/sliding_checkbox.dart',
- 'lib/src/elements/sliding_checkbox.html',
- 'lib/src/elements/vm_connect.dart',
- 'lib/src/elements/vm_connect.html',
- 'lib/src/elements/vm_ref.dart',
- 'lib/src/elements/vm_ref.html',
- 'lib/src/elements/vm_view.dart',
- 'lib/src/elements/vm_view.html',
- 'lib/src/elements/css/shared.css',
- 'lib/src/elements/img/chromium_icon.png',
- 'lib/src/elements/img/dart_icon.png',
- 'lib/src/elements/img/isolate_icon.png',
- 'lib/src/service/object.dart',
- 'lib/tracer.dart',
- 'lib/utils.dart',
- 'web/index.html',
- 'web/main.dart',
+ 'includes': [
+ 'observatory_sources.gypi',
],
'actions': [
{
diff --git a/runtime/observatory/observatory.status b/runtime/observatory/observatory.status
deleted file mode 100644
index e7bb129..0000000
--- a/runtime/observatory/observatory.status
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-[ $compiler == dart2dart ]
-# The transformations of dart2dart are not guaranteed to preserve the
-# state/properties of the VM that the Observatory tests are inspecting.
-observatory/test/*: Skip
-
-[ $browser ]
-observatory/test/*: SkipByDesign # Uses dart:io
diff --git a/runtime/observatory/observatory_sources.gypi b/runtime/observatory/observatory_sources.gypi
new file mode 100644
index 0000000..d16cbd8
--- /dev/null
+++ b/runtime/observatory/observatory_sources.gypi
@@ -0,0 +1,142 @@
+# Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# This file contains all dart, css, and html sources for Observatory.
+{
+ 'sources': [
+ 'lib/app.dart',
+ 'lib/cli.dart',
+ 'lib/cpu_profile.dart',
+ 'lib/debugger.dart',
+ 'lib/dominator_tree.dart',
+ 'lib/elements.dart',
+ 'lib/elements.html',
+ 'lib/object_graph.dart',
+ 'lib/service.dart',
+ 'lib/service_common.dart',
+ 'lib/service_io.dart',
+ 'lib/service_html.dart',
+ 'lib/src/app/application.dart',
+ 'lib/src/app/chart.dart',
+ 'lib/src/app/location_manager.dart',
+ 'lib/src/app/page.dart',
+ 'lib/src/app/settings.dart',
+ 'lib/src/app/target_manager.dart',
+ 'lib/src/app/view_model.dart',
+ 'lib/src/cli/command.dart',
+ 'lib/src/cpu_profile/cpu_profile.dart',
+ 'lib/src/debugger/debugger.dart',
+ 'lib/src/debugger/source_location.dart',
+ 'lib/src/elements/action_link.dart',
+ 'lib/src/elements/action_link.html',
+ 'lib/src/elements/class_ref.dart',
+ 'lib/src/elements/class_ref.html',
+ 'lib/src/elements/class_tree.dart',
+ 'lib/src/elements/class_tree.html',
+ 'lib/src/elements/class_view.dart',
+ 'lib/src/elements/class_view.html',
+ 'lib/src/elements/code_ref.dart',
+ 'lib/src/elements/code_ref.html',
+ 'lib/src/elements/code_view.dart',
+ 'lib/src/elements/code_view.html',
+ 'lib/src/elements/context_ref.dart',
+ 'lib/src/elements/context_ref.html',
+ 'lib/src/elements/context_view.dart',
+ 'lib/src/elements/context_view.html',
+ 'lib/src/elements/cpu_profile.dart',
+ 'lib/src/elements/cpu_profile.html',
+ 'lib/src/elements/curly_block.dart',
+ 'lib/src/elements/curly_block.html',
+ 'lib/src/elements/debugger.dart',
+ 'lib/src/elements/debugger.html',
+ 'lib/src/elements/error_ref.dart',
+ 'lib/src/elements/error_ref.html',
+ 'lib/src/elements/error_view.dart',
+ 'lib/src/elements/error_view.html',
+ 'lib/src/elements/eval_box.dart',
+ 'lib/src/elements/eval_box.html',
+ 'lib/src/elements/eval_link.dart',
+ 'lib/src/elements/eval_link.html',
+ 'lib/src/elements/field_ref.dart',
+ 'lib/src/elements/field_ref.html',
+ 'lib/src/elements/field_view.dart',
+ 'lib/src/elements/field_view.html',
+ 'lib/src/elements/flag_list.dart',
+ 'lib/src/elements/flag_list.html',
+ 'lib/src/elements/function_ref.dart',
+ 'lib/src/elements/function_ref.html',
+ 'lib/src/elements/function_view.dart',
+ 'lib/src/elements/function_view.html',
+ 'lib/src/elements/general_error.dart',
+ 'lib/src/elements/general_error.html',
+ 'lib/src/elements/heap_map.dart',
+ 'lib/src/elements/heap_map.html',
+ 'lib/src/elements/heap_profile.dart',
+ 'lib/src/elements/heap_profile.html',
+ 'lib/src/elements/inbound_reference.dart',
+ 'lib/src/elements/inbound_reference.html',
+ 'lib/src/elements/instance_ref.dart',
+ 'lib/src/elements/instance_ref.html',
+ 'lib/src/elements/instance_view.dart',
+ 'lib/src/elements/instance_view.html',
+ 'lib/src/elements/io_view.dart',
+ 'lib/src/elements/io_view.html',
+ 'lib/src/elements/isolate_ref.dart',
+ 'lib/src/elements/isolate_ref.html',
+ 'lib/src/elements/isolate_summary.dart',
+ 'lib/src/elements/isolate_summary.html',
+ 'lib/src/elements/isolate_view.dart',
+ 'lib/src/elements/isolate_view.html',
+ 'lib/src/elements/json_view.dart',
+ 'lib/src/elements/json_view.html',
+ 'lib/src/elements/library_ref.dart',
+ 'lib/src/elements/library_ref.html',
+ 'lib/src/elements/library_view.dart',
+ 'lib/src/elements/library_view.html',
+ 'lib/src/elements/metrics.dart',
+ 'lib/src/elements/metrics.html',
+ 'lib/src/elements/nav_bar.dart',
+ 'lib/src/elements/nav_bar.html',
+ 'lib/src/elements/object_common.dart',
+ 'lib/src/elements/object_common.html',
+ 'lib/src/elements/object_view.dart',
+ 'lib/src/elements/object_view.html',
+ 'lib/src/elements/observatory_application.dart',
+ 'lib/src/elements/observatory_application.html',
+ 'lib/src/elements/observatory_element.dart',
+ 'lib/src/elements/observatory_element.html',
+ 'lib/src/elements/script_inset.dart',
+ 'lib/src/elements/script_inset.html',
+ 'lib/src/elements/script_ref.dart',
+ 'lib/src/elements/script_ref.html',
+ 'lib/src/elements/script_view.dart',
+ 'lib/src/elements/script_view.html',
+ 'lib/src/elements/service_error_view.dart',
+ 'lib/src/elements/service_error_view.html',
+ 'lib/src/elements/service_exception_view.dart',
+ 'lib/src/elements/service_exception_view.html',
+ 'lib/src/elements/service_ref.dart',
+ 'lib/src/elements/service_ref.html',
+ 'lib/src/elements/service_view.dart',
+ 'lib/src/elements/service_view.html',
+ 'lib/src/elements/sliding_checkbox.dart',
+ 'lib/src/elements/sliding_checkbox.html',
+ 'lib/src/elements/vm_connect.dart',
+ 'lib/src/elements/vm_connect.html',
+ 'lib/src/elements/vm_ref.dart',
+ 'lib/src/elements/vm_ref.html',
+ 'lib/src/elements/vm_view.dart',
+ 'lib/src/elements/vm_view.html',
+ 'lib/src/elements/css/shared.css',
+ 'lib/src/elements/img/chromium_icon.png',
+ 'lib/src/elements/img/dart_icon.png',
+ 'lib/src/elements/img/isolate_icon.png',
+ 'lib/src/service/object.dart',
+ 'lib/tracer.dart',
+ 'lib/utils.dart',
+ 'web/index.html',
+ 'web/main.dart',
+ 'web/favicon.ico',
+ ],
+}
\ No newline at end of file
diff --git a/runtime/observatory/test/vm_test.dart b/runtime/observatory/test/vm_test.dart
deleted file mode 100644
index 86fa089..0000000
--- a/runtime/observatory/test/vm_test.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-import 'package:observatory/service_io.dart';
-import 'package:unittest/unittest.dart';
-import 'test_helper.dart';
-
-var tests = [
-
-(Isolate isolate) {
- VM vm = isolate.owner;
- expect(vm.targetCPU, isNotNull);
- expect(vm.architectureBits == 32 ||
- vm.architectureBits == 64, isTrue);
-},
-
-];
-
-main(args) => runIsolateTests(args, tests);
diff --git a/runtime/observatory/test/allocations_test.dart b/runtime/observatory/tests/service/allocations_test.dart
similarity index 91%
rename from runtime/observatory/test/allocations_test.dart
rename to runtime/observatory/tests/service/allocations_test.dart
index 959276d..4242afc 100644
--- a/runtime/observatory/test/allocations_test.dart
+++ b/runtime/observatory/tests/service/allocations_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
library allocations_test;
diff --git a/runtime/observatory/test/async_generator_breakpoint_test.dart b/runtime/observatory/tests/service/async_generator_breakpoint_test.dart
similarity index 76%
rename from runtime/observatory/test/async_generator_breakpoint_test.dart
rename to runtime/observatory/tests/service/async_generator_breakpoint_test.dart
index 5e8d802..91141fa 100644
--- a/runtime/observatory/test/async_generator_breakpoint_test.dart
+++ b/runtime/observatory/tests/service/async_generator_breakpoint_test.dart
@@ -1,24 +1,22 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-
-// VMOptions=--verbose-debug
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked --verbose-debug
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
import 'test_helper.dart';
-import 'dart:async';
-printSync() { // Line 12
+printSync() { // Line 10
print('sync');
}
-printAsync() async { // Line 15
+printAsync() async { // Line 13
print('async');
}
-printAsyncStar() async* { // Line 18
+printAsyncStar() async* { // Line 16
print('async*');
}
-printSyncStar() sync* { // Line 21
+printSyncStar() sync* { // Line 19
print('sync*');
}
@@ -36,7 +34,7 @@
var stream = printAsyncStar();
var iterator = printSyncStar();
- print('middle'); // Line 39.
+ print('middle'); // Line 37.
future.then((v) => print(v));
stream.toList();
@@ -47,26 +45,27 @@
await isolate.rootLib.load();
var script = isolate.rootLib.scripts[0];
- var bp1 = await isolate.addBreakpoint(script, 12);
+ var bp1 = await isolate.addBreakpoint(script, 10);
expect(bp1, isNotNull);
expect(bp1 is Breakpoint, isTrue);
- var bp2 = await isolate.addBreakpoint(script, 15);
+ var bp2 = await isolate.addBreakpoint(script, 13);
expect(bp2, isNotNull);
expect(bp2 is Breakpoint, isTrue);
- var bp3 = await isolate.addBreakpoint(script, 18);
+ var bp3 = await isolate.addBreakpoint(script, 16);
expect(bp3, isNotNull);
expect(bp3 is Breakpoint, isTrue);
- var bp4 = await isolate.addBreakpoint(script, 21);
+ var bp4 = await isolate.addBreakpoint(script, 19);
expect(bp4, isNotNull);
expect(bp4 is Breakpoint, isTrue);
- var bp5 = await isolate.addBreakpoint(script, 39);
+ var bp5 = await isolate.addBreakpoint(script, 37);
+ print("BP5 - $bp5");
expect(bp5, isNotNull);
expect(bp5 is Breakpoint, isTrue);
var hits = [];
isolate.eval(isolate.rootLib, 'testerReady = true;')
- .then((ServiceObject result) {
+ .then((Instance result) {
expect(result.valueAsString, equals('true'));
});
diff --git a/runtime/observatory/test/bad_web_socket_address_test.dart b/runtime/observatory/tests/service/bad_web_socket_address_test.dart
similarity index 87%
rename from runtime/observatory/test/bad_web_socket_address_test.dart
rename to runtime/observatory/tests/service/bad_web_socket_address_test.dart
index 65de6cf..06ba878 100644
--- a/runtime/observatory/test/bad_web_socket_address_test.dart
+++ b/runtime/observatory/tests/service/bad_web_socket_address_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import "package:observatory/service_io.dart";
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/test/caching_test.dart b/runtime/observatory/tests/service/caching_test.dart
similarity index 92%
rename from runtime/observatory/test/caching_test.dart
rename to runtime/observatory/tests/service/caching_test.dart
index dacfb18..68cb158 100644
--- a/runtime/observatory/test/caching_test.dart
+++ b/runtime/observatory/tests/service/caching_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
// If caching is working properly, the coverage data will go into the same
// Script object from which we requested coverage data, instead of a new
@@ -11,7 +12,6 @@
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
import 'test_helper.dart';
-import 'dart:async';
script() {
print("This executed");
diff --git a/runtime/observatory/test/call_site_data_test.dart b/runtime/observatory/tests/service/call_site_data_test.dart
similarity index 91%
rename from runtime/observatory/test/call_site_data_test.dart
rename to runtime/observatory/tests/service/call_site_data_test.dart
index 366c721..017bf98 100644
--- a/runtime/observatory/test/call_site_data_test.dart
+++ b/runtime/observatory/tests/service/call_site_data_test.dart
@@ -1,13 +1,13 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
library call_site_data_test;
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
import 'test_helper.dart';
-import 'dart:async';
class A { foo() => 'A'; }
class B { foo() => 'B'; }
@@ -88,7 +88,7 @@
Library lib = await isolate.rootLib.load();
ServiceFunction func =
lib.functions.singleWhere((f) => f.name == 'monomorphic');
- Map response = await isolate.invokeRpcNoUpgrade('getCallSiteData',
+ Map response = await isolate.invokeRpcNoUpgrade('_getCallSiteData',
{ 'targetId': func.id });
expect(response['type'], equals('CodeCoverage'));
Map callSite = response['coverage'].single['callSites'].single;
@@ -101,7 +101,7 @@
Library lib = await isolate.rootLib.load();
ServiceFunction func =
lib.functions.singleWhere((f) => f.name == 'polymorphic');
- Map response = await isolate.invokeRpcNoUpgrade('getCallSiteData',
+ Map response = await isolate.invokeRpcNoUpgrade('_getCallSiteData',
{ 'targetId': func.id });
expect(response['type'], equals('CodeCoverage'));
Map callSite = response['coverage'].single['callSites'].single;
@@ -114,7 +114,7 @@
Library lib = await isolate.rootLib.load();
ServiceFunction func =
lib.functions.singleWhere((f) => f.name == 'megamorphic');
- Map response = await isolate.invokeRpcNoUpgrade('getCallSiteData',
+ Map response = await isolate.invokeRpcNoUpgrade('_getCallSiteData',
{ 'targetId': func.id });
expect(response['type'], equals('CodeCoverage'));
Map callSite = response['coverage'].single['callSites'].single;
@@ -128,7 +128,7 @@
Library lib = await isolate.rootLib.load();
ServiceFunction func =
lib.functions.singleWhere((f) => f.name == 'staticCall');
- Map response = await isolate.invokeRpcNoUpgrade('getCallSiteData',
+ Map response = await isolate.invokeRpcNoUpgrade('_getCallSiteData',
{ 'targetId': func.id });
expect(response['type'], equals('CodeCoverage'));
Map callSite = response['coverage'].single['callSites'].single;
@@ -141,7 +141,7 @@
Library lib = await isolate.rootLib.load();
ServiceFunction func =
lib.functions.singleWhere((f) => f.name == 'constructorCall');
- Map response = await isolate.invokeRpcNoUpgrade('getCallSiteData',
+ Map response = await isolate.invokeRpcNoUpgrade('_getCallSiteData',
{ 'targetId': func.id });
expect(response['type'], equals('CodeCoverage'));
Map callSite = response['coverage'].single['callSites'].single;
@@ -154,7 +154,7 @@
Library lib = await isolate.rootLib.load();
ServiceFunction func =
lib.functions.singleWhere((f) => f.name == 'topLevelCall');
- Map response = await isolate.invokeRpcNoUpgrade('getCallSiteData',
+ Map response = await isolate.invokeRpcNoUpgrade('_getCallSiteData',
{ 'targetId': func.id });
expect(response['type'], equals('CodeCoverage'));
Map callSite = response['coverage'].single['callSites'].single;
@@ -167,7 +167,7 @@
Library lib = await isolate.rootLib.load();
Class cls = await lib.classes.singleWhere((f) => f.name == 'Sub').load();
ServiceFunction func = cls.functions.singleWhere((f) => f.name == 'bar');
- Map response = await isolate.invokeRpcNoUpgrade('getCallSiteData',
+ Map response = await isolate.invokeRpcNoUpgrade('_getCallSiteData',
{ 'targetId': func.id });
expect(response['type'], equals('CodeCoverage'));
Map callSite = response['coverage'].single['callSites'].single;
diff --git a/runtime/observatory/test/classes_test.dart b/runtime/observatory/tests/service/classes_test.dart
similarity index 82%
rename from runtime/observatory/test/classes_test.dart
rename to runtime/observatory/tests/service/classes_test.dart
index 85b64bb..9e8e286 100644
--- a/runtime/observatory/test/classes_test.dart
+++ b/runtime/observatory/tests/service/classes_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -15,7 +16,7 @@
(Isolate isolate) =>
isolate.getObject('classes/62').then((Class c) {
- expect(c.name, equals('_List'));
+ expect(c.name, equals('_ImmutableList'));
expect(c.vmCid, equals(62));
}),
diff --git a/runtime/observatory/test/code_test.dart b/runtime/observatory/tests/service/code_test.dart
similarity index 96%
rename from runtime/observatory/test/code_test.dart
rename to runtime/observatory/tests/service/code_test.dart
index 16806ee..b91972c 100644
--- a/runtime/observatory/test/code_test.dart
+++ b/runtime/observatory/tests/service/code_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -33,7 +34,6 @@
return isolate.rootLib.load().then((_) {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
- List events = [];
isolate.vm.events.stream.listen((ServiceEvent event) {
if (event.eventType == ServiceEvent.kPauseBreakpoint) {
print('Breakpoint reached');
diff --git a/runtime/observatory/test/command_test.dart b/runtime/observatory/tests/service/command_test.dart
similarity index 98%
rename from runtime/observatory/test/command_test.dart
rename to runtime/observatory/tests/service/command_test.dart
index 260684e..a52f1a1 100644
--- a/runtime/observatory/test/command_test.dart
+++ b/runtime/observatory/tests/service/command_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'dart:async';
@@ -63,7 +64,7 @@
cmd.completeCommand('alpha').then((result) {
expect(result, equals(['alpha ']));
});
-
+
// Extra space, no subcommands.
cmd.completeCommand('alpha ').then((result) {
expect(result, equals(['alpha ']));
@@ -168,7 +169,7 @@
new TestCommand(out, 'alpha', [
new TestCommand(out, 'beta', []),
new TestCommand(out, 'gamma', [])])]);
-
+
cmd.runCommand('a b').then(expectAsync((_) {
expect(out.toString(), equals('executing beta([])\n'));
out.clear();
diff --git a/runtime/observatory/test/contexts_test.dart b/runtime/observatory/tests/service/contexts_test.dart
similarity index 82%
rename from runtime/observatory/test/contexts_test.dart
rename to runtime/observatory/tests/service/contexts_test.dart
index dc0f6e9..7928a74 100644
--- a/runtime/observatory/test/contexts_test.dart
+++ b/runtime/observatory/tests/service/contexts_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
library inbound_references_test;
@@ -72,7 +73,11 @@
return block.closureCtxt.load().then((Context ctxt) {
expect(ctxt.variables.single['value'].isString, isTrue);
expect(ctxt.variables.single['value'].valueAsString, equals('I could be copied into the block'));
- expect(block.closureCtxt.parentContext.isNull, isTrue);
+ expect(ctxt.parentContext.isContext, isTrue);
+ expect(ctxt.parentContext.length, equals(0));
+ return ctxt.parentContext.load().then((Context outerCtxt) {
+ expect(outerCtxt.parentContext.isNull, isTrue);
+ });
});
});
}),
@@ -87,7 +92,11 @@
return block.closureCtxt.load().then((ctxt) {
expect(ctxt.variables.single['value'].isInt, isTrue);
expect(ctxt.variables.single['value'].valueAsString, equals('43'));
- expect(ctxt.parentContext.isNull, isTrue);
+ expect(ctxt.parentContext.isContext, isTrue);
+ expect(ctxt.parentContext.length, equals(0));
+ return ctxt.parentContext.load().then((Context outerCtxt) {
+ expect(outerCtxt.parentContext.isNull, isTrue);
+ });
});
});
}),
@@ -107,7 +116,11 @@
return ctxt.parentContext.load().then((Context outerCtxt) {
expect(outerCtxt.variables.single['value'].isInt, isTrue);
expect(outerCtxt.variables.single['value'].valueAsString, equals('421'));
- expect(outerCtxt.parentContext.isNull, isTrue);
+ expect(outerCtxt.parentContext.isContext, isTrue);
+ expect(outerCtxt.parentContext.length, equals(0));
+ return outerCtxt.parentContext.load().then((Context outerCtxt2) {
+ expect(outerCtxt2.parentContext.isNull, isTrue);
+ });
});
});
});
diff --git a/runtime/observatory/test/coverage_test.dart b/runtime/observatory/tests/service/coverage_test.dart
similarity index 84%
rename from runtime/observatory/test/coverage_test.dart
rename to runtime/observatory/tests/service/coverage_test.dart
index 207b67d..db9db76 100644
--- a/runtime/observatory/test/coverage_test.dart
+++ b/runtime/observatory/tests/service/coverage_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -56,7 +57,6 @@
return isolate.rootLib.load().then((_) {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
- List events = [];
isolate.vm.events.stream.listen((ServiceEvent event) {
if (event.eventType == ServiceEvent.kPauseBreakpoint) {
print('Breakpoint reached');
@@ -83,12 +83,13 @@
// Make sure we are in the right place.
expect(stack.type, equals('Stack'));
expect(stack['frames'].length, greaterThanOrEqualTo(2));
- expect(stack['frames'][0]['function'].owningClass.name, equals('MyClass'));
+ expect(stack['frames'][0]['function'].name, equals('myFunction'));
+ expect(stack['frames'][0]['function'].dartOwner.name, equals('MyClass'));
var lib = isolate.rootLib;
var func = stack['frames'][0]['function'];
expect(func.name, equals('myFunction'));
- var cls = stack['frames'][0]['function'].owningClass;
+ var cls = stack['frames'][0]['function'].dartOwner;
expect(cls.name, equals('MyClass'));
List tests = [];
@@ -99,7 +100,7 @@
expect(coverage['type'], equals('CodeCoverage'));
expect(coverage['coverage'].length, equals(1));
expect(normalize(coverage['coverage'][0]['hits']),
- equals([14, 1, 15, 1, 16, 0, 18, 1]));
+ equals([15, 1, 16, 1, 17, 0, 19, 1]));
}));
// Class
tests.add(isolate.invokeRpcNoUpgrade('getCoverage',
@@ -108,8 +109,8 @@
expect(coverage['type'], equals('CodeCoverage'));
expect(coverage['coverage'].length, equals(1));
expect(normalize(coverage['coverage'][0]['hits']),
- equals([14, 1, 15, 1, 16, 0, 18, 1,
- 23, 1, 24, 1, 26, 0]));
+ equals([15, 1, 16, 1, 17, 0, 19, 1,
+ 24, 1, 25, 1, 27, 0]));
}));
// Library
tests.add(isolate.invokeRpcNoUpgrade('getCoverage',
@@ -118,10 +119,10 @@
expect(coverage['type'], equals('CodeCoverage'));
expect(coverage['coverage'].length, equals(3));
expect(normalize(coverage['coverage'][0]['hits']),
- equals([14, 1, 15, 1, 16, 0, 18, 1,
- 23, 1, 24, 1, 26, 0]));
+ equals([15, 1, 16, 1, 17, 0, 19, 1,
+ 24, 1, 25, 1, 27, 0]));
expect(normalize(coverage['coverage'][1]['hits']).take(12),
- equals([32, 0, 35, 0, 36, 0, 32, 1, 35, 1, 36, 0]));
+ equals([33, 1, 36, 1, 37, 0, 32, 1, 45, 0, 46, 0]));
}));
// Script
tests.add(cls.load().then((_) {
@@ -131,10 +132,10 @@
expect(coverage['type'], equals('CodeCoverage'));
expect(coverage['coverage'].length, equals(3));
expect(normalize(coverage['coverage'][0]['hits']),
- equals([14, 1, 15, 1, 16, 0, 18, 1,
- 23, 1, 24, 1, 26, 0]));
+ equals([15, 1, 16, 1, 17, 0, 19, 1,
+ 24, 1, 25, 1, 27, 0]));
expect(normalize(coverage['coverage'][1]['hits']).take(12),
- equals([32, 0, 35, 0, 36, 0, 32, 1, 35, 1, 36, 0]));
+ equals([33, 1, 36, 1, 37, 0, 32, 1, 45, 0, 46, 0]));
});
}));
// Isolate
diff --git a/runtime/observatory/test/debugging_test.dart b/runtime/observatory/tests/service/debugging_test.dart
similarity index 92%
rename from runtime/observatory/test/debugging_test.dart
rename to runtime/observatory/tests/service/debugging_test.dart
index c149ff7..c60b145 100644
--- a/runtime/observatory/test/debugging_test.dart
+++ b/runtime/observatory/tests/service/debugging_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -55,7 +56,6 @@
return isolate.rootLib.load().then((_) {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
- List events = [];
var subscription;
subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
if (event.eventType == ServiceEvent.kPauseBreakpoint) {
@@ -72,7 +72,7 @@
Breakpoint bpt = result;
expect(bpt.type, equals('Breakpoint'));
expect(bpt.script.id, equals(script.id));
- expect(bpt.tokenPos, equals(66));
+ expect(bpt.tokenPos, equals(58));
expect(isolate.breakpoints.length, equals(1));
return completer.future; // Wait for breakpoint events.
});
@@ -85,6 +85,7 @@
expect(stack.type, equals('Stack'));
expect(stack['frames'].length, greaterThanOrEqualTo(1));
expect(stack['frames'][0]['function'].name, equals('testFunction'));
+ expect(stack['frames'][0]['tokenPos'], equals(58));
});
},
@@ -92,7 +93,6 @@
(Isolate isolate) {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
- List events = [];
var subscription;
subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
if (event.eventType == ServiceEvent.kPauseBreakpoint) {
@@ -101,18 +101,19 @@
completer.complete();
}
});
-
+
return isolate.stepInto().then((isolate) {
return completer.future; // Wait for breakpoint events.
});
},
-// Get the stack trace again. We are in 'helper'.
+// Get the stack trace again. Our position has updated.
(Isolate isolate) {
return isolate.getStack().then((ServiceMap stack) {
expect(stack.type, equals('Stack'));
expect(stack['frames'].length, greaterThanOrEqualTo(2));
- expect(stack['frames'][0]['function'].name, equals('helper'));
+ expect(stack['frames'][0]['function'].name, equals('testFunction'));
+ expect(stack['frames'][0]['tokenPos'], equals(60));
});
},
@@ -120,7 +121,6 @@
(Isolate isolate) {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
- List events = [];
var subscription;
subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
if (event.eventType == ServiceEvent.kBreakpointRemoved) {
@@ -156,7 +156,6 @@
(Isolate isolate) {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
- List events = [];
var subscription;
subscription = isolate.vm.events.stream.listen((ServiceEvent event) {
if (event.eventType == ServiceEvent.kPauseBreakpoint) {
@@ -165,7 +164,7 @@
completer.complete();
}
});
-
+
// Find a specific function.
ServiceFunction function = isolate.rootLib.functions.firstWhere(
(f) => f.name == 'helper');
@@ -177,7 +176,7 @@
Breakpoint bpt = result;
expect(bpt.type, equals('Breakpoint'));
expect(bpt.script.name, equals('debugging_test.dart'));
- expect(bpt.tokenPos, equals(28));
+ expect(bpt.tokenPos, equals(29));
expect(isolate.breakpoints.length, equals(1));
return completer.future; // Wait for breakpoint events.
});
diff --git a/runtime/observatory/test/dominator_tree_test.dart b/runtime/observatory/tests/service/dominator_tree_test.dart
similarity index 94%
rename from runtime/observatory/test/dominator_tree_test.dart
rename to runtime/observatory/tests/service/dominator_tree_test.dart
index 0bd52b3..6db7b3c 100644
--- a/runtime/observatory/test/dominator_tree_test.dart
+++ b/runtime/observatory/tests/service/dominator_tree_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'package:observatory/dominator_tree.dart';
import 'package:unittest/unittest.dart';
@@ -39,7 +40,7 @@
expect(d.dominator('A'), equals('R'));
expect(d.dominator('D'), equals('R'));
expect(d.dominator('B'), equals('R'));
-
+
expect(d.dominator('F'), equals('C'));
expect(d.dominator('G'), equals('C'));
expect(d.dominator('J'), equals('G'));
diff --git a/runtime/observatory/test/echo_test.dart b/runtime/observatory/tests/service/echo_test.dart
similarity index 93%
rename from runtime/observatory/test/echo_test.dart
rename to runtime/observatory/tests/service/echo_test.dart
index 6a10e24..1e68a2b 100644
--- a/runtime/observatory/test/echo_test.dart
+++ b/runtime/observatory/tests/service/echo_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'dart:async';
import 'package:observatory/service_io.dart';
diff --git a/runtime/observatory/test/eval_test.dart b/runtime/observatory/tests/service/eval_test.dart
similarity index 92%
rename from runtime/observatory/test/eval_test.dart
rename to runtime/observatory/tests/service/eval_test.dart
index 8355f7e..89afdfa 100644
--- a/runtime/observatory/test/eval_test.dart
+++ b/runtime/observatory/tests/service/eval_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -33,7 +34,6 @@
return isolate.rootLib.load().then((_) {
// Set up a listener to wait for breakpoint events.
Completer completer = new Completer();
- List events = [];
isolate.vm.events.stream.listen((ServiceEvent event) {
if (event.eventType == ServiceEvent.kPauseBreakpoint) {
print('Breakpoint reached');
@@ -57,10 +57,10 @@
expect(stack.type, equals('Stack'));
expect(stack['frames'].length, greaterThanOrEqualTo(2));
expect(stack['frames'][0]['function'].name, equals('printValue'));
- expect(stack['frames'][0]['function'].owningClass.name, equals('MyClass'));
+ expect(stack['frames'][0]['function'].dartOwner.name, equals('MyClass'));
var lib = isolate.rootLib;
- var cls = stack['frames'][0]['function'].owningClass;
+ var cls = stack['frames'][0]['function'].dartOwner;
var instance = stack['frames'][0]['vars'][0]['value'];
List evals = [];
diff --git a/runtime/observatory/test/functions_test.dart b/runtime/observatory/tests/service/functions_test.dart
similarity index 92%
rename from runtime/observatory/test/functions_test.dart
rename to runtime/observatory/tests/service/functions_test.dart
index 9290a4b..844de8c 100644
--- a/runtime/observatory/test/functions_test.dart
+++ b/runtime/observatory/tests/service/functions_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
library functions_test;
diff --git a/runtime/observatory/test/gc_test.dart b/runtime/observatory/tests/service/gc_test.dart
similarity index 92%
rename from runtime/observatory/test/gc_test.dart
rename to runtime/observatory/tests/service/gc_test.dart
index 11ba8c5..f6d6293 100644
--- a/runtime/observatory/test/gc_test.dart
+++ b/runtime/observatory/tests/service/gc_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'package:observatory/service_io.dart';
import 'test_helper.dart';
diff --git a/runtime/observatory/test/graph_test.dart b/runtime/observatory/tests/service/graph_test.dart
similarity index 96%
rename from runtime/observatory/test/graph_test.dart
rename to runtime/observatory/tests/service/graph_test.dart
index a496088..2b2d07a 100644
--- a/runtime/observatory/test/graph_test.dart
+++ b/runtime/observatory/tests/service/graph_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'dart:async';
import 'package:observatory/object_graph.dart';
@@ -25,7 +26,7 @@
r.left = a;
r.right = b;
a.left = b;
-
+
lst = new List(2);
lst[0] = lst; // Self-loop.
// Larger than any other fixed-size list in a fresh heap.
@@ -52,14 +53,14 @@
(ObjectVertex obj) => obj.succ.length == 1).length, equals(1));
expect(foos.where(
(ObjectVertex obj) => obj.succ.length == 2).length, equals(1));
-
+
ObjectVertex bVertex = foos.where(
(ObjectVertex obj) => obj.succ.length == 0).first;
ObjectVertex aVertex = foos.where(
(ObjectVertex obj) => obj.succ.length == 1).first;
ObjectVertex rVertex = foos.where(
(ObjectVertex obj) => obj.succ.length == 2).first;
-
+
// TODO(koda): Check actual byte sizes.
expect(aVertex.retainedSize, equals(aVertex.shallowSize));
@@ -67,8 +68,8 @@
expect(rVertex.retainedSize, equals(aVertex.shallowSize +
bVertex.shallowSize +
rVertex.shallowSize));
-
- const int fixedSizeListCid = 62;
+
+ const int fixedSizeListCid = 61;
List<ObjectVertex> lists = new List.from(graph.vertices.where(
(ObjectVertex obj) => obj.classId == fixedSizeListCid));
expect(lists.length >= 2, isTrue);
diff --git a/runtime/observatory/test/inbound_references_test.dart b/runtime/observatory/tests/service/inbound_references_test.dart
similarity index 95%
rename from runtime/observatory/test/inbound_references_test.dart
rename to runtime/observatory/tests/service/inbound_references_test.dart
index 0586620..a9805e8 100644
--- a/runtime/observatory/test/inbound_references_test.dart
+++ b/runtime/observatory/tests/service/inbound_references_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
library inbound_references_test;
diff --git a/runtime/observatory/test/isolate_lifecycle_test.dart b/runtime/observatory/tests/service/isolate_lifecycle_test.dart
similarity index 93%
rename from runtime/observatory/test/isolate_lifecycle_test.dart
rename to runtime/observatory/tests/service/isolate_lifecycle_test.dart
index c814ca9..08a2a1b 100644
--- a/runtime/observatory/test/isolate_lifecycle_test.dart
+++ b/runtime/observatory/tests/service/isolate_lifecycle_test.dart
@@ -1,10 +1,10 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'dart:async';
import 'dart:isolate' as I;
-import 'dart:math';
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
@@ -27,7 +27,7 @@
print('spawned all isolates');
}
-Future during() {
+Future during() async {
}
var tests = [
@@ -67,7 +67,7 @@
var resumesIssued = 0;
var isolateList = vm.isolates.toList();
for (var isolate in isolateList) {
- if (isolate.name == 'root') {
+ if (isolate.name.endsWith('main')) {
continue;
}
try {
diff --git a/runtime/observatory/test/malformed_test.dart b/runtime/observatory/tests/service/malformed_test.dart
similarity index 91%
rename from runtime/observatory/test/malformed_test.dart
rename to runtime/observatory/tests/service/malformed_test.dart
index 76fffb4..989457d 100644
--- a/runtime/observatory/test/malformed_test.dart
+++ b/runtime/observatory/tests/service/malformed_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/test/metrics_test.dart b/runtime/observatory/tests/service/metrics_test.dart
similarity index 93%
rename from runtime/observatory/test/metrics_test.dart
rename to runtime/observatory/tests/service/metrics_test.dart
index ef227c4..996e1c1 100644
--- a/runtime/observatory/test/metrics_test.dart
+++ b/runtime/observatory/tests/service/metrics_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/test/mirror_references_test.dart b/runtime/observatory/tests/service/mirror_references_test.dart
similarity index 94%
rename from runtime/observatory/test/mirror_references_test.dart
rename to runtime/observatory/tests/service/mirror_references_test.dart
index d6e5f39..0433f28 100644
--- a/runtime/observatory/test/mirror_references_test.dart
+++ b/runtime/observatory/tests/service/mirror_references_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
library vm_references_test;
diff --git a/runtime/observatory/test/native_metrics_test.dart b/runtime/observatory/tests/service/native_metrics_test.dart
similarity index 79%
rename from runtime/observatory/test/native_metrics_test.dart
rename to runtime/observatory/tests/service/native_metrics_test.dart
index 39b23d1..5467823 100644
--- a/runtime/observatory/test/native_metrics_test.dart
+++ b/runtime/observatory/tests/service/native_metrics_test.dart
@@ -1,3 +1,8 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
+
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
import 'test_helper.dart';
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
new file mode 100644
index 0000000..d3c936e
--- /dev/null
+++ b/runtime/observatory/tests/service/service.status
@@ -0,0 +1,27 @@
+# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+[ $system == linux ]
+call_site_data_test: Pass, Fail # Issue 23160
+
+# Unexpected number format
+[ $system == windows ]
+code_test: Skip
+
+# Tests that depend on token positions (which differ in release mode).
+[ $mode == release ]
+debugging_test: Skip
+
+# Disable on simulators.
+[ $arch == simarm || $arch == simmips || $arch == simarm64]
+*: Skip # Slow
+
+# The transformations of dart2dart are not guaranteed to preserve the
+# state/properties of the VM that the Observatory tests are inspecting.
+[ $compiler == dart2dart ]
+*: Skip
+
+# All tests use dart:io
+[ $browser || $compiler == dart2js ]
+*: SkipByDesign
diff --git a/runtime/observatory/test/source_location_test.dart b/runtime/observatory/tests/service/source_location_test.dart
similarity index 94%
rename from runtime/observatory/test/source_location_test.dart
rename to runtime/observatory/tests/service/source_location_test.dart
index e0cdd21..d658b2a 100644
--- a/runtime/observatory/test/source_location_test.dart
+++ b/runtime/observatory/tests/service/source_location_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'package:observatory/service_io.dart';
import 'package:observatory/debugger.dart';
@@ -11,7 +12,7 @@
void testFunction() {
int i = 0;
while (true) {
- if (++i % 100000000 == 0) { // line 14
+ if (++i % 100000000 == 0) { // line 15
print(i);
}
}
@@ -20,6 +21,7 @@
class TestDebugger extends Debugger {
TestDebugger(this.isolate, this.stack);
+ VM get vm => isolate.vm;
Isolate isolate;
ServiceMap stack;
int currentFrame = 0;
@@ -49,7 +51,7 @@
var tests = [
-// Bring the isolate to a breakpoint at line 14.
+// Bring the isolate to a breakpoint at line 15.
(Isolate isolate) {
return isolate.rootLib.load().then((_) {
// Listen for breakpoint event.
@@ -62,7 +64,7 @@
// Add the breakpoint.
var script = isolate.rootLib.scripts[0];
- return isolate.addBreakpoint(script, 14).then((ServiceObject bpt) {
+ return isolate.addBreakpoint(script, 15).then((ServiceObject bpt) {
return completer.future; // Wait for breakpoint events.
});
});
@@ -73,7 +75,7 @@
return initDebugger(isolate).then((debugger) {
return SourceLocation.parse(debugger, '').then((SourceLocation loc) {
expect(loc.valid, isTrue);
- expect(loc.toString(), equals('source_location_test.dart:14'));
+ expect(loc.toString(), equals('source_location_test.dart:15'));
});
});
},
@@ -81,9 +83,9 @@
// Parse line
(Isolate isolate) {
return initDebugger(isolate).then((debugger) {
- return SourceLocation.parse(debugger, '15').then((SourceLocation loc) {
+ return SourceLocation.parse(debugger, '16').then((SourceLocation loc) {
expect(loc.valid, isTrue);
- expect(loc.toString(), equals('source_location_test.dart:15'));
+ expect(loc.toString(), equals('source_location_test.dart:16'));
});
});
},
@@ -91,9 +93,9 @@
// Parse line + col
(Isolate isolate) {
return initDebugger(isolate).then((debugger) {
- return SourceLocation.parse(debugger, '15:11').then((SourceLocation loc) {
+ return SourceLocation.parse(debugger, '16:11').then((SourceLocation loc) {
expect(loc.valid, isTrue);
- expect(loc.toString(), equals('source_location_test.dart:15:11'));
+ expect(loc.toString(), equals('source_location_test.dart:16:11'));
});
});
},
diff --git a/runtime/observatory/test/string_escaping_test.dart b/runtime/observatory/tests/service/string_escaping_test.dart
similarity index 97%
rename from runtime/observatory/test/string_escaping_test.dart
rename to runtime/observatory/tests/service/string_escaping_test.dart
index 453eb05..050b3ce 100644
--- a/runtime/observatory/test/string_escaping_test.dart
+++ b/runtime/observatory/tests/service/string_escaping_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
library string_escaping_test;
diff --git a/runtime/observatory/test/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
similarity index 76%
rename from runtime/observatory/test/test_helper.dart
rename to runtime/observatory/tests/service/test_helper.dart
index aa3c2a0..3dddedd 100644
--- a/runtime/observatory/test/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -1,15 +1,22 @@
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
library test_helper;
import 'dart:async';
import 'dart:convert';
import 'dart:io';
-import 'package:unittest/unittest.dart';
import 'package:observatory/service_io.dart';
+bool _isWebSocketDisconnect(e) {
+ if (e is! ServiceException) {
+ return false;
+ }
+ return (e as ServiceException).message == 'WebSocket disconnected';
+}
+
// This invocation should set up the state being tested.
const String _TESTEE_MODE_FLAG = "--testee-mode";
@@ -61,15 +68,15 @@
print(line);
});
process.exitCode.then((exitCode) {
- expect(exitCode, equals(0));
+ print("** Process exited");
});
return completer.future;
});
}
void requestExit() {
- print('** Requesting script to exit.');
- process.stdin.add([32, 13, 10]);
+ print('** Killing script');
+ process.kill();
}
}
@@ -93,7 +100,7 @@
if (testeeConcurrent != null) {
testeeConcurrent();
}
- // Wait until signaled from spawning test.
+ // Wait around for the process to be killed.
stdin.first.then((_) => exit(0));
} else {
var process = new _TestLauncher();
@@ -102,13 +109,20 @@
var testIndex = 0;
var totalTests = tests.length - 1;
var name = Platform.script.pathSegments.last;
- new WebSocketVM(new WebSocketVMTarget(addr)).load()
- .then((VM vm) => vm.isolates.first.load())
- .then((Isolate isolate) => Future.forEach(tests, (test) {
- print('Running $name [$testIndex/$totalTests]');
- testIndex++;
- return test(isolate);
- })).then((_) => exit(0));
+ runZoned(() {
+ new WebSocketVM(new WebSocketVMTarget(addr)).load()
+ .then((VM vm) => vm.isolates.first.load())
+ .then((Isolate isolate) => Future.forEach(tests, (test) {
+ print('Running $name [$testIndex/$totalTests]');
+ testIndex++;
+ return test(isolate);
+ })).then((_) => process.requestExit());
+ }, onError: (e, st) {
+ if (!_isWebSocketDisconnect(e)) {
+ print('Unexpected exception in service tests: $e $st');
+ throw e;
+ }
+ });
});
}
}
@@ -147,7 +161,7 @@
if (testeeConcurrent != null) {
await testeeConcurrent();
}
- // Wait until signaled from spawning test.
+ // Wait around for the process to be killed.
stdin.first.then((_) => exit(0));
} else {
var process = new _TestLauncher();
@@ -156,12 +170,19 @@
var testIndex = 0;
var totalTests = tests.length - 1;
var name = Platform.script.pathSegments.last;
- new WebSocketVM(new WebSocketVMTarget(addr)).load()
- .then((VM vm) => Future.forEach(tests, (test) {
- print('Running $name [$testIndex/$totalTests]');
- testIndex++;
- return test(vm);
- })).then((_) => exit(0));
+ runZoned(() {
+ new WebSocketVM(new WebSocketVMTarget(addr)).load()
+ .then((VM vm) => Future.forEach(tests, (test) {
+ print('Running $name [$testIndex/$totalTests]');
+ testIndex++;
+ return test(vm);
+ })).then((_) => process.requestExit());
+ }, onError: (e, st) {
+ if (!_isWebSocketDisconnect(e)) {
+ print('Unexpected exception in service tests: $e $st');
+ throw e;
+ }
+ });
});
}
-}
\ No newline at end of file
+}
diff --git a/runtime/observatory/test/type_arguments_test.dart b/runtime/observatory/tests/service/type_arguments_test.dart
similarity index 95%
rename from runtime/observatory/test/type_arguments_test.dart
rename to runtime/observatory/tests/service/type_arguments_test.dart
index 4b82421..aaa85c7 100644
--- a/runtime/observatory/test/type_arguments_test.dart
+++ b/runtime/observatory/tests/service/type_arguments_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
import 'package:observatory/service_io.dart';
import 'package:unittest/unittest.dart';
diff --git a/runtime/observatory/tests/service/vm_test.dart b/runtime/observatory/tests/service/vm_test.dart
new file mode 100644
index 0000000..aea81ca
--- /dev/null
+++ b/runtime/observatory/tests/service/vm_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+
+var tests = [
+
+(Isolate isolate) {
+ VM vm = isolate.owner;
+ expect(vm.targetCPU, isNotNull);
+ expect(vm.architectureBits == 32 ||
+ vm.architectureBits == 64, isTrue);
+},
+
+];
+
+main(args) => runIsolateTests(args, tests);
diff --git a/runtime/observatory/test/weak_properties_test.dart b/runtime/observatory/tests/service/weak_properties_test.dart
similarity index 95%
rename from runtime/observatory/test/weak_properties_test.dart
rename to runtime/observatory/tests/service/weak_properties_test.dart
index c0e3ff7..c37c38f 100644
--- a/runtime/observatory/test/weak_properties_test.dart
+++ b/runtime/observatory/tests/service/weak_properties_test.dart
@@ -1,6 +1,7 @@
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--compile-all --error_on_bad_type --error_on_bad_override --checked
library vm_references_test;
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 8eff2f4..54ebf4d 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -201,6 +201,19 @@
static bool DoublesBitEqual(const double a, const double b) {
return bit_cast<int64_t, double>(a) == bit_cast<int64_t, double>(b);
}
+
+ // dart2js represents integers as double precision floats, which can
+ // represent anything in the range -2^53 ... 2^53.
+ static bool IsJavascriptInt64(int64_t value) {
+ return ((-0x20000000000000LL <= value) && (value <= 0x20000000000000LL));
+ }
+ static bool IsJavascriptInt(intptr_t value) {
+#if defined(ARCH_IS_64BIT)
+ return ((-0x20000000000000LL <= value) && (value <= 0x20000000000000LL));
+#else
+ return true;
+#endif
+ }
};
} // namespace dart
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index e1d95ce..01622e6 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -84,9 +84,6 @@
[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
dart/optimized_stacktrace_test: StaticWarning
-[ $compiler == none && $runtime == ContentShellOnAndroid ]
-dart/byte_array_test: RuntimeError # Issue 17612
-
[ $runtime != vm ]
dart/snapshot_version_test: SkipByDesign # Spawns processes
diff --git a/runtime/third_party/jscre/ASCIICType.h b/runtime/third_party/jscre/ASCIICType.h
deleted file mode 100644
index 1550b83..0000000
--- a/runtime/third_party/jscre/ASCIICType.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_JSCRE_ASCIICTYPE_H_
-#define THIRD_PARTY_JSCRE_ASCIICTYPE_H_
-
-// The behavior of many of the functions in the <ctype.h> header is dependent
-// on the current locale. But in the WebKit project, all uses of those functions
-// are in code processing something that's not locale-specific. These
-// equivalents for some of the <ctype.h> functions are named more explicitly,
-// not dependent on the C library locale, and we should also optimize them
-// as needed.
-
-// All functions return false or leave the character unchanged if passed
-// a character that is outside the range 0-7F. So they can be used on
-// Unicode strings or characters if the intent is to do processing only
-// if the character is ASCII.
-
- inline bool isASCIIAlpha(char c) {
- return (c | 0x20) >= 'a' && (c | 0x20) <= 'z';
- }
- inline bool isASCIIAlpha(uint16_t c) {
- return (c | 0x20) >= 'a' && (c | 0x20) <= 'z';
- }
- inline bool isASCIIAlpha(int c) {
- return (c | 0x20) >= 'a' && (c | 0x20) <= 'z';
- }
-
- inline bool isASCIIAlphanumeric(char c) {
- return (c >= '0' && c <= '9') ||
- ((c | 0x20) >= 'a' && (c | 0x20) <= 'z');
- }
- inline bool isASCIIAlphanumeric(uint16_t c) {
- return (c >= '0' && c <= '9') ||
- ((c | 0x20) >= 'a' && (c | 0x20) <= 'z');
- }
- inline bool isASCIIAlphanumeric(int c) {
- return (c >= '0' && c <= '9') ||
- ((c | 0x20) >= 'a' && (c | 0x20) <= 'z');
- }
-
- inline bool isASCIIDigit(char c) { return (c >= '0') & (c <= '9'); }
- inline bool isASCIIDigit(uint16_t c) {
- return (c >= '0') & (c <= '9');
- }
- inline bool isASCIIDigit(int c) { return (c >= '0') & (c <= '9'); }
-
- inline bool isASCIIHexDigit(char c) {
- return (c >= '0' && c <= '9') ||
- ((c | 0x20) >= 'a' && (c | 0x20) <= 'f');
- }
- inline bool isASCIIHexDigit(uint16_t c) {
- return (c >= '0' && c <= '9') ||
- ((c | 0x20) >= 'a' && (c | 0x20) <= 'f');
- }
- inline bool isASCIIHexDigit(int c) {
- return (c >= '0' && c <= '9') ||
- ((c | 0x20) >= 'a' && (c | 0x20) <= 'f');
- }
-
- inline bool isASCIILower(char c) { return c >= 'a' && c <= 'z'; }
- inline bool isASCIILower(uint16_t c) { return c >= 'a' && c <= 'z'; }
- inline bool isASCIILower(int c) { return c >= 'a' && c <= 'z'; }
-
- inline bool isASCIIUpper(char c) { return c >= 'A' && c <= 'Z'; }
- inline bool isASCIIUpper(uint16_t c) { return c >= 'A' && c <= 'Z'; }
- inline bool isASCIIUpper(int c) { return c >= 'A' && c <= 'Z'; }
-
- /*
- Statistics from a run of Apple's page load test for callers of
- isASCIISpace:
-
- character count
- --------- -----
- non-spaces 689383
- 20 space 294720
- 0A \n 89059
- 09 \t 28320
- 0D \r 0
- 0C \f 0
- 0B \v 0
- */
- inline bool isASCIISpace(char c) {
- return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9));
- }
- inline bool isASCIISpace(uint16_t c) {
- return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9));
- }
- inline bool isASCIISpace(int c) {
- return c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9));
- }
-
- inline char toASCIILower(char c) {
- return c | ((c >= 'A' && c <= 'Z') << 5);
- }
- inline uint16_t toASCIILower(uint16_t c) {
- return c | ((c >= 'A' && c <= 'Z') << 5);
- }
- inline int toASCIILower(int c) {
- return c | ((c >= 'A' && c <= 'Z') << 5);
- }
-
- inline char toASCIIUpper(char c) {
- return static_cast<char>(c & ~((c >= 'a' && c <= 'z') << 5));
- }
- inline uint16_t toASCIIUpper(uint16_t c) {
- return static_cast<uint16_t>(c & ~((c >= 'a' && c <= 'z') << 5));
- }
- inline int toASCIIUpper(int c) {
- return static_cast<int>(c & ~((c >= 'a' && c <= 'z') << 5));
- }
-
- inline int toASCIIHexValue(char c) {
- ASSERT(isASCIIHexDigit(c));
- return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF;
- }
- inline int toASCIIHexValue(uint16_t c) {
- ASSERT(isASCIIHexDigit(c));
- return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF;
- }
- inline int toASCIIHexValue(int c) {
- ASSERT(isASCIIHexDigit(c));
- return c < 'A' ? c - '0' : (c - 'A' + 10) & 0xF;
- }
-
-#endif // THIRD_PARTY_JSCRE_ASCIICTYPE_H_
diff --git a/runtime/third_party/jscre/AUTHORS b/runtime/third_party/jscre/AUTHORS
deleted file mode 100644
index dbac2a5..0000000
--- a/runtime/third_party/jscre/AUTHORS
+++ /dev/null
@@ -1,12 +0,0 @@
-Originally written by: Philip Hazel
-Email local part: ph10
-Email domain: cam.ac.uk
-
-University of Cambridge Computing Service,
-Cambridge, England. Phone: +44 1223 334714.
-
-Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
-
-Adapted for JavaScriptCore and WebKit by Apple Inc.
-
-Copyright (c) 2005, 2006, 2007 Apple Inc. All rights reserved.
diff --git a/runtime/third_party/jscre/BUILD.gn b/runtime/third_party/jscre/BUILD.gn
deleted file mode 100644
index 59c91a8..0000000
--- a/runtime/third_party/jscre/BUILD.gn
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-static_library("libjscre") {
- configs += [ "../..:dart_config", ]
- defines = [
- "SUPPORT_UTF8",
- "SUPPORT_UCP",
- "NO_RECURSE",
- ]
- sources = [
- "ASCIICType.h",
- "config.h",
- "pcre.h",
- "pcre_internal.h",
- "ucpinternal.h",
- "pcre_compile.cpp",
- "pcre_exec.cpp",
- "pcre_tables.cpp",
- "pcre_ucp_searchfuncs.cpp",
- "pcre_xclass.cpp",
- ]
- include_dirs = [
- ".",
- ]
-}
diff --git a/runtime/third_party/jscre/COPYING b/runtime/third_party/jscre/COPYING
deleted file mode 100644
index 6ffdc24..0000000
--- a/runtime/third_party/jscre/COPYING
+++ /dev/null
@@ -1,35 +0,0 @@
-PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
-This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed.
-
-Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the name of Apple
- Inc. nor the names of their contributors may be used to endorse or
- promote products derived from this software without specific prior
- written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
diff --git a/runtime/third_party/jscre/LICENSE b/runtime/third_party/jscre/LICENSE
deleted file mode 100644
index 020c45f..0000000
--- a/runtime/third_party/jscre/LICENSE
+++ /dev/null
@@ -1,85 +0,0 @@
------------------------------------------------------------------------------
-The following license text is extracted from the header of the file
-ASCIICType.h and applies only to that file.
------------------------------------------------------------------------------
-
-Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- its contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
------------------------------------------------------------------------------
-The following license text is from the file COPYING and applies to the other
-source files in this directory.
------------------------------------------------------------------------------
-
-PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
-This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed.
-
-Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the name of Apple
- Inc. nor the names of their contributors may be used to endorse or
- promote products derived from this software without specific prior
- written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
------------------------------------------------------------------------------
-The following copyright lines are found in individual files other than
-ASCIICType.h
------------------------------------------------------------------------------
-
-
-Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
-Copyright (C) 2002, 2004, 2006, 2007, 2008 Apple Inc. All rights reserved.
-Copyright (C) 2007 Eric Seidel <eric@webkit.org>
-Copyright (c) 1997-2005 University of Cambridge
-Copyright (c) 1997-2005 University of Cambridge. All rights reserved.
-Copyright (c) 1997-2006 University of Cambridge
-Copyright (c) 2005, 2006, 2007 Apple Inc. All rights reserved.
diff --git a/runtime/third_party/jscre/config.h b/runtime/third_party/jscre/config.h
deleted file mode 100644
index 5ed9ff1..0000000
--- a/runtime/third_party/jscre/config.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/* This is the public header file for JavaScriptCore's variant of the PCRE
-library. While this library started out as a copy of PCRE, many of the
-features of PCRE have been removed. This library now supports only the
-regular expression features required by the JavaScript language
-specification, and has only the functions needed by JavaScriptCore and the
-rest of WebKit.
-
- Copyright (c) 1997-2005 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* On Unix-like systems config.in is converted by "configure" into config.h.
-Some other environments also support the use of "configure". PCRE is written in
-Standard C, but there are a few non-standard things it can cope with, allowing
-it to run on SunOS4 and other "close to standard" systems.
-
-On a non-Unix-like system you should just copy this file into config.h, and set
-up the macros the way you need them. You should normally change the definitions
-of HAVE_STRERROR and HAVE_MEMMOVE to 1. Unfortunately, because of the way
-autoconf works, these cannot be made the defaults. If your system has bcopy()
-and not memmove(), change the definition of HAVE_BCOPY instead of HAVE_MEMMOVE.
-If your system has neither bcopy() nor memmove(), leave them both as 0; an
-emulation function will be used. */
-
-/* If you are compiling for a system that uses EBCDIC instead of ASCII
-character codes, define this macro as 1. On systems that can use "configure",
-this can be done via --enable-ebcdic. */
-
-#ifndef THIRD_PARTY_JSCRE_CONFIG_H_
-#define THIRD_PARTY_JSCRE_CONFIG_H_
-
-#ifndef EBCDIC
-#define EBCDIC 0
-#endif
-
-/* If you are compiling for a system other than a Unix-like system or Win32,
-and it needs some magic to be inserted before the definition of a function that
-is exported by the library, define this macro to contain the relevant magic. If
-you do not define this macro, it defaults to "extern" for a C compiler and
-"extern C" for a C++ compiler on non-Win32 systems. This macro apears at the
-start of every exported function that is part of the external API. It does not
-appear on functions that are "external" in the C sense, but which are internal
-to the library. */
-
-/* #define PCRE_DATA_SCOPE */
-
-/* Define the following macro to empty if the "const" keyword does not work. */
-
-#undef const
-
-/* Define the following macro to "unsigned" if <stddef.h> does not define
-size_t. */
-
-#undef size_t
-
-/* The following two definitions are mainly for the benefit of SunOS4, which
-does not have the strerror() or memmove() functions that should be present in
-all Standard C libraries. The macros HAVE_STRERROR and HAVE_MEMMOVE should
-normally be defined with the value 1 for other systems, but unfortunately we
-cannot make this the default because "configure" files generated by autoconf
-will only change 0 to 1; they won't change 1 to 0 if the functions are not
-found. */
-
-#define HAVE_STRERROR 1
-#define HAVE_MEMMOVE 1
-
-/* There are some non-Unix-like systems that don't even have bcopy(). If this
-macro is false, an emulation is used. If HAVE_MEMMOVE is set to 1, the value of
-HAVE_BCOPY is not relevant. */
-
-#define HAVE_BCOPY 0
-
-/* The value of NEWLINE determines the newline character. The default is to
-leave it up to the compiler, but some sites want to force a particular value.
-On Unix-like systems, "configure" can be used to override this default. */
-
-#ifndef NEWLINE
-#define NEWLINE '\n'
-#endif
-
-/* The value of LINK_SIZE determines the number of bytes used to store links as
-offsets within the compiled regex. The default is 2, which allows for compiled
-patterns up to 64K long. This covers the vast majority of cases. However, PCRE
-can also be compiled to use 3 or 4 bytes instead. This allows for longer
-patterns in extreme cases. On systems that support it, "configure" can be used
-to override this default. */
-
-#ifndef LINK_SIZE
-#define LINK_SIZE 2
-#endif
-
-/* When calling PCRE via the POSIX interface, additional working storage is
-required for holding the pointers to capturing substrings because PCRE requires
-three integers per substring, whereas the POSIX interface provides only two. If
-the number of expected substrings is small, the wrapper function uses space on
-the stack, because this is faster than using malloc() for each call. The
-threshold above which the stack is no longer used is defined by POSIX_MALLOC_
-THRESHOLD. On systems that support it, "configure" can be used to override this
-default. */
-
-#ifndef POSIX_MALLOC_THRESHOLD
-#define POSIX_MALLOC_THRESHOLD 10
-#endif
-
-/* PCRE uses recursive function calls to handle backtracking while matching.
-This can sometimes be a problem on systems that have stacks of limited size.
-Define NO_RECURSE to get a version that doesn't use recursion in the match()
-function; instead it creates its own stack by steam using pcre_recurse_malloc()
-to obtain memory from the heap. For more detail, see the comments and other
-stuff just above the match() function. On systems that support it, "configure"
-can be used to set this in the Makefile (use --disable-stack-for-recursion). */
-
-/* #define NO_RECURSE */
-
-/* The value of MATCH_LIMIT determines the default number of times the internal
-match() function can be called during a single execution of pcre_exec(). There
-is a runtime interface for setting a different limit. The limit exists in order
-to catch runaway regular expressions that take for ever to determine that they
-do not match. The default is set very large so that it does not accidentally
-catch legitimate cases. On systems that support it, "configure" can be used to
-override this default default. */
-
-#ifndef MATCH_LIMIT
-#define MATCH_LIMIT 10000000
-#endif
-
-/* The above limit applies to all calls of match(), whether or not they
-increase the recursion depth. In some environments it is desirable to limit the
-depth of recursive calls of match() more strictly, in order to restrict the
-maximum amount of stack (or heap, if NO_RECURSE is defined) that is used. The
-value of MATCH_LIMIT_RECURSION applies only to recursive calls of match(). To
-have any useful effect, it must be less than the value of MATCH_LIMIT. There is
-a runtime method for setting a different limit. On systems that support it,
-"configure" can be used to override this default default. */
-
-#ifndef MATCH_LIMIT_RECURSION
-#define MATCH_LIMIT_RECURSION MATCH_LIMIT
-#endif
-
-/* These three limits are parameterized just in case anybody ever wants to
-change them. Care must be taken if they are increased, because they guard
-against integer overflow caused by enormously large patterns. */
-
-#ifndef MAX_NAME_SIZE
-#define MAX_NAME_SIZE 32
-#endif
-
-#ifndef MAX_NAME_COUNT
-#define MAX_NAME_COUNT 10000
-#endif
-
-#ifndef MAX_DUPLENGTH
-#define MAX_DUPLENGTH 30000
-#endif
-
-/* End */
-#endif // THIRD_PARTY_JSCRE_CONFIG_H_
diff --git a/runtime/third_party/jscre/jscre.gypi b/runtime/third_party/jscre/jscre.gypi
deleted file mode 100644
index acb6d8c..0000000
--- a/runtime/third_party/jscre/jscre.gypi
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2010 Google Inc. All Rights Reserved.
-
-{
- 'targets': [
- {
- 'target_name': 'libjscre',
- 'type': 'static_library',
- 'toolsets':['target','host'],
- 'dependencies': [
- ],
- 'include_dirs': [
- '.',
- ],
- 'defines': [
- 'SUPPORT_UTF8',
- 'SUPPORT_UCP',
- 'NO_RECURSE',
- ],
- 'sources': [
- 'ASCIICType.h',
- 'config.h',
- 'pcre.h',
- 'pcre_internal.h',
- 'ucpinternal.h',
- 'pcre_compile.cpp',
- 'pcre_exec.cpp',
- 'pcre_tables.cpp',
- 'pcre_ucp_searchfuncs.cpp',
- 'pcre_xclass.cpp',
- ],
- },
- ],
-}
diff --git a/runtime/third_party/jscre/pcre.h b/runtime/third_party/jscre/pcre.h
deleted file mode 100644
index d854fe0..0000000
--- a/runtime/third_party/jscre/pcre.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* This is the public header file for JavaScriptCore's variant of the PCRE
-library. While this library started out as a copy of PCRE, many of the
-features of PCRE have been removed. This library now supports only the
-regular expression features required by the JavaScript language
-specification, and has only the functions needed by JavaScriptCore and the
-rest of WebKit.
-
- Copyright (c) 1997-2005 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-#ifndef THIRD_PARTY_JSCRE_PCRE_H_
-#define THIRD_PARTY_JSCRE_PCRE_H_
-
-#if defined(_WIN32)
-typedef unsigned __int16 uint16_t;
-#else
-#include <inttypes.h>
-#include <stdint.h>
-#endif
-
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-// JSCRE is very chatty in debug mode, so in order to keep it slient
-// while still importing v8.h correctly (it contains #ifdef DEBUGs)
-// we allow DEBUG to be set and undef it manually.
-#undef DEBUG
-
-namespace dart { namespace jscre {
-
-typedef uint16_t UChar;
-
-struct JSRegExp;
-typedef struct JSRegExp JscreRegExp;
-
-enum JSRegExpIgnoreCaseOption { JSRegExpDoNotIgnoreCase, JSRegExpIgnoreCase };
-enum JSRegExpMultilineOption { JSRegExpSingleLine, JSRegExpMultiline };
-
-/* jsRegExpExecute error codes */
-const int JSRegExpErrorNoMatch = -1;
-const int JSRegExpErrorHitLimit = -2;
-const int JSRegExpErrorNoMemory = -3;
-const int JSRegExpErrorInternal = -4;
-
-typedef void* malloc_t(size_t size);
-typedef void free_t(void* address);
-
-JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength,
- JSRegExpIgnoreCaseOption, JSRegExpMultilineOption,
- unsigned* numSubpatterns, const char** errorMessage,
- malloc_t* allocate_function, free_t* free_function);
-
-int jsRegExpExecute(const JSRegExp*,
- const UChar* subject, int subjectLength, int startOffset,
- int* offsetsVector, int offsetsVectorLength);
-
-void jsRegExpFree(JSRegExp* regexp);
-
-} } // namespace dart::jscre
-
-#endif // THIRD_PARTY_JSCRE_PCRE_H_
diff --git a/runtime/third_party/jscre/pcre_chartables.c b/runtime/third_party/jscre/pcre_chartables.c
deleted file mode 100644
index c5fe2c5..0000000
--- a/runtime/third_party/jscre/pcre_chartables.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* This file is automatically written by the dftables auxiliary
-program. If you edit it by hand, you might like to edit the Makefile to
-prevent its ever being regenerated.
-
-This file contains the default tables for characters with codes less than
-128 (ASCII characters). These tables are used when no external tables are
-passed to PCRE. */
-
-const unsigned char kjs_pcre_default_tables[480] = {
-
-/* This table is a lower casing table. */
-
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
- 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
- 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
-
-/* This table is a case flipping table. */
-
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
- 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
- 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
- 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
-
-/* This table contains bit maps for various character classes.
-Each map is 32 bytes long and the bits run from the least
-significant end of each byte. The classes are: space, digit, word. */
-
- 0x00, 0x3E, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
- 0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-/* This table identifies various classes of character by individual bits:
- 0x01 white space character
- 0x08 hexadecimal digit
- 0x10 alphanumeric or '_'
-*/
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0- 7 */
- 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 8- 15 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 16- 23 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 24- 31 */
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* - ' */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ( - / */
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 0 - 7 */
- 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8 - ? */
- 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10, /* @ - G */
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, /* H - O */
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, /* P - W */
- 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, /* X - _ */
- 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x10, /* ` - g */
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, /* h - o */
- 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, /* p - w */
- 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}; /* x -127 */
-
-
-/* End of chartables.c */
diff --git a/runtime/third_party/jscre/pcre_compile.cpp b/runtime/third_party/jscre/pcre_compile.cpp
deleted file mode 100644
index 110a32e..0000000
--- a/runtime/third_party/jscre/pcre_compile.cpp
+++ /dev/null
@@ -1,2675 +0,0 @@
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
- Copyright (C) 2007 Eric Seidel <eric@webkit.org>
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* This module contains the external function jsRegExpExecute(), along with
-supporting internal functions that are not used by other modules. */
-
-#include "config.h"
-
-#include "pcre_internal.h"
-
-#include <string.h>
-#include "ASCIICType.h"
-
-/* Negative values for the firstchar and reqchar variables */
-
-#define REQ_UNSET (-2)
-#define REQ_NONE (-1)
-
-/*************************************************
-* Code parameters and static tables *
-*************************************************/
-
-/* Maximum number of items on the nested bracket stacks at compile time. This
-applies to the nesting of all kinds of parentheses. It does not limit
-un-nested, non-capturing parentheses. This number can be made bigger if
-necessary - it is used to dimension one int and one unsigned char vector at
-compile time. */
-
-#define BRASTACK_SIZE 200
-
-namespace dart { namespace jscre {
-
-/* Table for handling escaped characters in the range '0'-'z'. Positive returns
-are simple data values; negative values are for special things like \d and so
-on. Zero means further processing is needed (for things like \x), or the escape
-is invalid. */
-
-static const short escapes[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */
- 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */
- '@', 0, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */
- 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
- 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */
- 0, 0, 0, '[', '\\', ']', '^', '_', /* X - _ */
- '`', 7, -ESC_b, 0, -ESC_d, 0, '\f', 0, /* ` - g */
- 0, 0, 0, 0, 0, 0, '\n', 0, /* h - o */
- 0, 0, '\r', -ESC_s, '\t', 0, '\v', -ESC_w, /* p - w */
- 0, 0, 0 /* x - z */
-};
-
-/* Error code numbers. They are given names so that they can more easily be
-tracked. */
-
-enum ErrorCode {
- ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9,
- ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17
-};
-
-/* The texts of compile-time error messages. These are "char *" because they
-are passed to the outside world. */
-
-static const char* errorText(ErrorCode code)
-{
- static const char errorTexts[] =
- /* 1 */
- "\\ at end of pattern\0"
- "\\c at end of pattern\0"
- "character value in \\x{...} sequence is too large\0"
- "numbers out of order in {} quantifier\0"
- /* 5 */
- "number too big in {} quantifier\0"
- "missing terminating ] for character class\0"
- "internal error: code overflow\0"
- "range out of order in character class\0"
- "nothing to repeat\0"
- /* 10 */
- "unmatched parentheses\0"
- "internal error: unexpected repeat\0"
- "unrecognized character after (?\0"
- "failed to get memory\0"
- "missing )\0"
- /* 15 */
- "reference to non-existent subpattern\0"
- "regular expression too large\0"
- "parentheses nested too deeply"
- ;
-
- int i = code;
- const char* text = errorTexts;
- while (i > 1)
- i -= !*text++;
- return text;
-}
-
-/* Structure for passing "static" information around between the functions
-doing the compiling. */
-
-struct CompileData {
- CompileData() {
- top_backref = 0;
- backrefMap = 0;
- req_varyopt = 0;
- needOuterBracket = false;
- numCapturingBrackets = 0;
- }
- int top_backref; /* Maximum back reference */
- unsigned backrefMap; /* Bitmap of low back refs */
- int req_varyopt; /* "After variable item" flag for reqbyte */
- bool needOuterBracket;
- int numCapturingBrackets;
-};
-
-/* Definitions to allow mutual recursion */
-
-static bool compileBracket(int, int*, unsigned char**, const UChar**, const UChar*, ErrorCode*, int, int*, int*, CompileData&);
-static bool bracketIsAnchored(const unsigned char* code);
-static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap);
-static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert);
-
-/*************************************************
-* Handle escapes *
-*************************************************/
-
-/* This function is called when a \ has been encountered. It either returns a
-positive value for a simple escape such as \n, or a negative value which
-encodes one of the more complicated things such as \d. When UTF-8 is enabled,
-a positive value greater than 255 may be returned. On entry, ptr is pointing at
-the \. On exit, it is on the final character of the escape sequence.
-
-Arguments:
- ptrptr points to the pattern position pointer
- errorcodeptr points to the errorcode variable
- bracount number of previous extracting brackets
- options the options bits
- isclass true if inside a character class
-
-Returns: zero or positive => a data character
- negative => a special escape sequence
- on error, errorptr is set
-*/
-
-static int checkEscape(const UChar** ptrptr, const UChar* patternEnd, ErrorCode* errorcodeptr, int bracount, bool isclass)
-{
- const UChar* ptr = *ptrptr + 1;
-
- /* If backslash is at the end of the pattern, it's an error. */
- if (ptr == patternEnd) {
- *errorcodeptr = ERR1;
- *ptrptr = ptr;
- return 0;
- }
-
- int c = *ptr;
-
- /* Non-alphamerics are literals. For digits or letters, do an initial lookup in
- a table. A non-zero result is something that can be returned immediately.
- Otherwise further processing may be required. */
-
- if (c < '0' || c > 'z') { /* Not alphameric */
- } else if (int escapeValue = escapes[c - '0']) {
- c = escapeValue;
- if (isclass) {
- if (-c == ESC_b)
- c = '\b'; /* \b is backslash in a class */
- else if (-c == ESC_B)
- c = 'B'; /* and \B is a capital B in a class (in browsers event though ECMAScript 15.10.2.19 says it raises an error) */
- }
- /* Escapes that need further processing, or are illegal. */
-
- } else {
- switch (c) {
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- /* Escape sequences starting with a non-zero digit are backreferences,
- unless there are insufficient brackets, in which case they are octal
- escape sequences. Those sequences end on the first non-octal character
- or when we overflow 0-255, whichever comes first. */
-
- if (!isclass) {
- const UChar* oldptr = ptr;
- c -= '0';
- while ((ptr + 1 < patternEnd) && isASCIIDigit(ptr[1]) && c <= bracount)
- c = c * 10 + *(++ptr) - '0';
- if (c <= bracount) {
- c = -(ESC_REF + c);
- break;
- }
- ptr = oldptr; /* Put the pointer back and fall through */
- }
-
- /* Handle an octal number following \. If the first digit is 8 or 9,
- this is not octal. */
-
- if ((c = *ptr) >= '8')
- break;
-
- /* \0 always starts an octal number, but we may drop through to here with a
- larger first octal digit. */
-
- case '0': {
- c -= '0';
- int i;
- for (i = 1; i <= 2; ++i) {
- if (ptr + i >= patternEnd || ptr[i] < '0' || ptr[i] > '7')
- break;
- int cc = c * 8 + ptr[i] - '0';
- if (cc > 255)
- break;
- c = cc;
- }
- ptr += i - 1;
- break;
- }
-
- case 'x': {
- c = 0;
- int i;
- for (i = 1; i <= 2; ++i) {
- if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) {
- c = 'x';
- i = 1;
- break;
- }
- int cc = ptr[i];
- if (cc >= 'a')
- cc -= 32; /* Convert to upper case */
- c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10));
- }
- ptr += i - 1;
- break;
- }
-
- case 'u': {
- c = 0;
- int i;
- for (i = 1; i <= 4; ++i) {
- if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) {
- c = 'u';
- i = 1;
- break;
- }
- int cc = ptr[i];
- if (cc >= 'a')
- cc -= 32; /* Convert to upper case */
- c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10));
- }
- ptr += i - 1;
- break;
- }
-
- case 'c':
- if (++ptr == patternEnd) {
- *errorcodeptr = ERR2;
- return 0;
- }
- c = *ptr;
-
- /* A letter is upper-cased; then the 0x40 bit is flipped. This coding
- is ASCII-specific, but then the whole concept of \cx is ASCII-specific. */
- c = toASCIIUpper(c) ^ 0x40;
- break;
- }
- }
-
- *ptrptr = ptr;
- return c;
-}
-
-/*************************************************
-* Check for counted repeat *
-*************************************************/
-
-/* This function is called when a '{' is encountered in a place where it might
-start a quantifier. It looks ahead to see if it really is a quantifier or not.
-It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd}
-where the ddds are digits.
-
-Arguments:
- p pointer to the first char after '{'
-
-Returns: true or false
-*/
-
-static bool isCountedRepeat(const UChar* p, const UChar* patternEnd)
-{
- if (p >= patternEnd || !isASCIIDigit(*p))
- return false;
- p++;
- while (p < patternEnd && isASCIIDigit(*p))
- p++;
- if (p < patternEnd && *p == '}')
- return true;
-
- if (p >= patternEnd || *p++ != ',')
- return false;
- if (p < patternEnd && *p == '}')
- return true;
-
- if (p >= patternEnd || !isASCIIDigit(*p))
- return false;
- p++;
- while (p < patternEnd && isASCIIDigit(*p))
- p++;
-
- return (p < patternEnd && *p == '}');
-}
-
-/*************************************************
-* Read repeat counts *
-*************************************************/
-
-/* Read an item of the form {n,m} and return the values. This is called only
-after isCountedRepeat() has confirmed that a repeat-count quantifier exists,
-so the syntax is guaranteed to be correct, but we need to check the values.
-
-Arguments:
- p pointer to first char after '{'
- minp pointer to int for min
- maxp pointer to int for max
- returned as -1 if no max
- errorcodeptr points to error code variable
-
-Returns: pointer to '}' on success;
- current ptr on error, with errorcodeptr set non-zero
-*/
-
-static const UChar* readRepeatCounts(const UChar* p, int* minp, int* maxp, ErrorCode* errorcodeptr)
-{
- int min = 0;
- int max = -1;
-
- /* Read the minimum value and do a paranoid check: a negative value indicates
- an integer overflow. */
-
- while (isASCIIDigit(*p))
- min = min * 10 + *p++ - '0';
- if (min < 0 || min > 65535) {
- *errorcodeptr = ERR5;
- return p;
- }
-
- /* Read the maximum value if there is one, and again do a paranoid on its size.
- Also, max must not be less than min. */
-
- if (*p == '}')
- max = min;
- else {
- if (*(++p) != '}') {
- max = 0;
- while (isASCIIDigit(*p))
- max = max * 10 + *p++ - '0';
- if (max < 0 || max > 65535) {
- *errorcodeptr = ERR5;
- return p;
- }
- if (max < min) {
- *errorcodeptr = ERR4;
- return p;
- }
- }
- }
-
- /* Fill in the required variables, and pass back the pointer to the terminating
- '}'. */
-
- *minp = min;
- *maxp = max;
- return p;
-}
-
-/*************************************************
-* Find first significant op code *
-*************************************************/
-
-/* This is called by several functions that scan a compiled expression looking
-for a fixed first character, or an anchoring op code etc. It skips over things
-that do not influence this.
-
-Arguments:
- code pointer to the start of the group
-Returns: pointer to the first significant opcode
-*/
-
-static const unsigned char* firstSignificantOpcode(const unsigned char* code)
-{
- while (*code == OP_BRANUMBER)
- code += 3;
- return code;
-}
-
-static const unsigned char* firstSignificantOpcodeSkippingAssertions(const unsigned char* code)
-{
- while (true) {
- switch (*code) {
- case OP_ASSERT_NOT:
- advanceToEndOfBracket(code);
- code += 1 + LINK_SIZE;
- break;
- case OP_WORD_BOUNDARY:
- case OP_NOT_WORD_BOUNDARY:
- ++code;
- break;
- case OP_BRANUMBER:
- code += 3;
- break;
- default:
- return code;
- }
- }
-}
-
-/*************************************************
-* Get othercase range *
-*************************************************/
-
-/* This function is passed the start and end of a class range, in UTF-8 mode
-with UCP support. It searches up the characters, looking for internal ranges of
-characters in the "other" case. Each call returns the next one, updating the
-start address.
-
-Arguments:
- cptr points to starting character value; updated
- d end value
- ocptr where to put start of othercase range
- odptr where to put end of othercase range
-
-Yield: true when range returned; false when no more
-*/
-
-static bool getOthercaseRange(int* cptr, int d, int* ocptr, int* odptr)
-{
- int c, othercase = 0;
-
- for (c = *cptr; c <= d; c++) {
- if ((othercase = kjs_pcre_ucp_othercase(c)) >= 0)
- break;
- }
-
- if (c > d)
- return false;
-
- *ocptr = othercase;
- int next = othercase + 1;
-
- for (++c; c <= d; c++) {
- if (kjs_pcre_ucp_othercase(c) != next)
- break;
- next++;
- }
-
- *odptr = next - 1;
- *cptr = c;
-
- return true;
-}
-
-/*************************************************
- * Convert character value to UTF-8 *
- *************************************************/
-
-/* This function takes an integer value in the range 0 - 0x7fffffff
- and encodes it as a UTF-8 character in 0 to 6 bytes.
-
- Arguments:
- cvalue the character value
- buffer pointer to buffer for result - at least 6 bytes long
-
- Returns: number of characters placed in the buffer
- */
-
-static int encodeUTF8(int cvalue, unsigned char *buffer)
-{
- int i;
- for (i = 0; i < kjs_pcre_utf8_table1_size; i++)
- if (cvalue <= kjs_pcre_utf8_table1[i])
- break;
- buffer += i;
- for (int j = i; j > 0; j--) {
- *buffer-- = 0x80 | (cvalue & 0x3f);
- cvalue >>= 6;
- }
- *buffer = kjs_pcre_utf8_table2[i] | cvalue;
- return i + 1;
-}
-
-/*************************************************
-* Compile one branch *
-*************************************************/
-
-/* Scan the pattern, compiling it into the code vector.
-
-Arguments:
- options the option bits
- brackets points to number of extracting brackets used
- codeptr points to the pointer to the current code point
- ptrptr points to the current pattern pointer
- errorcodeptr points to error code variable
- firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE)
- reqbyteptr set to the last literal character required, else < 0
- cd contains pointers to tables etc.
-
-Returns: true on success
- false, with *errorcodeptr set non-zero on error
-*/
-
-static inline bool safelyCheckNextChar(const UChar* ptr, const UChar* patternEnd, UChar expected)
-{
- return ((ptr + 1 < patternEnd) && ptr[1] == expected);
-}
-
-static bool
-compileBranch(int options, int* brackets, unsigned char** codeptr,
- const UChar** ptrptr, const UChar* patternEnd, ErrorCode* errorcodeptr, int *firstbyteptr,
- int* reqbyteptr, CompileData& cd)
-{
- int repeat_type, op_type;
- int repeat_min = 0, repeat_max = 0; /* To please picky compilers */
- int bravalue = 0;
- int reqvary, tempreqvary;
- int c;
- unsigned char* code = *codeptr;
- unsigned char* tempcode;
- bool groupsetfirstbyte = false;
- const UChar* ptr = *ptrptr;
- unsigned char* previous = NULL;
- unsigned char classbits[32];
-
- bool class_utf8;
- unsigned char* class_utf8data;
- unsigned char utf8_char[6];
-
- /* Initialize no first byte, no required byte. REQ_UNSET means "no char
- matching encountered yet". It gets changed to REQ_NONE if we hit something that
- matches a non-fixed char first char; reqbyte just remains unset if we never
- find one.
-
- When we hit a repeat whose minimum is zero, we may have to adjust these values
- to take the zero repeat into account. This is implemented by setting them to
- zerofirstbyte and zeroreqbyte when such a repeat is encountered. The individual
- item types that can be repeated set these backoff variables appropriately. */
-
- int firstbyte = REQ_UNSET;
- int reqbyte = REQ_UNSET;
- int zeroreqbyte = REQ_UNSET;
- int zerofirstbyte = REQ_UNSET;
-
- /* The variable req_caseopt contains either the REQ_IGNORE_CASE value or zero,
- according to the current setting of the ignores-case flag. REQ_IGNORE_CASE is a bit
- value > 255. It is added into the firstbyte or reqbyte variables to record the
- case status of the value. This is used only for ASCII characters. */
-
- int req_caseopt = (options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0;
-
- /* Switch on next character until the end of the branch */
-
- for (;; ptr++) {
- bool negate_class;
- bool should_flip_negation; /* If a negative special such as \S is used, we should negate the whole class to properly support Unicode. */
- int class_charcount;
- int class_lastchar;
- int skipbytes;
- int subreqbyte;
- int subfirstbyte;
- int mclength;
- unsigned char mcbuffer[8];
-
- /* Next byte in the pattern */
-
- c = ptr < patternEnd ? *ptr : 0;
-
- /* Fill in length of a previous callout, except when the next thing is
- a quantifier. */
-
- bool is_quantifier = c == '*' || c == '+' || c == '?' || (c == '{' && isCountedRepeat(ptr + 1, patternEnd));
-
- switch (c) {
- /* The branch terminates at end of string, |, or ). */
-
- case 0:
- if (ptr < patternEnd)
- goto NORMAL_CHAR;
- // End of string; fall through
- case '|':
- case ')':
- *firstbyteptr = firstbyte;
- *reqbyteptr = reqbyte;
- *codeptr = code;
- *ptrptr = ptr;
- return true;
-
- /* Handle single-character metacharacters. In multiline mode, ^ disables
- the setting of any following char as a first character. */
-
- case '^':
- if (options & MatchAcrossMultipleLinesOption) {
- if (firstbyte == REQ_UNSET)
- firstbyte = REQ_NONE;
- *code++ = OP_BOL;
- } else
- *code++ = OP_CIRC;
- previous = NULL;
- break;
-
- case '$':
- previous = NULL;
- if (options & MatchAcrossMultipleLinesOption)
- *code++ = OP_EOL;
- else
- *code++ = OP_DOLL;
- break;
-
- /* There can never be a first char if '.' is first, whatever happens about
- repeats. The value of reqbyte doesn't change either. */
-
- case '.':
- if (firstbyte == REQ_UNSET)
- firstbyte = REQ_NONE;
- zerofirstbyte = firstbyte;
- zeroreqbyte = reqbyte;
- previous = code;
- *code++ = OP_NOT_NEWLINE;
- break;
-
- /* Character classes. If the included characters are all < 256, we build a
- 32-byte bitmap of the permitted characters, except in the special case
- where there is only one such character. For negated classes, we build the
- map as usual, then invert it at the end. However, we use a different opcode
- so that data characters > 255 can be handled correctly.
-
- If the class contains characters outside the 0-255 range, a different
- opcode is compiled. It may optionally have a bit map for characters < 256,
- but those above are are explicitly listed afterwards. A flag byte tells
- whether the bitmap is present, and whether this is a negated class or not.
- */
-
- case '[': {
- previous = code;
- should_flip_negation = false;
-
- /* PCRE supports POSIX class stuff inside a class. Perl gives an error if
- they are encountered at the top level, so we'll do that too. */
-
- /* If the first character is '^', set the negation flag and skip it. */
-
- if (ptr + 1 >= patternEnd) {
- *errorcodeptr = ERR6;
- return false;
- }
-
- if (ptr[1] == '^') {
- negate_class = true;
- ++ptr;
- } else
- negate_class = false;
-
- /* Keep a count of chars with values < 256 so that we can optimize the case
- of just a single character (as long as it's < 256). For higher valued UTF-8
- characters, we don't yet do any optimization. */
-
- class_charcount = 0;
- class_lastchar = -1;
-
- class_utf8 = false; /* No chars >= 256 */
- class_utf8data = code + LINK_SIZE + 34; /* For UTF-8 items */
-
- /* Initialize the 32-char bit map to all zeros. We have to build the
- map in a temporary bit of store, in case the class contains only 1
- character (< 256), because in that case the compiled code doesn't use the
- bit map. */
-
- memset(classbits, 0, 32 * sizeof(unsigned char));
-
- /* Process characters until ] is reached. The first pass
- through the regex checked the overall syntax, so we don't need to be very
- strict here. At the start of the loop, c contains the first byte of the
- character. */
-
- while ((++ptr < patternEnd) && (c = *ptr) != ']') {
- /* Backslash may introduce a single character, or it may introduce one
- of the specials, which just set a flag. Escaped items are checked for
- validity in the pre-compiling pass. The sequence \b is a special case.
- Inside a class (and only there) it is treated as backspace. Elsewhere
- it marks a word boundary. Other escapes have preset maps ready to
- or into the one we are building. We assume they have more than one
- character in them, so set class_charcount bigger than one. */
-
- if (c == '\\') {
- c = checkEscape(&ptr, patternEnd, errorcodeptr, cd.numCapturingBrackets, true);
- if (c < 0) {
- class_charcount += 2; /* Greater than 1 is what matters */
- switch (-c) {
- case ESC_d:
- for (c = 0; c < 32; c++)
- classbits[c] |= classBitmapForChar(c + cbit_digit);
- continue;
-
- case ESC_D:
- should_flip_negation = true;
- for (c = 0; c < 32; c++)
- classbits[c] |= ~classBitmapForChar(c + cbit_digit);
- continue;
-
- case ESC_w:
- for (c = 0; c < 32; c++)
- classbits[c] |= classBitmapForChar(c + cbit_word);
- continue;
-
- case ESC_W:
- should_flip_negation = true;
- for (c = 0; c < 32; c++)
- classbits[c] |= ~classBitmapForChar(c + cbit_word);
- continue;
-
- case ESC_s:
- for (c = 0; c < 32; c++)
- classbits[c] |= classBitmapForChar(c + cbit_space);
- continue;
-
- case ESC_S:
- should_flip_negation = true;
- for (c = 0; c < 32; c++)
- classbits[c] |= ~classBitmapForChar(c + cbit_space);
- continue;
-
- /* Unrecognized escapes are faulted if PCRE is running in its
- strict mode. By default, for compatibility with Perl, they are
- treated as literals. */
-
- default:
- c = *ptr; /* The final character */
- class_charcount -= 2; /* Undo the default count from above */
- }
- }
-
- /* Fall through if we have a single character (c >= 0). This may be
- > 256 in UTF-8 mode. */
-
- } /* End of backslash handling */
-
- /* A single character may be followed by '-' to form a range. However,
- Perl does not permit ']' to be the end of the range. A '-' character
- here is treated as a literal. */
-
- if ((ptr + 2 < patternEnd) && ptr[1] == '-' && ptr[2] != ']') {
- ptr += 2;
-
- int d = *ptr;
-
- /* The second part of a range can be a single-character escape, but
- not any of the other escapes. Perl 5.6 treats a hyphen as a literal
- in such circumstances. */
-
- if (d == '\\') {
- const UChar* oldptr = ptr;
- d = checkEscape(&ptr, patternEnd, errorcodeptr, cd.numCapturingBrackets, true);
-
- /* \X is literal X; any other special means the '-' was literal */
- if (d < 0) {
- ptr = oldptr - 2;
- goto LONE_SINGLE_CHARACTER; /* A few lines below */
- }
- }
-
- /* The check that the two values are in the correct order happens in
- the pre-pass. Optimize one-character ranges */
-
- if (d == c)
- goto LONE_SINGLE_CHARACTER; /* A few lines below */
-
- /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless
- matching, we have to use an XCLASS with extra data items. Caseless
- matching for characters > 127 is available only if UCP support is
- available. */
-
- if ((d > 255 || ((options & IgnoreCaseOption) && d > 127))) {
- class_utf8 = true;
-
- /* With UCP support, we can find the other case equivalents of
- the relevant characters. There may be several ranges. Optimize how
- they fit with the basic range. */
-
- if (options & IgnoreCaseOption) {
- int occ, ocd;
- int cc = c;
- int origd = d;
- while (getOthercaseRange(&cc, origd, &occ, &ocd)) {
- if (occ >= c && ocd <= d)
- continue; /* Skip embedded ranges */
-
- if (occ < c && ocd >= c - 1) /* Extend the basic range */
- { /* if there is overlap, */
- c = occ; /* noting that if occ < c */
- continue; /* we can't have ocd > d */
- } /* because a subrange is */
- if (ocd > d && occ <= d + 1) /* always shorter than */
- { /* the basic range. */
- d = ocd;
- continue;
- }
-
- if (occ == ocd)
- *class_utf8data++ = XCL_SINGLE;
- else {
- *class_utf8data++ = XCL_RANGE;
- class_utf8data += encodeUTF8(occ, class_utf8data);
- }
- class_utf8data += encodeUTF8(ocd, class_utf8data);
- }
- }
-
- /* Now record the original range, possibly modified for UCP caseless
- overlapping ranges. */
-
- *class_utf8data++ = XCL_RANGE;
- class_utf8data += encodeUTF8(c, class_utf8data);
- class_utf8data += encodeUTF8(d, class_utf8data);
-
- /* With UCP support, we are done. Without UCP support, there is no
- caseless matching for UTF-8 characters > 127; we can use the bit map
- for the smaller ones. */
-
- continue; /* With next character in the class */
- }
-
- /* We use the bit map for all cases when not in UTF-8 mode; else
- ranges that lie entirely within 0-127 when there is UCP support; else
- for partial ranges without UCP support. */
-
- for (; c <= d; c++) {
- classbits[c/8] |= (1 << (c&7));
- if (options & IgnoreCaseOption) {
- int uc = flipCase(c);
- classbits[uc/8] |= (1 << (uc&7));
- }
- class_charcount++; /* in case a one-char range */
- class_lastchar = c;
- }
-
- continue; /* Go get the next char in the class */
- }
-
- /* Handle a lone single character - we can get here for a normal
- non-escape char, or after \ that introduces a single character or for an
- apparent range that isn't. */
-
- LONE_SINGLE_CHARACTER:
-
- /* Handle a character that cannot go in the bit map */
-
- if ((c > 255 || ((options & IgnoreCaseOption) && c > 127))) {
- class_utf8 = true;
- *class_utf8data++ = XCL_SINGLE;
- class_utf8data += encodeUTF8(c, class_utf8data);
-
- if (options & IgnoreCaseOption) {
- int othercase;
- if ((othercase = kjs_pcre_ucp_othercase(c)) >= 0) {
- *class_utf8data++ = XCL_SINGLE;
- class_utf8data += encodeUTF8(othercase, class_utf8data);
- }
- }
- } else {
- /* Handle a single-byte character */
- classbits[c/8] |= (1 << (c&7));
- if (options & IgnoreCaseOption) {
- c = flipCase(c);
- classbits[c/8] |= (1 << (c&7));
- }
- class_charcount++;
- class_lastchar = c;
- }
- }
-
- /* If class_charcount is 1, we saw precisely one character whose value is
- less than 256. In non-UTF-8 mode we can always optimize. In UTF-8 mode, we
- can optimize the negative case only if there were no characters >= 128
- because OP_NOT and the related opcodes like OP_NOTSTAR operate on
- single-bytes only. This is an historical hangover. Maybe one day we can
- tidy these opcodes to handle multi-byte characters.
-
- The optimization throws away the bit map. We turn the item into a
- 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note
- that OP_NOT does not support multibyte characters. In the positive case, it
- can cause firstbyte to be set. Otherwise, there can be no first char if
- this item is first, whatever repeat count may follow. In the case of
- reqbyte, save the previous value for reinstating. */
-
- if (class_charcount == 1 && (!class_utf8 && (!negate_class || class_lastchar < 128))) {
- zeroreqbyte = reqbyte;
-
- /* The OP_NOT opcode works on one-byte characters only. */
-
- if (negate_class) {
- if (firstbyte == REQ_UNSET)
- firstbyte = REQ_NONE;
- zerofirstbyte = firstbyte;
- *code++ = OP_NOT;
- *code++ = class_lastchar;
- break;
- }
-
- /* For a single, positive character, get the value into c, and
- then we can handle this with the normal one-character code. */
-
- c = class_lastchar;
- goto NORMAL_CHAR;
- } /* End of 1-char optimization */
-
- /* The general case - not the one-char optimization. If this is the first
- thing in the branch, there can be no first char setting, whatever the
- repeat count. Any reqbyte setting must remain unchanged after any kind of
- repeat. */
-
- if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;
- zerofirstbyte = firstbyte;
- zeroreqbyte = reqbyte;
-
- /* If there are characters with values > 255, we have to compile an
- extended class, with its own opcode. If there are no characters < 256,
- we can omit the bitmap. */
-
- if (class_utf8 && !should_flip_negation) {
- *class_utf8data++ = XCL_END; /* Marks the end of extra data */
- *code++ = OP_XCLASS;
- code += LINK_SIZE;
- *code = negate_class? XCL_NOT : 0;
-
- /* If the map is required, install it, and move on to the end of
- the extra data */
-
- if (class_charcount > 0) {
- *code++ |= XCL_MAP;
- memcpy(code, classbits, 32);
- code = class_utf8data;
- }
-
- /* If the map is not required, slide down the extra data. */
-
- else {
- int len = class_utf8data - (code + 33);
- memmove(code + 1, code + 33, len);
- code += len + 1;
- }
-
- /* Now fill in the complete length of the item */
-
- putLinkValue(previous + 1, code - previous);
- break; /* End of class handling */
- }
-
- /* If there are no characters > 255, negate the 32-byte map if necessary,
- and copy it into the code vector. If this is the first thing in the branch,
- there can be no first char setting, whatever the repeat count. Any reqbyte
- setting must remain unchanged after any kind of repeat. */
-
- *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS;
- if (negate_class)
- for (c = 0; c < 32; c++)
- code[c] = ~classbits[c];
- else
- memcpy(code, classbits, 32);
- code += 32;
- break;
- }
-
- /* Various kinds of repeat; '{' is not necessarily a quantifier, but this
- has been tested above. */
-
- case '{':
- if (!is_quantifier)
- goto NORMAL_CHAR;
- ptr = readRepeatCounts(ptr + 1, &repeat_min, &repeat_max, errorcodeptr);
- if (*errorcodeptr)
- goto FAILED;
- goto REPEAT;
-
- case '*':
- repeat_min = 0;
- repeat_max = -1;
- goto REPEAT;
-
- case '+':
- repeat_min = 1;
- repeat_max = -1;
- goto REPEAT;
-
- case '?':
- repeat_min = 0;
- repeat_max = 1;
-
- REPEAT:
- if (!previous) {
- *errorcodeptr = ERR9;
- goto FAILED;
- }
-
- if (repeat_min == 0) {
- firstbyte = zerofirstbyte; /* Adjust for zero repeat */
- reqbyte = zeroreqbyte; /* Ditto */
- }
-
- /* Remember whether this is a variable length repeat */
-
- reqvary = (repeat_min == repeat_max) ? 0 : REQ_VARY;
-
- op_type = 0; /* Default single-char op codes */
-
- /* Save start of previous item, in case we have to move it up to make space
- for an inserted OP_ONCE for the additional '+' extension. */
- /* FIXME: Probably don't need this because we don't use OP_ONCE. */
-
- tempcode = previous;
-
- /* If the next character is '+', we have a possessive quantifier. This
- implies greediness, whatever the setting of the PCRE_UNGREEDY option.
- If the next character is '?' this is a minimizing repeat, by default,
- but if PCRE_UNGREEDY is set, it works the other way round. We change the
- repeat type to the non-default. */
-
- if (safelyCheckNextChar(ptr, patternEnd, '?')) {
- repeat_type = 1;
- ptr++;
- } else
- repeat_type = 0;
-
- /* If previous was a character match, abolish the item and generate a
- repeat item instead. If a char item has a minumum of more than one, ensure
- that it is set in reqbyte - it might not be if a sequence such as x{3} is
- the first thing in a branch because the x will have gone into firstbyte
- instead. */
-
- if (*previous == OP_CHAR || *previous == OP_CHAR_IGNORING_CASE) {
- /* Deal with UTF-8 characters that take up more than one byte. It's
- easier to write this out separately than try to macrify it. Use c to
- hold the length of the character in bytes, plus 0x80 to flag that it's a
- length rather than a small character. */
-
- if (code[-1] & 0x80) {
- unsigned char *lastchar = code - 1;
- while((*lastchar & 0xc0) == 0x80)
- lastchar--;
- c = code - lastchar; /* Length of UTF-8 character */
- memcpy(utf8_char, lastchar, c); /* Save the char */
- c |= 0x80; /* Flag c as a length */
- }
- else {
- c = code[-1];
- if (repeat_min > 1)
- reqbyte = c | req_caseopt | cd.req_varyopt;
- }
-
- goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */
- }
-
- else if (*previous == OP_ASCII_CHAR || *previous == OP_ASCII_LETTER_IGNORING_CASE) {
- c = previous[1];
- if (repeat_min > 1)
- reqbyte = c | req_caseopt | cd.req_varyopt;
- goto OUTPUT_SINGLE_REPEAT;
- }
-
- /* If previous was a single negated character ([^a] or similar), we use
- one of the special opcodes, replacing it. The code is shared with single-
- character repeats by setting opt_type to add a suitable offset into
- repeat_type. OP_NOT is currently used only for single-byte chars. */
-
- else if (*previous == OP_NOT) {
- op_type = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */
- c = previous[1];
- goto OUTPUT_SINGLE_REPEAT;
- }
-
- /* If previous was a character type match (\d or similar), abolish it and
- create a suitable repeat item. The code is shared with single-character
- repeats by setting op_type to add a suitable offset into repeat_type. */
-
- else if (*previous <= OP_NOT_NEWLINE) {
- op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */
- c = *previous;
-
- OUTPUT_SINGLE_REPEAT:
- int prop_type = -1;
- int prop_value = -1;
-
- unsigned char* oldcode = code;
- code = previous; /* Usually overwrite previous item */
-
- /* If the maximum is zero then the minimum must also be zero; Perl allows
- this case, so we do too - by simply omitting the item altogether. */
-
- if (repeat_max == 0)
- goto END_REPEAT;
-
- /* Combine the op_type with the repeat_type */
-
- repeat_type += op_type;
-
- /* A minimum of zero is handled either as the special case * or ?, or as
- an UPTO, with the maximum given. */
-
- if (repeat_min == 0) {
- if (repeat_max == -1)
- *code++ = OP_STAR + repeat_type;
- else if (repeat_max == 1)
- *code++ = OP_QUERY + repeat_type;
- else {
- *code++ = OP_UPTO + repeat_type;
- put2ByteValueAndAdvance(code, repeat_max);
- }
- }
-
- /* A repeat minimum of 1 is optimized into some special cases. If the
- maximum is unlimited, we use OP_PLUS. Otherwise, the original item it
- left in place and, if the maximum is greater than 1, we use OP_UPTO with
- one less than the maximum. */
-
- else if (repeat_min == 1) {
- if (repeat_max == -1)
- *code++ = OP_PLUS + repeat_type;
- else {
- code = oldcode; /* leave previous item in place */
- if (repeat_max == 1)
- goto END_REPEAT;
- *code++ = OP_UPTO + repeat_type;
- put2ByteValueAndAdvance(code, repeat_max - 1);
- }
- }
-
- /* The case {n,n} is just an EXACT, while the general case {n,m} is
- handled as an EXACT followed by an UPTO. */
-
- else {
- *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */
- put2ByteValueAndAdvance(code, repeat_min);
-
- /* If the maximum is unlimited, insert an OP_STAR. Before doing so,
- we have to insert the character for the previous code. For a repeated
- Unicode property match, there are two extra bytes that define the
- required property. In UTF-8 mode, long characters have their length in
- c, with the 0x80 bit as a flag. */
-
- if (repeat_max < 0) {
- if (c >= 128) {
- memcpy(code, utf8_char, c & 7);
- code += c & 7;
- } else {
- *code++ = c;
- if (prop_type >= 0) {
- *code++ = prop_type;
- *code++ = prop_value;
- }
- }
- *code++ = OP_STAR + repeat_type;
- }
-
- /* Else insert an UPTO if the max is greater than the min, again
- preceded by the character, for the previously inserted code. */
-
- else if (repeat_max != repeat_min) {
- if (c >= 128) {
- memcpy(code, utf8_char, c & 7);
- code += c & 7;
- } else
- *code++ = c;
- if (prop_type >= 0) {
- *code++ = prop_type;
- *code++ = prop_value;
- }
- repeat_max -= repeat_min;
- *code++ = OP_UPTO + repeat_type;
- put2ByteValueAndAdvance(code, repeat_max);
- }
- }
-
- /* The character or character type itself comes last in all cases. */
-
- if (c >= 128) {
- memcpy(code, utf8_char, c & 7);
- code += c & 7;
- } else
- *code++ = c;
-
- /* For a repeated Unicode property match, there are two extra bytes that
- define the required property. */
-
- if (prop_type >= 0) {
- *code++ = prop_type;
- *code++ = prop_value;
- }
- }
-
- /* If previous was a character class or a back reference, we put the repeat
- stuff after it, but just skip the item if the repeat was {0,0}. */
-
- else if (*previous == OP_CLASS ||
- *previous == OP_NCLASS ||
- *previous == OP_XCLASS ||
- *previous == OP_REF)
- {
- if (repeat_max == 0) {
- code = previous;
- goto END_REPEAT;
- }
-
- if (repeat_min == 0 && repeat_max == -1)
- *code++ = OP_CRSTAR + repeat_type;
- else if (repeat_min == 1 && repeat_max == -1)
- *code++ = OP_CRPLUS + repeat_type;
- else if (repeat_min == 0 && repeat_max == 1)
- *code++ = OP_CRQUERY + repeat_type;
- else {
- *code++ = OP_CRRANGE + repeat_type;
- put2ByteValueAndAdvance(code, repeat_min);
- if (repeat_max == -1)
- repeat_max = 0; /* 2-byte encoding for max */
- put2ByteValueAndAdvance(code, repeat_max);
- }
- }
-
- /* If previous was a bracket group, we may have to replicate it in certain
- cases. */
-
- else if (*previous >= OP_BRA) {
- int ketoffset = 0;
- int len = code - previous;
- unsigned char* bralink = NULL;
-
- /* If the maximum repeat count is unlimited, find the end of the bracket
- by scanning through from the start, and compute the offset back to it
- from the current code pointer. There may be an OP_OPT setting following
- the final KET, so we can't find the end just by going back from the code
- pointer. */
-
- if (repeat_max == -1) {
- const unsigned char* ket = previous;
- advanceToEndOfBracket(ket);
- ketoffset = code - ket;
- }
-
- /* The case of a zero minimum is special because of the need to stick
- OP_BRAZERO in front of it, and because the group appears once in the
- data, whereas in other cases it appears the minimum number of times. For
- this reason, it is simplest to treat this case separately, as otherwise
- the code gets far too messy. There are several special subcases when the
- minimum is zero. */
-
- if (repeat_min == 0) {
- /* If the maximum is also zero, we just omit the group from the output
- altogether. */
-
- if (repeat_max == 0) {
- code = previous;
- goto END_REPEAT;
- }
-
- /* If the maximum is 1 or unlimited, we just have to stick in the
- BRAZERO and do no more at this point. However, we do need to adjust
- any OP_RECURSE calls inside the group that refer to the group itself or
- any internal group, because the offset is from the start of the whole
- regex. Temporarily terminate the pattern while doing this. */
-
- if (repeat_max <= 1) {
- *code = OP_END;
- memmove(previous+1, previous, len);
- code++;
- *previous++ = OP_BRAZERO + repeat_type;
- }
-
- /* If the maximum is greater than 1 and limited, we have to replicate
- in a nested fashion, sticking OP_BRAZERO before each set of brackets.
- The first one has to be handled carefully because it's the original
- copy, which has to be moved up. The remainder can be handled by code
- that is common with the non-zero minimum case below. We have to
- adjust the value of repeat_max, since one less copy is required. */
-
- else {
- *code = OP_END;
- memmove(previous + 2 + LINK_SIZE, previous, len);
- code += 2 + LINK_SIZE;
- *previous++ = OP_BRAZERO + repeat_type;
- *previous++ = OP_BRA;
-
- /* We chain together the bracket offset fields that have to be
- filled in later when the ends of the brackets are reached. */
-
- int offset = (!bralink) ? 0 : previous - bralink;
- bralink = previous;
- putLinkValueAllowZeroAndAdvance(previous, offset);
- }
-
- repeat_max--;
- }
-
- /* If the minimum is greater than zero, replicate the group as many
- times as necessary, and adjust the maximum to the number of subsequent
- copies that we need. If we set a first char from the group, and didn't
- set a required char, copy the latter from the former. */
-
- else {
- if (repeat_min > 1) {
- if (groupsetfirstbyte && reqbyte < 0)
- reqbyte = firstbyte;
- for (int i = 1; i < repeat_min; i++) {
- memcpy(code, previous, len);
- code += len;
- }
- }
- if (repeat_max > 0)
- repeat_max -= repeat_min;
- }
-
- /* This code is common to both the zero and non-zero minimum cases. If
- the maximum is limited, it replicates the group in a nested fashion,
- remembering the bracket starts on a stack. In the case of a zero minimum,
- the first one was set up above. In all cases the repeat_max now specifies
- the number of additional copies needed. */
-
- if (repeat_max >= 0) {
- for (int i = repeat_max - 1; i >= 0; i--) {
- *code++ = OP_BRAZERO + repeat_type;
-
- /* All but the final copy start a new nesting, maintaining the
- chain of brackets outstanding. */
-
- if (i != 0) {
- *code++ = OP_BRA;
- int offset = (!bralink) ? 0 : code - bralink;
- bralink = code;
- putLinkValueAllowZeroAndAdvance(code, offset);
- }
-
- memcpy(code, previous, len);
- code += len;
- }
-
- /* Now chain through the pending brackets, and fill in their length
- fields (which are holding the chain links pro tem). */
-
- while (bralink) {
- int offset = code - bralink + 1;
- unsigned char* bra = code - offset;
- int oldlinkoffset = getLinkValueAllowZero(bra + 1);
- bralink = (!oldlinkoffset) ? 0 : bralink - oldlinkoffset;
- *code++ = OP_KET;
- putLinkValueAndAdvance(code, offset);
- putLinkValue(bra + 1, offset);
- }
- }
-
- /* If the maximum is unlimited, set a repeater in the final copy. We
- can't just offset backwards from the current code point, because we
- don't know if there's been an options resetting after the ket. The
- correct offset was computed above. */
-
- else
- code[-ketoffset] = OP_KETRMAX + repeat_type;
- }
-
- /* Else there's some kind of shambles */
-
- else {
- *errorcodeptr = ERR11;
- goto FAILED;
- }
-
- /* In all case we no longer have a previous item. We also set the
- "follows varying string" flag for subsequently encountered reqbytes if
- it isn't already set and we have just passed a varying length item. */
-
- END_REPEAT:
- previous = NULL;
- cd.req_varyopt |= reqvary;
- break;
-
- /* Start of nested bracket sub-expression, or comment or lookahead or
- lookbehind or option setting or condition. First deal with special things
- that can come after a bracket; all are introduced by ?, and the appearance
- of any of them means that this is not a referencing group. They were
- checked for validity in the first pass over the string, so we don't have to
- check for syntax errors here. */
-
- case '(':
- skipbytes = 0;
-
- if (*(++ptr) == '?') {
- switch (*(++ptr)) {
- case ':': /* Non-extracting bracket */
- bravalue = OP_BRA;
- ptr++;
- break;
-
- case '=': /* Positive lookahead */
- bravalue = OP_ASSERT;
- ptr++;
- break;
-
- case '!': /* Negative lookahead */
- bravalue = OP_ASSERT_NOT;
- ptr++;
- break;
-
- /* Character after (? not specially recognized */
-
- default:
- *errorcodeptr = ERR12;
- goto FAILED;
- }
- }
-
- /* Else we have a referencing group; adjust the opcode. If the bracket
- number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and
- arrange for the true number to follow later, in an OP_BRANUMBER item. */
-
- else {
- if (++(*brackets) > EXTRACT_BASIC_MAX) {
- bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1;
- code[1 + LINK_SIZE] = OP_BRANUMBER;
- put2ByteValue(code + 2 + LINK_SIZE, *brackets);
- skipbytes = 3;
- }
- else
- bravalue = OP_BRA + *brackets;
- }
-
- /* Process nested bracketed re. Assertions may not be repeated, but other
- kinds can be. We copy code into a non-variable in order to be able
- to pass its address because some compilers complain otherwise. Pass in a
- new setting for the ims options if they have changed. */
-
- previous = (bravalue >= OP_BRAZERO) ? code : 0;
- *code = bravalue;
- tempcode = code;
- tempreqvary = cd.req_varyopt; /* Save value before bracket */
-
- if (!compileBracket(
- options,
- brackets, /* Extracting bracket count */
- &tempcode, /* Where to put code (updated) */
- &ptr, /* Input pointer (updated) */
- patternEnd,
- errorcodeptr, /* Where to put an error message */
- skipbytes, /* Skip over OP_BRANUMBER */
- &subfirstbyte, /* For possible first char */
- &subreqbyte, /* For possible last char */
- cd)) /* Tables block */
- goto FAILED;
-
- /* At the end of compiling, code is still pointing to the start of the
- group, while tempcode has been updated to point past the end of the group
- and any option resetting that may follow it. The pattern pointer (ptr)
- is on the bracket. */
-
- /* Handle updating of the required and first characters. Update for normal
- brackets of all kinds, and conditions with two branches (see code above).
- If the bracket is followed by a quantifier with zero repeat, we have to
- back off. Hence the definition of zeroreqbyte and zerofirstbyte outside the
- main loop so that they can be accessed for the back off. */
-
- zeroreqbyte = reqbyte;
- zerofirstbyte = firstbyte;
- groupsetfirstbyte = false;
-
- if (bravalue >= OP_BRA) {
- /* If we have not yet set a firstbyte in this branch, take it from the
- subpattern, remembering that it was set here so that a repeat of more
- than one can replicate it as reqbyte if necessary. If the subpattern has
- no firstbyte, set "none" for the whole branch. In both cases, a zero
- repeat forces firstbyte to "none". */
-
- if (firstbyte == REQ_UNSET) {
- if (subfirstbyte >= 0) {
- firstbyte = subfirstbyte;
- groupsetfirstbyte = true;
- }
- else
- firstbyte = REQ_NONE;
- zerofirstbyte = REQ_NONE;
- }
-
- /* If firstbyte was previously set, convert the subpattern's firstbyte
- into reqbyte if there wasn't one, using the vary flag that was in
- existence beforehand. */
-
- else if (subfirstbyte >= 0 && subreqbyte < 0)
- subreqbyte = subfirstbyte | tempreqvary;
-
- /* If the subpattern set a required byte (or set a first byte that isn't
- really the first byte - see above), set it. */
-
- if (subreqbyte >= 0)
- reqbyte = subreqbyte;
- }
-
- /* For a forward assertion, we take the reqbyte, if set. This can be
- helpful if the pattern that follows the assertion doesn't set a different
- char. For example, it's useful for /(?=abcde).+/. We can't set firstbyte
- for an assertion, however because it leads to incorrect effect for patterns
- such as /(?=a)a.+/ when the "real" "a" would then become a reqbyte instead
- of a firstbyte. This is overcome by a scan at the end if there's no
- firstbyte, looking for an asserted first char. */
-
- else if (bravalue == OP_ASSERT && subreqbyte >= 0)
- reqbyte = subreqbyte;
-
- /* Now update the main code pointer to the end of the group. */
-
- code = tempcode;
-
- /* Error if hit end of pattern */
-
- if (ptr >= patternEnd || *ptr != ')') {
- *errorcodeptr = ERR14;
- goto FAILED;
- }
- break;
-
- /* Check \ for being a real metacharacter; if not, fall through and handle
- it as a data character at the start of a string. Escape items are checked
- for validity in the pre-compiling pass. */
-
- case '\\':
- c = checkEscape(&ptr, patternEnd, errorcodeptr, cd.numCapturingBrackets, false);
-
- /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values
- are arranged to be the negation of the corresponding OP_values. For the
- back references, the values are ESC_REF plus the reference number. Only
- back references and those types that consume a character may be repeated.
- We can test for values between ESC_b and ESC_w for the latter; this may
- have to change if any new ones are ever created. */
-
- if (c < 0) {
- /* For metasequences that actually match a character, we disable the
- setting of a first character if it hasn't already been set. */
-
- if (firstbyte == REQ_UNSET && -c > ESC_b && -c <= ESC_w)
- firstbyte = REQ_NONE;
-
- /* Set values to reset to if this is followed by a zero repeat. */
-
- zerofirstbyte = firstbyte;
- zeroreqbyte = reqbyte;
-
- /* Back references are handled specially */
-
- if (-c >= ESC_REF) {
- int number = -c - ESC_REF;
- previous = code;
- *code++ = OP_REF;
- put2ByteValueAndAdvance(code, number);
- }
-
- /* For the rest, we can obtain the OP value by negating the escape
- value */
-
- else {
- previous = (-c > ESC_b && -c <= ESC_w) ? code : NULL;
- *code++ = -c;
- }
- continue;
- }
-
- /* Fall through. */
-
- /* Handle a literal character. It is guaranteed not to be whitespace or #
- when the extended flag is set. If we are in UTF-8 mode, it may be a
- multi-byte literal character. */
-
- default:
- NORMAL_CHAR:
-
- previous = code;
-
- if (c < 128) {
- mclength = 1;
- mcbuffer[0] = c;
-
- if ((options & IgnoreCaseOption) && (c | 0x20) >= 'a' && (c | 0x20) <= 'z') {
- *code++ = OP_ASCII_LETTER_IGNORING_CASE;
- *code++ = c | 0x20;
- } else {
- *code++ = OP_ASCII_CHAR;
- *code++ = c;
- }
- } else {
- mclength = encodeUTF8(c, mcbuffer);
-
- *code++ = (options & IgnoreCaseOption) ? OP_CHAR_IGNORING_CASE : OP_CHAR;
- for (c = 0; c < mclength; c++)
- *code++ = mcbuffer[c];
- }
-
- /* Set the first and required bytes appropriately. If no previous first
- byte, set it from this character, but revert to none on a zero repeat.
- Otherwise, leave the firstbyte value alone, and don't change it on a zero
- repeat. */
-
- if (firstbyte == REQ_UNSET) {
- zerofirstbyte = REQ_NONE;
- zeroreqbyte = reqbyte;
-
- /* If the character is more than one byte long, we can set firstbyte
- only if it is not to be matched caselessly. */
-
- if (mclength == 1 || req_caseopt == 0) {
- firstbyte = mcbuffer[0] | req_caseopt;
- if (mclength != 1)
- reqbyte = code[-1] | cd.req_varyopt;
- }
- else
- firstbyte = reqbyte = REQ_NONE;
- }
-
- /* firstbyte was previously set; we can set reqbyte only the length is
- 1 or the matching is caseful. */
-
- else {
- zerofirstbyte = firstbyte;
- zeroreqbyte = reqbyte;
- if (mclength == 1 || req_caseopt == 0)
- reqbyte = code[-1] | req_caseopt | cd.req_varyopt;
- }
-
- break; /* End of literal character handling */
- }
- } /* end of big loop */
-
- /* Control never reaches here by falling through, only by a goto for all the
- error states. Pass back the position in the pattern so that it can be displayed
- to the user for diagnosing the error. */
-
-FAILED:
- *ptrptr = ptr;
- return false;
-}
-
-/*************************************************
-* Compile sequence of alternatives *
-*************************************************/
-
-/* On entry, ptr is pointing past the bracket character, but on return
-it points to the closing bracket, or vertical bar, or end of string.
-The code variable is pointing at the byte into which the BRA operator has been
-stored. If the ims options are changed at the start (for a (?ims: group) or
-during any branch, we need to insert an OP_OPT item at the start of every
-following branch to ensure they get set correctly at run time, and also pass
-the new options into every subsequent branch compile.
-
-Argument:
- options option bits, including any changes for this subpattern
- brackets -> int containing the number of extracting brackets used
- codeptr -> the address of the current code pointer
- ptrptr -> the address of the current pattern pointer
- errorcodeptr -> pointer to error code variable
- skipbytes skip this many bytes at start (for OP_BRANUMBER)
- firstbyteptr place to put the first required character, or a negative number
- reqbyteptr place to put the last required character, or a negative number
- cd points to the data block with tables pointers etc.
-
-Returns: true on success
-*/
-
-static bool
-compileBracket(int options, int* brackets, unsigned char** codeptr,
- const UChar** ptrptr, const UChar* patternEnd, ErrorCode* errorcodeptr, int skipbytes,
- int* firstbyteptr, int* reqbyteptr, CompileData& cd)
-{
- const UChar* ptr = *ptrptr;
- unsigned char* code = *codeptr;
- unsigned char* last_branch = code;
- unsigned char* start_bracket = code;
- int firstbyte = REQ_UNSET;
- int reqbyte = REQ_UNSET;
-
- /* Offset is set zero to mark that this bracket is still open */
-
- putLinkValueAllowZero(code + 1, 0);
- code += 1 + LINK_SIZE + skipbytes;
-
- /* Loop for each alternative branch */
-
- while (true) {
- /* Now compile the branch */
-
- int branchfirstbyte;
- int branchreqbyte;
- if (!compileBranch(options, brackets, &code, &ptr, patternEnd, errorcodeptr,
- &branchfirstbyte, &branchreqbyte, cd)) {
- *ptrptr = ptr;
- return false;
- }
-
- /* If this is the first branch, the firstbyte and reqbyte values for the
- branch become the values for the regex. */
-
- if (*last_branch != OP_ALT) {
- firstbyte = branchfirstbyte;
- reqbyte = branchreqbyte;
- }
-
- /* If this is not the first branch, the first char and reqbyte have to
- match the values from all the previous branches, except that if the previous
- value for reqbyte didn't have REQ_VARY set, it can still match, and we set
- REQ_VARY for the regex. */
-
- else {
- /* If we previously had a firstbyte, but it doesn't match the new branch,
- we have to abandon the firstbyte for the regex, but if there was previously
- no reqbyte, it takes on the value of the old firstbyte. */
-
- if (firstbyte >= 0 && firstbyte != branchfirstbyte) {
- if (reqbyte < 0)
- reqbyte = firstbyte;
- firstbyte = REQ_NONE;
- }
-
- /* If we (now or from before) have no firstbyte, a firstbyte from the
- branch becomes a reqbyte if there isn't a branch reqbyte. */
-
- if (firstbyte < 0 && branchfirstbyte >= 0 && branchreqbyte < 0)
- branchreqbyte = branchfirstbyte;
-
- /* Now ensure that the reqbytes match */
-
- if ((reqbyte & ~REQ_VARY) != (branchreqbyte & ~REQ_VARY))
- reqbyte = REQ_NONE;
- else
- reqbyte |= branchreqbyte; /* To "or" REQ_VARY */
- }
-
- /* Reached end of expression, either ')' or end of pattern. Go back through
- the alternative branches and reverse the chain of offsets, with the field in
- the BRA item now becoming an offset to the first alternative. If there are
- no alternatives, it points to the end of the group. The length in the
- terminating ket is always the length of the whole bracketed item. If any of
- the ims options were changed inside the group, compile a resetting op-code
- following, except at the very end of the pattern. Return leaving the pointer
- at the terminating char. */
-
- if (ptr >= patternEnd || *ptr != '|') {
- int length = code - last_branch;
- do {
- int prev_length = getLinkValueAllowZero(last_branch + 1);
- putLinkValue(last_branch + 1, length);
- length = prev_length;
- last_branch -= length;
- } while (length > 0);
-
- /* Fill in the ket */
-
- *code = OP_KET;
- putLinkValue(code + 1, code - start_bracket);
- code += 1 + LINK_SIZE;
-
- /* Set values to pass back */
-
- *codeptr = code;
- *ptrptr = ptr;
- *firstbyteptr = firstbyte;
- *reqbyteptr = reqbyte;
- return true;
- }
-
- /* Another branch follows; insert an "or" node. Its length field points back
- to the previous branch while the bracket remains open. At the end the chain
- is reversed. It's done like this so that the start of the bracket has a
- zero offset until it is closed, making it possible to detect recursion. */
-
- *code = OP_ALT;
- putLinkValue(code + 1, code - last_branch);
- last_branch = code;
- code += 1 + LINK_SIZE;
- ptr++;
- }
- ASSERT_NOT_REACHED();
-}
-
-/*************************************************
-* Check for anchored expression *
-*************************************************/
-
-/* Try to find out if this is an anchored regular expression. Consider each
-alternative branch. If they all start OP_CIRC, or with a bracket
-all of whose alternatives start OP_CIRC (recurse ad lib), then
-it's anchored.
-
-Arguments:
- code points to start of expression (the bracket)
- captureMap a bitmap of which brackets we are inside while testing; this
- handles up to substring 31; all brackets after that share
- the zero bit
- backrefMap the back reference bitmap
-*/
-
-static bool branchIsAnchored(const unsigned char* code)
-{
- const unsigned char* scode = firstSignificantOpcode(code);
- int op = *scode;
-
- /* Brackets */
- if (op >= OP_BRA || op == OP_ASSERT)
- return bracketIsAnchored(scode);
-
- /* Check for explicit anchoring */
- return op == OP_CIRC;
-}
-
-static bool bracketIsAnchored(const unsigned char* code)
-{
- do {
- if (!branchIsAnchored(code + 1 + LINK_SIZE))
- return false;
- code += getLinkValue(code + 1);
- } while (*code == OP_ALT); /* Loop for each alternative */
- return true;
-}
-
-/*************************************************
-* Check for starting with ^ or .* *
-*************************************************/
-
-/* This is called to find out if every branch starts with ^ or .* so that
-"first char" processing can be done to speed things up in multiline
-matching and for non-DOTALL patterns that start with .* (which must start at
-the beginning or after \n)
-
-Except when the .* appears inside capturing parentheses, and there is a
-subsequent back reference to those parentheses. By keeping a bitmap of the
-first 31 back references, we can catch some of the more common cases more
-precisely; all the greater back references share a single bit.
-
-Arguments:
- code points to start of expression (the bracket)
- captureMap a bitmap of which brackets we are inside while testing; this
- handles up to substring 31; all brackets after that share
- the zero bit
- backrefMap the back reference bitmap
-*/
-
-static bool branchNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap)
-{
- const unsigned char* scode = firstSignificantOpcode(code);
- int op = *scode;
-
- /* Capturing brackets */
- if (op > OP_BRA) {
- int captureNum = op - OP_BRA;
- if (captureNum > EXTRACT_BASIC_MAX)
- captureNum = get2ByteValue(scode + 2 + LINK_SIZE);
- int bracketMask = (captureNum < 32) ? (1 << captureNum) : 1;
- return bracketNeedsLineStart(scode, captureMap | bracketMask, backrefMap);
- }
-
- /* Other brackets */
- if (op == OP_BRA || op == OP_ASSERT)
- return bracketNeedsLineStart(scode, captureMap, backrefMap);
-
- /* .* means "start at start or after \n" if it isn't in brackets that
- may be referenced. */
-
- if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR)
- return scode[1] == OP_NOT_NEWLINE && !(captureMap & backrefMap);
-
- /* Explicit ^ */
- return op == OP_CIRC || op == OP_BOL;
-}
-
-static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap)
-{
- do {
- if (!branchNeedsLineStart(code + 1 + LINK_SIZE, captureMap, backrefMap))
- return false;
- code += getLinkValue(code + 1);
- } while (*code == OP_ALT); /* Loop for each alternative */
- return true;
-}
-
-/*************************************************
-* Check for asserted fixed first char *
-*************************************************/
-
-/* During compilation, the "first char" settings from forward assertions are
-discarded, because they can cause conflicts with actual literals that follow.
-However, if we end up without a first char setting for an unanchored pattern,
-it is worth scanning the regex to see if there is an initial asserted first
-char. If all branches start with the same asserted char, or with a bracket all
-of whose alternatives start with the same asserted char (recurse ad lib), then
-we return that char, otherwise -1.
-
-Arguments:
- code points to start of expression (the bracket)
- options pointer to the options (used to check casing changes)
- inassert true if in an assertion
-
-Returns: -1 or the fixed first char
-*/
-
-static int branchFindFirstAssertedCharacter(const unsigned char* code, bool inassert)
-{
- const unsigned char* scode = firstSignificantOpcodeSkippingAssertions(code);
- int op = *scode;
-
- if (op >= OP_BRA)
- op = OP_BRA;
-
- switch (op) {
- default:
- return -1;
-
- case OP_BRA:
- case OP_ASSERT:
- return bracketFindFirstAssertedCharacter(scode, op == OP_ASSERT);
-
- case OP_EXACT:
- scode += 2;
- /* Fall through */
-
- case OP_CHAR:
- case OP_CHAR_IGNORING_CASE:
- case OP_ASCII_CHAR:
- case OP_ASCII_LETTER_IGNORING_CASE:
- case OP_PLUS:
- case OP_MINPLUS:
- if (!inassert)
- return -1;
- return scode[1];
- }
-}
-
-static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert)
-{
- int c = -1;
- do {
- int d = branchFindFirstAssertedCharacter(code + 1 + LINK_SIZE, inassert);
- if (d < 0)
- return -1;
- if (c < 0)
- c = d;
- else if (c != d)
- return -1;
- code += getLinkValue(code + 1);
- } while (*code == OP_ALT);
- return c;
-}
-
-static inline int multiplyWithOverflowCheck(int a, int b)
-{
- if (!a || !b)
- return 0;
- if (a > MAX_PATTERN_SIZE / b)
- return -1;
- return a * b;
-}
-
-static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase,
- CompileData& cd, ErrorCode& errorcode)
-{
- /* Make a pass over the pattern to compute the
- amount of store required to hold the compiled code. This does not have to be
- perfect as long as errors are overestimates. */
-
- if (patternLength > MAX_PATTERN_SIZE) {
- errorcode = ERR16;
- return -1;
- }
-
- int length = 1 + LINK_SIZE; /* For initial BRA plus length */
- int branch_extra = 0;
- int lastitemlength = 0;
- unsigned brastackptr = 0;
- int brastack[BRASTACK_SIZE];
- unsigned char bralenstack[BRASTACK_SIZE];
- int bracount = 0;
-
- const UChar* ptr = reinterpret_cast<const UChar*>(pattern - 1);
- const UChar* patternEnd = reinterpret_cast<const UChar*>(pattern + patternLength);
-
- while (++ptr < patternEnd) {
- int minRepeats = 0, maxRepeats = 0;
- int c = *ptr;
-
- switch (c) {
- /* A backslashed item may be an escaped data character or it may be a
- character type. */
-
- case '\\':
- c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, false);
- if (errorcode != 0)
- return -1;
-
- lastitemlength = 1; /* Default length of last item for repeats */
-
- if (c >= 0) { /* Data character */
- length += 2; /* For a one-byte character */
-
- if (c > 127) {
- int i;
- for (i = 0; i < kjs_pcre_utf8_table1_size; i++)
- if (c <= kjs_pcre_utf8_table1[i]) break;
- length += i;
- lastitemlength += i;
- }
-
- continue;
- }
-
- /* Other escapes need one byte */
-
- length++;
-
- /* A back reference needs an additional 2 bytes, plus either one or 5
- bytes for a repeat. We also need to keep the value of the highest
- back reference. */
-
- if (c <= -ESC_REF) {
- int refnum = -c - ESC_REF;
- cd.backrefMap |= (refnum < 32) ? (1 << refnum) : 1;
- if (refnum > cd.top_backref)
- cd.top_backref = refnum;
- length += 2; /* For single back reference */
- if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) {
- ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode);
- if (errorcode)
- return -1;
- if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) ||
- (minRepeats == 1 && maxRepeats == -1))
- length++;
- else
- length += 5;
- if (safelyCheckNextChar(ptr, patternEnd, '?'))
- ptr++;
- }
- }
- continue;
-
- case '^': /* Single-byte metacharacters */
- case '.':
- case '$':
- length++;
- lastitemlength = 1;
- continue;
-
- case '*': /* These repeats won't be after brackets; */
- case '+': /* those are handled separately */
- case '?':
- length++;
- goto POSSESSIVE;
-
- /* This covers the cases of braced repeats after a single char, metachar,
- class, or back reference. */
-
- case '{':
- if (!isCountedRepeat(ptr + 1, patternEnd))
- goto NORMAL_CHAR;
- ptr = readRepeatCounts(ptr + 1, &minRepeats, &maxRepeats, &errorcode);
- if (errorcode != 0)
- return -1;
-
- /* These special cases just insert one extra opcode */
-
- if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) ||
- (minRepeats == 1 && maxRepeats == -1))
- length++;
-
- /* These cases might insert additional copies of a preceding character. */
-
- else {
- if (minRepeats != 1) {
- length -= lastitemlength; /* Uncount the original char or metachar */
- if (minRepeats > 0)
- length += 3 + lastitemlength;
- }
- length += lastitemlength + ((maxRepeats > 0) ? 3 : 1);
- }
-
- if (safelyCheckNextChar(ptr, patternEnd, '?'))
- ptr++; /* Needs no extra length */
-
- POSSESSIVE: /* Test for possessive quantifier */
- if (safelyCheckNextChar(ptr, patternEnd, '+')) {
- ptr++;
- length += 2 + 2 * LINK_SIZE; /* Allow for atomic brackets */
- }
- continue;
-
- /* An alternation contains an offset to the next branch or ket. If any ims
- options changed in the previous branch(es), and/or if we are in a
- lookbehind assertion, extra space will be needed at the start of the
- branch. This is handled by branch_extra. */
-
- case '|':
- if (brastackptr == 0)
- cd.needOuterBracket = true;
- length += 1 + LINK_SIZE + branch_extra;
- continue;
-
- /* A character class uses 33 characters provided that all the character
- values are less than 256. Otherwise, it uses a bit map for low valued
- characters, and individual items for others. Don't worry about character
- types that aren't allowed in classes - they'll get picked up during the
- compile. A character class that contains only one single-byte character
- uses 2 or 3 bytes, depending on whether it is negated or not. Notice this
- where we can. (In UTF-8 mode we can do this only for chars < 128.) */
-
- case '[': {
- int class_optcount;
- if (*(++ptr) == '^') {
- class_optcount = 10; /* Greater than one */
- ptr++;
- }
- else
- class_optcount = 0;
-
- bool class_utf8 = false;
-
- for (; ptr < patternEnd && *ptr != ']'; ++ptr) {
- /* Check for escapes */
-
- if (*ptr == '\\') {
- c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true);
- if (errorcode != 0)
- return -1;
-
- /* Handle escapes that turn into characters */
-
- if (c >= 0)
- goto NON_SPECIAL_CHARACTER;
-
- /* Escapes that are meta-things. The normal ones just affect the
- bit map, but Unicode properties require an XCLASS extended item. */
-
- else
- class_optcount = 10; /* \d, \s etc; make sure > 1 */
- }
-
- /* Anything else increments the possible optimization count. We have to
- detect ranges here so that we can compute the number of extra ranges for
- caseless wide characters when UCP support is available. If there are wide
- characters, we are going to have to use an XCLASS, even for single
- characters. */
-
- else {
- c = *ptr;
-
- /* Come here from handling \ above when it escapes to a char value */
-
- NON_SPECIAL_CHARACTER:
- class_optcount++;
-
- int d = -1;
- if (safelyCheckNextChar(ptr, patternEnd, '-')) {
- UChar const *hyptr = ptr++;
- if (safelyCheckNextChar(ptr, patternEnd, '\\')) {
- ptr++;
- d = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true);
- if (errorcode != 0)
- return -1;
- }
- else if ((ptr + 1 < patternEnd) && ptr[1] != ']')
- d = *++ptr;
- if (d < 0)
- ptr = hyptr; /* go back to hyphen as data */
- }
-
- /* If d >= 0 we have a range. In UTF-8 mode, if the end is > 255, or >
- 127 for caseless matching, we will need to use an XCLASS. */
-
- if (d >= 0) {
- class_optcount = 10; /* Ensure > 1 */
- if (d < c) {
- errorcode = ERR8;
- return -1;
- }
-
- if ((d > 255 || (ignoreCase && d > 127))) {
- unsigned char buffer[6];
- if (!class_utf8) /* Allow for XCLASS overhead */
- {
- class_utf8 = true;
- length += LINK_SIZE + 2;
- }
-
- /* If we have UCP support, find out how many extra ranges are
- needed to map the other case of characters within this range. We
- have to mimic the range optimization here, because extending the
- range upwards might push d over a boundary that makes it use
- another byte in the UTF-8 representation. */
-
- if (ignoreCase) {
- int occ, ocd;
- int cc = c;
- int origd = d;
- while (getOthercaseRange(&cc, origd, &occ, &ocd)) {
- if (occ >= c && ocd <= d)
- continue; /* Skip embedded */
-
- if (occ < c && ocd >= c - 1) /* Extend the basic range */
- { /* if there is overlap, */
- c = occ; /* noting that if occ < c */
- continue; /* we can't have ocd > d */
- } /* because a subrange is */
- if (ocd > d && occ <= d + 1) /* always shorter than */
- { /* the basic range. */
- d = ocd;
- continue;
- }
-
- /* An extra item is needed */
-
- length += 1 + encodeUTF8(occ, buffer) +
- ((occ == ocd) ? 0 : encodeUTF8(ocd, buffer));
- }
- }
-
- /* The length of the (possibly extended) range */
-
- length += 1 + encodeUTF8(c, buffer) + encodeUTF8(d, buffer);
- }
-
- }
-
- /* We have a single character. There is nothing to be done unless we
- are in UTF-8 mode. If the char is > 255, or 127 when caseless, we must
- allow for an XCL_SINGLE item, doubled for caselessness if there is UCP
- support. */
-
- else {
- if ((c > 255 || (ignoreCase && c > 127))) {
- unsigned char buffer[6];
- class_optcount = 10; /* Ensure > 1 */
- if (!class_utf8) /* Allow for XCLASS overhead */
- {
- class_utf8 = true;
- length += LINK_SIZE + 2;
- }
- length += (ignoreCase ? 2 : 1) * (1 + encodeUTF8(c, buffer));
- }
- }
- }
- }
-
- if (ptr >= patternEnd) { /* Missing terminating ']' */
- errorcode = ERR6;
- return -1;
- }
-
- /* We can optimize when there was only one optimizable character.
- Note that this does not detect the case of a negated single character.
- In that case we do an incorrect length computation, but it's not a serious
- problem because the computed length is too large rather than too small. */
-
- if (class_optcount == 1)
- goto NORMAL_CHAR;
-
- /* Here, we handle repeats for the class opcodes. */
- {
- length += 33;
-
- /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier,
- we also need extra for wrapping the whole thing in a sub-pattern. */
-
- if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) {
- ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode);
- if (errorcode != 0)
- return -1;
- if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) ||
- (minRepeats == 1 && maxRepeats == -1))
- length++;
- else
- length += 5;
- if (safelyCheckNextChar(ptr, patternEnd, '+')) {
- ptr++;
- length += 2 + 2 * LINK_SIZE;
- } else if (safelyCheckNextChar(ptr, patternEnd, '?'))
- ptr++;
- }
- }
- continue;
- }
-
- /* Brackets may be genuine groups or special things */
-
- case '(': {
- int branch_newextra = 0;
- int bracket_length = 1 + LINK_SIZE;
- bool capturing = false;
-
- /* Handle special forms of bracket, which all start (? */
-
- if (safelyCheckNextChar(ptr, patternEnd, '?')) {
- switch (c = (ptr + 2 < patternEnd ? ptr[2] : 0)) {
- /* Non-referencing groups and lookaheads just move the pointer on, and
- then behave like a non-special bracket, except that they don't increment
- the count of extracting brackets. Ditto for the "once only" bracket,
- which is in Perl from version 5.005. */
-
- case ':':
- case '=':
- case '!':
- ptr += 2;
- break;
-
- /* Else loop checking valid options until ) is met. Anything else is an
- error. If we are without any brackets, i.e. at top level, the settings
- act as if specified in the options, so massage the options immediately.
- This is for backward compatibility with Perl 5.004. */
-
- default:
- errorcode = ERR12;
- return -1;
- }
- } else
- capturing = 1;
-
- /* Capturing brackets must be counted so we can process escapes in a
- Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need
- an additional 3 bytes of memory per capturing bracket. */
-
- if (capturing) {
- bracount++;
- if (bracount > EXTRACT_BASIC_MAX)
- bracket_length += 3;
- }
-
- /* Save length for computing whole length at end if there's a repeat that
- requires duplication of the group. Also save the current value of
- branch_extra, and start the new group with the new value. If non-zero, this
- will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */
-
- if (brastackptr >= sizeof(brastack)/sizeof(int)) {
- errorcode = ERR17;
- return -1;
- }
-
- bralenstack[brastackptr] = branch_extra;
- branch_extra = branch_newextra;
-
- brastack[brastackptr++] = length;
- length += bracket_length;
- continue;
- }
-
- /* Handle ket. Look for subsequent maxRepeats/minRepeats; for certain sets of values we
- have to replicate this bracket up to that many times. If brastackptr is
- 0 this is an unmatched bracket which will generate an error, but take care
- not to try to access brastack[-1] when computing the length and restoring
- the branch_extra value. */
-
- case ')': {
- int duplength;
- length += 1 + LINK_SIZE;
- if (brastackptr > 0) {
- duplength = length - brastack[--brastackptr];
- branch_extra = bralenstack[brastackptr];
- }
- else
- duplength = 0;
-
- /* Leave ptr at the final char; for readRepeatCounts this happens
- automatically; for the others we need an increment. */
-
- if ((ptr + 1 < patternEnd) && (c = ptr[1]) == '{' && isCountedRepeat(ptr + 2, patternEnd)) {
- ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode);
- if (errorcode)
- return -1;
- } else if (c == '*') {
- minRepeats = 0;
- maxRepeats = -1;
- ptr++;
- } else if (c == '+') {
- minRepeats = 1;
- maxRepeats = -1;
- ptr++;
- } else if (c == '?') {
- minRepeats = 0;
- maxRepeats = 1;
- ptr++;
- } else {
- minRepeats = 1;
- maxRepeats = 1;
- }
-
- /* If the minimum is zero, we have to allow for an OP_BRAZERO before the
- group, and if the maximum is greater than zero, we have to replicate
- maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting
- bracket set. */
-
- int repeatsLength;
- if (minRepeats == 0) {
- length++;
- if (maxRepeats > 0) {
- repeatsLength = multiplyWithOverflowCheck(maxRepeats - 1, duplength + 3 + 2 * LINK_SIZE);
- if (repeatsLength < 0) {
- errorcode = ERR16;
- return -1;
- }
- length += repeatsLength;
- if (length > MAX_PATTERN_SIZE) {
- errorcode = ERR16;
- return -1;
- }
- }
- }
-
- /* When the minimum is greater than zero, we have to replicate up to
- minval-1 times, with no additions required in the copies. Then, if there
- is a limited maximum we have to replicate up to maxval-1 times allowing
- for a BRAZERO item before each optional copy and nesting brackets for all
- but one of the optional copies. */
-
- else {
- repeatsLength = multiplyWithOverflowCheck(minRepeats - 1, duplength);
- if (repeatsLength < 0) {
- errorcode = ERR16;
- return -1;
- }
- length += repeatsLength;
- if (maxRepeats > minRepeats) { /* Need this test as maxRepeats=-1 means no limit */
- repeatsLength = multiplyWithOverflowCheck(maxRepeats - minRepeats, duplength + 3 + 2 * LINK_SIZE);
- if (repeatsLength < 0) {
- errorcode = ERR16;
- return -1;
- }
- length += repeatsLength - (2 + 2 * LINK_SIZE);
- }
- if (length > MAX_PATTERN_SIZE) {
- errorcode = ERR16;
- return -1;
- }
- }
-
- /* Allow space for once brackets for "possessive quantifier" */
-
- if (safelyCheckNextChar(ptr, patternEnd, '+')) {
- ptr++;
- length += 2 + 2 * LINK_SIZE;
- }
- continue;
- }
-
- /* Non-special character. It won't be space or # in extended mode, so it is
- always a genuine character. If we are in a \Q...\E sequence, check for the
- end; if not, we have a literal. */
-
- default:
- NORMAL_CHAR:
- length += 2; /* For a one-byte character */
- lastitemlength = 1; /* Default length of last item for repeats */
-
- if (c > 127) {
- int i;
- for (i = 0; i < kjs_pcre_utf8_table1_size; i++)
- if (c <= kjs_pcre_utf8_table1[i])
- break;
- length += i;
- lastitemlength += i;
- }
-
- continue;
- }
- }
-
- length += 2 + LINK_SIZE; /* For final KET and END */
-
- cd.numCapturingBrackets = bracount;
- return length;
-}
-
-/*************************************************
-* Compile a Regular Expression *
-*************************************************/
-
-/* This function takes a string and returns a pointer to a block of store
-holding a compiled version of the expression. The original API for this
-function had no error code return variable; it is retained for backwards
-compatibility. The new function is given a new name.
-
-Arguments:
- pattern the regular expression
- options various option bits
- errorcodeptr pointer to error code variable (pcre_compile2() only)
- can be NULL if you don't want a code value
- errorptr pointer to pointer to error text
- erroroffset ptr offset in pattern where error was detected
- tables pointer to character tables or NULL
-
-Returns: pointer to compiled data block, or NULL on error,
- with errorptr and erroroffset set
-*/
-
-static inline JSRegExp* returnError(ErrorCode errorcode, const char** errorptr)
-{
- *errorptr = errorText(errorcode);
- return 0;
-}
-
-JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength,
- JSRegExpIgnoreCaseOption ignoreCase, JSRegExpMultilineOption multiline,
- unsigned* numSubpatterns, const char** errorptr,
- malloc_t* allocate_function, free_t* free_function)
-{
- /* We can't pass back an error message if errorptr is NULL; I guess the best we
- can do is just return NULL, but we can set a code value if there is a code pointer. */
- if (!errorptr)
- return 0;
- *errorptr = NULL;
-
- CompileData cd;
-
- ErrorCode errorcode = ERR0;
- /* Call this once just to count the brackets. */
- calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode);
- /* Call it again to compute the length. */
- int length = calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode);
- if (errorcode)
- return returnError(errorcode, errorptr);
-
- if (length > MAX_PATTERN_SIZE)
- return returnError(ERR16, errorptr);
-
- size_t size = length + sizeof(JSRegExp);
- JSRegExp* re = reinterpret_cast<JSRegExp*>((*allocate_function)(size));
-
- if (!re)
- return returnError(ERR13, errorptr);
-
- re->options = (ignoreCase ? IgnoreCaseOption : 0) | (multiline ? MatchAcrossMultipleLinesOption : 0);
-
- /* The starting points of the name/number translation table and of the code are
- passed around in the compile data block. */
-
- unsigned char* codeStart = reinterpret_cast<unsigned char*>(re + 1);
-
- /* Set up a starting, non-extracting bracket, then compile the expression. On
- error, errorcode will be set non-zero, so we don't need to look at the result
- of the function here. */
-
- const UChar* ptr = reinterpret_cast<const UChar*>(pattern);
- const UChar* patternEnd = pattern + patternLength;
- unsigned char* code = reinterpret_cast<unsigned char*>(codeStart);
- int firstbyte, reqbyte;
- int bracketCount = 0;
- if (!cd.needOuterBracket)
- compileBranch(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, &firstbyte, &reqbyte, cd);
- else {
- *code = OP_BRA;
- compileBracket(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, 0, &firstbyte, &reqbyte, cd);
- }
- re->top_bracket = bracketCount;
- re->top_backref = cd.top_backref;
-
- /* If not reached end of pattern on success, there's an excess bracket. */
-
- if (errorcode == 0 && ptr < patternEnd)
- errorcode = ERR10;
-
- /* Fill in the terminating state and check for disastrous overflow, but
- if debugging, leave the test till after things are printed out. */
-
- *code++ = OP_END;
-
- ASSERT(code - codeStart <= length);
- if (code - codeStart > length)
- errorcode = ERR7;
-
- /* Give an error if there's back reference to a non-existent capturing
- subpattern. */
-
- if (re->top_backref > re->top_bracket)
- errorcode = ERR15;
-
- /* Failed to compile, or error while post-processing */
-
- if (errorcode != ERR0) {
- (*free_function)(reinterpret_cast<void*>(re));
- return returnError(errorcode, errorptr);
- }
-
- /* If the anchored option was not passed, set the flag if we can determine that
- the pattern is anchored by virtue of ^ characters or \A or anything else (such
- as starting with .* when DOTALL is set).
-
- Otherwise, if we know what the first character has to be, save it, because that
- speeds up unanchored matches no end. If not, see if we can set the
- UseMultiLineFirstByteOptimizationOption flag. This is helpful for multiline matches when all branches
- start with ^. and also when all branches start with .* for non-DOTALL matches.
- */
-
- if (cd.needOuterBracket ? bracketIsAnchored(codeStart) : branchIsAnchored(codeStart))
- re->options |= IsAnchoredOption;
- else {
- if (firstbyte < 0) {
- firstbyte = (cd.needOuterBracket
- ? bracketFindFirstAssertedCharacter(codeStart, false)
- : branchFindFirstAssertedCharacter(codeStart, false))
- | ((re->options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0);
- }
- if (firstbyte >= 0) {
- int ch = firstbyte & 255;
- if (ch < 127) {
- re->first_byte = ((firstbyte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? ch : firstbyte;
- re->options |= UseFirstByteOptimizationOption;
- }
- } else {
- if (cd.needOuterBracket ? bracketNeedsLineStart(codeStart, 0, cd.backrefMap) : branchNeedsLineStart(codeStart, 0, cd.backrefMap))
- re->options |= UseMultiLineFirstByteOptimizationOption;
- }
- }
-
- /* For an anchored pattern, we use the "required byte" only if it follows a
- variable length item in the regex. Remove the caseless flag for non-caseable
- bytes. */
-
- if (reqbyte >= 0 && (!(re->options & IsAnchoredOption) || (reqbyte & REQ_VARY))) {
- int ch = reqbyte & 255;
- if (ch < 127) {
- re->req_byte = ((reqbyte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? (reqbyte & ~REQ_IGNORE_CASE) : reqbyte;
- re->options |= UseRequiredByteOptimizationOption;
- }
- }
-
- if (numSubpatterns)
- *numSubpatterns = re->top_bracket;
- return re;
-}
-
-void jsRegExpFree(JSRegExp* re, free_t* free_function)
-{
- (*free_function)(reinterpret_cast<void*>(re));
-}
-
-} } // namespace dart::jscre
diff --git a/runtime/third_party/jscre/pcre_exec.cpp b/runtime/third_party/jscre/pcre_exec.cpp
deleted file mode 100644
index 98e7f15..0000000
--- a/runtime/third_party/jscre/pcre_exec.cpp
+++ /dev/null
@@ -1,2086 +0,0 @@
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
- Copyright (C) 2007 Eric Seidel <eric@webkit.org>
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* This module contains jsRegExpExecute(), the externally visible function
-that does pattern matching using an NFA algorithm, following the rules from
-the JavaScript specification. There are also some supporting functions. */
-
-#include "config.h"
-
-#include "pcre_internal.h"
-
-#include "ASCIICType.h"
-
-#include <ctype.h>
-#include <limits.h>
-#include <string.h> /* for memcpy */
-
-#ifdef __GNUC__
-#define USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-//#define USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-#endif
-
-/* Avoid warnings on Windows. */
-#undef min
-#undef max
-
-namespace dart { namespace jscre {
-
-#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-typedef int ReturnLocation;
-#else
-typedef void* ReturnLocation;
-#endif
-
-/* Structure for building a chain of data for holding the values of
-the subject pointer at the start of each bracket, used to detect when
-an empty string has been matched by a bracket to break infinite loops. */
-struct BracketChainNode {
- BracketChainNode* previousBracket;
- const UChar* bracketStart;
-};
-
-struct MatchFrame {
- ReturnLocation returnLocation;
- struct MatchFrame* previousFrame;
-
- /* Function arguments that may change */
- struct {
- const UChar* subjectPtr;
- const unsigned char* instructionPtr;
- int offsetTop;
- BracketChainNode* bracketChain;
- } args;
-
-
- /* PCRE uses "fake" recursion built off of gotos, thus
- stack-based local variables are not safe to use. Instead we have to
- store local variables on the current MatchFrame. */
- struct {
- const unsigned char* data;
- const unsigned char* startOfRepeatingBracket;
- const UChar* subjectPtrAtStartOfInstruction; // Several instrutions stash away a subjectPtr here for later compare
- const unsigned char* instructionPtrAtStartOfOnce;
-
- int repeatOthercase;
-
- int ctype;
- int fc;
- int fi;
- int length;
- int max;
- int number;
- int offset;
- int saveOffset1;
- int saveOffset2;
- int saveOffset3;
-
- BracketChainNode bracketChainNode;
- } locals;
-};
-
-/* Structure for passing "static" information around between the functions
-doing traditional NFA matching, so that they are thread-safe. */
-
-struct MatchData {
- int* offsetVector; /* Offset vector */
- int offsetEnd; /* One past the end */
- int offsetMax; /* The maximum usable for return data */
- bool offsetOverflow; /* Set if too many extractions */
- const UChar* startSubject; /* Start of the subject string */
- const UChar* endSubject; /* End of the subject string */
- const UChar* endMatchPtr; /* Subject position at end match */
- int endOffsetTop; /* Highwater mark at end of match */
- bool multiline;
- bool ignoreCase;
-};
-
-/* The maximum remaining length of subject we are prepared to search for a
-req_byte match. */
-
-#define REQ_BYTE_MAX 1000
-
-/* The below limit restricts the number of "recursive" match calls in order to
-avoid spending exponential time on complex regular expressions. */
-
-static const unsigned matchLimit = 100000;
-
-#ifdef DEBUG
-/*************************************************
-* Debugging function to print chars *
-*************************************************/
-
-/* Print a sequence of chars in printable format, stopping at the end of the
-subject if the requested.
-
-Arguments:
- p points to characters
- length number to print
- isSubject true if printing from within md.startSubject
- md pointer to matching data block, if isSubject is true
-*/
-
-static void pchars(const UChar* p, int length, bool isSubject, const MatchData& md)
-{
- if (isSubject && length > md.endSubject - p)
- length = md.endSubject - p;
- while (length-- > 0) {
- int c;
- if (isprint(c = *(p++)))
- printf("%c", c);
- else if (c < 256)
- printf("\\x%02x", c);
- else
- printf("\\x{%x}", c);
- }
-}
-#endif
-
-/*************************************************
-* Match a back-reference *
-*************************************************/
-
-/* If a back reference hasn't been set, the length that is passed is greater
-than the number of characters left in the string, so the match fails.
-
-Arguments:
- offset index into the offset vector
- subjectPtr points into the subject
- length length to be matched
- md points to match data block
-
-Returns: true if matched
-*/
-
-static bool matchRef(int offset, const UChar* subjectPtr, int length, const MatchData& md)
-{
- const UChar* p = md.startSubject + md.offsetVector[offset];
-
-#ifdef DEBUG
- if (subjectPtr >= md.endSubject)
- printf("matching subject <null>");
- else {
- printf("matching subject ");
- pchars(subjectPtr, length, true, md);
- }
- printf(" against backref ");
- pchars(p, length, false, md);
- printf("\n");
-#endif
-
- /* Always fail if not enough characters left */
-
- if (length > md.endSubject - subjectPtr)
- return false;
-
- /* Separate the caselesss case for speed */
-
- if (md.ignoreCase) {
- while (length-- > 0) {
- UChar c = *p++;
- int othercase = kjs_pcre_ucp_othercase(c);
- UChar d = *subjectPtr++;
- if (c != d && othercase != d)
- return false;
- }
- }
- else {
- while (length-- > 0)
- if (*p++ != *subjectPtr++)
- return false;
- }
-
- return true;
-}
-
-#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-
-/* Use numbered labels and switch statement at the bottom of the match function. */
-
-#define RMATCH_WHERE(num) num
-#define RRETURN_LABEL RRETURN_SWITCH
-
-#else
-
-/* Use GCC's computed goto extension. */
-
-/* For one test case this is more than 40% faster than the switch statement.
-We could avoid the use of the num argument entirely by using local labels,
-but using it for the GCC case as well as the non-GCC case allows us to share
-a bit more code and notice if we use conflicting numbers.*/
-
-#define RMATCH_WHERE(num) &&RRETURN_##num
-#define RRETURN_LABEL *stack.currentFrame->returnLocation
-
-#endif
-
-#define RECURSIVE_MATCH_COMMON(num) \
- goto RECURSE;\
- RRETURN_##num: \
- stack.popCurrentFrame();
-
-#define RECURSIVE_MATCH(num, ra, rb) \
- do { \
- stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \
- RECURSIVE_MATCH_COMMON(num) \
- } while (0)
-
-#define RECURSIVE_MATCH_STARTNG_NEW_GROUP(num, ra, rb) \
- do { \
- stack.pushNewFrame((ra), (rb), RMATCH_WHERE(num)); \
- startNewGroup(stack.currentFrame); \
- RECURSIVE_MATCH_COMMON(num) \
- } while (0)
-
-#define RRETURN goto RRETURN_LABEL
-
-#define RRETURN_NO_MATCH do { isMatch = false; RRETURN; } while (0)
-
-/*************************************************
-* Match from current position *
-*************************************************/
-
-/* On entry instructionPtr points to the first opcode, and subjectPtr to the first character
-in the subject string, while substringStart holds the value of subjectPtr at the start of the
-last bracketed group - used for breaking infinite loops matching zero-length
-strings. This function is called recursively in many circumstances. Whenever it
-returns a negative (error) response, the outer match() call must also return the
-same response.
-
-Arguments:
- subjectPtr pointer in subject
- instructionPtr position in code
- offsetTop current top pointer
- md pointer to "static" info for the match
-
-Returns: 1 if matched ) these values are >= 0
- 0 if failed to match )
- a negative error value if aborted by an error condition
- (e.g. stopped by repeated call or recursion limit)
-*/
-
-static const unsigned FRAMES_ON_STACK = 16;
-
-struct MatchStack {
- MatchStack()
- : framesEnd(frames + FRAMES_ON_STACK)
- , currentFrame(frames)
- , size(1) // match() creates accesses the first frame w/o calling pushNewFrame
- {
- ASSERT((sizeof(frames) / sizeof(frames[0])) == FRAMES_ON_STACK);
- }
-
- MatchFrame frames[FRAMES_ON_STACK];
- MatchFrame* framesEnd;
- MatchFrame* currentFrame;
- unsigned size;
-
- inline bool canUseStackBufferForNextFrame()
- {
- return size < FRAMES_ON_STACK;
- }
-
- inline MatchFrame* allocateNextFrame()
- {
- if (canUseStackBufferForNextFrame())
- return currentFrame + 1;
- return new MatchFrame;
- }
-
- inline void pushNewFrame(const unsigned char* instructionPtr, BracketChainNode* bracketChain, ReturnLocation returnLocation)
- {
- MatchFrame* newframe = allocateNextFrame();
- newframe->previousFrame = currentFrame;
-
- newframe->args.subjectPtr = currentFrame->args.subjectPtr;
- newframe->args.offsetTop = currentFrame->args.offsetTop;
- newframe->args.instructionPtr = instructionPtr;
- newframe->args.bracketChain = bracketChain;
- newframe->returnLocation = returnLocation;
- size++;
-
- currentFrame = newframe;
- }
-
- inline void popCurrentFrame()
- {
- MatchFrame* oldFrame = currentFrame;
- currentFrame = currentFrame->previousFrame;
- if (size > FRAMES_ON_STACK)
- delete oldFrame;
- size--;
- }
-
- void popAllFrames()
- {
- while (size)
- popCurrentFrame();
- }
-};
-
-static int matchError(int errorCode, MatchStack& stack)
-{
- stack.popAllFrames();
- return errorCode;
-}
-
-/* Get the next UTF-8 character, not advancing the pointer, incrementing length
- if there are extra bytes. This is called when we know we are in UTF-8 mode. */
-
-static inline void getUTF8CharAndIncrementLength(int& c, const unsigned char* subjectPtr, int& len)
-{
- c = *subjectPtr;
- if ((c & 0xc0) == 0xc0) {
- int gcaa = kjs_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */
- int gcss = 6 * gcaa;
- c = (c & kjs_pcre_utf8_table3[gcaa]) << gcss;
- for (int gcii = 1; gcii <= gcaa; gcii++) {
- gcss -= 6;
- c |= (subjectPtr[gcii] & 0x3f) << gcss;
- }
- len += gcaa;
- }
-}
-
-static inline void startNewGroup(MatchFrame* currentFrame)
-{
- /* At the start of a bracketed group, add the current subject pointer to the
- stack of such pointers, to be re-instated at the end of the group when we hit
- the closing ket. When match() is called in other circumstances, we don't add to
- this stack. */
-
- currentFrame->locals.bracketChainNode.previousBracket = currentFrame->args.bracketChain;
- currentFrame->locals.bracketChainNode.bracketStart = currentFrame->args.subjectPtr;
- currentFrame->args.bracketChain = ¤tFrame->locals.bracketChainNode;
-}
-
-// FIXME: "minimize" means "not greedy", we should invert the callers to ask for "greedy" to be less confusing
-static inline void repeatInformationFromInstructionOffset(short instructionOffset, bool& minimize, int& minimumRepeats, int& maximumRepeats)
-{
- // Instruction offsets are based off of OP_CRSTAR, OP_STAR, OP_TYPESTAR, OP_NOTSTAR
- static const char minimumRepeatsFromInstructionOffset[] = { 0, 0, 1, 1, 0, 0 };
- static const int maximumRepeatsFromInstructionOffset[] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX, 1, 1 };
-
- ASSERT(instructionOffset >= 0);
- ASSERT(instructionOffset <= (OP_CRMINQUERY - OP_CRSTAR));
-
- minimize = (instructionOffset & 1); // this assumes ordering: Instruction, MinimizeInstruction, Instruction2, MinimizeInstruction2
- minimumRepeats = minimumRepeatsFromInstructionOffset[instructionOffset];
- maximumRepeats = maximumRepeatsFromInstructionOffset[instructionOffset];
-}
-
-static int match(const UChar* subjectPtr, const unsigned char* instructionPtr, int offsetTop, MatchData& md)
-{
- bool isMatch = false;
- int min;
- bool minimize = false; /* Initialization not really needed, but some compilers think so. */
- unsigned matchCount = 0;
-
- MatchStack stack;
-
- /* The opcode jump table. */
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-#define EMIT_JUMP_TABLE_ENTRY(opcode) &&LABEL_OP_##opcode,
- static void* opcodeJumpTable[256] = { FOR_EACH_OPCODE(EMIT_JUMP_TABLE_ENTRY) };
-#undef EMIT_JUMP_TABLE_ENTRY
-#endif
-
- /* One-time setup of the opcode jump table. */
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
- for (int i = 255; !opcodeJumpTable[i]; i--)
- opcodeJumpTable[i] = &&CAPTURING_BRACKET;
-#endif
-
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
- // Shark shows this as a hot line
- // Using a static const here makes this line disappear, but makes later access hotter (not sure why)
- stack.currentFrame->returnLocation = &&RETURN;
-#else
- stack.currentFrame->returnLocation = 0;
-#endif
- stack.currentFrame->args.subjectPtr = subjectPtr;
- stack.currentFrame->args.instructionPtr = instructionPtr;
- stack.currentFrame->args.offsetTop = offsetTop;
- stack.currentFrame->args.bracketChain = 0;
- startNewGroup(stack.currentFrame);
-
- /* This is where control jumps back to to effect "recursion" */
-
-RECURSE:
- if (++matchCount > matchLimit)
- return matchError(JSRegExpErrorHitLimit, stack);
-
- /* Now start processing the operations. */
-
-#ifndef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
- while (true)
-#endif
- {
-
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
-#define BEGIN_OPCODE(opcode) LABEL_OP_##opcode
-#define NEXT_OPCODE goto *opcodeJumpTable[*stack.currentFrame->args.instructionPtr]
-#else
-#define BEGIN_OPCODE(opcode) case OP_##opcode
-#define NEXT_OPCODE continue
-#endif
-
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
- NEXT_OPCODE;
-#else
- switch (*stack.currentFrame->args.instructionPtr)
-#endif
- {
- /* Non-capturing bracket: optimized */
-
- BEGIN_OPCODE(BRA):
- NON_CAPTURING_BRACKET:
- DPRINTF(("start bracket 0\n"));
- do {
- RECURSIVE_MATCH_STARTNG_NEW_GROUP(2, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
- DPRINTF(("bracket 0 failed\n"));
- RRETURN;
-
- /* Skip over large extraction number data if encountered. */
-
- BEGIN_OPCODE(BRANUMBER):
- stack.currentFrame->args.instructionPtr += 3;
- NEXT_OPCODE;
-
- /* End of the pattern. */
-
- BEGIN_OPCODE(END):
- md.endMatchPtr = stack.currentFrame->args.subjectPtr; /* Record where we ended */
- md.endOffsetTop = stack.currentFrame->args.offsetTop; /* and how many extracts were taken */
- isMatch = true;
- RRETURN;
-
- /* Assertion brackets. Check the alternative branches in turn - the
- matching won't pass the KET for an assertion. If any one branch matches,
- the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
- start of each branch to move the current point backwards, so the code at
- this level is identical to the lookahead case. */
-
- BEGIN_OPCODE(ASSERT):
- do {
- RECURSIVE_MATCH_STARTNG_NEW_GROUP(6, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, NULL);
- if (isMatch)
- break;
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
- if (*stack.currentFrame->args.instructionPtr == OP_KET)
- RRETURN_NO_MATCH;
-
- /* Continue from after the assertion, updating the offsets high water
- mark, since extracts may have been taken during the assertion. */
-
- advanceToEndOfBracket(stack.currentFrame->args.instructionPtr);
- stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE;
- stack.currentFrame->args.offsetTop = md.endOffsetTop;
- NEXT_OPCODE;
-
- /* Negative assertion: all branches must fail to match */
-
- BEGIN_OPCODE(ASSERT_NOT):
- do {
- RECURSIVE_MATCH_STARTNG_NEW_GROUP(7, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, NULL);
- if (isMatch)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
-
- stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE;
- NEXT_OPCODE;
-
- /* An alternation is the end of a branch; scan along to find the end of the
- bracketed group and go to there. */
-
- BEGIN_OPCODE(ALT):
- advanceToEndOfBracket(stack.currentFrame->args.instructionPtr);
- NEXT_OPCODE;
-
- /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating
- that it may occur zero times. It may repeat infinitely, or not at all -
- i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
- repeat limits are compiled as a number of copies, with the optional ones
- preceded by BRAZERO or BRAMINZERO. */
-
- BEGIN_OPCODE(BRAZERO): {
- stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1;
- RECURSIVE_MATCH_STARTNG_NEW_GROUP(14, stack.currentFrame->locals.startOfRepeatingBracket, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket);
- stack.currentFrame->args.instructionPtr = stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE;
- NEXT_OPCODE;
- }
-
- BEGIN_OPCODE(BRAMINZERO): {
- stack.currentFrame->locals.startOfRepeatingBracket = stack.currentFrame->args.instructionPtr + 1;
- advanceToEndOfBracket(stack.currentFrame->locals.startOfRepeatingBracket);
- RECURSIVE_MATCH_STARTNG_NEW_GROUP(15, stack.currentFrame->locals.startOfRepeatingBracket + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
- }
-
- /* End of a group, repeated or non-repeating. If we are at the end of
- an assertion "group", stop matching and return 1, but record the
- current high water mark for use by positive assertions. Do this also
- for the "once" (not-backup up) groups. */
-
- BEGIN_OPCODE(KET):
- BEGIN_OPCODE(KETRMIN):
- BEGIN_OPCODE(KETRMAX):
- stack.currentFrame->locals.instructionPtrAtStartOfOnce = stack.currentFrame->args.instructionPtr - getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.bracketChain->bracketStart;
-
- /* Back up the stack of bracket start pointers. */
-
- stack.currentFrame->args.bracketChain = stack.currentFrame->args.bracketChain->previousBracket;
-
- if (*stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT || *stack.currentFrame->locals.instructionPtrAtStartOfOnce == OP_ASSERT_NOT) {
- md.endOffsetTop = stack.currentFrame->args.offsetTop;
- isMatch = true;
- RRETURN;
- }
-
- /* In all other cases except a conditional group we have to check the
- group number back at the start and if necessary complete handling an
- extraction by setting the offsets and bumping the high water mark. */
-
- stack.currentFrame->locals.number = *stack.currentFrame->locals.instructionPtrAtStartOfOnce - OP_BRA;
-
- /* For extended extraction brackets (large number), we have to fish out
- the number from a dummy opcode at the start. */
-
- if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX)
- stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->locals.instructionPtrAtStartOfOnce + 2 + LINK_SIZE);
- stack.currentFrame->locals.offset = stack.currentFrame->locals.number << 1;
-
-#ifdef DEBUG
- printf("end bracket %d", stack.currentFrame->locals.number);
- printf("\n");
-#endif
-
- /* Test for a numbered group. This includes groups called as a result
- of recursion. Note that whole-pattern recursion is coded as a recurse
- into group 0, so it won't be picked up here. Instead, we catch it when
- the OP_END is reached. */
-
- if (stack.currentFrame->locals.number > 0) {
- if (stack.currentFrame->locals.offset >= md.offsetMax)
- md.offsetOverflow = true;
- else {
- md.offsetVector[stack.currentFrame->locals.offset] =
- md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number];
- md.offsetVector[stack.currentFrame->locals.offset+1] = stack.currentFrame->args.subjectPtr - md.startSubject;
- if (stack.currentFrame->args.offsetTop <= stack.currentFrame->locals.offset)
- stack.currentFrame->args.offsetTop = stack.currentFrame->locals.offset + 2;
- }
- }
-
- /* For a non-repeating ket, just continue at this level. This also
- happens for a repeating ket if no characters were matched in the group.
- This is the forcible breaking of infinite loops as implemented in Perl
- 5.005. If there is an options reset, it will get obeyed in the normal
- course of events. */
-
- if (*stack.currentFrame->args.instructionPtr == OP_KET || stack.currentFrame->args.subjectPtr == stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
- stack.currentFrame->args.instructionPtr += 1 + LINK_SIZE;
- NEXT_OPCODE;
- }
-
- /* The repeating kets try the rest of the pattern or restart from the
- preceding bracket, in the appropriate order. */
-
- if (*stack.currentFrame->args.instructionPtr == OP_KETRMIN) {
- RECURSIVE_MATCH(16, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- RECURSIVE_MATCH_STARTNG_NEW_GROUP(17, stack.currentFrame->locals.instructionPtrAtStartOfOnce, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- } else { /* OP_KETRMAX */
- RECURSIVE_MATCH_STARTNG_NEW_GROUP(18, stack.currentFrame->locals.instructionPtrAtStartOfOnce, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- RECURSIVE_MATCH(19, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- }
- RRETURN;
-
- /* Start of subject. */
-
- BEGIN_OPCODE(CIRC):
- if (stack.currentFrame->args.subjectPtr != md.startSubject)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* After internal newline if multiline. */
-
- BEGIN_OPCODE(BOL):
- if (stack.currentFrame->args.subjectPtr != md.startSubject && !isNewline(stack.currentFrame->args.subjectPtr[-1]))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* End of subject. */
-
- BEGIN_OPCODE(DOLL):
- if (stack.currentFrame->args.subjectPtr < md.endSubject)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* Before internal newline if multiline. */
-
- BEGIN_OPCODE(EOL):
- if (stack.currentFrame->args.subjectPtr < md.endSubject && !isNewline(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* Word boundary assertions */
-
- BEGIN_OPCODE(NOT_WORD_BOUNDARY):
- BEGIN_OPCODE(WORD_BOUNDARY): {
- bool currentCharIsWordChar = false;
- bool previousCharIsWordChar = false;
-
- if (stack.currentFrame->args.subjectPtr > md.startSubject)
- previousCharIsWordChar = isWordChar(stack.currentFrame->args.subjectPtr[-1]);
- if (stack.currentFrame->args.subjectPtr < md.endSubject)
- currentCharIsWordChar = isWordChar(*stack.currentFrame->args.subjectPtr);
-
- /* Now see if the situation is what we want */
- bool wordBoundaryDesired = (*stack.currentFrame->args.instructionPtr++ == OP_WORD_BOUNDARY);
- if (wordBoundaryDesired ? currentCharIsWordChar == previousCharIsWordChar : currentCharIsWordChar != previousCharIsWordChar)
- RRETURN_NO_MATCH;
- NEXT_OPCODE;
- }
-
- /* Match a single character type; inline for speed */
-
- BEGIN_OPCODE(NOT_NEWLINE):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (isNewline(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(NOT_DIGIT):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (isASCIIDigit(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(DIGIT):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(NOT_WHITESPACE):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (isSpaceChar(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(WHITESPACE):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (!isSpaceChar(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(NOT_WORDCHAR):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (isWordChar(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- BEGIN_OPCODE(WORDCHAR):
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (!isWordChar(*stack.currentFrame->args.subjectPtr++))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- NEXT_OPCODE;
-
- /* Match a back reference, possibly repeatedly. Look past the end of the
- item to see if there is repeat information following. The code is similar
- to that for character classes, but repeated for efficiency. Then obey
- similar code to character type repeats - written out again for speed.
- However, if the referenced string is the empty string, always treat
- it as matched, any number of times (otherwise there could be infinite
- loops). */
-
- BEGIN_OPCODE(REF):
- stack.currentFrame->locals.offset = get2ByteValue(stack.currentFrame->args.instructionPtr + 1) << 1; /* Doubled ref number */
- stack.currentFrame->args.instructionPtr += 3; /* Advance past item */
-
- /* If the reference is unset, set the length to be longer than the amount
- of subject left; this ensures that every attempt at a match fails. We
- can't just fail here, because of the possibility of quantifiers with zero
- minima. */
-
- if (stack.currentFrame->locals.offset >= stack.currentFrame->args.offsetTop || md.offsetVector[stack.currentFrame->locals.offset] < 0)
- stack.currentFrame->locals.length = 0;
- else
- stack.currentFrame->locals.length = md.offsetVector[stack.currentFrame->locals.offset+1] - md.offsetVector[stack.currentFrame->locals.offset];
-
- /* Set up for repetition, or handle the non-repeated case */
-
- switch (*stack.currentFrame->args.instructionPtr) {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max);
- break;
-
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE);
- min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3);
- if (stack.currentFrame->locals.max == 0)
- stack.currentFrame->locals.max = INT_MAX;
- stack.currentFrame->args.instructionPtr += 5;
- break;
-
- default: /* No repeat follows */
- if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
- NEXT_OPCODE;
- }
-
- /* If the length of the reference is zero, just continue with the
- main loop. */
-
- if (stack.currentFrame->locals.length == 0)
- NEXT_OPCODE;
-
- /* First, ensure the minimum number of matches are present. */
-
- for (int i = 1; i <= min; i++) {
- if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
- RRETURN_NO_MATCH;
- stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
- }
-
- /* If min = max, continue at the same level without recursion.
- They are not both allowed to be zero. */
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- /* If minimizing, keep trying and advancing the pointer */
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(20, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || !matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
- RRETURN;
- stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
- }
- /* Control never reaches here */
- }
-
- /* If maximizing, find the longest string and work backwards */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (!matchRef(stack.currentFrame->locals.offset, stack.currentFrame->args.subjectPtr, stack.currentFrame->locals.length, md))
- break;
- stack.currentFrame->args.subjectPtr += stack.currentFrame->locals.length;
- }
- while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
- RECURSIVE_MATCH(21, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.subjectPtr -= stack.currentFrame->locals.length;
- }
- RRETURN_NO_MATCH;
- }
- /* Control never reaches here */
-
- /* Match a bit-mapped character class, possibly repeatedly. This op code is
- used when all the characters in the class have values in the range 0-255,
- and either the matching is caseful, or the characters are in the range
- 0-127 when UTF-8 processing is enabled. The only difference between
- OP_CLASS and OP_NCLASS occurs when a data character outside the range is
- encountered.
-
- First, look past the end of the item to see if there is repeat information
- following. Then obey similar code to character type repeats - written out
- again for speed. */
-
- BEGIN_OPCODE(NCLASS):
- BEGIN_OPCODE(CLASS):
- stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1; /* Save for matching */
- stack.currentFrame->args.instructionPtr += 33; /* Advance past the item */
-
- switch (*stack.currentFrame->args.instructionPtr) {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max);
- break;
-
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE);
- min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3);
- if (stack.currentFrame->locals.max == 0)
- stack.currentFrame->locals.max = INT_MAX;
- stack.currentFrame->args.instructionPtr += 5;
- break;
-
- default: /* No repeat follows */
- min = stack.currentFrame->locals.max = 1;
- break;
- }
-
- /* First, ensure the minimum number of matches are present. */
-
- for (int i = 1; i <= min; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (c > 255) {
- if (stack.currentFrame->locals.data[-1] == OP_CLASS)
- RRETURN_NO_MATCH;
- } else {
- if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7))))
- RRETURN_NO_MATCH;
- }
- }
-
- /* If max == min we can continue with the main loop without the
- need to recurse. */
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- /* If minimizing, keep testing the rest of the expression and advancing
- the pointer while it matches the class. */
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(22, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (c > 255) {
- if (stack.currentFrame->locals.data[-1] == OP_CLASS)
- RRETURN;
- } else {
- if ((stack.currentFrame->locals.data[c/8] & (1 << (c&7))) == 0)
- RRETURN;
- }
- }
- /* Control never reaches here */
- }
- /* If maximizing, find the longest possible run, then work backwards. */
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
-
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (c > 255) {
- if (stack.currentFrame->locals.data[-1] == OP_CLASS)
- break;
- } else {
- if (!(stack.currentFrame->locals.data[c / 8] & (1 << (c & 7))))
- break;
- }
- ++stack.currentFrame->args.subjectPtr;
- }
- for (;;) {
- RECURSIVE_MATCH(24, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
-
- RRETURN;
- }
- /* Control never reaches here */
-
- /* Match an extended character class. */
-
- BEGIN_OPCODE(XCLASS):
- stack.currentFrame->locals.data = stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE; /* Save for matching */
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1); /* Advance past the item */
-
- switch (*stack.currentFrame->args.instructionPtr) {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_CRSTAR, minimize, min, stack.currentFrame->locals.max);
- break;
-
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- minimize = (*stack.currentFrame->args.instructionPtr == OP_CRMINRANGE);
- min = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 3);
- if (stack.currentFrame->locals.max == 0)
- stack.currentFrame->locals.max = INT_MAX;
- stack.currentFrame->args.instructionPtr += 5;
- break;
-
- default: /* No repeat follows */
- min = stack.currentFrame->locals.max = 1;
- }
-
- /* First, ensure the minimum number of matches are present. */
-
- for (int i = 1; i <= min; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (!kjs_pcre_xclass(c, stack.currentFrame->locals.data))
- RRETURN_NO_MATCH;
- }
-
- /* If max == min we can continue with the main loop without the
- need to recurse. */
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- /* If minimizing, keep testing the rest of the expression and advancing
- the pointer while it matches the class. */
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(26, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (!kjs_pcre_xclass(c, stack.currentFrame->locals.data))
- RRETURN;
- }
- /* Control never reaches here */
- }
-
- /* If maximizing, find the longest possible run, then work backwards. */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (!kjs_pcre_xclass(c, stack.currentFrame->locals.data))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- for(;;) {
- RECURSIVE_MATCH(27, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
- RRETURN;
- }
-
- /* Control never reaches here */
-
- /* Match a single character, casefully */
-
- BEGIN_OPCODE(CHAR):
- stack.currentFrame->locals.length = 1;
- stack.currentFrame->args.instructionPtr++;
- getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length);
- stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length;
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- if (stack.currentFrame->locals.fc != *stack.currentFrame->args.subjectPtr++)
- RRETURN_NO_MATCH;
- NEXT_OPCODE;
-
- /* Match a single character, caselessly */
-
- BEGIN_OPCODE(CHAR_IGNORING_CASE): {
- stack.currentFrame->locals.length = 1;
- stack.currentFrame->args.instructionPtr++;
- getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length);
- stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length;
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- int dc = *stack.currentFrame->args.subjectPtr++;
- if (stack.currentFrame->locals.fc != dc && kjs_pcre_ucp_othercase(stack.currentFrame->locals.fc) != dc)
- RRETURN_NO_MATCH;
- NEXT_OPCODE;
- }
-
- /* Match a single ASCII character. */
-
- BEGIN_OPCODE(ASCII_CHAR):
- if (md.endSubject == stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->args.instructionPtr[1])
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- stack.currentFrame->args.instructionPtr += 2;
- NEXT_OPCODE;
-
- /* Match one of two cases of an ASCII letter. */
-
- BEGIN_OPCODE(ASCII_LETTER_IGNORING_CASE):
- if (md.endSubject == stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- if ((*stack.currentFrame->args.subjectPtr | 0x20) != stack.currentFrame->args.instructionPtr[1])
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- stack.currentFrame->args.instructionPtr += 2;
- NEXT_OPCODE;
-
- /* Match a single character repeatedly; different opcodes share code. */
-
- BEGIN_OPCODE(EXACT):
- min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = false;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATCHAR;
-
- BEGIN_OPCODE(UPTO):
- BEGIN_OPCODE(MINUPTO):
- min = 0;
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = *stack.currentFrame->args.instructionPtr == OP_MINUPTO;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATCHAR;
-
- BEGIN_OPCODE(STAR):
- BEGIN_OPCODE(MINSTAR):
- BEGIN_OPCODE(PLUS):
- BEGIN_OPCODE(MINPLUS):
- BEGIN_OPCODE(QUERY):
- BEGIN_OPCODE(MINQUERY):
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_STAR, minimize, min, stack.currentFrame->locals.max);
-
- /* Common code for all repeated single-character matches. We can give
- up quickly if there are fewer than the minimum number of characters left in
- the subject. */
-
- REPEATCHAR:
-
- stack.currentFrame->locals.length = 1;
- getUTF8CharAndIncrementLength(stack.currentFrame->locals.fc, stack.currentFrame->args.instructionPtr, stack.currentFrame->locals.length);
- if (min * (stack.currentFrame->locals.fc > 0xFFFF ? 2 : 1) > md.endSubject - stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr += stack.currentFrame->locals.length;
-
- if (stack.currentFrame->locals.fc <= 0xFFFF) {
- int othercase;
- othercase = md.ignoreCase ? kjs_pcre_ucp_othercase(stack.currentFrame->locals.fc) : -1;
-
- for (int i = 1; i <= min; i++) {
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase)
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- if (minimize) {
- stack.currentFrame->locals.repeatOthercase = othercase;
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(28, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.repeatOthercase)
- RRETURN;
- ++stack.currentFrame->args.subjectPtr;
- }
- /* Control never reaches here */
- } else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc && *stack.currentFrame->args.subjectPtr != othercase)
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
- RECURSIVE_MATCH(29, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- --stack.currentFrame->args.subjectPtr;
- }
- RRETURN_NO_MATCH;
- }
- /* Control never reaches here */
- } else {
- /* No case on surrogate pairs, so no need to bother with "othercase". */
-
- for (int i = 1; i <= min; i++) {
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.subjectPtr += 2;
- }
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(30, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc)
- RRETURN;
- stack.currentFrame->args.subjectPtr += 2;
- }
- /* Control never reaches here */
- } else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr > md.endSubject - 2)
- break;
- if (*stack.currentFrame->args.subjectPtr != stack.currentFrame->locals.fc)
- break;
- stack.currentFrame->args.subjectPtr += 2;
- }
- while (stack.currentFrame->args.subjectPtr >= stack.currentFrame->locals.subjectPtrAtStartOfInstruction) {
- RECURSIVE_MATCH(31, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.subjectPtr -= 2;
- }
- RRETURN_NO_MATCH;
- }
- /* Control never reaches here */
- }
- /* Control never reaches here */
-
- /* Match a negated single one-byte character. */
-
- BEGIN_OPCODE(NOT): {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN_NO_MATCH;
- stack.currentFrame->args.instructionPtr++;
- int c = *stack.currentFrame->args.subjectPtr++;
- if (md.ignoreCase) {
- if (c < 128)
- c = toLowerCase(c);
- if (toLowerCase(*stack.currentFrame->args.instructionPtr++) == c)
- RRETURN_NO_MATCH;
- } else {
- if (*stack.currentFrame->args.instructionPtr++ == c)
- RRETURN_NO_MATCH;
- }
- NEXT_OPCODE;
- }
-
- /* Match a negated single one-byte character repeatedly. This is almost a
- repeat of the code for a repeated single character, but I haven't found a
- nice way of commoning these up that doesn't require a test of the
- positive/negative option for each character match. Maybe that wouldn't add
- very much to the time taken, but character matching *is* what this is all
- about... */
-
- BEGIN_OPCODE(NOTEXACT):
- min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = false;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATNOTCHAR;
-
- BEGIN_OPCODE(NOTUPTO):
- BEGIN_OPCODE(NOTMINUPTO):
- min = 0;
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = *stack.currentFrame->args.instructionPtr == OP_NOTMINUPTO;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATNOTCHAR;
-
- BEGIN_OPCODE(NOTSTAR):
- BEGIN_OPCODE(NOTMINSTAR):
- BEGIN_OPCODE(NOTPLUS):
- BEGIN_OPCODE(NOTMINPLUS):
- BEGIN_OPCODE(NOTQUERY):
- BEGIN_OPCODE(NOTMINQUERY):
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_NOTSTAR, minimize, min, stack.currentFrame->locals.max);
-
- /* Common code for all repeated single-byte matches. We can give up quickly
- if there are fewer than the minimum number of bytes left in the
- subject. */
-
- REPEATNOTCHAR:
- if (min > md.endSubject - stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- stack.currentFrame->locals.fc = *stack.currentFrame->args.instructionPtr++;
-
- /* The code is duplicated for the caseless and caseful cases, for speed,
- since matching characters is likely to be quite common. First, ensure the
- minimum number of matches are present. If min = max, continue at the same
- level without recursing. Otherwise, if minimizing, keep trying the rest of
- the expression and advancing one matching character if failing, up to the
- maximum. Alternatively, if maximizing, find the maximum number of
- characters and work backwards. */
-
- DPRINTF(("negative matching %c{%d,%d}\n", stack.currentFrame->locals.fc, min, stack.currentFrame->locals.max));
-
- if (md.ignoreCase) {
- if (stack.currentFrame->locals.fc < 128)
- stack.currentFrame->locals.fc = toLowerCase(stack.currentFrame->locals.fc);
-
- for (int i = 1; i <= min; i++) {
- int d = *stack.currentFrame->args.subjectPtr++;
- if (d < 128)
- d = toLowerCase(d);
- if (stack.currentFrame->locals.fc == d)
- RRETURN_NO_MATCH;
- }
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(38, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- int d = *stack.currentFrame->args.subjectPtr++;
- if (d < 128)
- d = toLowerCase(d);
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d)
- RRETURN;
- }
- /* Control never reaches here */
- }
-
- /* Maximize case */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
-
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int d = *stack.currentFrame->args.subjectPtr;
- if (d < 128)
- d = toLowerCase(d);
- if (stack.currentFrame->locals.fc == d)
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- for (;;) {
- RECURSIVE_MATCH(40, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
-
- RRETURN;
- }
- /* Control never reaches here */
- }
-
- /* Caseful comparisons */
-
- else {
- for (int i = 1; i <= min; i++) {
- int d = *stack.currentFrame->args.subjectPtr++;
- if (stack.currentFrame->locals.fc == d)
- RRETURN_NO_MATCH;
- }
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(42, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- int d = *stack.currentFrame->args.subjectPtr++;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject || stack.currentFrame->locals.fc == d)
- RRETURN;
- }
- /* Control never reaches here */
- }
-
- /* Maximize case */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr;
-
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int d = *stack.currentFrame->args.subjectPtr;
- if (stack.currentFrame->locals.fc == d)
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- for (;;) {
- RECURSIVE_MATCH(44, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
-
- RRETURN;
- }
- }
- /* Control never reaches here */
-
- /* Match a single character type repeatedly; several different opcodes
- share code. This is very similar to the code for single characters, but we
- repeat it in the interests of efficiency. */
-
- BEGIN_OPCODE(TYPEEXACT):
- min = stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = true;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATTYPE;
-
- BEGIN_OPCODE(TYPEUPTO):
- BEGIN_OPCODE(TYPEMINUPTO):
- min = 0;
- stack.currentFrame->locals.max = get2ByteValue(stack.currentFrame->args.instructionPtr + 1);
- minimize = *stack.currentFrame->args.instructionPtr == OP_TYPEMINUPTO;
- stack.currentFrame->args.instructionPtr += 3;
- goto REPEATTYPE;
-
- BEGIN_OPCODE(TYPESTAR):
- BEGIN_OPCODE(TYPEMINSTAR):
- BEGIN_OPCODE(TYPEPLUS):
- BEGIN_OPCODE(TYPEMINPLUS):
- BEGIN_OPCODE(TYPEQUERY):
- BEGIN_OPCODE(TYPEMINQUERY):
- repeatInformationFromInstructionOffset(*stack.currentFrame->args.instructionPtr++ - OP_TYPESTAR, minimize, min, stack.currentFrame->locals.max);
-
- /* Common code for all repeated single character type matches. Note that
- in UTF-8 mode, '.' matches a character of any length, but for the other
- character types, the valid characters are all one-byte long. */
-
- REPEATTYPE:
- stack.currentFrame->locals.ctype = *stack.currentFrame->args.instructionPtr++; /* Code for the character type */
-
- /* First, ensure the minimum number of matches are present. Use inline
- code for maximizing the speed, and do the type test once at the start
- (i.e. keep it out of the loop). Also we can test that there are at least
- the minimum number of characters before we start. */
-
- if (min > md.endSubject - stack.currentFrame->args.subjectPtr)
- RRETURN_NO_MATCH;
- if (min > 0) {
- switch (stack.currentFrame->locals.ctype) {
- case OP_NOT_NEWLINE:
- for (int i = 1; i <= min; i++) {
- if (isNewline(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_DIGIT:
- for (int i = 1; i <= min; i++) {
- if (isASCIIDigit(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_DIGIT:
- for (int i = 1; i <= min; i++) {
- if (!isASCIIDigit(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_WHITESPACE:
- for (int i = 1; i <= min; i++) {
- if (isSpaceChar(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_WHITESPACE:
- for (int i = 1; i <= min; i++) {
- if (!isSpaceChar(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_WORDCHAR:
- for (int i = 1; i <= min; i++) {
- if (isWordChar(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_WORDCHAR:
- for (int i = 1; i <= min; i++) {
- if (!isWordChar(*stack.currentFrame->args.subjectPtr))
- RRETURN_NO_MATCH;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- default:
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
- } /* End switch(stack.currentFrame->locals.ctype) */
- }
-
- /* If min = max, continue at the same level without recursing */
-
- if (min == stack.currentFrame->locals.max)
- NEXT_OPCODE;
-
- /* If minimizing, we have to test the rest of the pattern before each
- subsequent match. */
-
- if (minimize) {
- for (stack.currentFrame->locals.fi = min;; stack.currentFrame->locals.fi++) {
- RECURSIVE_MATCH(48, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->locals.fi >= stack.currentFrame->locals.max || stack.currentFrame->args.subjectPtr >= md.endSubject)
- RRETURN;
-
- int c = *stack.currentFrame->args.subjectPtr++;
- switch (stack.currentFrame->locals.ctype) {
- case OP_NOT_NEWLINE:
- if (isNewline(c))
- RRETURN;
- break;
-
- case OP_NOT_DIGIT:
- if (isASCIIDigit(c))
- RRETURN;
- break;
-
- case OP_DIGIT:
- if (!isASCIIDigit(c))
- RRETURN;
- break;
-
- case OP_NOT_WHITESPACE:
- if (isSpaceChar(c))
- RRETURN;
- break;
-
- case OP_WHITESPACE:
- if (!isSpaceChar(c))
- RRETURN;
- break;
-
- case OP_NOT_WORDCHAR:
- if (isWordChar(c))
- RRETURN;
- break;
-
- case OP_WORDCHAR:
- if (!isWordChar(c))
- RRETURN;
- break;
-
- default:
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
- }
- }
- /* Control never reaches here */
- }
-
- /* If maximizing it is worth using inline code for speed, doing the type
- test once at the start (i.e. keep it out of the loop). */
-
- else {
- stack.currentFrame->locals.subjectPtrAtStartOfInstruction = stack.currentFrame->args.subjectPtr; /* Remember where we started */
-
- switch (stack.currentFrame->locals.ctype) {
- case OP_NOT_NEWLINE:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject || isNewline(*stack.currentFrame->args.subjectPtr))
- break;
- stack.currentFrame->args.subjectPtr++;
- }
- break;
-
- case OP_NOT_DIGIT:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (isASCIIDigit(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_DIGIT:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (!isASCIIDigit(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_WHITESPACE:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (isSpaceChar(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_WHITESPACE:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (!isSpaceChar(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_NOT_WORDCHAR:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (isWordChar(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- case OP_WORDCHAR:
- for (int i = min; i < stack.currentFrame->locals.max; i++) {
- if (stack.currentFrame->args.subjectPtr >= md.endSubject)
- break;
- int c = *stack.currentFrame->args.subjectPtr;
- if (!isWordChar(c))
- break;
- ++stack.currentFrame->args.subjectPtr;
- }
- break;
-
- default:
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
- }
-
- /* stack.currentFrame->args.subjectPtr is now past the end of the maximum run */
-
- for (;;) {
- RECURSIVE_MATCH(52, stack.currentFrame->args.instructionPtr, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- if (stack.currentFrame->args.subjectPtr-- == stack.currentFrame->locals.subjectPtrAtStartOfInstruction)
- break; /* Stop if tried at original pos */
- }
-
- /* Get here if we can't make it match with any permitted repetitions */
-
- RRETURN;
- }
- /* Control never reaches here */
-
- BEGIN_OPCODE(CRMINPLUS):
- BEGIN_OPCODE(CRMINQUERY):
- BEGIN_OPCODE(CRMINRANGE):
- BEGIN_OPCODE(CRMINSTAR):
- BEGIN_OPCODE(CRPLUS):
- BEGIN_OPCODE(CRQUERY):
- BEGIN_OPCODE(CRRANGE):
- BEGIN_OPCODE(CRSTAR):
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
-
-#ifdef USE_COMPUTED_GOTO_FOR_MATCH_OPCODE_LOOP
- CAPTURING_BRACKET:
-#else
- default:
-#endif
- /* Opening capturing bracket. If there is space in the offset vector, save
- the current subject position in the working slot at the top of the vector. We
- mustn't change the current values of the data slot, because they may be set
- from a previous iteration of this group, and be referred to by a reference
- inside the group.
-
- If the bracket fails to match, we need to restore this value and also the
- values of the final offsets, in case they were set by a previous iteration of
- the same bracket.
-
- If there isn't enough space in the offset vector, treat this as if it were a
- non-capturing bracket. Don't worry about setting the flag for the error case
- here; that is handled in the code for KET. */
-
- ASSERT(*stack.currentFrame->args.instructionPtr > OP_BRA);
-
- stack.currentFrame->locals.number = *stack.currentFrame->args.instructionPtr - OP_BRA;
-
- /* For extended extraction brackets (large number), we have to fish out the
- number from a dummy opcode at the start. */
-
- if (stack.currentFrame->locals.number > EXTRACT_BASIC_MAX)
- stack.currentFrame->locals.number = get2ByteValue(stack.currentFrame->args.instructionPtr + 2 + LINK_SIZE);
- stack.currentFrame->locals.offset = stack.currentFrame->locals.number << 1;
-
-#ifdef DEBUG
- printf("start bracket %d subject=", stack.currentFrame->locals.number);
- pchars(stack.currentFrame->args.subjectPtr, 16, true, md);
- printf("\n");
-#endif
-
- if (stack.currentFrame->locals.offset < md.offsetMax) {
- stack.currentFrame->locals.saveOffset1 = md.offsetVector[stack.currentFrame->locals.offset];
- stack.currentFrame->locals.saveOffset2 = md.offsetVector[stack.currentFrame->locals.offset + 1];
- stack.currentFrame->locals.saveOffset3 = md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number];
-
- DPRINTF(("saving %d %d %d\n", stack.currentFrame->locals.saveOffset1, stack.currentFrame->locals.saveOffset2, stack.currentFrame->locals.saveOffset3));
- md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->args.subjectPtr - md.startSubject;
-
- do {
- RECURSIVE_MATCH_STARTNG_NEW_GROUP(1, stack.currentFrame->args.instructionPtr + 1 + LINK_SIZE, stack.currentFrame->args.bracketChain);
- if (isMatch)
- RRETURN;
- stack.currentFrame->args.instructionPtr += getLinkValue(stack.currentFrame->args.instructionPtr + 1);
- } while (*stack.currentFrame->args.instructionPtr == OP_ALT);
-
- DPRINTF(("bracket %d failed\n", stack.currentFrame->locals.number));
-
- md.offsetVector[stack.currentFrame->locals.offset] = stack.currentFrame->locals.saveOffset1;
- md.offsetVector[stack.currentFrame->locals.offset + 1] = stack.currentFrame->locals.saveOffset2;
- md.offsetVector[md.offsetEnd - stack.currentFrame->locals.number] = stack.currentFrame->locals.saveOffset3;
-
- RRETURN;
- }
-
- /* Insufficient room for saving captured contents */
-
- goto NON_CAPTURING_BRACKET;
- }
-
- /* Do not stick any code in here without much thought; it is assumed
- that "continue" in the code above comes out to here to repeat the main
- loop. */
-
- } /* End of main loop */
-
- ASSERT_NOT_REACHED();
-
-#ifndef USE_COMPUTED_GOTO_FOR_MATCH_RECURSION
-
-RRETURN_SWITCH:
- switch (stack.currentFrame->returnLocation) {
- case 0: goto RETURN;
- case 1: goto RRETURN_1;
- case 2: goto RRETURN_2;
- case 6: goto RRETURN_6;
- case 7: goto RRETURN_7;
- case 14: goto RRETURN_14;
- case 15: goto RRETURN_15;
- case 16: goto RRETURN_16;
- case 17: goto RRETURN_17;
- case 18: goto RRETURN_18;
- case 19: goto RRETURN_19;
- case 20: goto RRETURN_20;
- case 21: goto RRETURN_21;
- case 22: goto RRETURN_22;
- case 24: goto RRETURN_24;
- case 26: goto RRETURN_26;
- case 27: goto RRETURN_27;
- case 28: goto RRETURN_28;
- case 29: goto RRETURN_29;
- case 30: goto RRETURN_30;
- case 31: goto RRETURN_31;
- case 38: goto RRETURN_38;
- case 40: goto RRETURN_40;
- case 42: goto RRETURN_42;
- case 44: goto RRETURN_44;
- case 48: goto RRETURN_48;
- case 52: goto RRETURN_52;
- }
-
- ASSERT_NOT_REACHED();
- return matchError(JSRegExpErrorInternal, stack);
-
-#endif
-
-RETURN:
- return isMatch;
-}
-
-
-/*************************************************
-* Execute a Regular Expression *
-*************************************************/
-
-/* This function applies a compiled re to a subject string and picks out
-portions of the string if it matches. Two elements in the vector are set for
-each substring: the offsets to the start and end of the substring.
-
-Arguments:
- re points to the compiled expression
- extra_data points to extra data or is NULL
- subject points to the subject string
- length length of subject string (may contain binary zeros)
- start_offset where to start in the subject string
- options option bits
- offsets points to a vector of ints to be filled in with offsets
- offsetcount the number of elements in the vector
-
-Returns: > 0 => success; value is the number of elements filled in
- = 0 => success, but offsets is not big enough
- -1 => failed to match
- < -1 => some kind of unexpected problem
-*/
-
-static void tryFirstByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int first_byte, bool first_byte_caseless, bool useMultiLineFirstCharOptimization, const UChar* originalSubjectStart)
-{
- // If first_byte is set, try scanning to the first instance of that byte
- // no need to try and match against any earlier part of the subject string.
- if (first_byte >= 0) {
- UChar first_char = first_byte;
- if (first_byte_caseless)
- while (subjectPtr < endSubject) {
- int c = *subjectPtr;
- if (c > 127)
- break;
- if (toLowerCase(c) == first_char)
- break;
- subjectPtr++;
- }
- else {
- while (subjectPtr < endSubject && *subjectPtr != first_char)
- subjectPtr++;
- }
- } else if (useMultiLineFirstCharOptimization) {
- /* Or to just after \n for a multiline match if possible */
- // I'm not sure why this != originalSubjectStart check is necessary -- ecs 11/18/07
- if (subjectPtr > originalSubjectStart) {
- while (subjectPtr < endSubject && !isNewline(subjectPtr[-1]))
- subjectPtr++;
- }
- }
-}
-
-static bool tryRequiredByteOptimization(const UChar*& subjectPtr, const UChar* endSubject, int req_byte, int req_byte2, bool req_byte_caseless, bool hasFirstByte, const UChar*& reqBytePtr)
-{
- /* If req_byte is set, we know that that character must appear in the subject
- for the match to succeed. If the first character is set, req_byte must be
- later in the subject; otherwise the test starts at the match point. This
- optimization can save a huge amount of backtracking in patterns with nested
- unlimited repeats that aren't going to match. Writing separate code for
- cased/caseless versions makes it go faster, as does using an autoincrement
- and backing off on a match.
-
- HOWEVER: when the subject string is very, very long, searching to its end can
- take a long time, and give bad performance on quite ordinary patterns. This
- showed up when somebody was matching /^C/ on a 32-megabyte string... so we
- don't do this when the string is sufficiently long.
- */
-
- if (req_byte >= 0 && endSubject - subjectPtr < REQ_BYTE_MAX) {
- const UChar* p = subjectPtr + (hasFirstByte ? 1 : 0);
-
- /* We don't need to repeat the search if we haven't yet reached the
- place we found it at last time. */
-
- if (p > reqBytePtr) {
- if (req_byte_caseless) {
- while (p < endSubject) {
- int pp = *p++;
- if (pp == req_byte || pp == req_byte2) {
- p--;
- break;
- }
- }
- } else {
- while (p < endSubject) {
- if (*p++ == req_byte) {
- p--;
- break;
- }
- }
- }
-
- /* If we can't find the required character, break the matching loop */
-
- if (p >= endSubject)
- return true;
-
- /* If we have found the required character, save the point where we
- found it, so that we don't search again next time round the loop if
- the start hasn't passed this character yet. */
-
- reqBytePtr = p;
- }
- }
- return false;
-}
-
-int jsRegExpExecute(const JSRegExp* re,
- const UChar* subject, int length, int start_offset, int* offsets,
- int offsetcount)
-{
- ASSERT(re);
- ASSERT(subject);
- ASSERT(offsetcount >= 0);
- ASSERT(offsets || offsetcount == 0);
-
- MatchData matchBlock;
- matchBlock.startSubject = subject;
- matchBlock.endSubject = matchBlock.startSubject + length;
- const UChar* endSubject = matchBlock.endSubject;
-
- matchBlock.multiline = (re->options & MatchAcrossMultipleLinesOption);
- matchBlock.ignoreCase = (re->options & IgnoreCaseOption);
-
- /* If the expression has got more back references than the offsets supplied can
- hold, we get a temporary chunk of working store to use during the matching.
- Otherwise, we can use the vector supplied, rounding down its size to a multiple
- of 3. */
-
- int ocount = offsetcount - (offsetcount % 3);
-
- // FIXME: This is lame that we have to second-guess our caller here.
- // The API should change to either fail-hard when we don't have enough offset space
- // or that we shouldn't ask our callers to pre-allocate in the first place.
- bool using_temporary_offsets = false;
- if (re->top_backref > 0 && re->top_backref >= ocount/3) {
- ocount = re->top_backref * 3 + 3;
- matchBlock.offsetVector = new int[ocount];
- if (!matchBlock.offsetVector)
- return JSRegExpErrorNoMemory;
- using_temporary_offsets = true;
- } else
- matchBlock.offsetVector = offsets;
-
- matchBlock.offsetEnd = ocount;
- matchBlock.offsetMax = (2*ocount)/3;
- matchBlock.offsetOverflow = false;
-
- /* Compute the minimum number of offsets that we need to reset each time. Doing
- this makes a huge difference to execution time when there aren't many brackets
- in the pattern. */
-
- int resetcount = 2 + re->top_bracket * 2;
- if (resetcount > offsetcount)
- resetcount = ocount;
-
- /* Reset the working variable associated with each extraction. These should
- never be used unless previously set, but they get saved and restored, and so we
- initialize them to avoid reading uninitialized locations. */
-
- if (matchBlock.offsetVector) {
- int* iptr = matchBlock.offsetVector + ocount;
- int* iend = iptr - resetcount/2 + 1;
- while (--iptr >= iend)
- *iptr = -1;
- }
-
- /* Set up the first character to match, if available. The first_byte value is
- never set for an anchored regular expression, but the anchoring may be forced
- at run time, so we have to test for anchoring. The first char may be unset for
- an unanchored pattern, of course. If there's no first char and the pattern was
- studied, there may be a bitmap of possible first characters. */
-
- bool first_byte_caseless = false;
- int first_byte = -1;
- if (re->options & UseFirstByteOptimizationOption) {
- first_byte = re->first_byte & 255;
- if ((first_byte_caseless = (re->first_byte & REQ_IGNORE_CASE)))
- first_byte = toLowerCase(first_byte);
- }
-
- /* For anchored or unanchored matches, there may be a "last known required
- character" set. */
-
- bool req_byte_caseless = false;
- int req_byte = -1;
- int req_byte2 = -1;
- if (re->options & UseRequiredByteOptimizationOption) {
- req_byte = re->req_byte & 255; // FIXME: This optimization could be made to work for UTF16 chars as well...
- req_byte_caseless = (re->req_byte & REQ_IGNORE_CASE);
- req_byte2 = flipCase(req_byte);
- }
-
- /* Loop for handling unanchored repeated matching attempts; for anchored regexs
- the loop runs just once. */
-
- const UChar* startMatch = subject + start_offset;
- const UChar* reqBytePtr = startMatch - 1;
- bool useMultiLineFirstCharOptimization = re->options & UseMultiLineFirstByteOptimizationOption;
-
- do {
- /* Reset the maximum number of extractions we might see. */
- if (matchBlock.offsetVector) {
- int* iptr = matchBlock.offsetVector;
- int* iend = iptr + resetcount;
- while (iptr < iend)
- *iptr++ = -1;
- }
-
- tryFirstByteOptimization(startMatch, endSubject, first_byte, first_byte_caseless, useMultiLineFirstCharOptimization, matchBlock.startSubject + start_offset);
- if (tryRequiredByteOptimization(startMatch, endSubject, req_byte, req_byte2, req_byte_caseless, first_byte >= 0, reqBytePtr))
- break;
-
- /* When a match occurs, substrings will be set for all internal extractions;
- we just need to set up the whole thing as substring 0 before returning. If
- there were too many extractions, set the return code to zero. In the case
- where we had to get some local store to hold offsets for backreferences, copy
- those back references that we can. In this case there need not be overflow
- if certain parts of the pattern were not used. */
-
- /* The code starts after the JSRegExp block and the capture name table. */
- const unsigned char* start_code = reinterpret_cast<const unsigned char*>(re + 1);
-
- int returnCode = match(startMatch, start_code, 2, matchBlock);
-
- /* When the result is no match, advance the pointer to the next character
- and continue. */
- if (returnCode == 0) {
- startMatch++;
- continue;
- }
-
- if (returnCode != 1) {
- ASSERT(returnCode == JSRegExpErrorHitLimit || returnCode == JSRegExpErrorNoMemory);
- DPRINTF((">>>> error: returning %d\n", returnCode));
- return returnCode;
- }
-
- /* We have a match! Copy the offset information from temporary store if
- necessary */
-
- if (using_temporary_offsets) {
- if (offsetcount >= 4) {
- memcpy(offsets + 2, matchBlock.offsetVector + 2, (offsetcount - 2) * sizeof(int));
- DPRINTF(("Copied offsets from temporary memory\n"));
- }
- if (matchBlock.endOffsetTop > offsetcount)
- matchBlock.offsetOverflow = true;
-
- DPRINTF(("Freeing temporary memory\n"));
- delete [] matchBlock.offsetVector;
- }
-
- returnCode = matchBlock.offsetOverflow ? 0 : matchBlock.endOffsetTop / 2;
-
- if (offsetcount < 2)
- returnCode = 0;
- else {
- offsets[0] = startMatch - matchBlock.startSubject;
- offsets[1] = matchBlock.endMatchPtr - matchBlock.startSubject;
- }
-
- DPRINTF((">>>> returning %d\n", returnCode));
- return returnCode;
- } while (!(re->options & IsAnchoredOption) && startMatch <= endSubject);
-
- if (using_temporary_offsets) {
- DPRINTF(("Freeing temporary memory\n"));
- delete [] matchBlock.offsetVector;
- }
-
- DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n"));
- return JSRegExpErrorNoMatch;
-}
-
-} } // namespace dart::jscre
diff --git a/runtime/third_party/jscre/pcre_internal.h b/runtime/third_party/jscre/pcre_internal.h
deleted file mode 100644
index 92011f8..0000000
--- a/runtime/third_party/jscre/pcre_internal.h
+++ /dev/null
@@ -1,428 +0,0 @@
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* This header contains definitions that are shared between the different
-modules, but which are not relevant to the exported API. This includes some
-functions whose names all begin with "_pcre_". */
-
-#ifndef THIRD_PARTY_JSCRE_PCRE_INTERNAL_H_
-#define THIRD_PARTY_JSCRE_PCRE_INTERNAL_H_
-
-#if defined(_WIN32)
-typedef unsigned __int32 uint32_t;
-#else
-#include <inttypes.h>
-#include <stdint.h>
-#endif
-
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-/* Bit definitions for entries in the pcre_ctypes table. */
-
-#define ctype_space 0x01
-#define ctype_xdigit 0x08
-#define ctype_word 0x10 /* alphameric or '_' */
-
-/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set
-of bits for a class map. Some classes are built by combining these tables. */
-
-#define cbit_space 0 /* \s */
-#define cbit_digit 32 /* \d */
-#define cbit_word 64 /* \w */
-#define cbit_length 96 /* Length of the cbits table */
-
-/* Offsets of the various tables from the base tables pointer, and
-total length. */
-
-#define lcc_offset 0
-#define fcc_offset 128
-#define cbits_offset 256
-#define ctypes_offset (cbits_offset + cbit_length)
-#define tables_length (ctypes_offset + 128)
-
-#ifndef DFTABLES
-
-// TODO(xxx): Hook this up to something that checks assertions.
-#define ASSERT(x) if (!(x)) abort()
-#define ASSERT_NOT_REACHED() abort()
-
-#ifdef WIN32
-#pragma warning(disable: 4232)
-#pragma warning(disable: 4244)
-#endif
-
-#include "./pcre.h"
-
-/* The value of LINK_SIZE determines the number of bytes used to store links as
-offsets within the compiled regex. The default is 2, which allows for compiled
-patterns up to 64K long. */
-
-#define LINK_SIZE 2
-
-/* Define DEBUG to get debugging output on stdout. */
-
-#if 0
-#define DEBUG
-#endif
-
-/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef
-inline, and there are *still* stupid compilers about that don't like indented
-pre-processor statements, or at least there were when I first wrote this. After
-all, it had only been about 10 years then... */
-
-#ifdef DEBUG
-#define DPRINTF(p) printf p
-#else
-#define DPRINTF(p) /*nothing*/
-#endif
-
-namespace dart { namespace jscre {
-
-/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored
-in big-endian order) by default. These are used, for example, to link from the
-start of a subpattern to its alternatives and its end. The use of 2 bytes per
-offset limits the size of the compiled regex to around 64K, which is big enough
-for almost everybody. However, I received a request for an even bigger limit.
-For this reason, and also to make the code easier to maintain, the storing and
-loading of offsets from the byte string is now handled by the functions that are
-defined here. */
-
-/* PCRE uses some other 2-byte quantities that do not change when the size of
-offsets changes. There are used for repeat counts and for other things such as
-capturing parenthesis numbers in back references. */
-
-static inline void put2ByteValue(unsigned char* opcodePtr, int value) {
- ASSERT(value >= 0 && value <= 0xFFFF);
- opcodePtr[0] = value >> 8;
- opcodePtr[1] = value;
-}
-
-static inline int get2ByteValue(const unsigned char* opcodePtr) {
- return (opcodePtr[0] << 8) | opcodePtr[1];
-}
-
-static inline void put2ByteValueAndAdvance(unsigned char*& opcodePtr,
- int value) {
- put2ByteValue(opcodePtr, value);
- opcodePtr += 2;
-}
-
-static inline void putLinkValueAllowZero(unsigned char* opcodePtr,
- int value) {
- put2ByteValue(opcodePtr, value);
-}
-
-static inline int getLinkValueAllowZero(const unsigned char* opcodePtr) {
- return get2ByteValue(opcodePtr);
-}
-
-#define MAX_PATTERN_SIZE (1 << 16)
-
-static inline void putLinkValue(unsigned char* opcodePtr, int value) {
- ASSERT(value);
- putLinkValueAllowZero(opcodePtr, value);
-}
-
-static inline int getLinkValue(const unsigned char* opcodePtr) {
- int value = getLinkValueAllowZero(opcodePtr);
- ASSERT(value);
- return value;
-}
-
-static inline void putLinkValueAndAdvance(unsigned char*& opcodePtr,
- int value) {
- putLinkValue(opcodePtr, value);
- opcodePtr += LINK_SIZE;
-}
-
-static inline void putLinkValueAllowZeroAndAdvance(unsigned char*& opcodePtr,
- int value) {
- putLinkValueAllowZero(opcodePtr, value);
- opcodePtr += LINK_SIZE;
-}
-
-// FIXME: These are really more of a "compiled regexp state"
-// than "regexp options"
-enum RegExpOptions {
- UseFirstByteOptimizationOption = 0x40000000, /* first_byte is set */
- UseRequiredByteOptimizationOption = 0x20000000, /* req_byte is set */
- UseMultiLineFirstByteOptimizationOption = 0x10000000,
- /* start after \n for multiline */
- IsAnchoredOption = 0x02000000, /* can't use partial with this regex */
- IgnoreCaseOption = 0x00000001,
- MatchAcrossMultipleLinesOption = 0x00000002
-};
-
-/* Flags added to firstbyte or reqbyte; a "non-literal" item is either a
-variable-length repeat, or a anything other than literal characters. */
-
-#define REQ_IGNORE_CASE 0x0100 /* indicates should ignore case */
-#define REQ_VARY 0x0200 /* reqbyte followed non-literal item */
-
-/* Miscellaneous definitions */
-
-/* Flag bits and data types for the extended class (OP_XCLASS) for classes that
-contain UTF-8 characters with values greater than 255. */
-
-#define XCL_NOT 0x01 /* Flag: this is a negative class */
-#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */
-
-#define XCL_END 0 /* Marks end of individual items */
-#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */
-#define XCL_RANGE 2 /* A range (two multibyte chars) follows */
-
-/* These are escaped items that aren't just an encoding of a particular data
-value such as \n. They must have non-zero values, as check_escape() returns
-their negation. Also, they must appear in the same order as in the opcode
-definitions below, up to ESC_w. The final one must be
-ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two
-tests in the code for an escape > ESC_b and <= ESC_w to
-detect the types that may be repeated. These are the types that consume
-characters. If any new escapes are put in between that don't consume a
-character, that code will have to change. */
-
-enum { ESC_B = 1, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W, ESC_w, ESC_REF };
-
-/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets
-that extract substrings. Starting from 1 (i.e. after OP_END), the values up to
-OP_EOD must correspond in order to the list of escapes immediately above.
-Note that whenever this list is updated, the two macro definitions that follow
-must also be updated to match. */
-
-#define FOR_EACH_OPCODE(macro) \
- macro(END) \
- \
- macro(NOT_WORD_BOUNDARY) \
- macro(WORD_BOUNDARY) \
- macro(NOT_DIGIT) \
- macro(DIGIT) \
- macro(NOT_WHITESPACE) \
- macro(WHITESPACE) \
- macro(NOT_WORDCHAR) \
- macro(WORDCHAR) \
- \
- macro(NOT_NEWLINE) \
- \
- macro(CIRC) \
- macro(DOLL) \
- macro(BOL) \
- macro(EOL) \
- macro(CHAR) \
- macro(CHAR_IGNORING_CASE) \
- macro(ASCII_CHAR) \
- macro(ASCII_LETTER_IGNORING_CASE) \
- macro(NOT) \
- \
- macro(STAR) \
- macro(MINSTAR) \
- macro(PLUS) \
- macro(MINPLUS) \
- macro(QUERY) \
- macro(MINQUERY) \
- macro(UPTO) \
- macro(MINUPTO) \
- macro(EXACT) \
- \
- macro(NOTSTAR) \
- macro(NOTMINSTAR) \
- macro(NOTPLUS) \
- macro(NOTMINPLUS) \
- macro(NOTQUERY) \
- macro(NOTMINQUERY) \
- macro(NOTUPTO) \
- macro(NOTMINUPTO) \
- macro(NOTEXACT) \
- \
- macro(TYPESTAR) \
- macro(TYPEMINSTAR) \
- macro(TYPEPLUS) \
- macro(TYPEMINPLUS) \
- macro(TYPEQUERY) \
- macro(TYPEMINQUERY) \
- macro(TYPEUPTO) \
- macro(TYPEMINUPTO) \
- macro(TYPEEXACT) \
- \
- macro(CRSTAR) \
- macro(CRMINSTAR) \
- macro(CRPLUS) \
- macro(CRMINPLUS) \
- macro(CRQUERY) \
- macro(CRMINQUERY) \
- macro(CRRANGE) \
- macro(CRMINRANGE) \
- \
- macro(CLASS) \
- macro(NCLASS) \
- macro(XCLASS) \
- \
- macro(REF) \
- \
- macro(ALT) \
- macro(KET) \
- macro(KETRMAX) \
- macro(KETRMIN) \
- \
- macro(ASSERT) \
- macro(ASSERT_NOT) \
- \
- macro(BRAZERO) \
- macro(BRAMINZERO) \
- macro(BRANUMBER) \
- macro(BRA)
-
-#define OPCODE_ENUM_VALUE(opcode) OP_##opcode,
-enum { FOR_EACH_OPCODE(OPCODE_ENUM_VALUE) };
-
-/* WARNING WARNING WARNING: There is an implicit assumption in pcre.c and
-study.c that all opcodes are less than 128 in value. This makes handling UTF-8
-character sequences easier. */
-
-/* The highest extraction number before we have to start using additional
-bytes. (Originally PCRE didn't have support for extraction counts higher than
-this number.) The value is limited by the number of opcodes left after OP_BRA,
-i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional
-opcodes. */
-
-/* FIXME: Note that OP_BRA + 100 is > 128, so the two comments above
-are in conflict! */
-
-#define EXTRACT_BASIC_MAX 100
-
-/* The index of names and the
-code vector run on as long as necessary after the end. We store an explicit
-offset to the name table so that if a regex is compiled on one host, saved, and
-then run on another where the size of pointers is different, all might still
-be well. For the case of compiled-on-4 and run-on-8, we include an extra
-pointer that is always NULL.
-*/
-
-struct JSRegExp {
- uint32_t options;
-
- uint16_t top_bracket;
- uint16_t top_backref;
-
- uint16_t first_byte;
- uint16_t req_byte;
-};
-
-/* Internal shared data tables. These are tables that are used by more than one
- of the exported public functions. They have to be "external" in the C sense,
- but are not part of the PCRE public API. The data for these tables is in the
- pcre_tables.c module. */
-
-#define kjs_pcre_utf8_table1_size 6
-
-extern const int kjs_pcre_utf8_table1[6];
-extern const int kjs_pcre_utf8_table2[6];
-extern const int kjs_pcre_utf8_table3[6];
-extern const unsigned char kjs_pcre_utf8_table4[0x40];
-
-extern const unsigned char kjs_pcre_default_tables[tables_length];
-
-static inline unsigned char toLowerCase(unsigned char c) {
- static const unsigned char* lowerCaseChars =
- kjs_pcre_default_tables + lcc_offset;
- return lowerCaseChars[c];
-}
-
-static inline unsigned char flipCase(unsigned char c) {
- static const unsigned char* flippedCaseChars =
- kjs_pcre_default_tables + fcc_offset;
- return flippedCaseChars[c];
-}
-
-static inline unsigned char classBitmapForChar(unsigned char c) {
- static const unsigned char* charClassBitmaps =
- kjs_pcre_default_tables + cbits_offset;
- return charClassBitmaps[c];
-}
-
-static inline unsigned char charTypeForChar(unsigned char c) {
- const unsigned char* charTypeMap = kjs_pcre_default_tables + ctypes_offset;
- return charTypeMap[c];
-}
-
-static inline bool isWordChar(UChar c) {
- return c < 128 && (charTypeForChar(c) & ctype_word);
-}
-
-static inline bool isSpaceChar(UChar c) {
- return (c < 128 && (charTypeForChar(c) & ctype_space));
-}
-
-static inline bool isNewline(UChar nl) {
- return (nl == 0xA || nl == 0xD || nl == 0x2028 || nl == 0x2029);
-}
-
-static inline bool isBracketStartOpcode(unsigned char opcode) {
- if (opcode >= OP_BRA)
- return true;
- switch (opcode) {
- case OP_ASSERT:
- case OP_ASSERT_NOT:
- return true;
- default:
- return false;
- }
-}
-
-static inline void advanceToEndOfBracket(const unsigned char*& opcodePtr) {
- ASSERT(isBracketStartOpcode(*opcodePtr) || *opcodePtr == OP_ALT);
- do
- opcodePtr += getLinkValue(opcodePtr + 1);
- while (*opcodePtr == OP_ALT);
-}
-
-/* Internal shared functions. These are functions that are used in more
-that one of the source files. They have to have external linkage, but
-but are not part of the public API and so not exported from the library. */
-
-extern int kjs_pcre_ucp_othercase(unsigned);
-extern bool kjs_pcre_xclass(int, const unsigned char*);
-
-} } // namespace dart::jscre
-#endif
-
-#endif // THIRD_PARTY_JSCRE_PCRE_INTERNAL_H_
diff --git a/runtime/third_party/jscre/pcre_tables.cpp b/runtime/third_party/jscre/pcre_tables.cpp
deleted file mode 100644
index 943b80c..0000000
--- a/runtime/third_party/jscre/pcre_tables.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* This module contains some fixed tables that are used by more than one of the
-PCRE code modules. */
-
-#include "pcre_internal.h"
-
-namespace dart { namespace jscre {
-
-/*************************************************
-* Tables for UTF-8 support *
-*************************************************/
-
-/* These are the breakpoints for different numbers of bytes in a UTF-8
-character. */
-
-const int kjs_pcre_utf8_table1[6] =
- { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
-
-/* These are the indicator bits and the mask for the data bits to set in the
-first byte of a character, indexed by the number of additional bytes. */
-
-const int kjs_pcre_utf8_table2[6] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
-const int kjs_pcre_utf8_table3[6] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
-
-/* Table of the number of extra characters, indexed by the first character
-masked with 0x3f. The highest number for a valid UTF-8 character is in fact
-0x3d. */
-
-const unsigned char kjs_pcre_utf8_table4[0x40] = {
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
-
-#include "pcre_chartables.c"
-
-} } // namespace dart::jscre
diff --git a/runtime/third_party/jscre/pcre_ucp_searchfuncs.cpp b/runtime/third_party/jscre/pcre_ucp_searchfuncs.cpp
deleted file mode 100644
index 07fa42b..0000000
--- a/runtime/third_party/jscre/pcre_ucp_searchfuncs.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This module contains code for searching the table of Unicode character
-properties. */
-
-#include "pcre_internal.h"
-
-#include "ucpinternal.h" /* Internal table details */
-#include "ucptable.cpp" /* The table itself */
-
-namespace dart { namespace jscre {
-
-/*************************************************
-* Search table and return other case *
-*************************************************/
-
-/* If the given character is a letter, and there is another case for the
-letter, return the other case. Otherwise, return -1.
-
-Arguments:
- c the character value
-
-Returns: the other case or -1 if none
-*/
-
-int kjs_pcre_ucp_othercase(unsigned c)
-{
- int bot = 0;
- int top = sizeof(ucp_table) / sizeof(cnode);
- int mid;
-
- /* The table is searched using a binary chop. You might think that using
- intermediate variables to hold some of the common expressions would speed
- things up, but tests with gcc 3.4.4 on Linux showed that, on the contrary, it
- makes things a lot slower. */
-
- for (;;) {
- if (top <= bot)
- return -1;
- mid = (bot + top) >> 1;
- if (c == (ucp_table[mid].f0 & f0_charmask))
- break;
- if (c < (ucp_table[mid].f0 & f0_charmask))
- top = mid;
- else {
- if ((ucp_table[mid].f0 & f0_rangeflag) && (c <= (ucp_table[mid].f0 & f0_charmask) + (ucp_table[mid].f1 & f1_rangemask)))
- break;
- bot = mid + 1;
- }
- }
-
- /* Found an entry in the table. Return -1 for a range entry. Otherwise return
- the other case if there is one, else -1. */
-
- if (ucp_table[mid].f0 & f0_rangeflag)
- return -1;
-
- int offset = ucp_table[mid].f1 & f1_casemask;
- if (offset & f1_caseneg)
- offset |= f1_caseneg;
- return !offset ? -1 : c + offset;
-}
-
-} } // namespace dart::jscre
diff --git a/runtime/third_party/jscre/pcre_xclass.cpp b/runtime/third_party/jscre/pcre_xclass.cpp
deleted file mode 100644
index 5d170e5..0000000
--- a/runtime/third_party/jscre/pcre_xclass.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* This module contains an internal function that is used to match an extended
-class (one that contains characters whose values are > 255). */
-
-#include "pcre_internal.h"
-
-namespace dart { namespace jscre {
-
-/*************************************************
-* Match character against an XCLASS *
-*************************************************/
-
-/* This function is called to match a character against an extended class that
-might contain values > 255.
-
-Arguments:
- c the character
- data points to the flag byte of the XCLASS data
-
-Returns: true if character matches, else false
-*/
-
-/* Get the next UTF-8 character, advancing the pointer. This is called when we
- know we are in UTF-8 mode. */
-
-static inline void getUTF8CharAndAdvancePointer(int& c, const unsigned char*& subjectPtr)
-{
- c = *subjectPtr++;
- if ((c & 0xc0) == 0xc0) {
- int gcaa = kjs_pcre_utf8_table4[c & 0x3f]; /* Number of additional bytes */
- int gcss = 6 * gcaa;
- c = (c & kjs_pcre_utf8_table3[gcaa]) << gcss;
- while (gcaa-- > 0) {
- gcss -= 6;
- c |= (*subjectPtr++ & 0x3f) << gcss;
- }
- }
-}
-
-bool kjs_pcre_xclass(int c, const unsigned char* data)
-{
- bool negated = (*data & XCL_NOT);
-
- /* Character values < 256 are matched against a bitmap, if one is present. If
- not, we still carry on, because there may be ranges that start below 256 in the
- additional data. */
-
- if (c < 256) {
- if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0)
- return !negated; /* char found */
- }
-
- /* First skip the bit map if present. Then match against the list of Unicode
- properties or large chars or ranges that end with a large char. We won't ever
- encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */
-
- if ((*data++ & XCL_MAP) != 0)
- data += 32;
-
- int t;
- while ((t = *data++) != XCL_END) {
- if (t == XCL_SINGLE) {
- int x;
- getUTF8CharAndAdvancePointer(x, data);
- if (c == x)
- return !negated;
- }
- else if (t == XCL_RANGE) {
- int x, y;
- getUTF8CharAndAdvancePointer(x, data);
- getUTF8CharAndAdvancePointer(y, data);
- if (c >= x && c <= y)
- return !negated;
- }
- }
-
- return negated; /* char did not match */
-}
-
-} } // namespace dart::jscre
diff --git a/runtime/third_party/jscre/ucpinternal.h b/runtime/third_party/jscre/ucpinternal.h
deleted file mode 100644
index c7b3c46..0000000
--- a/runtime/third_party/jscre/ucpinternal.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/* This is JavaScriptCore's variant of the PCRE library. While this library
-started out as a copy of PCRE, many of the features of PCRE have been
-removed. This library now supports only the regular expression features
-required by the JavaScript language specification, and has only the functions
-needed by JavaScriptCore and the rest of WebKit.
-
- Originally written by Philip Hazel
- Copyright (c) 1997-2006 University of Cambridge
- Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved.
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-#ifndef THIRD_PARTY_JSCRE_UCPINTERNAL_H_
-#define THIRD_PARTY_JSCRE_UCPINTERNAL_H_
-
-/*************************************************
-* Unicode Property Table handler *
-*************************************************/
-
-/* Internal header file defining the layout of the bits in each pair of 32-bit
-words that form a data item in the table. */
-
-typedef struct cnode {
- unsigned f0;
- unsigned f1;
-} cnode;
-
-/* Things for the f0 field */
-
-#define f0_scriptmask 0xff000000 /* Mask for script field */
-#define f0_scriptshift 24 /* Shift for script value */
-#define f0_rangeflag 0x00f00000 /* Flag for a range item */
-#define f0_charmask 0x001fffff /* Mask for code point value */
-
-/* Things for the f1 field */
-
-#define f1_typemask 0xfc000000 /* Mask for char type field */
-#define f1_typeshift 26 /* Shift for the type field */
-#define f1_rangemask 0x0000ffff /* Mask for a range offset */
-#define f1_casemask 0x0000ffff /* Mask for a case offset */
-#define f1_caseneg 0xffff8000 /* Bits for negation */
-
-/* The data consists of a vector of structures of type cnode. The two unsigned
-32-bit integers are used as follows:
-
-(f0) (1) The most significant byte holds the script number. The numbers are
- defined by the enum in ucp.h.
-
- (2) The 0x00800000 bit is set if this entry defines a range of characters.
- It is not set if this entry defines a single character
-
- (3) The 0x00600000 bits are spare.
-
- (4) The 0x001fffff bits contain the code point. No Unicode code point will
- ever be greater than 0x0010ffff, so this should be OK for ever.
-
-(f1) (1) The 0xfc000000 bits contain the character type number. The numbers are
- defined by an enum in ucp.h.
-
- (2) The 0x03ff0000 bits are spare.
-
- (3) The 0x0000ffff bits contain EITHER the unsigned offset to the top of
- range if this entry defines a range, OR the *signed* offset to the
- character's "other case" partner if this entry defines a single
- character. There is no partner if the value is zero.
-
--------------------------------------------------------------------------------
-| script (8) |.|.|.| codepoint (21) || type (6) |.|.| spare (8) | offset (16) |
--------------------------------------------------------------------------------
- | | | | |
- | | |-> spare | |-> spare
- | | |
- | |-> spare |-> spare
- |
- |-> range flag
-
-The upper/lower casing information is set only for characters that come in
-pairs. The non-one-to-one mappings in the Unicode data are ignored.
-
-When searching the data, proceed as follows:
-
-(1) Set up for a binary chop search.
-
-(2) If the top is not greater than the bottom, the character is not in the
- table. Its type must therefore be "Cn" ("Undefined").
-
-(3) Find the middle vector element.
-
-(4) Extract the code point and compare. If equal, we are done.
-
-(5) If the test character is smaller, set the top to the current point, and
- goto (2).
-
-(6) If the current entry defines a range, compute the last character by adding
- the offset, and see if the test character is within the range. If it is,
- we are done.
-
-(7) Otherwise, set the bottom to one element past the current point and goto
- (2).
-*/
-
-/* End of ucpinternal.h */
-#endif // THIRD_PARTY_JSCRE_UCPINTERNAL_H_
diff --git a/runtime/third_party/jscre/ucptable.cpp b/runtime/third_party/jscre/ucptable.cpp
deleted file mode 100644
index 011f7f5..0000000
--- a/runtime/third_party/jscre/ucptable.cpp
+++ /dev/null
@@ -1,2968 +0,0 @@
-/* This source module is automatically generated from the Unicode
-property table. See ucpinternal.h for a description of the layout. */
-
-static const cnode ucp_table[] = {
- { 0x09800000, 0x0000001f },
- { 0x09000020, 0x74000000 },
- { 0x09800021, 0x54000002 },
- { 0x09000024, 0x5c000000 },
- { 0x09800025, 0x54000002 },
- { 0x09000028, 0x58000000 },
- { 0x09000029, 0x48000000 },
- { 0x0900002a, 0x54000000 },
- { 0x0900002b, 0x64000000 },
- { 0x0900002c, 0x54000000 },
- { 0x0900002d, 0x44000000 },
- { 0x0980002e, 0x54000001 },
- { 0x09800030, 0x34000009 },
- { 0x0980003a, 0x54000001 },
- { 0x0980003c, 0x64000002 },
- { 0x0980003f, 0x54000001 },
- { 0x21000041, 0x24000020 },
- { 0x21000042, 0x24000020 },
- { 0x21000043, 0x24000020 },
- { 0x21000044, 0x24000020 },
- { 0x21000045, 0x24000020 },
- { 0x21000046, 0x24000020 },
- { 0x21000047, 0x24000020 },
- { 0x21000048, 0x24000020 },
- { 0x21000049, 0x24000020 },
- { 0x2100004a, 0x24000020 },
- { 0x2100004b, 0x24000020 },
- { 0x2100004c, 0x24000020 },
- { 0x2100004d, 0x24000020 },
- { 0x2100004e, 0x24000020 },
- { 0x2100004f, 0x24000020 },
- { 0x21000050, 0x24000020 },
- { 0x21000051, 0x24000020 },
- { 0x21000052, 0x24000020 },
- { 0x21000053, 0x24000020 },
- { 0x21000054, 0x24000020 },
- { 0x21000055, 0x24000020 },
- { 0x21000056, 0x24000020 },
- { 0x21000057, 0x24000020 },
- { 0x21000058, 0x24000020 },
- { 0x21000059, 0x24000020 },
- { 0x2100005a, 0x24000020 },
- { 0x0900005b, 0x58000000 },
- { 0x0900005c, 0x54000000 },
- { 0x0900005d, 0x48000000 },
- { 0x0900005e, 0x60000000 },
- { 0x0900005f, 0x40000000 },
- { 0x09000060, 0x60000000 },
- { 0x21000061, 0x1400ffe0 },
- { 0x21000062, 0x1400ffe0 },
- { 0x21000063, 0x1400ffe0 },
- { 0x21000064, 0x1400ffe0 },
- { 0x21000065, 0x1400ffe0 },
- { 0x21000066, 0x1400ffe0 },
- { 0x21000067, 0x1400ffe0 },
- { 0x21000068, 0x1400ffe0 },
- { 0x21000069, 0x1400ffe0 },
- { 0x2100006a, 0x1400ffe0 },
- { 0x2100006b, 0x1400ffe0 },
- { 0x2100006c, 0x1400ffe0 },
- { 0x2100006d, 0x1400ffe0 },
- { 0x2100006e, 0x1400ffe0 },
- { 0x2100006f, 0x1400ffe0 },
- { 0x21000070, 0x1400ffe0 },
- { 0x21000071, 0x1400ffe0 },
- { 0x21000072, 0x1400ffe0 },
- { 0x21000073, 0x1400ffe0 },
- { 0x21000074, 0x1400ffe0 },
- { 0x21000075, 0x1400ffe0 },
- { 0x21000076, 0x1400ffe0 },
- { 0x21000077, 0x1400ffe0 },
- { 0x21000078, 0x1400ffe0 },
- { 0x21000079, 0x1400ffe0 },
- { 0x2100007a, 0x1400ffe0 },
- { 0x0900007b, 0x58000000 },
- { 0x0900007c, 0x64000000 },
- { 0x0900007d, 0x48000000 },
- { 0x0900007e, 0x64000000 },
- { 0x0980007f, 0x00000020 },
- { 0x090000a0, 0x74000000 },
- { 0x090000a1, 0x54000000 },
- { 0x098000a2, 0x5c000003 },
- { 0x098000a6, 0x68000001 },
- { 0x090000a8, 0x60000000 },
- { 0x090000a9, 0x68000000 },
- { 0x210000aa, 0x14000000 },
- { 0x090000ab, 0x50000000 },
- { 0x090000ac, 0x64000000 },
- { 0x090000ad, 0x04000000 },
- { 0x090000ae, 0x68000000 },
- { 0x090000af, 0x60000000 },
- { 0x090000b0, 0x68000000 },
- { 0x090000b1, 0x64000000 },
- { 0x098000b2, 0x3c000001 },
- { 0x090000b4, 0x60000000 },
- { 0x090000b5, 0x140002e7 },
- { 0x090000b6, 0x68000000 },
- { 0x090000b7, 0x54000000 },
- { 0x090000b8, 0x60000000 },
- { 0x090000b9, 0x3c000000 },
- { 0x210000ba, 0x14000000 },
- { 0x090000bb, 0x4c000000 },
- { 0x098000bc, 0x3c000002 },
- { 0x090000bf, 0x54000000 },
- { 0x210000c0, 0x24000020 },
- { 0x210000c1, 0x24000020 },
- { 0x210000c2, 0x24000020 },
- { 0x210000c3, 0x24000020 },
- { 0x210000c4, 0x24000020 },
- { 0x210000c5, 0x24000020 },
- { 0x210000c6, 0x24000020 },
- { 0x210000c7, 0x24000020 },
- { 0x210000c8, 0x24000020 },
- { 0x210000c9, 0x24000020 },
- { 0x210000ca, 0x24000020 },
- { 0x210000cb, 0x24000020 },
- { 0x210000cc, 0x24000020 },
- { 0x210000cd, 0x24000020 },
- { 0x210000ce, 0x24000020 },
- { 0x210000cf, 0x24000020 },
- { 0x210000d0, 0x24000020 },
- { 0x210000d1, 0x24000020 },
- { 0x210000d2, 0x24000020 },
- { 0x210000d3, 0x24000020 },
- { 0x210000d4, 0x24000020 },
- { 0x210000d5, 0x24000020 },
- { 0x210000d6, 0x24000020 },
- { 0x090000d7, 0x64000000 },
- { 0x210000d8, 0x24000020 },
- { 0x210000d9, 0x24000020 },
- { 0x210000da, 0x24000020 },
- { 0x210000db, 0x24000020 },
- { 0x210000dc, 0x24000020 },
- { 0x210000dd, 0x24000020 },
- { 0x210000de, 0x24000020 },
- { 0x210000df, 0x14000000 },
- { 0x210000e0, 0x1400ffe0 },
- { 0x210000e1, 0x1400ffe0 },
- { 0x210000e2, 0x1400ffe0 },
- { 0x210000e3, 0x1400ffe0 },
- { 0x210000e4, 0x1400ffe0 },
- { 0x210000e5, 0x1400ffe0 },
- { 0x210000e6, 0x1400ffe0 },
- { 0x210000e7, 0x1400ffe0 },
- { 0x210000e8, 0x1400ffe0 },
- { 0x210000e9, 0x1400ffe0 },
- { 0x210000ea, 0x1400ffe0 },
- { 0x210000eb, 0x1400ffe0 },
- { 0x210000ec, 0x1400ffe0 },
- { 0x210000ed, 0x1400ffe0 },
- { 0x210000ee, 0x1400ffe0 },
- { 0x210000ef, 0x1400ffe0 },
- { 0x210000f0, 0x1400ffe0 },
- { 0x210000f1, 0x1400ffe0 },
- { 0x210000f2, 0x1400ffe0 },
- { 0x210000f3, 0x1400ffe0 },
- { 0x210000f4, 0x1400ffe0 },
- { 0x210000f5, 0x1400ffe0 },
- { 0x210000f6, 0x1400ffe0 },
- { 0x090000f7, 0x64000000 },
- { 0x210000f8, 0x1400ffe0 },
- { 0x210000f9, 0x1400ffe0 },
- { 0x210000fa, 0x1400ffe0 },
- { 0x210000fb, 0x1400ffe0 },
- { 0x210000fc, 0x1400ffe0 },
- { 0x210000fd, 0x1400ffe0 },
- { 0x210000fe, 0x1400ffe0 },
- { 0x210000ff, 0x14000079 },
- { 0x21000100, 0x24000001 },
- { 0x21000101, 0x1400ffff },
- { 0x21000102, 0x24000001 },
- { 0x21000103, 0x1400ffff },
- { 0x21000104, 0x24000001 },
- { 0x21000105, 0x1400ffff },
- { 0x21000106, 0x24000001 },
- { 0x21000107, 0x1400ffff },
- { 0x21000108, 0x24000001 },
- { 0x21000109, 0x1400ffff },
- { 0x2100010a, 0x24000001 },
- { 0x2100010b, 0x1400ffff },
- { 0x2100010c, 0x24000001 },
- { 0x2100010d, 0x1400ffff },
- { 0x2100010e, 0x24000001 },
- { 0x2100010f, 0x1400ffff },
- { 0x21000110, 0x24000001 },
- { 0x21000111, 0x1400ffff },
- { 0x21000112, 0x24000001 },
- { 0x21000113, 0x1400ffff },
- { 0x21000114, 0x24000001 },
- { 0x21000115, 0x1400ffff },
- { 0x21000116, 0x24000001 },
- { 0x21000117, 0x1400ffff },
- { 0x21000118, 0x24000001 },
- { 0x21000119, 0x1400ffff },
- { 0x2100011a, 0x24000001 },
- { 0x2100011b, 0x1400ffff },
- { 0x2100011c, 0x24000001 },
- { 0x2100011d, 0x1400ffff },
- { 0x2100011e, 0x24000001 },
- { 0x2100011f, 0x1400ffff },
- { 0x21000120, 0x24000001 },
- { 0x21000121, 0x1400ffff },
- { 0x21000122, 0x24000001 },
- { 0x21000123, 0x1400ffff },
- { 0x21000124, 0x24000001 },
- { 0x21000125, 0x1400ffff },
- { 0x21000126, 0x24000001 },
- { 0x21000127, 0x1400ffff },
- { 0x21000128, 0x24000001 },
- { 0x21000129, 0x1400ffff },
- { 0x2100012a, 0x24000001 },
- { 0x2100012b, 0x1400ffff },
- { 0x2100012c, 0x24000001 },
- { 0x2100012d, 0x1400ffff },
- { 0x2100012e, 0x24000001 },
- { 0x2100012f, 0x1400ffff },
- { 0x21000130, 0x2400ff39 },
- { 0x21000131, 0x1400ff18 },
- { 0x21000132, 0x24000001 },
- { 0x21000133, 0x1400ffff },
- { 0x21000134, 0x24000001 },
- { 0x21000135, 0x1400ffff },
- { 0x21000136, 0x24000001 },
- { 0x21000137, 0x1400ffff },
- { 0x21000138, 0x14000000 },
- { 0x21000139, 0x24000001 },
- { 0x2100013a, 0x1400ffff },
- { 0x2100013b, 0x24000001 },
- { 0x2100013c, 0x1400ffff },
- { 0x2100013d, 0x24000001 },
- { 0x2100013e, 0x1400ffff },
- { 0x2100013f, 0x24000001 },
- { 0x21000140, 0x1400ffff },
- { 0x21000141, 0x24000001 },
- { 0x21000142, 0x1400ffff },
- { 0x21000143, 0x24000001 },
- { 0x21000144, 0x1400ffff },
- { 0x21000145, 0x24000001 },
- { 0x21000146, 0x1400ffff },
- { 0x21000147, 0x24000001 },
- { 0x21000148, 0x1400ffff },
- { 0x21000149, 0x14000000 },
- { 0x2100014a, 0x24000001 },
- { 0x2100014b, 0x1400ffff },
- { 0x2100014c, 0x24000001 },
- { 0x2100014d, 0x1400ffff },
- { 0x2100014e, 0x24000001 },
- { 0x2100014f, 0x1400ffff },
- { 0x21000150, 0x24000001 },
- { 0x21000151, 0x1400ffff },
- { 0x21000152, 0x24000001 },
- { 0x21000153, 0x1400ffff },
- { 0x21000154, 0x24000001 },
- { 0x21000155, 0x1400ffff },
- { 0x21000156, 0x24000001 },
- { 0x21000157, 0x1400ffff },
- { 0x21000158, 0x24000001 },
- { 0x21000159, 0x1400ffff },
- { 0x2100015a, 0x24000001 },
- { 0x2100015b, 0x1400ffff },
- { 0x2100015c, 0x24000001 },
- { 0x2100015d, 0x1400ffff },
- { 0x2100015e, 0x24000001 },
- { 0x2100015f, 0x1400ffff },
- { 0x21000160, 0x24000001 },
- { 0x21000161, 0x1400ffff },
- { 0x21000162, 0x24000001 },
- { 0x21000163, 0x1400ffff },
- { 0x21000164, 0x24000001 },
- { 0x21000165, 0x1400ffff },
- { 0x21000166, 0x24000001 },
- { 0x21000167, 0x1400ffff },
- { 0x21000168, 0x24000001 },
- { 0x21000169, 0x1400ffff },
- { 0x2100016a, 0x24000001 },
- { 0x2100016b, 0x1400ffff },
- { 0x2100016c, 0x24000001 },
- { 0x2100016d, 0x1400ffff },
- { 0x2100016e, 0x24000001 },
- { 0x2100016f, 0x1400ffff },
- { 0x21000170, 0x24000001 },
- { 0x21000171, 0x1400ffff },
- { 0x21000172, 0x24000001 },
- { 0x21000173, 0x1400ffff },
- { 0x21000174, 0x24000001 },
- { 0x21000175, 0x1400ffff },
- { 0x21000176, 0x24000001 },
- { 0x21000177, 0x1400ffff },
- { 0x21000178, 0x2400ff87 },
- { 0x21000179, 0x24000001 },
- { 0x2100017a, 0x1400ffff },
- { 0x2100017b, 0x24000001 },
- { 0x2100017c, 0x1400ffff },
- { 0x2100017d, 0x24000001 },
- { 0x2100017e, 0x1400ffff },
- { 0x2100017f, 0x1400fed4 },
- { 0x21000180, 0x14000000 },
- { 0x21000181, 0x240000d2 },
- { 0x21000182, 0x24000001 },
- { 0x21000183, 0x1400ffff },
- { 0x21000184, 0x24000001 },
- { 0x21000185, 0x1400ffff },
- { 0x21000186, 0x240000ce },
- { 0x21000187, 0x24000001 },
- { 0x21000188, 0x1400ffff },
- { 0x21000189, 0x240000cd },
- { 0x2100018a, 0x240000cd },
- { 0x2100018b, 0x24000001 },
- { 0x2100018c, 0x1400ffff },
- { 0x2100018d, 0x14000000 },
- { 0x2100018e, 0x2400004f },
- { 0x2100018f, 0x240000ca },
- { 0x21000190, 0x240000cb },
- { 0x21000191, 0x24000001 },
- { 0x21000192, 0x1400ffff },
- { 0x21000193, 0x240000cd },
- { 0x21000194, 0x240000cf },
- { 0x21000195, 0x14000061 },
- { 0x21000196, 0x240000d3 },
- { 0x21000197, 0x240000d1 },
- { 0x21000198, 0x24000001 },
- { 0x21000199, 0x1400ffff },
- { 0x2100019a, 0x140000a3 },
- { 0x2100019b, 0x14000000 },
- { 0x2100019c, 0x240000d3 },
- { 0x2100019d, 0x240000d5 },
- { 0x2100019e, 0x14000082 },
- { 0x2100019f, 0x240000d6 },
- { 0x210001a0, 0x24000001 },
- { 0x210001a1, 0x1400ffff },
- { 0x210001a2, 0x24000001 },
- { 0x210001a3, 0x1400ffff },
- { 0x210001a4, 0x24000001 },
- { 0x210001a5, 0x1400ffff },
- { 0x210001a6, 0x240000da },
- { 0x210001a7, 0x24000001 },
- { 0x210001a8, 0x1400ffff },
- { 0x210001a9, 0x240000da },
- { 0x218001aa, 0x14000001 },
- { 0x210001ac, 0x24000001 },
- { 0x210001ad, 0x1400ffff },
- { 0x210001ae, 0x240000da },
- { 0x210001af, 0x24000001 },
- { 0x210001b0, 0x1400ffff },
- { 0x210001b1, 0x240000d9 },
- { 0x210001b2, 0x240000d9 },
- { 0x210001b3, 0x24000001 },
- { 0x210001b4, 0x1400ffff },
- { 0x210001b5, 0x24000001 },
- { 0x210001b6, 0x1400ffff },
- { 0x210001b7, 0x240000db },
- { 0x210001b8, 0x24000001 },
- { 0x210001b9, 0x1400ffff },
- { 0x210001ba, 0x14000000 },
- { 0x210001bb, 0x1c000000 },
- { 0x210001bc, 0x24000001 },
- { 0x210001bd, 0x1400ffff },
- { 0x210001be, 0x14000000 },
- { 0x210001bf, 0x14000038 },
- { 0x218001c0, 0x1c000003 },
- { 0x210001c4, 0x24000002 },
- { 0x210001c5, 0x2000ffff },
- { 0x210001c6, 0x1400fffe },
- { 0x210001c7, 0x24000002 },
- { 0x210001c8, 0x2000ffff },
- { 0x210001c9, 0x1400fffe },
- { 0x210001ca, 0x24000002 },
- { 0x210001cb, 0x2000ffff },
- { 0x210001cc, 0x1400fffe },
- { 0x210001cd, 0x24000001 },
- { 0x210001ce, 0x1400ffff },
- { 0x210001cf, 0x24000001 },
- { 0x210001d0, 0x1400ffff },
- { 0x210001d1, 0x24000001 },
- { 0x210001d2, 0x1400ffff },
- { 0x210001d3, 0x24000001 },
- { 0x210001d4, 0x1400ffff },
- { 0x210001d5, 0x24000001 },
- { 0x210001d6, 0x1400ffff },
- { 0x210001d7, 0x24000001 },
- { 0x210001d8, 0x1400ffff },
- { 0x210001d9, 0x24000001 },
- { 0x210001da, 0x1400ffff },
- { 0x210001db, 0x24000001 },
- { 0x210001dc, 0x1400ffff },
- { 0x210001dd, 0x1400ffb1 },
- { 0x210001de, 0x24000001 },
- { 0x210001df, 0x1400ffff },
- { 0x210001e0, 0x24000001 },
- { 0x210001e1, 0x1400ffff },
- { 0x210001e2, 0x24000001 },
- { 0x210001e3, 0x1400ffff },
- { 0x210001e4, 0x24000001 },
- { 0x210001e5, 0x1400ffff },
- { 0x210001e6, 0x24000001 },
- { 0x210001e7, 0x1400ffff },
- { 0x210001e8, 0x24000001 },
- { 0x210001e9, 0x1400ffff },
- { 0x210001ea, 0x24000001 },
- { 0x210001eb, 0x1400ffff },
- { 0x210001ec, 0x24000001 },
- { 0x210001ed, 0x1400ffff },
- { 0x210001ee, 0x24000001 },
- { 0x210001ef, 0x1400ffff },
- { 0x210001f0, 0x14000000 },
- { 0x210001f1, 0x24000002 },
- { 0x210001f2, 0x2000ffff },
- { 0x210001f3, 0x1400fffe },
- { 0x210001f4, 0x24000001 },
- { 0x210001f5, 0x1400ffff },
- { 0x210001f6, 0x2400ff9f },
- { 0x210001f7, 0x2400ffc8 },
- { 0x210001f8, 0x24000001 },
- { 0x210001f9, 0x1400ffff },
- { 0x210001fa, 0x24000001 },
- { 0x210001fb, 0x1400ffff },
- { 0x210001fc, 0x24000001 },
- { 0x210001fd, 0x1400ffff },
- { 0x210001fe, 0x24000001 },
- { 0x210001ff, 0x1400ffff },
- { 0x21000200, 0x24000001 },
- { 0x21000201, 0x1400ffff },
- { 0x21000202, 0x24000001 },
- { 0x21000203, 0x1400ffff },
- { 0x21000204, 0x24000001 },
- { 0x21000205, 0x1400ffff },
- { 0x21000206, 0x24000001 },
- { 0x21000207, 0x1400ffff },
- { 0x21000208, 0x24000001 },
- { 0x21000209, 0x1400ffff },
- { 0x2100020a, 0x24000001 },
- { 0x2100020b, 0x1400ffff },
- { 0x2100020c, 0x24000001 },
- { 0x2100020d, 0x1400ffff },
- { 0x2100020e, 0x24000001 },
- { 0x2100020f, 0x1400ffff },
- { 0x21000210, 0x24000001 },
- { 0x21000211, 0x1400ffff },
- { 0x21000212, 0x24000001 },
- { 0x21000213, 0x1400ffff },
- { 0x21000214, 0x24000001 },
- { 0x21000215, 0x1400ffff },
- { 0x21000216, 0x24000001 },
- { 0x21000217, 0x1400ffff },
- { 0x21000218, 0x24000001 },
- { 0x21000219, 0x1400ffff },
- { 0x2100021a, 0x24000001 },
- { 0x2100021b, 0x1400ffff },
- { 0x2100021c, 0x24000001 },
- { 0x2100021d, 0x1400ffff },
- { 0x2100021e, 0x24000001 },
- { 0x2100021f, 0x1400ffff },
- { 0x21000220, 0x2400ff7e },
- { 0x21000221, 0x14000000 },
- { 0x21000222, 0x24000001 },
- { 0x21000223, 0x1400ffff },
- { 0x21000224, 0x24000001 },
- { 0x21000225, 0x1400ffff },
- { 0x21000226, 0x24000001 },
- { 0x21000227, 0x1400ffff },
- { 0x21000228, 0x24000001 },
- { 0x21000229, 0x1400ffff },
- { 0x2100022a, 0x24000001 },
- { 0x2100022b, 0x1400ffff },
- { 0x2100022c, 0x24000001 },
- { 0x2100022d, 0x1400ffff },
- { 0x2100022e, 0x24000001 },
- { 0x2100022f, 0x1400ffff },
- { 0x21000230, 0x24000001 },
- { 0x21000231, 0x1400ffff },
- { 0x21000232, 0x24000001 },
- { 0x21000233, 0x1400ffff },
- { 0x21800234, 0x14000005 },
- { 0x2100023a, 0x24000000 },
- { 0x2100023b, 0x24000001 },
- { 0x2100023c, 0x1400ffff },
- { 0x2100023d, 0x2400ff5d },
- { 0x2100023e, 0x24000000 },
- { 0x2180023f, 0x14000001 },
- { 0x21000241, 0x24000053 },
- { 0x21800250, 0x14000002 },
- { 0x21000253, 0x1400ff2e },
- { 0x21000254, 0x1400ff32 },
- { 0x21000255, 0x14000000 },
- { 0x21000256, 0x1400ff33 },
- { 0x21000257, 0x1400ff33 },
- { 0x21000258, 0x14000000 },
- { 0x21000259, 0x1400ff36 },
- { 0x2100025a, 0x14000000 },
- { 0x2100025b, 0x1400ff35 },
- { 0x2180025c, 0x14000003 },
- { 0x21000260, 0x1400ff33 },
- { 0x21800261, 0x14000001 },
- { 0x21000263, 0x1400ff31 },
- { 0x21800264, 0x14000003 },
- { 0x21000268, 0x1400ff2f },
- { 0x21000269, 0x1400ff2d },
- { 0x2180026a, 0x14000004 },
- { 0x2100026f, 0x1400ff2d },
- { 0x21800270, 0x14000001 },
- { 0x21000272, 0x1400ff2b },
- { 0x21800273, 0x14000001 },
- { 0x21000275, 0x1400ff2a },
- { 0x21800276, 0x14000009 },
- { 0x21000280, 0x1400ff26 },
- { 0x21800281, 0x14000001 },
- { 0x21000283, 0x1400ff26 },
- { 0x21800284, 0x14000003 },
- { 0x21000288, 0x1400ff26 },
- { 0x21000289, 0x14000000 },
- { 0x2100028a, 0x1400ff27 },
- { 0x2100028b, 0x1400ff27 },
- { 0x2180028c, 0x14000005 },
- { 0x21000292, 0x1400ff25 },
- { 0x21000293, 0x14000000 },
- { 0x21000294, 0x1400ffad },
- { 0x21800295, 0x1400001a },
- { 0x218002b0, 0x18000011 },
- { 0x098002c2, 0x60000003 },
- { 0x098002c6, 0x1800000b },
- { 0x098002d2, 0x6000000d },
- { 0x218002e0, 0x18000004 },
- { 0x098002e5, 0x60000008 },
- { 0x090002ee, 0x18000000 },
- { 0x098002ef, 0x60000010 },
- { 0x1b800300, 0x30000044 },
- { 0x1b000345, 0x30000054 },
- { 0x1b800346, 0x30000029 },
- { 0x13800374, 0x60000001 },
- { 0x1300037a, 0x18000000 },
- { 0x0900037e, 0x54000000 },
- { 0x13800384, 0x60000001 },
- { 0x13000386, 0x24000026 },
- { 0x09000387, 0x54000000 },
- { 0x13000388, 0x24000025 },
- { 0x13000389, 0x24000025 },
- { 0x1300038a, 0x24000025 },
- { 0x1300038c, 0x24000040 },
- { 0x1300038e, 0x2400003f },
- { 0x1300038f, 0x2400003f },
- { 0x13000390, 0x14000000 },
- { 0x13000391, 0x24000020 },
- { 0x13000392, 0x24000020 },
- { 0x13000393, 0x24000020 },
- { 0x13000394, 0x24000020 },
- { 0x13000395, 0x24000020 },
- { 0x13000396, 0x24000020 },
- { 0x13000397, 0x24000020 },
- { 0x13000398, 0x24000020 },
- { 0x13000399, 0x24000020 },
- { 0x1300039a, 0x24000020 },
- { 0x1300039b, 0x24000020 },
- { 0x1300039c, 0x24000020 },
- { 0x1300039d, 0x24000020 },
- { 0x1300039e, 0x24000020 },
- { 0x1300039f, 0x24000020 },
- { 0x130003a0, 0x24000020 },
- { 0x130003a1, 0x24000020 },
- { 0x130003a3, 0x24000020 },
- { 0x130003a4, 0x24000020 },
- { 0x130003a5, 0x24000020 },
- { 0x130003a6, 0x24000020 },
- { 0x130003a7, 0x24000020 },
- { 0x130003a8, 0x24000020 },
- { 0x130003a9, 0x24000020 },
- { 0x130003aa, 0x24000020 },
- { 0x130003ab, 0x24000020 },
- { 0x130003ac, 0x1400ffda },
- { 0x130003ad, 0x1400ffdb },
- { 0x130003ae, 0x1400ffdb },
- { 0x130003af, 0x1400ffdb },
- { 0x130003b0, 0x14000000 },
- { 0x130003b1, 0x1400ffe0 },
- { 0x130003b2, 0x1400ffe0 },
- { 0x130003b3, 0x1400ffe0 },
- { 0x130003b4, 0x1400ffe0 },
- { 0x130003b5, 0x1400ffe0 },
- { 0x130003b6, 0x1400ffe0 },
- { 0x130003b7, 0x1400ffe0 },
- { 0x130003b8, 0x1400ffe0 },
- { 0x130003b9, 0x1400ffe0 },
- { 0x130003ba, 0x1400ffe0 },
- { 0x130003bb, 0x1400ffe0 },
- { 0x130003bc, 0x1400ffe0 },
- { 0x130003bd, 0x1400ffe0 },
- { 0x130003be, 0x1400ffe0 },
- { 0x130003bf, 0x1400ffe0 },
- { 0x130003c0, 0x1400ffe0 },
- { 0x130003c1, 0x1400ffe0 },
- { 0x130003c2, 0x1400ffe1 },
- { 0x130003c3, 0x1400ffe0 },
- { 0x130003c4, 0x1400ffe0 },
- { 0x130003c5, 0x1400ffe0 },
- { 0x130003c6, 0x1400ffe0 },
- { 0x130003c7, 0x1400ffe0 },
- { 0x130003c8, 0x1400ffe0 },
- { 0x130003c9, 0x1400ffe0 },
- { 0x130003ca, 0x1400ffe0 },
- { 0x130003cb, 0x1400ffe0 },
- { 0x130003cc, 0x1400ffc0 },
- { 0x130003cd, 0x1400ffc1 },
- { 0x130003ce, 0x1400ffc1 },
- { 0x130003d0, 0x1400ffc2 },
- { 0x130003d1, 0x1400ffc7 },
- { 0x138003d2, 0x24000002 },
- { 0x130003d5, 0x1400ffd1 },
- { 0x130003d6, 0x1400ffca },
- { 0x130003d7, 0x14000000 },
- { 0x130003d8, 0x24000001 },
- { 0x130003d9, 0x1400ffff },
- { 0x130003da, 0x24000001 },
- { 0x130003db, 0x1400ffff },
- { 0x130003dc, 0x24000001 },
- { 0x130003dd, 0x1400ffff },
- { 0x130003de, 0x24000001 },
- { 0x130003df, 0x1400ffff },
- { 0x130003e0, 0x24000001 },
- { 0x130003e1, 0x1400ffff },
- { 0x0a0003e2, 0x24000001 },
- { 0x0a0003e3, 0x1400ffff },
- { 0x0a0003e4, 0x24000001 },
- { 0x0a0003e5, 0x1400ffff },
- { 0x0a0003e6, 0x24000001 },
- { 0x0a0003e7, 0x1400ffff },
- { 0x0a0003e8, 0x24000001 },
- { 0x0a0003e9, 0x1400ffff },
- { 0x0a0003ea, 0x24000001 },
- { 0x0a0003eb, 0x1400ffff },
- { 0x0a0003ec, 0x24000001 },
- { 0x0a0003ed, 0x1400ffff },
- { 0x0a0003ee, 0x24000001 },
- { 0x0a0003ef, 0x1400ffff },
- { 0x130003f0, 0x1400ffaa },
- { 0x130003f1, 0x1400ffb0 },
- { 0x130003f2, 0x14000007 },
- { 0x130003f3, 0x14000000 },
- { 0x130003f4, 0x2400ffc4 },
- { 0x130003f5, 0x1400ffa0 },
- { 0x130003f6, 0x64000000 },
- { 0x130003f7, 0x24000001 },
- { 0x130003f8, 0x1400ffff },
- { 0x130003f9, 0x2400fff9 },
- { 0x130003fa, 0x24000001 },
- { 0x130003fb, 0x1400ffff },
- { 0x130003fc, 0x14000000 },
- { 0x138003fd, 0x24000002 },
- { 0x0c000400, 0x24000050 },
- { 0x0c000401, 0x24000050 },
- { 0x0c000402, 0x24000050 },
- { 0x0c000403, 0x24000050 },
- { 0x0c000404, 0x24000050 },
- { 0x0c000405, 0x24000050 },
- { 0x0c000406, 0x24000050 },
- { 0x0c000407, 0x24000050 },
- { 0x0c000408, 0x24000050 },
- { 0x0c000409, 0x24000050 },
- { 0x0c00040a, 0x24000050 },
- { 0x0c00040b, 0x24000050 },
- { 0x0c00040c, 0x24000050 },
- { 0x0c00040d, 0x24000050 },
- { 0x0c00040e, 0x24000050 },
- { 0x0c00040f, 0x24000050 },
- { 0x0c000410, 0x24000020 },
- { 0x0c000411, 0x24000020 },
- { 0x0c000412, 0x24000020 },
- { 0x0c000413, 0x24000020 },
- { 0x0c000414, 0x24000020 },
- { 0x0c000415, 0x24000020 },
- { 0x0c000416, 0x24000020 },
- { 0x0c000417, 0x24000020 },
- { 0x0c000418, 0x24000020 },
- { 0x0c000419, 0x24000020 },
- { 0x0c00041a, 0x24000020 },
- { 0x0c00041b, 0x24000020 },
- { 0x0c00041c, 0x24000020 },
- { 0x0c00041d, 0x24000020 },
- { 0x0c00041e, 0x24000020 },
- { 0x0c00041f, 0x24000020 },
- { 0x0c000420, 0x24000020 },
- { 0x0c000421, 0x24000020 },
- { 0x0c000422, 0x24000020 },
- { 0x0c000423, 0x24000020 },
- { 0x0c000424, 0x24000020 },
- { 0x0c000425, 0x24000020 },
- { 0x0c000426, 0x24000020 },
- { 0x0c000427, 0x24000020 },
- { 0x0c000428, 0x24000020 },
- { 0x0c000429, 0x24000020 },
- { 0x0c00042a, 0x24000020 },
- { 0x0c00042b, 0x24000020 },
- { 0x0c00042c, 0x24000020 },
- { 0x0c00042d, 0x24000020 },
- { 0x0c00042e, 0x24000020 },
- { 0x0c00042f, 0x24000020 },
- { 0x0c000430, 0x1400ffe0 },
- { 0x0c000431, 0x1400ffe0 },
- { 0x0c000432, 0x1400ffe0 },
- { 0x0c000433, 0x1400ffe0 },
- { 0x0c000434, 0x1400ffe0 },
- { 0x0c000435, 0x1400ffe0 },
- { 0x0c000436, 0x1400ffe0 },
- { 0x0c000437, 0x1400ffe0 },
- { 0x0c000438, 0x1400ffe0 },
- { 0x0c000439, 0x1400ffe0 },
- { 0x0c00043a, 0x1400ffe0 },
- { 0x0c00043b, 0x1400ffe0 },
- { 0x0c00043c, 0x1400ffe0 },
- { 0x0c00043d, 0x1400ffe0 },
- { 0x0c00043e, 0x1400ffe0 },
- { 0x0c00043f, 0x1400ffe0 },
- { 0x0c000440, 0x1400ffe0 },
- { 0x0c000441, 0x1400ffe0 },
- { 0x0c000442, 0x1400ffe0 },
- { 0x0c000443, 0x1400ffe0 },
- { 0x0c000444, 0x1400ffe0 },
- { 0x0c000445, 0x1400ffe0 },
- { 0x0c000446, 0x1400ffe0 },
- { 0x0c000447, 0x1400ffe0 },
- { 0x0c000448, 0x1400ffe0 },
- { 0x0c000449, 0x1400ffe0 },
- { 0x0c00044a, 0x1400ffe0 },
- { 0x0c00044b, 0x1400ffe0 },
- { 0x0c00044c, 0x1400ffe0 },
- { 0x0c00044d, 0x1400ffe0 },
- { 0x0c00044e, 0x1400ffe0 },
- { 0x0c00044f, 0x1400ffe0 },
- { 0x0c000450, 0x1400ffb0 },
- { 0x0c000451, 0x1400ffb0 },
- { 0x0c000452, 0x1400ffb0 },
- { 0x0c000453, 0x1400ffb0 },
- { 0x0c000454, 0x1400ffb0 },
- { 0x0c000455, 0x1400ffb0 },
- { 0x0c000456, 0x1400ffb0 },
- { 0x0c000457, 0x1400ffb0 },
- { 0x0c000458, 0x1400ffb0 },
- { 0x0c000459, 0x1400ffb0 },
- { 0x0c00045a, 0x1400ffb0 },
- { 0x0c00045b, 0x1400ffb0 },
- { 0x0c00045c, 0x1400ffb0 },
- { 0x0c00045d, 0x1400ffb0 },
- { 0x0c00045e, 0x1400ffb0 },
- { 0x0c00045f, 0x1400ffb0 },
- { 0x0c000460, 0x24000001 },
- { 0x0c000461, 0x1400ffff },
- { 0x0c000462, 0x24000001 },
- { 0x0c000463, 0x1400ffff },
- { 0x0c000464, 0x24000001 },
- { 0x0c000465, 0x1400ffff },
- { 0x0c000466, 0x24000001 },
- { 0x0c000467, 0x1400ffff },
- { 0x0c000468, 0x24000001 },
- { 0x0c000469, 0x1400ffff },
- { 0x0c00046a, 0x24000001 },
- { 0x0c00046b, 0x1400ffff },
- { 0x0c00046c, 0x24000001 },
- { 0x0c00046d, 0x1400ffff },
- { 0x0c00046e, 0x24000001 },
- { 0x0c00046f, 0x1400ffff },
- { 0x0c000470, 0x24000001 },
- { 0x0c000471, 0x1400ffff },
- { 0x0c000472, 0x24000001 },
- { 0x0c000473, 0x1400ffff },
- { 0x0c000474, 0x24000001 },
- { 0x0c000475, 0x1400ffff },
- { 0x0c000476, 0x24000001 },
- { 0x0c000477, 0x1400ffff },
- { 0x0c000478, 0x24000001 },
- { 0x0c000479, 0x1400ffff },
- { 0x0c00047a, 0x24000001 },
- { 0x0c00047b, 0x1400ffff },
- { 0x0c00047c, 0x24000001 },
- { 0x0c00047d, 0x1400ffff },
- { 0x0c00047e, 0x24000001 },
- { 0x0c00047f, 0x1400ffff },
- { 0x0c000480, 0x24000001 },
- { 0x0c000481, 0x1400ffff },
- { 0x0c000482, 0x68000000 },
- { 0x0c800483, 0x30000003 },
- { 0x0c800488, 0x2c000001 },
- { 0x0c00048a, 0x24000001 },
- { 0x0c00048b, 0x1400ffff },
- { 0x0c00048c, 0x24000001 },
- { 0x0c00048d, 0x1400ffff },
- { 0x0c00048e, 0x24000001 },
- { 0x0c00048f, 0x1400ffff },
- { 0x0c000490, 0x24000001 },
- { 0x0c000491, 0x1400ffff },
- { 0x0c000492, 0x24000001 },
- { 0x0c000493, 0x1400ffff },
- { 0x0c000494, 0x24000001 },
- { 0x0c000495, 0x1400ffff },
- { 0x0c000496, 0x24000001 },
- { 0x0c000497, 0x1400ffff },
- { 0x0c000498, 0x24000001 },
- { 0x0c000499, 0x1400ffff },
- { 0x0c00049a, 0x24000001 },
- { 0x0c00049b, 0x1400ffff },
- { 0x0c00049c, 0x24000001 },
- { 0x0c00049d, 0x1400ffff },
- { 0x0c00049e, 0x24000001 },
- { 0x0c00049f, 0x1400ffff },
- { 0x0c0004a0, 0x24000001 },
- { 0x0c0004a1, 0x1400ffff },
- { 0x0c0004a2, 0x24000001 },
- { 0x0c0004a3, 0x1400ffff },
- { 0x0c0004a4, 0x24000001 },
- { 0x0c0004a5, 0x1400ffff },
- { 0x0c0004a6, 0x24000001 },
- { 0x0c0004a7, 0x1400ffff },
- { 0x0c0004a8, 0x24000001 },
- { 0x0c0004a9, 0x1400ffff },
- { 0x0c0004aa, 0x24000001 },
- { 0x0c0004ab, 0x1400ffff },
- { 0x0c0004ac, 0x24000001 },
- { 0x0c0004ad, 0x1400ffff },
- { 0x0c0004ae, 0x24000001 },
- { 0x0c0004af, 0x1400ffff },
- { 0x0c0004b0, 0x24000001 },
- { 0x0c0004b1, 0x1400ffff },
- { 0x0c0004b2, 0x24000001 },
- { 0x0c0004b3, 0x1400ffff },
- { 0x0c0004b4, 0x24000001 },
- { 0x0c0004b5, 0x1400ffff },
- { 0x0c0004b6, 0x24000001 },
- { 0x0c0004b7, 0x1400ffff },
- { 0x0c0004b8, 0x24000001 },
- { 0x0c0004b9, 0x1400ffff },
- { 0x0c0004ba, 0x24000001 },
- { 0x0c0004bb, 0x1400ffff },
- { 0x0c0004bc, 0x24000001 },
- { 0x0c0004bd, 0x1400ffff },
- { 0x0c0004be, 0x24000001 },
- { 0x0c0004bf, 0x1400ffff },
- { 0x0c0004c0, 0x24000000 },
- { 0x0c0004c1, 0x24000001 },
- { 0x0c0004c2, 0x1400ffff },
- { 0x0c0004c3, 0x24000001 },
- { 0x0c0004c4, 0x1400ffff },
- { 0x0c0004c5, 0x24000001 },
- { 0x0c0004c6, 0x1400ffff },
- { 0x0c0004c7, 0x24000001 },
- { 0x0c0004c8, 0x1400ffff },
- { 0x0c0004c9, 0x24000001 },
- { 0x0c0004ca, 0x1400ffff },
- { 0x0c0004cb, 0x24000001 },
- { 0x0c0004cc, 0x1400ffff },
- { 0x0c0004cd, 0x24000001 },
- { 0x0c0004ce, 0x1400ffff },
- { 0x0c0004d0, 0x24000001 },
- { 0x0c0004d1, 0x1400ffff },
- { 0x0c0004d2, 0x24000001 },
- { 0x0c0004d3, 0x1400ffff },
- { 0x0c0004d4, 0x24000001 },
- { 0x0c0004d5, 0x1400ffff },
- { 0x0c0004d6, 0x24000001 },
- { 0x0c0004d7, 0x1400ffff },
- { 0x0c0004d8, 0x24000001 },
- { 0x0c0004d9, 0x1400ffff },
- { 0x0c0004da, 0x24000001 },
- { 0x0c0004db, 0x1400ffff },
- { 0x0c0004dc, 0x24000001 },
- { 0x0c0004dd, 0x1400ffff },
- { 0x0c0004de, 0x24000001 },
- { 0x0c0004df, 0x1400ffff },
- { 0x0c0004e0, 0x24000001 },
- { 0x0c0004e1, 0x1400ffff },
- { 0x0c0004e2, 0x24000001 },
- { 0x0c0004e3, 0x1400ffff },
- { 0x0c0004e4, 0x24000001 },
- { 0x0c0004e5, 0x1400ffff },
- { 0x0c0004e6, 0x24000001 },
- { 0x0c0004e7, 0x1400ffff },
- { 0x0c0004e8, 0x24000001 },
- { 0x0c0004e9, 0x1400ffff },
- { 0x0c0004ea, 0x24000001 },
- { 0x0c0004eb, 0x1400ffff },
- { 0x0c0004ec, 0x24000001 },
- { 0x0c0004ed, 0x1400ffff },
- { 0x0c0004ee, 0x24000001 },
- { 0x0c0004ef, 0x1400ffff },
- { 0x0c0004f0, 0x24000001 },
- { 0x0c0004f1, 0x1400ffff },
- { 0x0c0004f2, 0x24000001 },
- { 0x0c0004f3, 0x1400ffff },
- { 0x0c0004f4, 0x24000001 },
- { 0x0c0004f5, 0x1400ffff },
- { 0x0c0004f6, 0x24000001 },
- { 0x0c0004f7, 0x1400ffff },
- { 0x0c0004f8, 0x24000001 },
- { 0x0c0004f9, 0x1400ffff },
- { 0x0c000500, 0x24000001 },
- { 0x0c000501, 0x1400ffff },
- { 0x0c000502, 0x24000001 },
- { 0x0c000503, 0x1400ffff },
- { 0x0c000504, 0x24000001 },
- { 0x0c000505, 0x1400ffff },
- { 0x0c000506, 0x24000001 },
- { 0x0c000507, 0x1400ffff },
- { 0x0c000508, 0x24000001 },
- { 0x0c000509, 0x1400ffff },
- { 0x0c00050a, 0x24000001 },
- { 0x0c00050b, 0x1400ffff },
- { 0x0c00050c, 0x24000001 },
- { 0x0c00050d, 0x1400ffff },
- { 0x0c00050e, 0x24000001 },
- { 0x0c00050f, 0x1400ffff },
- { 0x01000531, 0x24000030 },
- { 0x01000532, 0x24000030 },
- { 0x01000533, 0x24000030 },
- { 0x01000534, 0x24000030 },
- { 0x01000535, 0x24000030 },
- { 0x01000536, 0x24000030 },
- { 0x01000537, 0x24000030 },
- { 0x01000538, 0x24000030 },
- { 0x01000539, 0x24000030 },
- { 0x0100053a, 0x24000030 },
- { 0x0100053b, 0x24000030 },
- { 0x0100053c, 0x24000030 },
- { 0x0100053d, 0x24000030 },
- { 0x0100053e, 0x24000030 },
- { 0x0100053f, 0x24000030 },
- { 0x01000540, 0x24000030 },
- { 0x01000541, 0x24000030 },
- { 0x01000542, 0x24000030 },
- { 0x01000543, 0x24000030 },
- { 0x01000544, 0x24000030 },
- { 0x01000545, 0x24000030 },
- { 0x01000546, 0x24000030 },
- { 0x01000547, 0x24000030 },
- { 0x01000548, 0x24000030 },
- { 0x01000549, 0x24000030 },
- { 0x0100054a, 0x24000030 },
- { 0x0100054b, 0x24000030 },
- { 0x0100054c, 0x24000030 },
- { 0x0100054d, 0x24000030 },
- { 0x0100054e, 0x24000030 },
- { 0x0100054f, 0x24000030 },
- { 0x01000550, 0x24000030 },
- { 0x01000551, 0x24000030 },
- { 0x01000552, 0x24000030 },
- { 0x01000553, 0x24000030 },
- { 0x01000554, 0x24000030 },
- { 0x01000555, 0x24000030 },
- { 0x01000556, 0x24000030 },
- { 0x01000559, 0x18000000 },
- { 0x0180055a, 0x54000005 },
- { 0x01000561, 0x1400ffd0 },
- { 0x01000562, 0x1400ffd0 },
- { 0x01000563, 0x1400ffd0 },
- { 0x01000564, 0x1400ffd0 },
- { 0x01000565, 0x1400ffd0 },
- { 0x01000566, 0x1400ffd0 },
- { 0x01000567, 0x1400ffd0 },
- { 0x01000568, 0x1400ffd0 },
- { 0x01000569, 0x1400ffd0 },
- { 0x0100056a, 0x1400ffd0 },
- { 0x0100056b, 0x1400ffd0 },
- { 0x0100056c, 0x1400ffd0 },
- { 0x0100056d, 0x1400ffd0 },
- { 0x0100056e, 0x1400ffd0 },
- { 0x0100056f, 0x1400ffd0 },
- { 0x01000570, 0x1400ffd0 },
- { 0x01000571, 0x1400ffd0 },
- { 0x01000572, 0x1400ffd0 },
- { 0x01000573, 0x1400ffd0 },
- { 0x01000574, 0x1400ffd0 },
- { 0x01000575, 0x1400ffd0 },
- { 0x01000576, 0x1400ffd0 },
- { 0x01000577, 0x1400ffd0 },
- { 0x01000578, 0x1400ffd0 },
- { 0x01000579, 0x1400ffd0 },
- { 0x0100057a, 0x1400ffd0 },
- { 0x0100057b, 0x1400ffd0 },
- { 0x0100057c, 0x1400ffd0 },
- { 0x0100057d, 0x1400ffd0 },
- { 0x0100057e, 0x1400ffd0 },
- { 0x0100057f, 0x1400ffd0 },
- { 0x01000580, 0x1400ffd0 },
- { 0x01000581, 0x1400ffd0 },
- { 0x01000582, 0x1400ffd0 },
- { 0x01000583, 0x1400ffd0 },
- { 0x01000584, 0x1400ffd0 },
- { 0x01000585, 0x1400ffd0 },
- { 0x01000586, 0x1400ffd0 },
- { 0x01000587, 0x14000000 },
- { 0x09000589, 0x54000000 },
- { 0x0100058a, 0x44000000 },
- { 0x19800591, 0x30000028 },
- { 0x198005bb, 0x30000002 },
- { 0x190005be, 0x54000000 },
- { 0x190005bf, 0x30000000 },
- { 0x190005c0, 0x54000000 },
- { 0x198005c1, 0x30000001 },
- { 0x190005c3, 0x54000000 },
- { 0x198005c4, 0x30000001 },
- { 0x190005c6, 0x54000000 },
- { 0x190005c7, 0x30000000 },
- { 0x198005d0, 0x1c00001a },
- { 0x198005f0, 0x1c000002 },
- { 0x198005f3, 0x54000001 },
- { 0x09800600, 0x04000003 },
- { 0x0000060b, 0x5c000000 },
- { 0x0980060c, 0x54000001 },
- { 0x0080060e, 0x68000001 },
- { 0x00800610, 0x30000005 },
- { 0x0900061b, 0x54000000 },
- { 0x0080061e, 0x54000001 },
- { 0x00800621, 0x1c000019 },
- { 0x09000640, 0x18000000 },
- { 0x00800641, 0x1c000009 },
- { 0x1b80064b, 0x30000013 },
- { 0x09800660, 0x34000009 },
- { 0x0080066a, 0x54000003 },
- { 0x0080066e, 0x1c000001 },
- { 0x1b000670, 0x30000000 },
- { 0x00800671, 0x1c000062 },
- { 0x000006d4, 0x54000000 },
- { 0x000006d5, 0x1c000000 },
- { 0x008006d6, 0x30000006 },
- { 0x090006dd, 0x04000000 },
- { 0x000006de, 0x2c000000 },
- { 0x008006df, 0x30000005 },
- { 0x008006e5, 0x18000001 },
- { 0x008006e7, 0x30000001 },
- { 0x000006e9, 0x68000000 },
- { 0x008006ea, 0x30000003 },
- { 0x008006ee, 0x1c000001 },
- { 0x008006f0, 0x34000009 },
- { 0x008006fa, 0x1c000002 },
- { 0x008006fd, 0x68000001 },
- { 0x000006ff, 0x1c000000 },
- { 0x31800700, 0x5400000d },
- { 0x3100070f, 0x04000000 },
- { 0x31000710, 0x1c000000 },
- { 0x31000711, 0x30000000 },
- { 0x31800712, 0x1c00001d },
- { 0x31800730, 0x3000001a },
- { 0x3180074d, 0x1c000020 },
- { 0x37800780, 0x1c000025 },
- { 0x378007a6, 0x3000000a },
- { 0x370007b1, 0x1c000000 },
- { 0x0e800901, 0x30000001 },
- { 0x0e000903, 0x28000000 },
- { 0x0e800904, 0x1c000035 },
- { 0x0e00093c, 0x30000000 },
- { 0x0e00093d, 0x1c000000 },
- { 0x0e80093e, 0x28000002 },
- { 0x0e800941, 0x30000007 },
- { 0x0e800949, 0x28000003 },
- { 0x0e00094d, 0x30000000 },
- { 0x0e000950, 0x1c000000 },
- { 0x0e800951, 0x30000003 },
- { 0x0e800958, 0x1c000009 },
- { 0x0e800962, 0x30000001 },
- { 0x09800964, 0x54000001 },
- { 0x0e800966, 0x34000009 },
- { 0x09000970, 0x54000000 },
- { 0x0e00097d, 0x1c000000 },
- { 0x02000981, 0x30000000 },
- { 0x02800982, 0x28000001 },
- { 0x02800985, 0x1c000007 },
- { 0x0280098f, 0x1c000001 },
- { 0x02800993, 0x1c000015 },
- { 0x028009aa, 0x1c000006 },
- { 0x020009b2, 0x1c000000 },
- { 0x028009b6, 0x1c000003 },
- { 0x020009bc, 0x30000000 },
- { 0x020009bd, 0x1c000000 },
- { 0x028009be, 0x28000002 },
- { 0x028009c1, 0x30000003 },
- { 0x028009c7, 0x28000001 },
- { 0x028009cb, 0x28000001 },
- { 0x020009cd, 0x30000000 },
- { 0x020009ce, 0x1c000000 },
- { 0x020009d7, 0x28000000 },
- { 0x028009dc, 0x1c000001 },
- { 0x028009df, 0x1c000002 },
- { 0x028009e2, 0x30000001 },
- { 0x028009e6, 0x34000009 },
- { 0x028009f0, 0x1c000001 },
- { 0x028009f2, 0x5c000001 },
- { 0x028009f4, 0x3c000005 },
- { 0x020009fa, 0x68000000 },
- { 0x15800a01, 0x30000001 },
- { 0x15000a03, 0x28000000 },
- { 0x15800a05, 0x1c000005 },
- { 0x15800a0f, 0x1c000001 },
- { 0x15800a13, 0x1c000015 },
- { 0x15800a2a, 0x1c000006 },
- { 0x15800a32, 0x1c000001 },
- { 0x15800a35, 0x1c000001 },
- { 0x15800a38, 0x1c000001 },
- { 0x15000a3c, 0x30000000 },
- { 0x15800a3e, 0x28000002 },
- { 0x15800a41, 0x30000001 },
- { 0x15800a47, 0x30000001 },
- { 0x15800a4b, 0x30000002 },
- { 0x15800a59, 0x1c000003 },
- { 0x15000a5e, 0x1c000000 },
- { 0x15800a66, 0x34000009 },
- { 0x15800a70, 0x30000001 },
- { 0x15800a72, 0x1c000002 },
- { 0x14800a81, 0x30000001 },
- { 0x14000a83, 0x28000000 },
- { 0x14800a85, 0x1c000008 },
- { 0x14800a8f, 0x1c000002 },
- { 0x14800a93, 0x1c000015 },
- { 0x14800aaa, 0x1c000006 },
- { 0x14800ab2, 0x1c000001 },
- { 0x14800ab5, 0x1c000004 },
- { 0x14000abc, 0x30000000 },
- { 0x14000abd, 0x1c000000 },
- { 0x14800abe, 0x28000002 },
- { 0x14800ac1, 0x30000004 },
- { 0x14800ac7, 0x30000001 },
- { 0x14000ac9, 0x28000000 },
- { 0x14800acb, 0x28000001 },
- { 0x14000acd, 0x30000000 },
- { 0x14000ad0, 0x1c000000 },
- { 0x14800ae0, 0x1c000001 },
- { 0x14800ae2, 0x30000001 },
- { 0x14800ae6, 0x34000009 },
- { 0x14000af1, 0x5c000000 },
- { 0x2b000b01, 0x30000000 },
- { 0x2b800b02, 0x28000001 },
- { 0x2b800b05, 0x1c000007 },
- { 0x2b800b0f, 0x1c000001 },
- { 0x2b800b13, 0x1c000015 },
- { 0x2b800b2a, 0x1c000006 },
- { 0x2b800b32, 0x1c000001 },
- { 0x2b800b35, 0x1c000004 },
- { 0x2b000b3c, 0x30000000 },
- { 0x2b000b3d, 0x1c000000 },
- { 0x2b000b3e, 0x28000000 },
- { 0x2b000b3f, 0x30000000 },
- { 0x2b000b40, 0x28000000 },
- { 0x2b800b41, 0x30000002 },
- { 0x2b800b47, 0x28000001 },
- { 0x2b800b4b, 0x28000001 },
- { 0x2b000b4d, 0x30000000 },
- { 0x2b000b56, 0x30000000 },
- { 0x2b000b57, 0x28000000 },
- { 0x2b800b5c, 0x1c000001 },
- { 0x2b800b5f, 0x1c000002 },
- { 0x2b800b66, 0x34000009 },
- { 0x2b000b70, 0x68000000 },
- { 0x2b000b71, 0x1c000000 },
- { 0x35000b82, 0x30000000 },
- { 0x35000b83, 0x1c000000 },
- { 0x35800b85, 0x1c000005 },
- { 0x35800b8e, 0x1c000002 },
- { 0x35800b92, 0x1c000003 },
- { 0x35800b99, 0x1c000001 },
- { 0x35000b9c, 0x1c000000 },
- { 0x35800b9e, 0x1c000001 },
- { 0x35800ba3, 0x1c000001 },
- { 0x35800ba8, 0x1c000002 },
- { 0x35800bae, 0x1c00000b },
- { 0x35800bbe, 0x28000001 },
- { 0x35000bc0, 0x30000000 },
- { 0x35800bc1, 0x28000001 },
- { 0x35800bc6, 0x28000002 },
- { 0x35800bca, 0x28000002 },
- { 0x35000bcd, 0x30000000 },
- { 0x35000bd7, 0x28000000 },
- { 0x35800be6, 0x34000009 },
- { 0x35800bf0, 0x3c000002 },
- { 0x35800bf3, 0x68000005 },
- { 0x35000bf9, 0x5c000000 },
- { 0x35000bfa, 0x68000000 },
- { 0x36800c01, 0x28000002 },
- { 0x36800c05, 0x1c000007 },
- { 0x36800c0e, 0x1c000002 },
- { 0x36800c12, 0x1c000016 },
- { 0x36800c2a, 0x1c000009 },
- { 0x36800c35, 0x1c000004 },
- { 0x36800c3e, 0x30000002 },
- { 0x36800c41, 0x28000003 },
- { 0x36800c46, 0x30000002 },
- { 0x36800c4a, 0x30000003 },
- { 0x36800c55, 0x30000001 },
- { 0x36800c60, 0x1c000001 },
- { 0x36800c66, 0x34000009 },
- { 0x1c800c82, 0x28000001 },
- { 0x1c800c85, 0x1c000007 },
- { 0x1c800c8e, 0x1c000002 },
- { 0x1c800c92, 0x1c000016 },
- { 0x1c800caa, 0x1c000009 },
- { 0x1c800cb5, 0x1c000004 },
- { 0x1c000cbc, 0x30000000 },
- { 0x1c000cbd, 0x1c000000 },
- { 0x1c000cbe, 0x28000000 },
- { 0x1c000cbf, 0x30000000 },
- { 0x1c800cc0, 0x28000004 },
- { 0x1c000cc6, 0x30000000 },
- { 0x1c800cc7, 0x28000001 },
- { 0x1c800cca, 0x28000001 },
- { 0x1c800ccc, 0x30000001 },
- { 0x1c800cd5, 0x28000001 },
- { 0x1c000cde, 0x1c000000 },
- { 0x1c800ce0, 0x1c000001 },
- { 0x1c800ce6, 0x34000009 },
- { 0x24800d02, 0x28000001 },
- { 0x24800d05, 0x1c000007 },
- { 0x24800d0e, 0x1c000002 },
- { 0x24800d12, 0x1c000016 },
- { 0x24800d2a, 0x1c00000f },
- { 0x24800d3e, 0x28000002 },
- { 0x24800d41, 0x30000002 },
- { 0x24800d46, 0x28000002 },
- { 0x24800d4a, 0x28000002 },
- { 0x24000d4d, 0x30000000 },
- { 0x24000d57, 0x28000000 },
- { 0x24800d60, 0x1c000001 },
- { 0x24800d66, 0x34000009 },
- { 0x2f800d82, 0x28000001 },
- { 0x2f800d85, 0x1c000011 },
- { 0x2f800d9a, 0x1c000017 },
- { 0x2f800db3, 0x1c000008 },
- { 0x2f000dbd, 0x1c000000 },
- { 0x2f800dc0, 0x1c000006 },
- { 0x2f000dca, 0x30000000 },
- { 0x2f800dcf, 0x28000002 },
- { 0x2f800dd2, 0x30000002 },
- { 0x2f000dd6, 0x30000000 },
- { 0x2f800dd8, 0x28000007 },
- { 0x2f800df2, 0x28000001 },
- { 0x2f000df4, 0x54000000 },
- { 0x38800e01, 0x1c00002f },
- { 0x38000e31, 0x30000000 },
- { 0x38800e32, 0x1c000001 },
- { 0x38800e34, 0x30000006 },
- { 0x09000e3f, 0x5c000000 },
- { 0x38800e40, 0x1c000005 },
- { 0x38000e46, 0x18000000 },
- { 0x38800e47, 0x30000007 },
- { 0x38000e4f, 0x54000000 },
- { 0x38800e50, 0x34000009 },
- { 0x38800e5a, 0x54000001 },
- { 0x20800e81, 0x1c000001 },
- { 0x20000e84, 0x1c000000 },
- { 0x20800e87, 0x1c000001 },
- { 0x20000e8a, 0x1c000000 },
- { 0x20000e8d, 0x1c000000 },
- { 0x20800e94, 0x1c000003 },
- { 0x20800e99, 0x1c000006 },
- { 0x20800ea1, 0x1c000002 },
- { 0x20000ea5, 0x1c000000 },
- { 0x20000ea7, 0x1c000000 },
- { 0x20800eaa, 0x1c000001 },
- { 0x20800ead, 0x1c000003 },
- { 0x20000eb1, 0x30000000 },
- { 0x20800eb2, 0x1c000001 },
- { 0x20800eb4, 0x30000005 },
- { 0x20800ebb, 0x30000001 },
- { 0x20000ebd, 0x1c000000 },
- { 0x20800ec0, 0x1c000004 },
- { 0x20000ec6, 0x18000000 },
- { 0x20800ec8, 0x30000005 },
- { 0x20800ed0, 0x34000009 },
- { 0x20800edc, 0x1c000001 },
- { 0x39000f00, 0x1c000000 },
- { 0x39800f01, 0x68000002 },
- { 0x39800f04, 0x5400000e },
- { 0x39800f13, 0x68000004 },
- { 0x39800f18, 0x30000001 },
- { 0x39800f1a, 0x68000005 },
- { 0x39800f20, 0x34000009 },
- { 0x39800f2a, 0x3c000009 },
- { 0x39000f34, 0x68000000 },
- { 0x39000f35, 0x30000000 },
- { 0x39000f36, 0x68000000 },
- { 0x39000f37, 0x30000000 },
- { 0x39000f38, 0x68000000 },
- { 0x39000f39, 0x30000000 },
- { 0x39000f3a, 0x58000000 },
- { 0x39000f3b, 0x48000000 },
- { 0x39000f3c, 0x58000000 },
- { 0x39000f3d, 0x48000000 },
- { 0x39800f3e, 0x28000001 },
- { 0x39800f40, 0x1c000007 },
- { 0x39800f49, 0x1c000021 },
- { 0x39800f71, 0x3000000d },
- { 0x39000f7f, 0x28000000 },
- { 0x39800f80, 0x30000004 },
- { 0x39000f85, 0x54000000 },
- { 0x39800f86, 0x30000001 },
- { 0x39800f88, 0x1c000003 },
- { 0x39800f90, 0x30000007 },
- { 0x39800f99, 0x30000023 },
- { 0x39800fbe, 0x68000007 },
- { 0x39000fc6, 0x30000000 },
- { 0x39800fc7, 0x68000005 },
- { 0x39000fcf, 0x68000000 },
- { 0x39800fd0, 0x54000001 },
- { 0x26801000, 0x1c000021 },
- { 0x26801023, 0x1c000004 },
- { 0x26801029, 0x1c000001 },
- { 0x2600102c, 0x28000000 },
- { 0x2680102d, 0x30000003 },
- { 0x26001031, 0x28000000 },
- { 0x26001032, 0x30000000 },
- { 0x26801036, 0x30000001 },
- { 0x26001038, 0x28000000 },
- { 0x26001039, 0x30000000 },
- { 0x26801040, 0x34000009 },
- { 0x2680104a, 0x54000005 },
- { 0x26801050, 0x1c000005 },
- { 0x26801056, 0x28000001 },
- { 0x26801058, 0x30000001 },
- { 0x100010a0, 0x24001c60 },
- { 0x100010a1, 0x24001c60 },
- { 0x100010a2, 0x24001c60 },
- { 0x100010a3, 0x24001c60 },
- { 0x100010a4, 0x24001c60 },
- { 0x100010a5, 0x24001c60 },
- { 0x100010a6, 0x24001c60 },
- { 0x100010a7, 0x24001c60 },
- { 0x100010a8, 0x24001c60 },
- { 0x100010a9, 0x24001c60 },
- { 0x100010aa, 0x24001c60 },
- { 0x100010ab, 0x24001c60 },
- { 0x100010ac, 0x24001c60 },
- { 0x100010ad, 0x24001c60 },
- { 0x100010ae, 0x24001c60 },
- { 0x100010af, 0x24001c60 },
- { 0x100010b0, 0x24001c60 },
- { 0x100010b1, 0x24001c60 },
- { 0x100010b2, 0x24001c60 },
- { 0x100010b3, 0x24001c60 },
- { 0x100010b4, 0x24001c60 },
- { 0x100010b5, 0x24001c60 },
- { 0x100010b6, 0x24001c60 },
- { 0x100010b7, 0x24001c60 },
- { 0x100010b8, 0x24001c60 },
- { 0x100010b9, 0x24001c60 },
- { 0x100010ba, 0x24001c60 },
- { 0x100010bb, 0x24001c60 },
- { 0x100010bc, 0x24001c60 },
- { 0x100010bd, 0x24001c60 },
- { 0x100010be, 0x24001c60 },
- { 0x100010bf, 0x24001c60 },
- { 0x100010c0, 0x24001c60 },
- { 0x100010c1, 0x24001c60 },
- { 0x100010c2, 0x24001c60 },
- { 0x100010c3, 0x24001c60 },
- { 0x100010c4, 0x24001c60 },
- { 0x100010c5, 0x24001c60 },
- { 0x108010d0, 0x1c00002a },
- { 0x090010fb, 0x54000000 },
- { 0x100010fc, 0x18000000 },
- { 0x17801100, 0x1c000059 },
- { 0x1780115f, 0x1c000043 },
- { 0x178011a8, 0x1c000051 },
- { 0x0f801200, 0x1c000048 },
- { 0x0f80124a, 0x1c000003 },
- { 0x0f801250, 0x1c000006 },
- { 0x0f001258, 0x1c000000 },
- { 0x0f80125a, 0x1c000003 },
- { 0x0f801260, 0x1c000028 },
- { 0x0f80128a, 0x1c000003 },
- { 0x0f801290, 0x1c000020 },
- { 0x0f8012b2, 0x1c000003 },
- { 0x0f8012b8, 0x1c000006 },
- { 0x0f0012c0, 0x1c000000 },
- { 0x0f8012c2, 0x1c000003 },
- { 0x0f8012c8, 0x1c00000e },
- { 0x0f8012d8, 0x1c000038 },
- { 0x0f801312, 0x1c000003 },
- { 0x0f801318, 0x1c000042 },
- { 0x0f00135f, 0x30000000 },
- { 0x0f001360, 0x68000000 },
- { 0x0f801361, 0x54000007 },
- { 0x0f801369, 0x3c000013 },
- { 0x0f801380, 0x1c00000f },
- { 0x0f801390, 0x68000009 },
- { 0x088013a0, 0x1c000054 },
- { 0x07801401, 0x1c00026b },
- { 0x0780166d, 0x54000001 },
- { 0x0780166f, 0x1c000007 },
- { 0x28001680, 0x74000000 },
- { 0x28801681, 0x1c000019 },
- { 0x2800169b, 0x58000000 },
- { 0x2800169c, 0x48000000 },
- { 0x2d8016a0, 0x1c00004a },
- { 0x098016eb, 0x54000002 },
- { 0x2d8016ee, 0x38000002 },
- { 0x32801700, 0x1c00000c },
- { 0x3280170e, 0x1c000003 },
- { 0x32801712, 0x30000002 },
- { 0x18801720, 0x1c000011 },
- { 0x18801732, 0x30000002 },
- { 0x09801735, 0x54000001 },
- { 0x06801740, 0x1c000011 },
- { 0x06801752, 0x30000001 },
- { 0x33801760, 0x1c00000c },
- { 0x3380176e, 0x1c000002 },
- { 0x33801772, 0x30000001 },
- { 0x1f801780, 0x1c000033 },
- { 0x1f8017b4, 0x04000001 },
- { 0x1f0017b6, 0x28000000 },
- { 0x1f8017b7, 0x30000006 },
- { 0x1f8017be, 0x28000007 },
- { 0x1f0017c6, 0x30000000 },
- { 0x1f8017c7, 0x28000001 },
- { 0x1f8017c9, 0x3000000a },
- { 0x1f8017d4, 0x54000002 },
- { 0x1f0017d7, 0x18000000 },
- { 0x1f8017d8, 0x54000002 },
- { 0x1f0017db, 0x5c000000 },
- { 0x1f0017dc, 0x1c000000 },
- { 0x1f0017dd, 0x30000000 },
- { 0x1f8017e0, 0x34000009 },
- { 0x1f8017f0, 0x3c000009 },
- { 0x25801800, 0x54000005 },
- { 0x25001806, 0x44000000 },
- { 0x25801807, 0x54000003 },
- { 0x2580180b, 0x30000002 },
- { 0x2500180e, 0x74000000 },
- { 0x25801810, 0x34000009 },
- { 0x25801820, 0x1c000022 },
- { 0x25001843, 0x18000000 },
- { 0x25801844, 0x1c000033 },
- { 0x25801880, 0x1c000028 },
- { 0x250018a9, 0x30000000 },
- { 0x22801900, 0x1c00001c },
- { 0x22801920, 0x30000002 },
- { 0x22801923, 0x28000003 },
- { 0x22801927, 0x30000001 },
- { 0x22801929, 0x28000002 },
- { 0x22801930, 0x28000001 },
- { 0x22001932, 0x30000000 },
- { 0x22801933, 0x28000005 },
- { 0x22801939, 0x30000002 },
- { 0x22001940, 0x68000000 },
- { 0x22801944, 0x54000001 },
- { 0x22801946, 0x34000009 },
- { 0x34801950, 0x1c00001d },
- { 0x34801970, 0x1c000004 },
- { 0x27801980, 0x1c000029 },
- { 0x278019b0, 0x28000010 },
- { 0x278019c1, 0x1c000006 },
- { 0x278019c8, 0x28000001 },
- { 0x278019d0, 0x34000009 },
- { 0x278019de, 0x54000001 },
- { 0x1f8019e0, 0x6800001f },
- { 0x05801a00, 0x1c000016 },
- { 0x05801a17, 0x30000001 },
- { 0x05801a19, 0x28000002 },
- { 0x05801a1e, 0x54000001 },
- { 0x21801d00, 0x1400002b },
- { 0x21801d2c, 0x18000035 },
- { 0x21801d62, 0x14000015 },
- { 0x0c001d78, 0x18000000 },
- { 0x21801d79, 0x14000021 },
- { 0x21801d9b, 0x18000024 },
- { 0x1b801dc0, 0x30000003 },
- { 0x21001e00, 0x24000001 },
- { 0x21001e01, 0x1400ffff },
- { 0x21001e02, 0x24000001 },
- { 0x21001e03, 0x1400ffff },
- { 0x21001e04, 0x24000001 },
- { 0x21001e05, 0x1400ffff },
- { 0x21001e06, 0x24000001 },
- { 0x21001e07, 0x1400ffff },
- { 0x21001e08, 0x24000001 },
- { 0x21001e09, 0x1400ffff },
- { 0x21001e0a, 0x24000001 },
- { 0x21001e0b, 0x1400ffff },
- { 0x21001e0c, 0x24000001 },
- { 0x21001e0d, 0x1400ffff },
- { 0x21001e0e, 0x24000001 },
- { 0x21001e0f, 0x1400ffff },
- { 0x21001e10, 0x24000001 },
- { 0x21001e11, 0x1400ffff },
- { 0x21001e12, 0x24000001 },
- { 0x21001e13, 0x1400ffff },
- { 0x21001e14, 0x24000001 },
- { 0x21001e15, 0x1400ffff },
- { 0x21001e16, 0x24000001 },
- { 0x21001e17, 0x1400ffff },
- { 0x21001e18, 0x24000001 },
- { 0x21001e19, 0x1400ffff },
- { 0x21001e1a, 0x24000001 },
- { 0x21001e1b, 0x1400ffff },
- { 0x21001e1c, 0x24000001 },
- { 0x21001e1d, 0x1400ffff },
- { 0x21001e1e, 0x24000001 },
- { 0x21001e1f, 0x1400ffff },
- { 0x21001e20, 0x24000001 },
- { 0x21001e21, 0x1400ffff },
- { 0x21001e22, 0x24000001 },
- { 0x21001e23, 0x1400ffff },
- { 0x21001e24, 0x24000001 },
- { 0x21001e25, 0x1400ffff },
- { 0x21001e26, 0x24000001 },
- { 0x21001e27, 0x1400ffff },
- { 0x21001e28, 0x24000001 },
- { 0x21001e29, 0x1400ffff },
- { 0x21001e2a, 0x24000001 },
- { 0x21001e2b, 0x1400ffff },
- { 0x21001e2c, 0x24000001 },
- { 0x21001e2d, 0x1400ffff },
- { 0x21001e2e, 0x24000001 },
- { 0x21001e2f, 0x1400ffff },
- { 0x21001e30, 0x24000001 },
- { 0x21001e31, 0x1400ffff },
- { 0x21001e32, 0x24000001 },
- { 0x21001e33, 0x1400ffff },
- { 0x21001e34, 0x24000001 },
- { 0x21001e35, 0x1400ffff },
- { 0x21001e36, 0x24000001 },
- { 0x21001e37, 0x1400ffff },
- { 0x21001e38, 0x24000001 },
- { 0x21001e39, 0x1400ffff },
- { 0x21001e3a, 0x24000001 },
- { 0x21001e3b, 0x1400ffff },
- { 0x21001e3c, 0x24000001 },
- { 0x21001e3d, 0x1400ffff },
- { 0x21001e3e, 0x24000001 },
- { 0x21001e3f, 0x1400ffff },
- { 0x21001e40, 0x24000001 },
- { 0x21001e41, 0x1400ffff },
- { 0x21001e42, 0x24000001 },
- { 0x21001e43, 0x1400ffff },
- { 0x21001e44, 0x24000001 },
- { 0x21001e45, 0x1400ffff },
- { 0x21001e46, 0x24000001 },
- { 0x21001e47, 0x1400ffff },
- { 0x21001e48, 0x24000001 },
- { 0x21001e49, 0x1400ffff },
- { 0x21001e4a, 0x24000001 },
- { 0x21001e4b, 0x1400ffff },
- { 0x21001e4c, 0x24000001 },
- { 0x21001e4d, 0x1400ffff },
- { 0x21001e4e, 0x24000001 },
- { 0x21001e4f, 0x1400ffff },
- { 0x21001e50, 0x24000001 },
- { 0x21001e51, 0x1400ffff },
- { 0x21001e52, 0x24000001 },
- { 0x21001e53, 0x1400ffff },
- { 0x21001e54, 0x24000001 },
- { 0x21001e55, 0x1400ffff },
- { 0x21001e56, 0x24000001 },
- { 0x21001e57, 0x1400ffff },
- { 0x21001e58, 0x24000001 },
- { 0x21001e59, 0x1400ffff },
- { 0x21001e5a, 0x24000001 },
- { 0x21001e5b, 0x1400ffff },
- { 0x21001e5c, 0x24000001 },
- { 0x21001e5d, 0x1400ffff },
- { 0x21001e5e, 0x24000001 },
- { 0x21001e5f, 0x1400ffff },
- { 0x21001e60, 0x24000001 },
- { 0x21001e61, 0x1400ffff },
- { 0x21001e62, 0x24000001 },
- { 0x21001e63, 0x1400ffff },
- { 0x21001e64, 0x24000001 },
- { 0x21001e65, 0x1400ffff },
- { 0x21001e66, 0x24000001 },
- { 0x21001e67, 0x1400ffff },
- { 0x21001e68, 0x24000001 },
- { 0x21001e69, 0x1400ffff },
- { 0x21001e6a, 0x24000001 },
- { 0x21001e6b, 0x1400ffff },
- { 0x21001e6c, 0x24000001 },
- { 0x21001e6d, 0x1400ffff },
- { 0x21001e6e, 0x24000001 },
- { 0x21001e6f, 0x1400ffff },
- { 0x21001e70, 0x24000001 },
- { 0x21001e71, 0x1400ffff },
- { 0x21001e72, 0x24000001 },
- { 0x21001e73, 0x1400ffff },
- { 0x21001e74, 0x24000001 },
- { 0x21001e75, 0x1400ffff },
- { 0x21001e76, 0x24000001 },
- { 0x21001e77, 0x1400ffff },
- { 0x21001e78, 0x24000001 },
- { 0x21001e79, 0x1400ffff },
- { 0x21001e7a, 0x24000001 },
- { 0x21001e7b, 0x1400ffff },
- { 0x21001e7c, 0x24000001 },
- { 0x21001e7d, 0x1400ffff },
- { 0x21001e7e, 0x24000001 },
- { 0x21001e7f, 0x1400ffff },
- { 0x21001e80, 0x24000001 },
- { 0x21001e81, 0x1400ffff },
- { 0x21001e82, 0x24000001 },
- { 0x21001e83, 0x1400ffff },
- { 0x21001e84, 0x24000001 },
- { 0x21001e85, 0x1400ffff },
- { 0x21001e86, 0x24000001 },
- { 0x21001e87, 0x1400ffff },
- { 0x21001e88, 0x24000001 },
- { 0x21001e89, 0x1400ffff },
- { 0x21001e8a, 0x24000001 },
- { 0x21001e8b, 0x1400ffff },
- { 0x21001e8c, 0x24000001 },
- { 0x21001e8d, 0x1400ffff },
- { 0x21001e8e, 0x24000001 },
- { 0x21001e8f, 0x1400ffff },
- { 0x21001e90, 0x24000001 },
- { 0x21001e91, 0x1400ffff },
- { 0x21001e92, 0x24000001 },
- { 0x21001e93, 0x1400ffff },
- { 0x21001e94, 0x24000001 },
- { 0x21001e95, 0x1400ffff },
- { 0x21801e96, 0x14000004 },
- { 0x21001e9b, 0x1400ffc5 },
- { 0x21001ea0, 0x24000001 },
- { 0x21001ea1, 0x1400ffff },
- { 0x21001ea2, 0x24000001 },
- { 0x21001ea3, 0x1400ffff },
- { 0x21001ea4, 0x24000001 },
- { 0x21001ea5, 0x1400ffff },
- { 0x21001ea6, 0x24000001 },
- { 0x21001ea7, 0x1400ffff },
- { 0x21001ea8, 0x24000001 },
- { 0x21001ea9, 0x1400ffff },
- { 0x21001eaa, 0x24000001 },
- { 0x21001eab, 0x1400ffff },
- { 0x21001eac, 0x24000001 },
- { 0x21001ead, 0x1400ffff },
- { 0x21001eae, 0x24000001 },
- { 0x21001eaf, 0x1400ffff },
- { 0x21001eb0, 0x24000001 },
- { 0x21001eb1, 0x1400ffff },
- { 0x21001eb2, 0x24000001 },
- { 0x21001eb3, 0x1400ffff },
- { 0x21001eb4, 0x24000001 },
- { 0x21001eb5, 0x1400ffff },
- { 0x21001eb6, 0x24000001 },
- { 0x21001eb7, 0x1400ffff },
- { 0x21001eb8, 0x24000001 },
- { 0x21001eb9, 0x1400ffff },
- { 0x21001eba, 0x24000001 },
- { 0x21001ebb, 0x1400ffff },
- { 0x21001ebc, 0x24000001 },
- { 0x21001ebd, 0x1400ffff },
- { 0x21001ebe, 0x24000001 },
- { 0x21001ebf, 0x1400ffff },
- { 0x21001ec0, 0x24000001 },
- { 0x21001ec1, 0x1400ffff },
- { 0x21001ec2, 0x24000001 },
- { 0x21001ec3, 0x1400ffff },
- { 0x21001ec4, 0x24000001 },
- { 0x21001ec5, 0x1400ffff },
- { 0x21001ec6, 0x24000001 },
- { 0x21001ec7, 0x1400ffff },
- { 0x21001ec8, 0x24000001 },
- { 0x21001ec9, 0x1400ffff },
- { 0x21001eca, 0x24000001 },
- { 0x21001ecb, 0x1400ffff },
- { 0x21001ecc, 0x24000001 },
- { 0x21001ecd, 0x1400ffff },
- { 0x21001ece, 0x24000001 },
- { 0x21001ecf, 0x1400ffff },
- { 0x21001ed0, 0x24000001 },
- { 0x21001ed1, 0x1400ffff },
- { 0x21001ed2, 0x24000001 },
- { 0x21001ed3, 0x1400ffff },
- { 0x21001ed4, 0x24000001 },
- { 0x21001ed5, 0x1400ffff },
- { 0x21001ed6, 0x24000001 },
- { 0x21001ed7, 0x1400ffff },
- { 0x21001ed8, 0x24000001 },
- { 0x21001ed9, 0x1400ffff },
- { 0x21001eda, 0x24000001 },
- { 0x21001edb, 0x1400ffff },
- { 0x21001edc, 0x24000001 },
- { 0x21001edd, 0x1400ffff },
- { 0x21001ede, 0x24000001 },
- { 0x21001edf, 0x1400ffff },
- { 0x21001ee0, 0x24000001 },
- { 0x21001ee1, 0x1400ffff },
- { 0x21001ee2, 0x24000001 },
- { 0x21001ee3, 0x1400ffff },
- { 0x21001ee4, 0x24000001 },
- { 0x21001ee5, 0x1400ffff },
- { 0x21001ee6, 0x24000001 },
- { 0x21001ee7, 0x1400ffff },
- { 0x21001ee8, 0x24000001 },
- { 0x21001ee9, 0x1400ffff },
- { 0x21001eea, 0x24000001 },
- { 0x21001eeb, 0x1400ffff },
- { 0x21001eec, 0x24000001 },
- { 0x21001eed, 0x1400ffff },
- { 0x21001eee, 0x24000001 },
- { 0x21001eef, 0x1400ffff },
- { 0x21001ef0, 0x24000001 },
- { 0x21001ef1, 0x1400ffff },
- { 0x21001ef2, 0x24000001 },
- { 0x21001ef3, 0x1400ffff },
- { 0x21001ef4, 0x24000001 },
- { 0x21001ef5, 0x1400ffff },
- { 0x21001ef6, 0x24000001 },
- { 0x21001ef7, 0x1400ffff },
- { 0x21001ef8, 0x24000001 },
- { 0x21001ef9, 0x1400ffff },
- { 0x13001f00, 0x14000008 },
- { 0x13001f01, 0x14000008 },
- { 0x13001f02, 0x14000008 },
- { 0x13001f03, 0x14000008 },
- { 0x13001f04, 0x14000008 },
- { 0x13001f05, 0x14000008 },
- { 0x13001f06, 0x14000008 },
- { 0x13001f07, 0x14000008 },
- { 0x13001f08, 0x2400fff8 },
- { 0x13001f09, 0x2400fff8 },
- { 0x13001f0a, 0x2400fff8 },
- { 0x13001f0b, 0x2400fff8 },
- { 0x13001f0c, 0x2400fff8 },
- { 0x13001f0d, 0x2400fff8 },
- { 0x13001f0e, 0x2400fff8 },
- { 0x13001f0f, 0x2400fff8 },
- { 0x13001f10, 0x14000008 },
- { 0x13001f11, 0x14000008 },
- { 0x13001f12, 0x14000008 },
- { 0x13001f13, 0x14000008 },
- { 0x13001f14, 0x14000008 },
- { 0x13001f15, 0x14000008 },
- { 0x13001f18, 0x2400fff8 },
- { 0x13001f19, 0x2400fff8 },
- { 0x13001f1a, 0x2400fff8 },
- { 0x13001f1b, 0x2400fff8 },
- { 0x13001f1c, 0x2400fff8 },
- { 0x13001f1d, 0x2400fff8 },
- { 0x13001f20, 0x14000008 },
- { 0x13001f21, 0x14000008 },
- { 0x13001f22, 0x14000008 },
- { 0x13001f23, 0x14000008 },
- { 0x13001f24, 0x14000008 },
- { 0x13001f25, 0x14000008 },
- { 0x13001f26, 0x14000008 },
- { 0x13001f27, 0x14000008 },
- { 0x13001f28, 0x2400fff8 },
- { 0x13001f29, 0x2400fff8 },
- { 0x13001f2a, 0x2400fff8 },
- { 0x13001f2b, 0x2400fff8 },
- { 0x13001f2c, 0x2400fff8 },
- { 0x13001f2d, 0x2400fff8 },
- { 0x13001f2e, 0x2400fff8 },
- { 0x13001f2f, 0x2400fff8 },
- { 0x13001f30, 0x14000008 },
- { 0x13001f31, 0x14000008 },
- { 0x13001f32, 0x14000008 },
- { 0x13001f33, 0x14000008 },
- { 0x13001f34, 0x14000008 },
- { 0x13001f35, 0x14000008 },
- { 0x13001f36, 0x14000008 },
- { 0x13001f37, 0x14000008 },
- { 0x13001f38, 0x2400fff8 },
- { 0x13001f39, 0x2400fff8 },
- { 0x13001f3a, 0x2400fff8 },
- { 0x13001f3b, 0x2400fff8 },
- { 0x13001f3c, 0x2400fff8 },
- { 0x13001f3d, 0x2400fff8 },
- { 0x13001f3e, 0x2400fff8 },
- { 0x13001f3f, 0x2400fff8 },
- { 0x13001f40, 0x14000008 },
- { 0x13001f41, 0x14000008 },
- { 0x13001f42, 0x14000008 },
- { 0x13001f43, 0x14000008 },
- { 0x13001f44, 0x14000008 },
- { 0x13001f45, 0x14000008 },
- { 0x13001f48, 0x2400fff8 },
- { 0x13001f49, 0x2400fff8 },
- { 0x13001f4a, 0x2400fff8 },
- { 0x13001f4b, 0x2400fff8 },
- { 0x13001f4c, 0x2400fff8 },
- { 0x13001f4d, 0x2400fff8 },
- { 0x13001f50, 0x14000000 },
- { 0x13001f51, 0x14000008 },
- { 0x13001f52, 0x14000000 },
- { 0x13001f53, 0x14000008 },
- { 0x13001f54, 0x14000000 },
- { 0x13001f55, 0x14000008 },
- { 0x13001f56, 0x14000000 },
- { 0x13001f57, 0x14000008 },
- { 0x13001f59, 0x2400fff8 },
- { 0x13001f5b, 0x2400fff8 },
- { 0x13001f5d, 0x2400fff8 },
- { 0x13001f5f, 0x2400fff8 },
- { 0x13001f60, 0x14000008 },
- { 0x13001f61, 0x14000008 },
- { 0x13001f62, 0x14000008 },
- { 0x13001f63, 0x14000008 },
- { 0x13001f64, 0x14000008 },
- { 0x13001f65, 0x14000008 },
- { 0x13001f66, 0x14000008 },
- { 0x13001f67, 0x14000008 },
- { 0x13001f68, 0x2400fff8 },
- { 0x13001f69, 0x2400fff8 },
- { 0x13001f6a, 0x2400fff8 },
- { 0x13001f6b, 0x2400fff8 },
- { 0x13001f6c, 0x2400fff8 },
- { 0x13001f6d, 0x2400fff8 },
- { 0x13001f6e, 0x2400fff8 },
- { 0x13001f6f, 0x2400fff8 },
- { 0x13001f70, 0x1400004a },
- { 0x13001f71, 0x1400004a },
- { 0x13001f72, 0x14000056 },
- { 0x13001f73, 0x14000056 },
- { 0x13001f74, 0x14000056 },
- { 0x13001f75, 0x14000056 },
- { 0x13001f76, 0x14000064 },
- { 0x13001f77, 0x14000064 },
- { 0x13001f78, 0x14000080 },
- { 0x13001f79, 0x14000080 },
- { 0x13001f7a, 0x14000070 },
- { 0x13001f7b, 0x14000070 },
- { 0x13001f7c, 0x1400007e },
- { 0x13001f7d, 0x1400007e },
- { 0x13001f80, 0x14000008 },
- { 0x13001f81, 0x14000008 },
- { 0x13001f82, 0x14000008 },
- { 0x13001f83, 0x14000008 },
- { 0x13001f84, 0x14000008 },
- { 0x13001f85, 0x14000008 },
- { 0x13001f86, 0x14000008 },
- { 0x13001f87, 0x14000008 },
- { 0x13001f88, 0x2000fff8 },
- { 0x13001f89, 0x2000fff8 },
- { 0x13001f8a, 0x2000fff8 },
- { 0x13001f8b, 0x2000fff8 },
- { 0x13001f8c, 0x2000fff8 },
- { 0x13001f8d, 0x2000fff8 },
- { 0x13001f8e, 0x2000fff8 },
- { 0x13001f8f, 0x2000fff8 },
- { 0x13001f90, 0x14000008 },
- { 0x13001f91, 0x14000008 },
- { 0x13001f92, 0x14000008 },
- { 0x13001f93, 0x14000008 },
- { 0x13001f94, 0x14000008 },
- { 0x13001f95, 0x14000008 },
- { 0x13001f96, 0x14000008 },
- { 0x13001f97, 0x14000008 },
- { 0x13001f98, 0x2000fff8 },
- { 0x13001f99, 0x2000fff8 },
- { 0x13001f9a, 0x2000fff8 },
- { 0x13001f9b, 0x2000fff8 },
- { 0x13001f9c, 0x2000fff8 },
- { 0x13001f9d, 0x2000fff8 },
- { 0x13001f9e, 0x2000fff8 },
- { 0x13001f9f, 0x2000fff8 },
- { 0x13001fa0, 0x14000008 },
- { 0x13001fa1, 0x14000008 },
- { 0x13001fa2, 0x14000008 },
- { 0x13001fa3, 0x14000008 },
- { 0x13001fa4, 0x14000008 },
- { 0x13001fa5, 0x14000008 },
- { 0x13001fa6, 0x14000008 },
- { 0x13001fa7, 0x14000008 },
- { 0x13001fa8, 0x2000fff8 },
- { 0x13001fa9, 0x2000fff8 },
- { 0x13001faa, 0x2000fff8 },
- { 0x13001fab, 0x2000fff8 },
- { 0x13001fac, 0x2000fff8 },
- { 0x13001fad, 0x2000fff8 },
- { 0x13001fae, 0x2000fff8 },
- { 0x13001faf, 0x2000fff8 },
- { 0x13001fb0, 0x14000008 },
- { 0x13001fb1, 0x14000008 },
- { 0x13001fb2, 0x14000000 },
- { 0x13001fb3, 0x14000009 },
- { 0x13001fb4, 0x14000000 },
- { 0x13801fb6, 0x14000001 },
- { 0x13001fb8, 0x2400fff8 },
- { 0x13001fb9, 0x2400fff8 },
- { 0x13001fba, 0x2400ffb6 },
- { 0x13001fbb, 0x2400ffb6 },
- { 0x13001fbc, 0x2000fff7 },
- { 0x13001fbd, 0x60000000 },
- { 0x13001fbe, 0x1400e3db },
- { 0x13801fbf, 0x60000002 },
- { 0x13001fc2, 0x14000000 },
- { 0x13001fc3, 0x14000009 },
- { 0x13001fc4, 0x14000000 },
- { 0x13801fc6, 0x14000001 },
- { 0x13001fc8, 0x2400ffaa },
- { 0x13001fc9, 0x2400ffaa },
- { 0x13001fca, 0x2400ffaa },
- { 0x13001fcb, 0x2400ffaa },
- { 0x13001fcc, 0x2000fff7 },
- { 0x13801fcd, 0x60000002 },
- { 0x13001fd0, 0x14000008 },
- { 0x13001fd1, 0x14000008 },
- { 0x13801fd2, 0x14000001 },
- { 0x13801fd6, 0x14000001 },
- { 0x13001fd8, 0x2400fff8 },
- { 0x13001fd9, 0x2400fff8 },
- { 0x13001fda, 0x2400ff9c },
- { 0x13001fdb, 0x2400ff9c },
- { 0x13801fdd, 0x60000002 },
- { 0x13001fe0, 0x14000008 },
- { 0x13001fe1, 0x14000008 },
- { 0x13801fe2, 0x14000002 },
- { 0x13001fe5, 0x14000007 },
- { 0x13801fe6, 0x14000001 },
- { 0x13001fe8, 0x2400fff8 },
- { 0x13001fe9, 0x2400fff8 },
- { 0x13001fea, 0x2400ff90 },
- { 0x13001feb, 0x2400ff90 },
- { 0x13001fec, 0x2400fff9 },
- { 0x13801fed, 0x60000002 },
- { 0x13001ff2, 0x14000000 },
- { 0x13001ff3, 0x14000009 },
- { 0x13001ff4, 0x14000000 },
- { 0x13801ff6, 0x14000001 },
- { 0x13001ff8, 0x2400ff80 },
- { 0x13001ff9, 0x2400ff80 },
- { 0x13001ffa, 0x2400ff82 },
- { 0x13001ffb, 0x2400ff82 },
- { 0x13001ffc, 0x2000fff7 },
- { 0x13801ffd, 0x60000001 },
- { 0x09802000, 0x7400000a },
- { 0x0980200b, 0x04000004 },
- { 0x09802010, 0x44000005 },
- { 0x09802016, 0x54000001 },
- { 0x09002018, 0x50000000 },
- { 0x09002019, 0x4c000000 },
- { 0x0900201a, 0x58000000 },
- { 0x0980201b, 0x50000001 },
- { 0x0900201d, 0x4c000000 },
- { 0x0900201e, 0x58000000 },
- { 0x0900201f, 0x50000000 },
- { 0x09802020, 0x54000007 },
- { 0x09002028, 0x6c000000 },
- { 0x09002029, 0x70000000 },
- { 0x0980202a, 0x04000004 },
- { 0x0900202f, 0x74000000 },
- { 0x09802030, 0x54000008 },
- { 0x09002039, 0x50000000 },
- { 0x0900203a, 0x4c000000 },
- { 0x0980203b, 0x54000003 },
- { 0x0980203f, 0x40000001 },
- { 0x09802041, 0x54000002 },
- { 0x09002044, 0x64000000 },
- { 0x09002045, 0x58000000 },
- { 0x09002046, 0x48000000 },
- { 0x09802047, 0x5400000a },
- { 0x09002052, 0x64000000 },
- { 0x09002053, 0x54000000 },
- { 0x09002054, 0x40000000 },
- { 0x09802055, 0x54000009 },
- { 0x0900205f, 0x74000000 },
- { 0x09802060, 0x04000003 },
- { 0x0980206a, 0x04000005 },
- { 0x09002070, 0x3c000000 },
- { 0x21002071, 0x14000000 },
- { 0x09802074, 0x3c000005 },
- { 0x0980207a, 0x64000002 },
- { 0x0900207d, 0x58000000 },
- { 0x0900207e, 0x48000000 },
- { 0x2100207f, 0x14000000 },
- { 0x09802080, 0x3c000009 },
- { 0x0980208a, 0x64000002 },
- { 0x0900208d, 0x58000000 },
- { 0x0900208e, 0x48000000 },
- { 0x21802090, 0x18000004 },
- { 0x098020a0, 0x5c000015 },
- { 0x1b8020d0, 0x3000000c },
- { 0x1b8020dd, 0x2c000003 },
- { 0x1b0020e1, 0x30000000 },
- { 0x1b8020e2, 0x2c000002 },
- { 0x1b8020e5, 0x30000006 },
- { 0x09802100, 0x68000001 },
- { 0x09002102, 0x24000000 },
- { 0x09802103, 0x68000003 },
- { 0x09002107, 0x24000000 },
- { 0x09802108, 0x68000001 },
- { 0x0900210a, 0x14000000 },
- { 0x0980210b, 0x24000002 },
- { 0x0980210e, 0x14000001 },
- { 0x09802110, 0x24000002 },
- { 0x09002113, 0x14000000 },
- { 0x09002114, 0x68000000 },
- { 0x09002115, 0x24000000 },
- { 0x09802116, 0x68000002 },
- { 0x09802119, 0x24000004 },
- { 0x0980211e, 0x68000005 },
- { 0x09002124, 0x24000000 },
- { 0x09002125, 0x68000000 },
- { 0x13002126, 0x2400e2a3 },
- { 0x09002127, 0x68000000 },
- { 0x09002128, 0x24000000 },
- { 0x09002129, 0x68000000 },
- { 0x2100212a, 0x2400df41 },
- { 0x2100212b, 0x2400dfba },
- { 0x0980212c, 0x24000001 },
- { 0x0900212e, 0x68000000 },
- { 0x0900212f, 0x14000000 },
- { 0x09802130, 0x24000001 },
- { 0x09002132, 0x68000000 },
- { 0x09002133, 0x24000000 },
- { 0x09002134, 0x14000000 },
- { 0x09802135, 0x1c000003 },
- { 0x09002139, 0x14000000 },
- { 0x0980213a, 0x68000001 },
- { 0x0980213c, 0x14000001 },
- { 0x0980213e, 0x24000001 },
- { 0x09802140, 0x64000004 },
- { 0x09002145, 0x24000000 },
- { 0x09802146, 0x14000003 },
- { 0x0900214a, 0x68000000 },
- { 0x0900214b, 0x64000000 },
- { 0x0900214c, 0x68000000 },
- { 0x09802153, 0x3c00000c },
- { 0x09002160, 0x38000010 },
- { 0x09002161, 0x38000010 },
- { 0x09002162, 0x38000010 },
- { 0x09002163, 0x38000010 },
- { 0x09002164, 0x38000010 },
- { 0x09002165, 0x38000010 },
- { 0x09002166, 0x38000010 },
- { 0x09002167, 0x38000010 },
- { 0x09002168, 0x38000010 },
- { 0x09002169, 0x38000010 },
- { 0x0900216a, 0x38000010 },
- { 0x0900216b, 0x38000010 },
- { 0x0900216c, 0x38000010 },
- { 0x0900216d, 0x38000010 },
- { 0x0900216e, 0x38000010 },
- { 0x0900216f, 0x38000010 },
- { 0x09002170, 0x3800fff0 },
- { 0x09002171, 0x3800fff0 },
- { 0x09002172, 0x3800fff0 },
- { 0x09002173, 0x3800fff0 },
- { 0x09002174, 0x3800fff0 },
- { 0x09002175, 0x3800fff0 },
- { 0x09002176, 0x3800fff0 },
- { 0x09002177, 0x3800fff0 },
- { 0x09002178, 0x3800fff0 },
- { 0x09002179, 0x3800fff0 },
- { 0x0900217a, 0x3800fff0 },
- { 0x0900217b, 0x3800fff0 },
- { 0x0900217c, 0x3800fff0 },
- { 0x0900217d, 0x3800fff0 },
- { 0x0900217e, 0x3800fff0 },
- { 0x0900217f, 0x3800fff0 },
- { 0x09802180, 0x38000003 },
- { 0x09802190, 0x64000004 },
- { 0x09802195, 0x68000004 },
- { 0x0980219a, 0x64000001 },
- { 0x0980219c, 0x68000003 },
- { 0x090021a0, 0x64000000 },
- { 0x098021a1, 0x68000001 },
- { 0x090021a3, 0x64000000 },
- { 0x098021a4, 0x68000001 },
- { 0x090021a6, 0x64000000 },
- { 0x098021a7, 0x68000006 },
- { 0x090021ae, 0x64000000 },
- { 0x098021af, 0x6800001e },
- { 0x098021ce, 0x64000001 },
- { 0x098021d0, 0x68000001 },
- { 0x090021d2, 0x64000000 },
- { 0x090021d3, 0x68000000 },
- { 0x090021d4, 0x64000000 },
- { 0x098021d5, 0x6800001e },
- { 0x098021f4, 0x6400010b },
- { 0x09802300, 0x68000007 },
- { 0x09802308, 0x64000003 },
- { 0x0980230c, 0x68000013 },
- { 0x09802320, 0x64000001 },
- { 0x09802322, 0x68000006 },
- { 0x09002329, 0x58000000 },
- { 0x0900232a, 0x48000000 },
- { 0x0980232b, 0x68000050 },
- { 0x0900237c, 0x64000000 },
- { 0x0980237d, 0x6800001d },
- { 0x0980239b, 0x64000018 },
- { 0x090023b4, 0x58000000 },
- { 0x090023b5, 0x48000000 },
- { 0x090023b6, 0x54000000 },
- { 0x098023b7, 0x68000024 },
- { 0x09802400, 0x68000026 },
- { 0x09802440, 0x6800000a },
- { 0x09802460, 0x3c00003b },
- { 0x0980249c, 0x68000019 },
- { 0x090024b6, 0x6800001a },
- { 0x090024b7, 0x6800001a },
- { 0x090024b8, 0x6800001a },
- { 0x090024b9, 0x6800001a },
- { 0x090024ba, 0x6800001a },
- { 0x090024bb, 0x6800001a },
- { 0x090024bc, 0x6800001a },
- { 0x090024bd, 0x6800001a },
- { 0x090024be, 0x6800001a },
- { 0x090024bf, 0x6800001a },
- { 0x090024c0, 0x6800001a },
- { 0x090024c1, 0x6800001a },
- { 0x090024c2, 0x6800001a },
- { 0x090024c3, 0x6800001a },
- { 0x090024c4, 0x6800001a },
- { 0x090024c5, 0x6800001a },
- { 0x090024c6, 0x6800001a },
- { 0x090024c7, 0x6800001a },
- { 0x090024c8, 0x6800001a },
- { 0x090024c9, 0x6800001a },
- { 0x090024ca, 0x6800001a },
- { 0x090024cb, 0x6800001a },
- { 0x090024cc, 0x6800001a },
- { 0x090024cd, 0x6800001a },
- { 0x090024ce, 0x6800001a },
- { 0x090024cf, 0x6800001a },
- { 0x090024d0, 0x6800ffe6 },
- { 0x090024d1, 0x6800ffe6 },
- { 0x090024d2, 0x6800ffe6 },
- { 0x090024d3, 0x6800ffe6 },
- { 0x090024d4, 0x6800ffe6 },
- { 0x090024d5, 0x6800ffe6 },
- { 0x090024d6, 0x6800ffe6 },
- { 0x090024d7, 0x6800ffe6 },
- { 0x090024d8, 0x6800ffe6 },
- { 0x090024d9, 0x6800ffe6 },
- { 0x090024da, 0x6800ffe6 },
- { 0x090024db, 0x6800ffe6 },
- { 0x090024dc, 0x6800ffe6 },
- { 0x090024dd, 0x6800ffe6 },
- { 0x090024de, 0x6800ffe6 },
- { 0x090024df, 0x6800ffe6 },
- { 0x090024e0, 0x6800ffe6 },
- { 0x090024e1, 0x6800ffe6 },
- { 0x090024e2, 0x6800ffe6 },
- { 0x090024e3, 0x6800ffe6 },
- { 0x090024e4, 0x6800ffe6 },
- { 0x090024e5, 0x6800ffe6 },
- { 0x090024e6, 0x6800ffe6 },
- { 0x090024e7, 0x6800ffe6 },
- { 0x090024e8, 0x6800ffe6 },
- { 0x090024e9, 0x6800ffe6 },
- { 0x098024ea, 0x3c000015 },
- { 0x09802500, 0x680000b6 },
- { 0x090025b7, 0x64000000 },
- { 0x098025b8, 0x68000008 },
- { 0x090025c1, 0x64000000 },
- { 0x098025c2, 0x68000035 },
- { 0x098025f8, 0x64000007 },
- { 0x09802600, 0x6800006e },
- { 0x0900266f, 0x64000000 },
- { 0x09802670, 0x6800002c },
- { 0x098026a0, 0x68000011 },
- { 0x09802701, 0x68000003 },
- { 0x09802706, 0x68000003 },
- { 0x0980270c, 0x6800001b },
- { 0x09802729, 0x68000022 },
- { 0x0900274d, 0x68000000 },
- { 0x0980274f, 0x68000003 },
- { 0x09002756, 0x68000000 },
- { 0x09802758, 0x68000006 },
- { 0x09802761, 0x68000006 },
- { 0x09002768, 0x58000000 },
- { 0x09002769, 0x48000000 },
- { 0x0900276a, 0x58000000 },
- { 0x0900276b, 0x48000000 },
- { 0x0900276c, 0x58000000 },
- { 0x0900276d, 0x48000000 },
- { 0x0900276e, 0x58000000 },
- { 0x0900276f, 0x48000000 },
- { 0x09002770, 0x58000000 },
- { 0x09002771, 0x48000000 },
- { 0x09002772, 0x58000000 },
- { 0x09002773, 0x48000000 },
- { 0x09002774, 0x58000000 },
- { 0x09002775, 0x48000000 },
- { 0x09802776, 0x3c00001d },
- { 0x09002794, 0x68000000 },
- { 0x09802798, 0x68000017 },
- { 0x098027b1, 0x6800000d },
- { 0x098027c0, 0x64000004 },
- { 0x090027c5, 0x58000000 },
- { 0x090027c6, 0x48000000 },
- { 0x098027d0, 0x64000015 },
- { 0x090027e6, 0x58000000 },
- { 0x090027e7, 0x48000000 },
- { 0x090027e8, 0x58000000 },
- { 0x090027e9, 0x48000000 },
- { 0x090027ea, 0x58000000 },
- { 0x090027eb, 0x48000000 },
- { 0x098027f0, 0x6400000f },
- { 0x04802800, 0x680000ff },
- { 0x09802900, 0x64000082 },
- { 0x09002983, 0x58000000 },
- { 0x09002984, 0x48000000 },
- { 0x09002985, 0x58000000 },
- { 0x09002986, 0x48000000 },
- { 0x09002987, 0x58000000 },
- { 0x09002988, 0x48000000 },
- { 0x09002989, 0x58000000 },
- { 0x0900298a, 0x48000000 },
- { 0x0900298b, 0x58000000 },
- { 0x0900298c, 0x48000000 },
- { 0x0900298d, 0x58000000 },
- { 0x0900298e, 0x48000000 },
- { 0x0900298f, 0x58000000 },
- { 0x09002990, 0x48000000 },
- { 0x09002991, 0x58000000 },
- { 0x09002992, 0x48000000 },
- { 0x09002993, 0x58000000 },
- { 0x09002994, 0x48000000 },
- { 0x09002995, 0x58000000 },
- { 0x09002996, 0x48000000 },
- { 0x09002997, 0x58000000 },
- { 0x09002998, 0x48000000 },
- { 0x09802999, 0x6400003e },
- { 0x090029d8, 0x58000000 },
- { 0x090029d9, 0x48000000 },
- { 0x090029da, 0x58000000 },
- { 0x090029db, 0x48000000 },
- { 0x098029dc, 0x6400001f },
- { 0x090029fc, 0x58000000 },
- { 0x090029fd, 0x48000000 },
- { 0x098029fe, 0x64000101 },
- { 0x09802b00, 0x68000013 },
- { 0x11002c00, 0x24000030 },
- { 0x11002c01, 0x24000030 },
- { 0x11002c02, 0x24000030 },
- { 0x11002c03, 0x24000030 },
- { 0x11002c04, 0x24000030 },
- { 0x11002c05, 0x24000030 },
- { 0x11002c06, 0x24000030 },
- { 0x11002c07, 0x24000030 },
- { 0x11002c08, 0x24000030 },
- { 0x11002c09, 0x24000030 },
- { 0x11002c0a, 0x24000030 },
- { 0x11002c0b, 0x24000030 },
- { 0x11002c0c, 0x24000030 },
- { 0x11002c0d, 0x24000030 },
- { 0x11002c0e, 0x24000030 },
- { 0x11002c0f, 0x24000030 },
- { 0x11002c10, 0x24000030 },
- { 0x11002c11, 0x24000030 },
- { 0x11002c12, 0x24000030 },
- { 0x11002c13, 0x24000030 },
- { 0x11002c14, 0x24000030 },
- { 0x11002c15, 0x24000030 },
- { 0x11002c16, 0x24000030 },
- { 0x11002c17, 0x24000030 },
- { 0x11002c18, 0x24000030 },
- { 0x11002c19, 0x24000030 },
- { 0x11002c1a, 0x24000030 },
- { 0x11002c1b, 0x24000030 },
- { 0x11002c1c, 0x24000030 },
- { 0x11002c1d, 0x24000030 },
- { 0x11002c1e, 0x24000030 },
- { 0x11002c1f, 0x24000030 },
- { 0x11002c20, 0x24000030 },
- { 0x11002c21, 0x24000030 },
- { 0x11002c22, 0x24000030 },
- { 0x11002c23, 0x24000030 },
- { 0x11002c24, 0x24000030 },
- { 0x11002c25, 0x24000030 },
- { 0x11002c26, 0x24000030 },
- { 0x11002c27, 0x24000030 },
- { 0x11002c28, 0x24000030 },
- { 0x11002c29, 0x24000030 },
- { 0x11002c2a, 0x24000030 },
- { 0x11002c2b, 0x24000030 },
- { 0x11002c2c, 0x24000030 },
- { 0x11002c2d, 0x24000030 },
- { 0x11002c2e, 0x24000030 },
- { 0x11002c30, 0x1400ffd0 },
- { 0x11002c31, 0x1400ffd0 },
- { 0x11002c32, 0x1400ffd0 },
- { 0x11002c33, 0x1400ffd0 },
- { 0x11002c34, 0x1400ffd0 },
- { 0x11002c35, 0x1400ffd0 },
- { 0x11002c36, 0x1400ffd0 },
- { 0x11002c37, 0x1400ffd0 },
- { 0x11002c38, 0x1400ffd0 },
- { 0x11002c39, 0x1400ffd0 },
- { 0x11002c3a, 0x1400ffd0 },
- { 0x11002c3b, 0x1400ffd0 },
- { 0x11002c3c, 0x1400ffd0 },
- { 0x11002c3d, 0x1400ffd0 },
- { 0x11002c3e, 0x1400ffd0 },
- { 0x11002c3f, 0x1400ffd0 },
- { 0x11002c40, 0x1400ffd0 },
- { 0x11002c41, 0x1400ffd0 },
- { 0x11002c42, 0x1400ffd0 },
- { 0x11002c43, 0x1400ffd0 },
- { 0x11002c44, 0x1400ffd0 },
- { 0x11002c45, 0x1400ffd0 },
- { 0x11002c46, 0x1400ffd0 },
- { 0x11002c47, 0x1400ffd0 },
- { 0x11002c48, 0x1400ffd0 },
- { 0x11002c49, 0x1400ffd0 },
- { 0x11002c4a, 0x1400ffd0 },
- { 0x11002c4b, 0x1400ffd0 },
- { 0x11002c4c, 0x1400ffd0 },
- { 0x11002c4d, 0x1400ffd0 },
- { 0x11002c4e, 0x1400ffd0 },
- { 0x11002c4f, 0x1400ffd0 },
- { 0x11002c50, 0x1400ffd0 },
- { 0x11002c51, 0x1400ffd0 },
- { 0x11002c52, 0x1400ffd0 },
- { 0x11002c53, 0x1400ffd0 },
- { 0x11002c54, 0x1400ffd0 },
- { 0x11002c55, 0x1400ffd0 },
- { 0x11002c56, 0x1400ffd0 },
- { 0x11002c57, 0x1400ffd0 },
- { 0x11002c58, 0x1400ffd0 },
- { 0x11002c59, 0x1400ffd0 },
- { 0x11002c5a, 0x1400ffd0 },
- { 0x11002c5b, 0x1400ffd0 },
- { 0x11002c5c, 0x1400ffd0 },
- { 0x11002c5d, 0x1400ffd0 },
- { 0x11002c5e, 0x1400ffd0 },
- { 0x0a002c80, 0x24000001 },
- { 0x0a002c81, 0x1400ffff },
- { 0x0a002c82, 0x24000001 },
- { 0x0a002c83, 0x1400ffff },
- { 0x0a002c84, 0x24000001 },
- { 0x0a002c85, 0x1400ffff },
- { 0x0a002c86, 0x24000001 },
- { 0x0a002c87, 0x1400ffff },
- { 0x0a002c88, 0x24000001 },
- { 0x0a002c89, 0x1400ffff },
- { 0x0a002c8a, 0x24000001 },
- { 0x0a002c8b, 0x1400ffff },
- { 0x0a002c8c, 0x24000001 },
- { 0x0a002c8d, 0x1400ffff },
- { 0x0a002c8e, 0x24000001 },
- { 0x0a002c8f, 0x1400ffff },
- { 0x0a002c90, 0x24000001 },
- { 0x0a002c91, 0x1400ffff },
- { 0x0a002c92, 0x24000001 },
- { 0x0a002c93, 0x1400ffff },
- { 0x0a002c94, 0x24000001 },
- { 0x0a002c95, 0x1400ffff },
- { 0x0a002c96, 0x24000001 },
- { 0x0a002c97, 0x1400ffff },
- { 0x0a002c98, 0x24000001 },
- { 0x0a002c99, 0x1400ffff },
- { 0x0a002c9a, 0x24000001 },
- { 0x0a002c9b, 0x1400ffff },
- { 0x0a002c9c, 0x24000001 },
- { 0x0a002c9d, 0x1400ffff },
- { 0x0a002c9e, 0x24000001 },
- { 0x0a002c9f, 0x1400ffff },
- { 0x0a002ca0, 0x24000001 },
- { 0x0a002ca1, 0x1400ffff },
- { 0x0a002ca2, 0x24000001 },
- { 0x0a002ca3, 0x1400ffff },
- { 0x0a002ca4, 0x24000001 },
- { 0x0a002ca5, 0x1400ffff },
- { 0x0a002ca6, 0x24000001 },
- { 0x0a002ca7, 0x1400ffff },
- { 0x0a002ca8, 0x24000001 },
- { 0x0a002ca9, 0x1400ffff },
- { 0x0a002caa, 0x24000001 },
- { 0x0a002cab, 0x1400ffff },
- { 0x0a002cac, 0x24000001 },
- { 0x0a002cad, 0x1400ffff },
- { 0x0a002cae, 0x24000001 },
- { 0x0a002caf, 0x1400ffff },
- { 0x0a002cb0, 0x24000001 },
- { 0x0a002cb1, 0x1400ffff },
- { 0x0a002cb2, 0x24000001 },
- { 0x0a002cb3, 0x1400ffff },
- { 0x0a002cb4, 0x24000001 },
- { 0x0a002cb5, 0x1400ffff },
- { 0x0a002cb6, 0x24000001 },
- { 0x0a002cb7, 0x1400ffff },
- { 0x0a002cb8, 0x24000001 },
- { 0x0a002cb9, 0x1400ffff },
- { 0x0a002cba, 0x24000001 },
- { 0x0a002cbb, 0x1400ffff },
- { 0x0a002cbc, 0x24000001 },
- { 0x0a002cbd, 0x1400ffff },
- { 0x0a002cbe, 0x24000001 },
- { 0x0a002cbf, 0x1400ffff },
- { 0x0a002cc0, 0x24000001 },
- { 0x0a002cc1, 0x1400ffff },
- { 0x0a002cc2, 0x24000001 },
- { 0x0a002cc3, 0x1400ffff },
- { 0x0a002cc4, 0x24000001 },
- { 0x0a002cc5, 0x1400ffff },
- { 0x0a002cc6, 0x24000001 },
- { 0x0a002cc7, 0x1400ffff },
- { 0x0a002cc8, 0x24000001 },
- { 0x0a002cc9, 0x1400ffff },
- { 0x0a002cca, 0x24000001 },
- { 0x0a002ccb, 0x1400ffff },
- { 0x0a002ccc, 0x24000001 },
- { 0x0a002ccd, 0x1400ffff },
- { 0x0a002cce, 0x24000001 },
- { 0x0a002ccf, 0x1400ffff },
- { 0x0a002cd0, 0x24000001 },
- { 0x0a002cd1, 0x1400ffff },
- { 0x0a002cd2, 0x24000001 },
- { 0x0a002cd3, 0x1400ffff },
- { 0x0a002cd4, 0x24000001 },
- { 0x0a002cd5, 0x1400ffff },
- { 0x0a002cd6, 0x24000001 },
- { 0x0a002cd7, 0x1400ffff },
- { 0x0a002cd8, 0x24000001 },
- { 0x0a002cd9, 0x1400ffff },
- { 0x0a002cda, 0x24000001 },
- { 0x0a002cdb, 0x1400ffff },
- { 0x0a002cdc, 0x24000001 },
- { 0x0a002cdd, 0x1400ffff },
- { 0x0a002cde, 0x24000001 },
- { 0x0a002cdf, 0x1400ffff },
- { 0x0a002ce0, 0x24000001 },
- { 0x0a002ce1, 0x1400ffff },
- { 0x0a002ce2, 0x24000001 },
- { 0x0a002ce3, 0x1400ffff },
- { 0x0a002ce4, 0x14000000 },
- { 0x0a802ce5, 0x68000005 },
- { 0x0a802cf9, 0x54000003 },
- { 0x0a002cfd, 0x3c000000 },
- { 0x0a802cfe, 0x54000001 },
- { 0x10002d00, 0x1400e3a0 },
- { 0x10002d01, 0x1400e3a0 },
- { 0x10002d02, 0x1400e3a0 },
- { 0x10002d03, 0x1400e3a0 },
- { 0x10002d04, 0x1400e3a0 },
- { 0x10002d05, 0x1400e3a0 },
- { 0x10002d06, 0x1400e3a0 },
- { 0x10002d07, 0x1400e3a0 },
- { 0x10002d08, 0x1400e3a0 },
- { 0x10002d09, 0x1400e3a0 },
- { 0x10002d0a, 0x1400e3a0 },
- { 0x10002d0b, 0x1400e3a0 },
- { 0x10002d0c, 0x1400e3a0 },
- { 0x10002d0d, 0x1400e3a0 },
- { 0x10002d0e, 0x1400e3a0 },
- { 0x10002d0f, 0x1400e3a0 },
- { 0x10002d10, 0x1400e3a0 },
- { 0x10002d11, 0x1400e3a0 },
- { 0x10002d12, 0x1400e3a0 },
- { 0x10002d13, 0x1400e3a0 },
- { 0x10002d14, 0x1400e3a0 },
- { 0x10002d15, 0x1400e3a0 },
- { 0x10002d16, 0x1400e3a0 },
- { 0x10002d17, 0x1400e3a0 },
- { 0x10002d18, 0x1400e3a0 },
- { 0x10002d19, 0x1400e3a0 },
- { 0x10002d1a, 0x1400e3a0 },
- { 0x10002d1b, 0x1400e3a0 },
- { 0x10002d1c, 0x1400e3a0 },
- { 0x10002d1d, 0x1400e3a0 },
- { 0x10002d1e, 0x1400e3a0 },
- { 0x10002d1f, 0x1400e3a0 },
- { 0x10002d20, 0x1400e3a0 },
- { 0x10002d21, 0x1400e3a0 },
- { 0x10002d22, 0x1400e3a0 },
- { 0x10002d23, 0x1400e3a0 },
- { 0x10002d24, 0x1400e3a0 },
- { 0x10002d25, 0x1400e3a0 },
- { 0x3a802d30, 0x1c000035 },
- { 0x3a002d6f, 0x18000000 },
- { 0x0f802d80, 0x1c000016 },
- { 0x0f802da0, 0x1c000006 },
- { 0x0f802da8, 0x1c000006 },
- { 0x0f802db0, 0x1c000006 },
- { 0x0f802db8, 0x1c000006 },
- { 0x0f802dc0, 0x1c000006 },
- { 0x0f802dc8, 0x1c000006 },
- { 0x0f802dd0, 0x1c000006 },
- { 0x0f802dd8, 0x1c000006 },
- { 0x09802e00, 0x54000001 },
- { 0x09002e02, 0x50000000 },
- { 0x09002e03, 0x4c000000 },
- { 0x09002e04, 0x50000000 },
- { 0x09002e05, 0x4c000000 },
- { 0x09802e06, 0x54000002 },
- { 0x09002e09, 0x50000000 },
- { 0x09002e0a, 0x4c000000 },
- { 0x09002e0b, 0x54000000 },
- { 0x09002e0c, 0x50000000 },
- { 0x09002e0d, 0x4c000000 },
- { 0x09802e0e, 0x54000008 },
- { 0x09002e17, 0x44000000 },
- { 0x09002e1c, 0x50000000 },
- { 0x09002e1d, 0x4c000000 },
- { 0x16802e80, 0x68000019 },
- { 0x16802e9b, 0x68000058 },
- { 0x16802f00, 0x680000d5 },
- { 0x09802ff0, 0x6800000b },
- { 0x09003000, 0x74000000 },
- { 0x09803001, 0x54000002 },
- { 0x09003004, 0x68000000 },
- { 0x16003005, 0x18000000 },
- { 0x09003006, 0x1c000000 },
- { 0x16003007, 0x38000000 },
- { 0x09003008, 0x58000000 },
- { 0x09003009, 0x48000000 },
- { 0x0900300a, 0x58000000 },
- { 0x0900300b, 0x48000000 },
- { 0x0900300c, 0x58000000 },
- { 0x0900300d, 0x48000000 },
- { 0x0900300e, 0x58000000 },
- { 0x0900300f, 0x48000000 },
- { 0x09003010, 0x58000000 },
- { 0x09003011, 0x48000000 },
- { 0x09803012, 0x68000001 },
- { 0x09003014, 0x58000000 },
- { 0x09003015, 0x48000000 },
- { 0x09003016, 0x58000000 },
- { 0x09003017, 0x48000000 },
- { 0x09003018, 0x58000000 },
- { 0x09003019, 0x48000000 },
- { 0x0900301a, 0x58000000 },
- { 0x0900301b, 0x48000000 },
- { 0x0900301c, 0x44000000 },
- { 0x0900301d, 0x58000000 },
- { 0x0980301e, 0x48000001 },
- { 0x09003020, 0x68000000 },
- { 0x16803021, 0x38000008 },
- { 0x1b80302a, 0x30000005 },
- { 0x09003030, 0x44000000 },
- { 0x09803031, 0x18000004 },
- { 0x09803036, 0x68000001 },
- { 0x16803038, 0x38000002 },
- { 0x1600303b, 0x18000000 },
- { 0x0900303c, 0x1c000000 },
- { 0x0900303d, 0x54000000 },
- { 0x0980303e, 0x68000001 },
- { 0x1a803041, 0x1c000055 },
- { 0x1b803099, 0x30000001 },
- { 0x0980309b, 0x60000001 },
- { 0x1a80309d, 0x18000001 },
- { 0x1a00309f, 0x1c000000 },
- { 0x090030a0, 0x44000000 },
- { 0x1d8030a1, 0x1c000059 },
- { 0x090030fb, 0x54000000 },
- { 0x098030fc, 0x18000002 },
- { 0x1d0030ff, 0x1c000000 },
- { 0x03803105, 0x1c000027 },
- { 0x17803131, 0x1c00005d },
- { 0x09803190, 0x68000001 },
- { 0x09803192, 0x3c000003 },
- { 0x09803196, 0x68000009 },
- { 0x038031a0, 0x1c000017 },
- { 0x098031c0, 0x6800000f },
- { 0x1d8031f0, 0x1c00000f },
- { 0x17803200, 0x6800001e },
- { 0x09803220, 0x3c000009 },
- { 0x0980322a, 0x68000019 },
- { 0x09003250, 0x68000000 },
- { 0x09803251, 0x3c00000e },
- { 0x17803260, 0x6800001f },
- { 0x09803280, 0x3c000009 },
- { 0x0980328a, 0x68000026 },
- { 0x098032b1, 0x3c00000e },
- { 0x098032c0, 0x6800003e },
- { 0x09803300, 0x680000ff },
- { 0x16803400, 0x1c0019b5 },
- { 0x09804dc0, 0x6800003f },
- { 0x16804e00, 0x1c0051bb },
- { 0x3c80a000, 0x1c000014 },
- { 0x3c00a015, 0x18000000 },
- { 0x3c80a016, 0x1c000476 },
- { 0x3c80a490, 0x68000036 },
- { 0x0980a700, 0x60000016 },
- { 0x3080a800, 0x1c000001 },
- { 0x3000a802, 0x28000000 },
- { 0x3080a803, 0x1c000002 },
- { 0x3000a806, 0x30000000 },
- { 0x3080a807, 0x1c000003 },
- { 0x3000a80b, 0x30000000 },
- { 0x3080a80c, 0x1c000016 },
- { 0x3080a823, 0x28000001 },
- { 0x3080a825, 0x30000001 },
- { 0x3000a827, 0x28000000 },
- { 0x3080a828, 0x68000003 },
- { 0x1780ac00, 0x1c002ba3 },
- { 0x0980d800, 0x1000037f },
- { 0x0980db80, 0x1000007f },
- { 0x0980dc00, 0x100003ff },
- { 0x0980e000, 0x0c0018ff },
- { 0x1680f900, 0x1c00012d },
- { 0x1680fa30, 0x1c00003a },
- { 0x1680fa70, 0x1c000069 },
- { 0x2180fb00, 0x14000006 },
- { 0x0180fb13, 0x14000004 },
- { 0x1900fb1d, 0x1c000000 },
- { 0x1900fb1e, 0x30000000 },
- { 0x1980fb1f, 0x1c000009 },
- { 0x1900fb29, 0x64000000 },
- { 0x1980fb2a, 0x1c00000c },
- { 0x1980fb38, 0x1c000004 },
- { 0x1900fb3e, 0x1c000000 },
- { 0x1980fb40, 0x1c000001 },
- { 0x1980fb43, 0x1c000001 },
- { 0x1980fb46, 0x1c00006b },
- { 0x0080fbd3, 0x1c00016a },
- { 0x0900fd3e, 0x58000000 },
- { 0x0900fd3f, 0x48000000 },
- { 0x0080fd50, 0x1c00003f },
- { 0x0080fd92, 0x1c000035 },
- { 0x0080fdf0, 0x1c00000b },
- { 0x0000fdfc, 0x5c000000 },
- { 0x0900fdfd, 0x68000000 },
- { 0x1b80fe00, 0x3000000f },
- { 0x0980fe10, 0x54000006 },
- { 0x0900fe17, 0x58000000 },
- { 0x0900fe18, 0x48000000 },
- { 0x0900fe19, 0x54000000 },
- { 0x1b80fe20, 0x30000003 },
- { 0x0900fe30, 0x54000000 },
- { 0x0980fe31, 0x44000001 },
- { 0x0980fe33, 0x40000001 },
- { 0x0900fe35, 0x58000000 },
- { 0x0900fe36, 0x48000000 },
- { 0x0900fe37, 0x58000000 },
- { 0x0900fe38, 0x48000000 },
- { 0x0900fe39, 0x58000000 },
- { 0x0900fe3a, 0x48000000 },
- { 0x0900fe3b, 0x58000000 },
- { 0x0900fe3c, 0x48000000 },
- { 0x0900fe3d, 0x58000000 },
- { 0x0900fe3e, 0x48000000 },
- { 0x0900fe3f, 0x58000000 },
- { 0x0900fe40, 0x48000000 },
- { 0x0900fe41, 0x58000000 },
- { 0x0900fe42, 0x48000000 },
- { 0x0900fe43, 0x58000000 },
- { 0x0900fe44, 0x48000000 },
- { 0x0980fe45, 0x54000001 },
- { 0x0900fe47, 0x58000000 },
- { 0x0900fe48, 0x48000000 },
- { 0x0980fe49, 0x54000003 },
- { 0x0980fe4d, 0x40000002 },
- { 0x0980fe50, 0x54000002 },
- { 0x0980fe54, 0x54000003 },
- { 0x0900fe58, 0x44000000 },
- { 0x0900fe59, 0x58000000 },
- { 0x0900fe5a, 0x48000000 },
- { 0x0900fe5b, 0x58000000 },
- { 0x0900fe5c, 0x48000000 },
- { 0x0900fe5d, 0x58000000 },
- { 0x0900fe5e, 0x48000000 },
- { 0x0980fe5f, 0x54000002 },
- { 0x0900fe62, 0x64000000 },
- { 0x0900fe63, 0x44000000 },
- { 0x0980fe64, 0x64000002 },
- { 0x0900fe68, 0x54000000 },
- { 0x0900fe69, 0x5c000000 },
- { 0x0980fe6a, 0x54000001 },
- { 0x0080fe70, 0x1c000004 },
- { 0x0080fe76, 0x1c000086 },
- { 0x0900feff, 0x04000000 },
- { 0x0980ff01, 0x54000002 },
- { 0x0900ff04, 0x5c000000 },
- { 0x0980ff05, 0x54000002 },
- { 0x0900ff08, 0x58000000 },
- { 0x0900ff09, 0x48000000 },
- { 0x0900ff0a, 0x54000000 },
- { 0x0900ff0b, 0x64000000 },
- { 0x0900ff0c, 0x54000000 },
- { 0x0900ff0d, 0x44000000 },
- { 0x0980ff0e, 0x54000001 },
- { 0x0980ff10, 0x34000009 },
- { 0x0980ff1a, 0x54000001 },
- { 0x0980ff1c, 0x64000002 },
- { 0x0980ff1f, 0x54000001 },
- { 0x2100ff21, 0x24000020 },
- { 0x2100ff22, 0x24000020 },
- { 0x2100ff23, 0x24000020 },
- { 0x2100ff24, 0x24000020 },
- { 0x2100ff25, 0x24000020 },
- { 0x2100ff26, 0x24000020 },
- { 0x2100ff27, 0x24000020 },
- { 0x2100ff28, 0x24000020 },
- { 0x2100ff29, 0x24000020 },
- { 0x2100ff2a, 0x24000020 },
- { 0x2100ff2b, 0x24000020 },
- { 0x2100ff2c, 0x24000020 },
- { 0x2100ff2d, 0x24000020 },
- { 0x2100ff2e, 0x24000020 },
- { 0x2100ff2f, 0x24000020 },
- { 0x2100ff30, 0x24000020 },
- { 0x2100ff31, 0x24000020 },
- { 0x2100ff32, 0x24000020 },
- { 0x2100ff33, 0x24000020 },
- { 0x2100ff34, 0x24000020 },
- { 0x2100ff35, 0x24000020 },
- { 0x2100ff36, 0x24000020 },
- { 0x2100ff37, 0x24000020 },
- { 0x2100ff38, 0x24000020 },
- { 0x2100ff39, 0x24000020 },
- { 0x2100ff3a, 0x24000020 },
- { 0x0900ff3b, 0x58000000 },
- { 0x0900ff3c, 0x54000000 },
- { 0x0900ff3d, 0x48000000 },
- { 0x0900ff3e, 0x60000000 },
- { 0x0900ff3f, 0x40000000 },
- { 0x0900ff40, 0x60000000 },
- { 0x2100ff41, 0x1400ffe0 },
- { 0x2100ff42, 0x1400ffe0 },
- { 0x2100ff43, 0x1400ffe0 },
- { 0x2100ff44, 0x1400ffe0 },
- { 0x2100ff45, 0x1400ffe0 },
- { 0x2100ff46, 0x1400ffe0 },
- { 0x2100ff47, 0x1400ffe0 },
- { 0x2100ff48, 0x1400ffe0 },
- { 0x2100ff49, 0x1400ffe0 },
- { 0x2100ff4a, 0x1400ffe0 },
- { 0x2100ff4b, 0x1400ffe0 },
- { 0x2100ff4c, 0x1400ffe0 },
- { 0x2100ff4d, 0x1400ffe0 },
- { 0x2100ff4e, 0x1400ffe0 },
- { 0x2100ff4f, 0x1400ffe0 },
- { 0x2100ff50, 0x1400ffe0 },
- { 0x2100ff51, 0x1400ffe0 },
- { 0x2100ff52, 0x1400ffe0 },
- { 0x2100ff53, 0x1400ffe0 },
- { 0x2100ff54, 0x1400ffe0 },
- { 0x2100ff55, 0x1400ffe0 },
- { 0x2100ff56, 0x1400ffe0 },
- { 0x2100ff57, 0x1400ffe0 },
- { 0x2100ff58, 0x1400ffe0 },
- { 0x2100ff59, 0x1400ffe0 },
- { 0x2100ff5a, 0x1400ffe0 },
- { 0x0900ff5b, 0x58000000 },
- { 0x0900ff5c, 0x64000000 },
- { 0x0900ff5d, 0x48000000 },
- { 0x0900ff5e, 0x64000000 },
- { 0x0900ff5f, 0x58000000 },
- { 0x0900ff60, 0x48000000 },
- { 0x0900ff61, 0x54000000 },
- { 0x0900ff62, 0x58000000 },
- { 0x0900ff63, 0x48000000 },
- { 0x0980ff64, 0x54000001 },
- { 0x1d80ff66, 0x1c000009 },
- { 0x0900ff70, 0x18000000 },
- { 0x1d80ff71, 0x1c00002c },
- { 0x0980ff9e, 0x18000001 },
- { 0x1780ffa0, 0x1c00001e },
- { 0x1780ffc2, 0x1c000005 },
- { 0x1780ffca, 0x1c000005 },
- { 0x1780ffd2, 0x1c000005 },
- { 0x1780ffda, 0x1c000002 },
- { 0x0980ffe0, 0x5c000001 },
- { 0x0900ffe2, 0x64000000 },
- { 0x0900ffe3, 0x60000000 },
- { 0x0900ffe4, 0x68000000 },
- { 0x0980ffe5, 0x5c000001 },
- { 0x0900ffe8, 0x68000000 },
- { 0x0980ffe9, 0x64000003 },
- { 0x0980ffed, 0x68000001 },
- { 0x0980fff9, 0x04000002 },
- { 0x0980fffc, 0x68000001 },
- { 0x23810000, 0x1c00000b },
- { 0x2381000d, 0x1c000019 },
- { 0x23810028, 0x1c000012 },
- { 0x2381003c, 0x1c000001 },
- { 0x2381003f, 0x1c00000e },
- { 0x23810050, 0x1c00000d },
- { 0x23810080, 0x1c00007a },
- { 0x09810100, 0x54000001 },
- { 0x09010102, 0x68000000 },
- { 0x09810107, 0x3c00002c },
- { 0x09810137, 0x68000008 },
- { 0x13810140, 0x38000034 },
- { 0x13810175, 0x3c000003 },
- { 0x13810179, 0x68000010 },
- { 0x1301018a, 0x3c000000 },
- { 0x29810300, 0x1c00001e },
- { 0x29810320, 0x3c000003 },
- { 0x12810330, 0x1c000019 },
- { 0x1201034a, 0x38000000 },
- { 0x3b810380, 0x1c00001d },
- { 0x3b01039f, 0x54000000 },
- { 0x2a8103a0, 0x1c000023 },
- { 0x2a8103c8, 0x1c000007 },
- { 0x2a0103d0, 0x68000000 },
- { 0x2a8103d1, 0x38000004 },
- { 0x0d010400, 0x24000028 },
- { 0x0d010401, 0x24000028 },
- { 0x0d010402, 0x24000028 },
- { 0x0d010403, 0x24000028 },
- { 0x0d010404, 0x24000028 },
- { 0x0d010405, 0x24000028 },
- { 0x0d010406, 0x24000028 },
- { 0x0d010407, 0x24000028 },
- { 0x0d010408, 0x24000028 },
- { 0x0d010409, 0x24000028 },
- { 0x0d01040a, 0x24000028 },
- { 0x0d01040b, 0x24000028 },
- { 0x0d01040c, 0x24000028 },
- { 0x0d01040d, 0x24000028 },
- { 0x0d01040e, 0x24000028 },
- { 0x0d01040f, 0x24000028 },
- { 0x0d010410, 0x24000028 },
- { 0x0d010411, 0x24000028 },
- { 0x0d010412, 0x24000028 },
- { 0x0d010413, 0x24000028 },
- { 0x0d010414, 0x24000028 },
- { 0x0d010415, 0x24000028 },
- { 0x0d010416, 0x24000028 },
- { 0x0d010417, 0x24000028 },
- { 0x0d010418, 0x24000028 },
- { 0x0d010419, 0x24000028 },
- { 0x0d01041a, 0x24000028 },
- { 0x0d01041b, 0x24000028 },
- { 0x0d01041c, 0x24000028 },
- { 0x0d01041d, 0x24000028 },
- { 0x0d01041e, 0x24000028 },
- { 0x0d01041f, 0x24000028 },
- { 0x0d010420, 0x24000028 },
- { 0x0d010421, 0x24000028 },
- { 0x0d010422, 0x24000028 },
- { 0x0d010423, 0x24000028 },
- { 0x0d010424, 0x24000028 },
- { 0x0d010425, 0x24000028 },
- { 0x0d010426, 0x24000028 },
- { 0x0d010427, 0x24000028 },
- { 0x0d010428, 0x1400ffd8 },
- { 0x0d010429, 0x1400ffd8 },
- { 0x0d01042a, 0x1400ffd8 },
- { 0x0d01042b, 0x1400ffd8 },
- { 0x0d01042c, 0x1400ffd8 },
- { 0x0d01042d, 0x1400ffd8 },
- { 0x0d01042e, 0x1400ffd8 },
- { 0x0d01042f, 0x1400ffd8 },
- { 0x0d010430, 0x1400ffd8 },
- { 0x0d010431, 0x1400ffd8 },
- { 0x0d010432, 0x1400ffd8 },
- { 0x0d010433, 0x1400ffd8 },
- { 0x0d010434, 0x1400ffd8 },
- { 0x0d010435, 0x1400ffd8 },
- { 0x0d010436, 0x1400ffd8 },
- { 0x0d010437, 0x1400ffd8 },
- { 0x0d010438, 0x1400ffd8 },
- { 0x0d010439, 0x1400ffd8 },
- { 0x0d01043a, 0x1400ffd8 },
- { 0x0d01043b, 0x1400ffd8 },
- { 0x0d01043c, 0x1400ffd8 },
- { 0x0d01043d, 0x1400ffd8 },
- { 0x0d01043e, 0x1400ffd8 },
- { 0x0d01043f, 0x1400ffd8 },
- { 0x0d010440, 0x1400ffd8 },
- { 0x0d010441, 0x1400ffd8 },
- { 0x0d010442, 0x1400ffd8 },
- { 0x0d010443, 0x1400ffd8 },
- { 0x0d010444, 0x1400ffd8 },
- { 0x0d010445, 0x1400ffd8 },
- { 0x0d010446, 0x1400ffd8 },
- { 0x0d010447, 0x1400ffd8 },
- { 0x0d010448, 0x1400ffd8 },
- { 0x0d010449, 0x1400ffd8 },
- { 0x0d01044a, 0x1400ffd8 },
- { 0x0d01044b, 0x1400ffd8 },
- { 0x0d01044c, 0x1400ffd8 },
- { 0x0d01044d, 0x1400ffd8 },
- { 0x0d01044e, 0x1400ffd8 },
- { 0x0d01044f, 0x1400ffd8 },
- { 0x2e810450, 0x1c00004d },
- { 0x2c8104a0, 0x34000009 },
- { 0x0b810800, 0x1c000005 },
- { 0x0b010808, 0x1c000000 },
- { 0x0b81080a, 0x1c00002b },
- { 0x0b810837, 0x1c000001 },
- { 0x0b01083c, 0x1c000000 },
- { 0x0b01083f, 0x1c000000 },
- { 0x1e010a00, 0x1c000000 },
- { 0x1e810a01, 0x30000002 },
- { 0x1e810a05, 0x30000001 },
- { 0x1e810a0c, 0x30000003 },
- { 0x1e810a10, 0x1c000003 },
- { 0x1e810a15, 0x1c000002 },
- { 0x1e810a19, 0x1c00001a },
- { 0x1e810a38, 0x30000002 },
- { 0x1e010a3f, 0x30000000 },
- { 0x1e810a40, 0x3c000007 },
- { 0x1e810a50, 0x54000008 },
- { 0x0981d000, 0x680000f5 },
- { 0x0981d100, 0x68000026 },
- { 0x0981d12a, 0x6800003a },
- { 0x0981d165, 0x28000001 },
- { 0x1b81d167, 0x30000002 },
- { 0x0981d16a, 0x68000002 },
- { 0x0981d16d, 0x28000005 },
- { 0x0981d173, 0x04000007 },
- { 0x1b81d17b, 0x30000007 },
- { 0x0981d183, 0x68000001 },
- { 0x1b81d185, 0x30000006 },
- { 0x0981d18c, 0x6800001d },
- { 0x1b81d1aa, 0x30000003 },
- { 0x0981d1ae, 0x6800002f },
- { 0x1381d200, 0x68000041 },
- { 0x1381d242, 0x30000002 },
- { 0x1301d245, 0x68000000 },
- { 0x0981d300, 0x68000056 },
- { 0x0981d400, 0x24000019 },
- { 0x0981d41a, 0x14000019 },
- { 0x0981d434, 0x24000019 },
- { 0x0981d44e, 0x14000006 },
- { 0x0981d456, 0x14000011 },
- { 0x0981d468, 0x24000019 },
- { 0x0981d482, 0x14000019 },
- { 0x0901d49c, 0x24000000 },
- { 0x0981d49e, 0x24000001 },
- { 0x0901d4a2, 0x24000000 },
- { 0x0981d4a5, 0x24000001 },
- { 0x0981d4a9, 0x24000003 },
- { 0x0981d4ae, 0x24000007 },
- { 0x0981d4b6, 0x14000003 },
- { 0x0901d4bb, 0x14000000 },
- { 0x0981d4bd, 0x14000006 },
- { 0x0981d4c5, 0x1400000a },
- { 0x0981d4d0, 0x24000019 },
- { 0x0981d4ea, 0x14000019 },
- { 0x0981d504, 0x24000001 },
- { 0x0981d507, 0x24000003 },
- { 0x0981d50d, 0x24000007 },
- { 0x0981d516, 0x24000006 },
- { 0x0981d51e, 0x14000019 },
- { 0x0981d538, 0x24000001 },
- { 0x0981d53b, 0x24000003 },
- { 0x0981d540, 0x24000004 },
- { 0x0901d546, 0x24000000 },
- { 0x0981d54a, 0x24000006 },
- { 0x0981d552, 0x14000019 },
- { 0x0981d56c, 0x24000019 },
- { 0x0981d586, 0x14000019 },
- { 0x0981d5a0, 0x24000019 },
- { 0x0981d5ba, 0x14000019 },
- { 0x0981d5d4, 0x24000019 },
- { 0x0981d5ee, 0x14000019 },
- { 0x0981d608, 0x24000019 },
- { 0x0981d622, 0x14000019 },
- { 0x0981d63c, 0x24000019 },
- { 0x0981d656, 0x14000019 },
- { 0x0981d670, 0x24000019 },
- { 0x0981d68a, 0x1400001b },
- { 0x0981d6a8, 0x24000018 },
- { 0x0901d6c1, 0x64000000 },
- { 0x0981d6c2, 0x14000018 },
- { 0x0901d6db, 0x64000000 },
- { 0x0981d6dc, 0x14000005 },
- { 0x0981d6e2, 0x24000018 },
- { 0x0901d6fb, 0x64000000 },
- { 0x0981d6fc, 0x14000018 },
- { 0x0901d715, 0x64000000 },
- { 0x0981d716, 0x14000005 },
- { 0x0981d71c, 0x24000018 },
- { 0x0901d735, 0x64000000 },
- { 0x0981d736, 0x14000018 },
- { 0x0901d74f, 0x64000000 },
- { 0x0981d750, 0x14000005 },
- { 0x0981d756, 0x24000018 },
- { 0x0901d76f, 0x64000000 },
- { 0x0981d770, 0x14000018 },
- { 0x0901d789, 0x64000000 },
- { 0x0981d78a, 0x14000005 },
- { 0x0981d790, 0x24000018 },
- { 0x0901d7a9, 0x64000000 },
- { 0x0981d7aa, 0x14000018 },
- { 0x0901d7c3, 0x64000000 },
- { 0x0981d7c4, 0x14000005 },
- { 0x0981d7ce, 0x34000031 },
- { 0x16820000, 0x1c00a6d6 },
- { 0x1682f800, 0x1c00021d },
- { 0x090e0001, 0x04000000 },
- { 0x098e0020, 0x0400005f },
- { 0x1b8e0100, 0x300000ef },
- { 0x098f0000, 0x0c00fffd },
- { 0x09900000, 0x0c00fffd },
-};
diff --git a/runtime/tools/create_snapshot_bin.py b/runtime/tools/create_snapshot_bin.py
index 71b72e1..19c2943 100755
--- a/runtime/tools/create_snapshot_bin.py
+++ b/runtime/tools/create_snapshot_bin.py
@@ -24,9 +24,14 @@
result.add_option("--executable",
action="store", type="string",
help="path to snapshot generator executable")
+ result.add_option("--vm_output_bin",
+ action="store", type="string",
+ help="output file name into which vm isolate snapshot in binary form " +
+ "is generated")
result.add_option("--output_bin",
action="store", type="string",
- help="output file name into which snapshot in binary form is generated")
+ help="output file name into which isolate snapshot in binary form " +
+ "is generated")
result.add_option("--script",
action="store", type="string",
help="Dart script for which snapshot is to be generated")
@@ -54,6 +59,9 @@
if not options.executable:
sys.stderr.write('--executable not specified\n')
return False
+ if not options.vm_output_bin:
+ sys.stderr.write('--vm_output_bin not specified\n')
+ return False
if not options.output_bin:
sys.stderr.write('--output_bin not specified\n')
return False
@@ -83,8 +91,10 @@
if options.package_root:
script_args.append(''.join([ "--package_root=", options.package_root]))
- # First setup the snapshot output filename.
- script_args.append(''.join([ "--snapshot=", options.output_bin ]))
+ # First setup the vm isolate and regular isolate snapshot output filename.
+ script_args.append(''.join([ "--vm_isolate_snapshot=",
+ options.vm_output_bin ]))
+ script_args.append(''.join([ "--isolate_snapshot=", options.output_bin ]))
# Next setup all url mapping options specified.
for url_arg in options.url_mapping:
diff --git a/runtime/tools/create_snapshot_file.py b/runtime/tools/create_snapshot_file.py
index 98b3f82..d31cc06 100755
--- a/runtime/tools/create_snapshot_file.py
+++ b/runtime/tools/create_snapshot_file.py
@@ -20,9 +20,12 @@
def BuildOptions():
result = optparse.OptionParser()
+ result.add_option("--vm_input_bin",
+ action="store", type="string",
+ help="input file name of the vm isolate snapshot in binary form")
result.add_option("--input_bin",
action="store", type="string",
- help="input file name of the snapshot in binary form")
+ help="input file name of the isolate snapshot in binary form")
result.add_option("--input_cc",
action="store", type="string",
help="input file name which contains the C buffer template")
@@ -36,6 +39,9 @@
def ProcessOptions(options):
+ if not options.vm_input_bin:
+ sys.stderr.write('--vm_input_bin not specified\n')
+ return False
if not options.input_bin:
sys.stderr.write('--input_bin not specified\n')
return False
@@ -63,9 +69,11 @@
return result
-def makeFile(output_file, input_cc_file, input_file):
+def makeFile(output_file, input_cc_file,
+ vm_isolate_input_file, isolate_input_file):
snapshot_cc_text = open(input_cc_file).read()
- snapshot_cc_text = snapshot_cc_text % makeString(input_file)
+ snapshot_cc_text = snapshot_cc_text % (makeString(vm_isolate_input_file),
+ makeString(isolate_input_file))
open(output_file, 'w').write(snapshot_cc_text)
return True
@@ -83,7 +91,8 @@
parser.print_help()
return 1
- if not makeFile(options.output, options.input_cc, options.input_bin):
+ if not makeFile(options.output, options.input_cc,
+ options.vm_input_bin, options.input_bin):
print "Unable to generate snapshot in C buffer form"
return -1
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 1ec6a6e..ff60bdf 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -410,13 +410,8 @@
void Assembler::mla(Register rd, Register rn,
Register rm, Register ra, Condition cond) {
// rd <- ra + rn * rm.
- if (TargetCPUFeatures::arm_version() == ARMv7) {
- // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
- EmitMulOp(cond, B21, ra, rd, rn, rm);
- } else {
- mul(IP, rn, rm, cond);
- add(rd, ra, Operand(IP), cond);
- }
+ // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
+ EmitMulOp(cond, B21, ra, rd, rn, rm);
}
@@ -435,7 +430,6 @@
void Assembler::smull(Register rd_lo, Register rd_hi,
Register rn, Register rm, Condition cond) {
- ASSERT(TargetCPUFeatures::arm_version() == ARMv7);
// Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
EmitMulOp(cond, B23 | B22, rd_lo, rd_hi, rn, rm);
}
@@ -443,33 +437,33 @@
void Assembler::umull(Register rd_lo, Register rd_hi,
Register rn, Register rm, Condition cond) {
- ASSERT(TargetCPUFeatures::arm_version() == ARMv7);
// Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
EmitMulOp(cond, B23, rd_lo, rd_hi, rn, rm);
}
-void Assembler::smlal(Register rd_lo, Register rd_hi,
- Register rn, Register rm, Condition cond) {
- ASSERT(TargetCPUFeatures::arm_version() == ARMv7);
- // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
- EmitMulOp(cond, B23 | B22 | B21, rd_lo, rd_hi, rn, rm);
-}
-
-
void Assembler::umlal(Register rd_lo, Register rd_hi,
Register rn, Register rm, Condition cond) {
- ASSERT(TargetCPUFeatures::arm_version() == ARMv7);
// Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
EmitMulOp(cond, B23 | B21, rd_lo, rd_hi, rn, rm);
}
void Assembler::umaal(Register rd_lo, Register rd_hi,
- Register rn, Register rm, Condition cond) {
- ASSERT(TargetCPUFeatures::arm_version() == ARMv7);
- // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
- EmitMulOp(cond, B22, rd_lo, rd_hi, rn, rm);
+ Register rn, Register rm) {
+ ASSERT(rd_lo != IP);
+ ASSERT(rd_hi != IP);
+ ASSERT(rn != IP);
+ ASSERT(rm != IP);
+ if (TargetCPUFeatures::arm_version() != ARMv5TE) {
+ // Assembler registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
+ EmitMulOp(AL, B22, rd_lo, rd_hi, rn, rm);
+ } else {
+ mov(IP, Operand(0));
+ umlal(rd_lo, IP, rn, rm);
+ adds(rd_lo, rd_lo, Operand(rd_hi));
+ adc(rd_hi, IP, Operand(0));
+ }
}
@@ -540,15 +534,27 @@
}
-void Assembler::ldrd(Register rd, Address ad, Condition cond) {
+void Assembler::ldrd(Register rd, Register rn, int32_t offset, Condition cond) {
ASSERT((rd % 2) == 0);
- EmitMemOpAddressMode3(cond, B7 | B6 | B4, rd, ad);
+ if (TargetCPUFeatures::arm_version() == ARMv5TE) {
+ const Register rd2 = static_cast<Register>(static_cast<int32_t>(rd) + 1);
+ ldr(rd, Address(rn, offset), cond);
+ ldr(rd2, Address(rn, offset + kWordSize), cond);
+ } else {
+ EmitMemOpAddressMode3(cond, B7 | B6 | B4, rd, Address(rn, offset));
+ }
}
-void Assembler::strd(Register rd, Address ad, Condition cond) {
+void Assembler::strd(Register rd, Register rn, int32_t offset, Condition cond) {
ASSERT((rd % 2) == 0);
- EmitMemOpAddressMode3(cond, B7 | B6 | B5 | B4, rd, ad);
+ if (TargetCPUFeatures::arm_version() == ARMv5TE) {
+ const Register rd2 = static_cast<Register>(static_cast<int32_t>(rd) + 1);
+ str(rd, Address(rn, offset), cond);
+ str(rd2, Address(rn, offset + kWordSize), cond);
+ } else {
+ EmitMemOpAddressMode3(cond, B7 | B6 | B5 | B4, rd, Address(rn, offset));
+ }
}
@@ -556,11 +562,6 @@
Condition cond) {
ASSERT(regs != 0);
EmitMultiMemOp(cond, am, true, base, regs);
- if (TargetCPUFeatures::arm_version() == ARMv5TE) {
- // On ARMv5, touching a "banked" register after an ldm gives undefined
- // behavior, so we just add a nop here to make that case easy to avoid.
- nop();
- }
}
@@ -568,11 +569,6 @@
Condition cond) {
ASSERT(regs != 0);
EmitMultiMemOp(cond, am, false, base, regs);
- if (TargetCPUFeatures::arm_version() == ARMv5TE) {
- // On ARMv5, touching a "banked" register after an stm gives undefined
- // behavior, so we just add a nop here to make that case easy to avoid.
- nop();
- }
}
@@ -1676,10 +1672,10 @@
ASSERT(base != value_odd);
Operand shadow(GetVerifiedMemoryShadow());
add(base, base, shadow, cond);
- strd(value_even, Address(base, offset), cond);
+ strd(value_even, base, offset, cond);
sub(base, base, shadow, cond);
}
- strd(value_even, Address(base, offset), cond);
+ strd(value_even, base, offset, cond);
}
@@ -2794,7 +2790,7 @@
ldr(reg, Address(base, offset), cond);
break;
case kWordPair:
- ldrd(reg, Address(base, offset), cond);
+ ldrd(reg, base, offset, cond);
break;
default:
UNREACHABLE();
@@ -2826,7 +2822,7 @@
str(reg, Address(base, offset), cond);
break;
case kWordPair:
- strd(reg, Address(base, offset), cond);
+ strd(reg, base, offset, cond);
break;
default:
UNREACHABLE();
@@ -3132,60 +3128,6 @@
}
-// If we aren't on ARMv7, there is no smull, and we have to check for overflow
-// manually.
-void Assembler::CheckMultSignedOverflow(Register left,
- Register right,
- Register tmp,
- DRegister dtmp0, DRegister dtmp1,
- Label* overflow) {
- Label done, left_neg, left_pos_right_neg, left_neg_right_pos;
-
- CompareImmediate(left, 0);
- b(&left_neg, LT);
- b(&done, EQ);
- CompareImmediate(right, 0);
- b(&left_pos_right_neg, LT);
- b(&done, EQ);
-
- // Both positive.
- LoadImmediate(tmp, INT_MAX);
- IntegerDivide(tmp, tmp, left, dtmp0, dtmp1);
- cmp(tmp, Operand(right));
- b(overflow, LT);
- b(&done);
-
- // left positive, right non-positive.
- Bind(&left_pos_right_neg);
- LoadImmediate(tmp, INT_MIN);
- IntegerDivide(tmp, tmp, left, dtmp0, dtmp1);
- cmp(tmp, Operand(right));
- b(overflow, GT);
- b(&done);
-
- Bind(&left_neg);
- CompareImmediate(right, 0);
- b(&left_neg_right_pos, GT);
- b(&done, EQ);
-
- // both negative.
- LoadImmediate(tmp, INT_MAX);
- IntegerDivide(tmp, tmp, left, dtmp0, dtmp1);
- cmp(tmp, Operand(right));
- b(overflow, GT);
- b(&done);
-
- // left non-positive, right positive.
- Bind(&left_neg_right_pos);
- LoadImmediate(tmp, INT_MIN);
- IntegerDivide(tmp, tmp, right, dtmp0, dtmp1);
- cmp(tmp, Operand(left));
- b(overflow, GT);
-
- Bind(&done);
-}
-
-
static int NumRegsBelowFP(RegList regs) {
int count = 0;
for (int i = 0; i < FP; i++) {
@@ -3323,7 +3265,10 @@
// optimized function and there may be extra space for spill slots to
// allocate. We must also set up the pool pointer for the function.
void Assembler::EnterOsrFrame(intptr_t extra_size) {
- const intptr_t offset = CodeSize();
+ // mov(IP, Operand(PC)) loads PC + Instr::kPCReadOffset (8). This may be
+ // different from EntryPointToPcMarkerOffset().
+ const intptr_t offset =
+ CodeSize() + Instr::kPCReadOffset - EntryPointToPcMarkerOffset();
Comment("EnterOsrFrame");
mov(IP, Operand(PC));
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index aef4a6b..76317d2 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -438,8 +438,11 @@
Condition cond = AL);
void umlal(Register rd_lo, Register rd_hi, Register rn, Register rm,
Condition cond = AL);
- void umaal(Register rd_lo, Register rd_hi, Register rn, Register rm,
- Condition cond = AL);
+
+ // Emulation of this instruction uses IP and the condition codes. Therefore,
+ // none of the registers can be IP, and the instruction can only be used
+ // unconditionally.
+ void umaal(Register rd_lo, Register rd_hi, Register rn, Register rm);
// Division instructions.
void sdiv(Register rd, Register rn, Register rm, Condition cond = AL);
@@ -458,8 +461,11 @@
void ldrsb(Register rd, Address ad, Condition cond = AL);
void ldrsh(Register rd, Address ad, Condition cond = AL);
- void ldrd(Register rd, Address ad, Condition cond = AL);
- void strd(Register rd, Address ad, Condition cond = AL);
+ // ldrd and strd actually support the full range of addressing modes, but
+ // we don't use them, and we need to split them up into two instructions for
+ // ARMv5TE, so we only support the base + offset mode.
+ void ldrd(Register rd, Register rn, int32_t offset, Condition cond = AL);
+ void strd(Register rd, Register rn, int32_t offset, Condition cond = AL);
void ldm(BlockAddressMode am, Register base,
RegList regs, Condition cond = AL);
@@ -635,13 +641,6 @@
void IntegerDivide(Register result, Register left, Register right,
DRegister tmpl, DRegister tmpr);
- // If we aren't on ARMv7, there is no smull.
- void CheckMultSignedOverflow(Register left,
- Register right,
- Register tmp,
- DRegister dtmp0, DRegister dtmp1,
- Label* overflow);
-
// Load and Store.
// These three do not clobber IP.
void LoadPatchableImmediate(Register rd, int32_t value, Condition cond = AL);
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index f870156..dc1b56d 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -110,8 +110,6 @@
__ vmovdr(D3, 1, R1); // D3[1] == S7 = R1, S6:S7 == 41:43
__ vmovrrd(R0, R1, D3); // R0:R1 = D3, R0:R1 == 41:43
__ sub(R0, R1, Operand(R0)); // 43-41
- } else {
- __ LoadImmediate(R0, 2);
}
__ bx(LR);
}
@@ -119,8 +117,10 @@
ASSEMBLER_TEST_RUN(Vmov, test) {
EXPECT(test != NULL);
- typedef int (*Vmov)() DART_UNUSED;
- EXPECT_EQ(2, EXECUTE_TEST_CODE_INT32(Vmov, test->entry()));
+ if (TargetCPUFeatures::vfp_supported()) {
+ typedef int (*Vmov)() DART_UNUSED;
+ EXPECT_EQ(2, EXECUTE_TEST_CODE_INT32(Vmov, test->entry()));
+ }
}
@@ -133,8 +133,6 @@
__ vadds(S0, S0, S0);
__ vstrs(S0, Address(R2, (-kWordSize * 30)));
__ ldr(R0, Address(SP, (kWordSize * 30), Address::PostIndex));
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -146,9 +144,6 @@
typedef float (*SingleVLoadStore)() DART_UNUSED;
float res = EXECUTE_TEST_CODE_FLOAT(SingleVLoadStore, test->entry());
EXPECT_FLOAT_EQ(2*12.3f, res, 0.001f);
- } else {
- typedef int (*SingleVLoadStore)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(SingleVLoadStore, test->entry()));
}
}
@@ -167,8 +162,6 @@
// Expressing __ldr(R0, Address(SP, (kWordSize * 32), Address::PostIndex));
// as:
__ ldr(R0, Address(SP, R1, LSL, 5, Address::PostIndex));
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -180,9 +173,6 @@
typedef float (*SingleVLoadStore)() DART_UNUSED;
float res = EXECUTE_TEST_CODE_FLOAT(SingleVLoadStore, test->entry());
EXPECT_FLOAT_EQ(2*12.3f, res, 0.001f);
- } else {
- typedef int (*SingleVLoadStore)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(SingleVLoadStore, test->entry()));
}
}
@@ -200,8 +190,6 @@
__ vstrd(D0, Address(R2, (-kWordSize * 30)));
__ ldr(R1, Address(R2, (-kWordSize * 29)));
__ ldr(R0, Address(SP, (kWordSize * 30), Address::PostIndex));
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -213,9 +201,6 @@
typedef double (*DoubleVLoadStore)() DART_UNUSED;
float res = EXECUTE_TEST_CODE_DOUBLE(DoubleVLoadStore, test->entry());
EXPECT_FLOAT_EQ(2*12.3f, res, 0.001f);
- } else {
- typedef int (*DoubleVLoadStore)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(DoubleVLoadStore, test->entry()));
}
}
@@ -231,8 +216,6 @@
__ vsubs(S0, S0, S1); // 49.98f
__ vdivs(S0, S0, S1); // 14.7f
__ vsqrts(S0, S0); // 3.8340579f
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -244,9 +227,6 @@
typedef float (*SingleFPOperations)() DART_UNUSED;
float res = EXECUTE_TEST_CODE_FLOAT(SingleFPOperations, test->entry());
EXPECT_FLOAT_EQ(3.8340579f, res, 0.001f);
- } else {
- typedef int (*SingleFPOperations)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(SingleFPOperations, test->entry()));
}
}
@@ -262,8 +242,6 @@
__ vsubd(D0, D0, D1); // 49.98
__ vdivd(D0, D0, D1); // 14.7
__ vsqrtd(D0, D0); // 3.8340579
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -275,9 +253,6 @@
typedef double (*DoubleFPOperations)() DART_UNUSED;
double res = EXECUTE_TEST_CODE_DOUBLE(DoubleFPOperations, test->entry());
EXPECT_FLOAT_EQ(3.8340579, res, 0.001);
- } else {
- typedef int (*DoubleFPOperations)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(DoubleFPOperations, test->entry()));
}
}
@@ -291,8 +266,6 @@
__ vmstat();
__ mov(R0, Operand(1), VS);
__ mov(R0, Operand(0), VC);
- } else {
- __ LoadImmediate(R0, 1);
}
__ Ret();
}
@@ -300,8 +273,10 @@
ASSEMBLER_TEST_RUN(DoubleSqrtNeg, test) {
EXPECT(test != NULL);
- typedef int (*DoubleSqrtNeg)() DART_UNUSED;
- EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(DoubleSqrtNeg, test->entry()));
+ if (TargetCPUFeatures::vfp_supported()) {
+ typedef int (*DoubleSqrtNeg)() DART_UNUSED;
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(DoubleSqrtNeg, test->entry()));
+ }
}
@@ -310,8 +285,6 @@
__ mov(R3, Operand(6));
__ vmovsr(S3, R3);
__ vcvtdi(D0, S3);
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -324,10 +297,6 @@
double res = EXECUTE_TEST_CODE_DOUBLE(IntToDoubleConversionCode,
test->entry());
EXPECT_FLOAT_EQ(6.0, res, 0.001);
- } else {
- typedef int (*IntToDoubleConversionCode)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(IntToDoubleConversionCode,
- test->entry()));
}
}
@@ -343,8 +312,6 @@
__ vcvtdi(D1, S2);
__ LoadDImmediate(D2, 1.0 * (1LL << 32), R0);
__ vmlad(D0, D1, D2);
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -357,10 +324,6 @@
double res = EXECUTE_TEST_CODE_DOUBLE(LongToDoubleConversionCode,
test->entry());
EXPECT_FLOAT_EQ(60000000000.0, res, 0.001);
- } else {
- typedef int (*LongToDoubleConversionCode)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(LongToDoubleConversionCode,
- test->entry()));
}
}
@@ -370,8 +333,6 @@
__ mov(R3, Operand(6));
__ vmovsr(S3, R3);
__ vcvtsi(S0, S3);
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -384,10 +345,6 @@
float res = EXECUTE_TEST_CODE_FLOAT(IntToFloatConversionCode,
test->entry());
EXPECT_FLOAT_EQ(6.0, res, 0.001);
- } else {
- typedef int (*IntToFloatConversionCode)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(IntToFloatConversionCode,
- test->entry()));
}
}
@@ -396,8 +353,6 @@
if (TargetCPUFeatures::vfp_supported()) {
__ vcvtis(S1, S0);
__ vmovrs(R0, S1);
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -416,9 +371,6 @@
EXPECT_EQ(INT_MAX,
EXECUTE_TEST_CODE_INT32_F(FloatToIntConversion, test->entry(),
FLT_MAX));
- } else {
- typedef int (*FloatToIntConversion)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(FloatToIntConversion, test->entry()));
}
}
@@ -427,8 +379,6 @@
if (TargetCPUFeatures::vfp_supported()) {
__ vcvtid(S0, D0);
__ vmovrs(R0, S0);
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -447,26 +397,27 @@
EXPECT_EQ(INT_MAX,
EXECUTE_TEST_CODE_INT32_D(DoubleToIntConversion, test->entry(),
DBL_MAX));
- } else {
- typedef int (*DoubleToIntConversion)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(DoubleToIntConversion, test->entry()));
}
}
ASSEMBLER_TEST_GENERATE(FloatToDoubleConversion, assembler) {
- __ LoadSImmediate(S2, 12.8f);
- __ vcvtds(D0, S2);
+ if (TargetCPUFeatures::vfp_supported()) {
+ __ LoadSImmediate(S2, 12.8f);
+ __ vcvtds(D0, S2);
+ }
__ bx(LR);
}
ASSEMBLER_TEST_RUN(FloatToDoubleConversion, test) {
- typedef double (*FloatToDoubleConversionCode)() DART_UNUSED;
- EXPECT(test != NULL);
- double res = EXECUTE_TEST_CODE_DOUBLE(FloatToDoubleConversionCode,
- test->entry());
- EXPECT_FLOAT_EQ(12.8, res, 0.001);
+ if (TargetCPUFeatures::vfp_supported()) {
+ typedef double (*FloatToDoubleConversionCode)() DART_UNUSED;
+ EXPECT(test != NULL);
+ double res = EXECUTE_TEST_CODE_DOUBLE(FloatToDoubleConversionCode,
+ test->entry());
+ EXPECT_FLOAT_EQ(12.8, res, 0.001);
+ }
}
@@ -474,8 +425,6 @@
if (TargetCPUFeatures::vfp_supported()) {
__ LoadDImmediate(D1, 12.8, R0);
__ vcvtsd(S0, D1);
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -488,10 +437,6 @@
float res = EXECUTE_TEST_CODE_FLOAT(DoubleToFloatConversionCode,
test->entry());
EXPECT_FLOAT_EQ(12.8, res, 0.001);
- } else {
- typedef int (*DoubleToFloatConversionCode)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(DoubleToFloatConversionCode,
- test->entry()));
}
}
@@ -519,8 +464,6 @@
__ vmstat();
// Error if not unordered (not Nan).
__ add(R0, R0, Operand(16), VC);
- } else {
- __ LoadImmediate(R0, 0);
}
// R0 is 0 if all tests passed.
__ bx(LR);
@@ -529,8 +472,10 @@
ASSEMBLER_TEST_RUN(FloatCompare, test) {
EXPECT(test != NULL);
- typedef int (*FloatCompare)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(FloatCompare, test->entry()));
+ if (TargetCPUFeatures::vfp_supported()) {
+ typedef int (*FloatCompare)() DART_UNUSED;
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(FloatCompare, test->entry()));
+ }
}
@@ -557,8 +502,6 @@
__ vmstat();
// Error if not unordered (not Nan).
__ add(R0, R0, Operand(16), VC);
- } else {
- __ LoadImmediate(R0, 0);
}
// R0 is 0 if all tests passed.
__ bx(LR);
@@ -567,8 +510,10 @@
ASSEMBLER_TEST_RUN(DoubleCompare, test) {
EXPECT(test != NULL);
- typedef int (*DoubleCompare)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(DoubleCompare, test->entry()));
+ if (TargetCPUFeatures::vfp_supported()) {
+ typedef int (*DoubleCompare)() DART_UNUSED;
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(DoubleCompare, test->entry()));
+ }
}
@@ -667,10 +612,7 @@
ASSEMBLER_TEST_GENERATE(Semaphore, assembler) {
- if (TargetCPUFeatures::arm_version() == ARMv5TE) {
- __ mov(R0, Operand(42));
- __ bx(LR);
- } else {
+ if (TargetCPUFeatures::arm_version() != ARMv5TE) {
__ mov(R0, Operand(40));
__ mov(R1, Operand(42));
__ Push(R0);
@@ -681,23 +623,22 @@
__ tst(IP, Operand(0));
__ b(&retry, NE); // NE if context switch occurred between ldrex and strex.
__ Pop(R0); // 42
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Semaphore, test) {
EXPECT(test != NULL);
- typedef int (*Semaphore)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Semaphore, test->entry()));
+ if (TargetCPUFeatures::arm_version() != ARMv5TE) {
+ typedef int (*Semaphore)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Semaphore, test->entry()));
+ }
}
ASSEMBLER_TEST_GENERATE(FailedSemaphore, assembler) {
- if (TargetCPUFeatures::arm_version() == ARMv5TE) {
- __ mov(R0, Operand(41));
- __ bx(LR);
- } else {
+ if (TargetCPUFeatures::arm_version() != ARMv5TE) {
__ mov(R0, Operand(40));
__ mov(R1, Operand(42));
__ Push(R0);
@@ -706,15 +647,17 @@
__ strex(IP, R1, SP); // IP == 1, failure
__ Pop(R0); // 40
__ add(R0, R0, Operand(IP));
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(FailedSemaphore, test) {
EXPECT(test != NULL);
- typedef int (*FailedSemaphore)() DART_UNUSED;
- EXPECT_EQ(41, EXECUTE_TEST_CODE_INT32(FailedSemaphore, test->entry()));
+ if (TargetCPUFeatures::arm_version() != ARMv5TE) {
+ typedef int (*FailedSemaphore)() DART_UNUSED;
+ EXPECT_EQ(41, EXECUTE_TEST_CODE_INT32(FailedSemaphore, test->entry()));
+ }
}
@@ -883,8 +826,6 @@
__ vcvtid(S0, D0);
__ vmovrs(R1, S0); // r1 = r0/r2
__ mls(R0, R1, R2, R0); // r0 = r0 - r1*r2
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -898,34 +839,19 @@
EXPECT_EQ(0x1000400000da8LL,
EXECUTE_TEST_CODE_INT64_LL(QuotientRemainder, test->entry(),
0x12345678, 0x1234));
- } else {
- typedef int (*QuotientRemainder)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(QuotientRemainder, test->entry()));
}
}
ASSEMBLER_TEST_GENERATE(Multiply64To64, assembler) {
-#if defined(USING_SIMULATOR)
- const ARMVersion version = TargetCPUFeatures::arm_version();
- HostCPUFeatures::set_arm_version(ARMv7);
-#endif
- if (TargetCPUFeatures::arm_version() == ARMv7) {
- __ Push(R4);
- __ mov(IP, Operand(R0));
- __ mul(R4, R2, R1);
- __ umull(R0, R1, R2, IP);
- __ mla(R2, IP, R3, R4);
- __ add(R1, R2, Operand(R1));
- __ Pop(R4);
- } else {
- __ LoadImmediate(R0, 6);
- __ LoadImmediate(R1, 0);
- }
+ __ Push(R4);
+ __ mov(IP, Operand(R0));
+ __ mul(R4, R2, R1);
+ __ umull(R0, R1, R2, IP);
+ __ mla(R2, IP, R3, R4);
+ __ add(R1, R2, Operand(R1));
+ __ Pop(R4);
__ bx(LR);
-#if defined(USING_SIMULATOR)
- HostCPUFeatures::set_arm_version(version);
-#endif
}
@@ -939,20 +865,8 @@
ASSEMBLER_TEST_GENERATE(Multiply32To64, assembler) {
-#if defined(USING_SIMULATOR)
- const ARMVersion version = TargetCPUFeatures::arm_version();
- HostCPUFeatures::set_arm_version(ARMv7);
-#endif
- if (TargetCPUFeatures::arm_version() == ARMv7) {
- __ smull(R0, R1, R0, R2);
- } else {
- __ LoadImmediate(R0, 6);
- __ LoadImmediate(R1, 0);
- }
+ __ smull(R0, R1, R0, R2);
__ bx(LR);
-#if defined(USING_SIMULATOR)
- HostCPUFeatures::set_arm_version(version);
-#endif
}
@@ -965,48 +879,9 @@
}
-ASSEMBLER_TEST_GENERATE(MultiplyAccum32To64, assembler) {
-#if defined(USING_SIMULATOR)
- const ARMVersion version = TargetCPUFeatures::arm_version();
- HostCPUFeatures::set_arm_version(ARMv7);
-#endif
- if (TargetCPUFeatures::arm_version() == ARMv7) {
- __ smlal(R0, R1, R0, R2);
- } else {
- __ LoadImmediate(R0, 3);
- __ LoadImmediate(R1, 0);
- }
- __ bx(LR);
-#if defined(USING_SIMULATOR)
- HostCPUFeatures::set_arm_version(version);
-#endif
-}
-
-
-ASSEMBLER_TEST_RUN(MultiplyAccum32To64, test) {
- EXPECT(test != NULL);
- typedef int64_t (*MultiplyAccum32To64)
- (int64_t operand0, int64_t operand1) DART_UNUSED;
- EXPECT_EQ(3, EXECUTE_TEST_CODE_INT64_LL(MultiplyAccum32To64, test->entry(),
- -3, -2));
-}
-
-
ASSEMBLER_TEST_GENERATE(MultiplyAccumAccum32To64, assembler) {
-#if defined(USING_SIMULATOR)
- const ARMVersion version = TargetCPUFeatures::arm_version();
- HostCPUFeatures::set_arm_version(ARMv7);
-#endif
- if (TargetCPUFeatures::arm_version() == ARMv7) {
- __ umaal(R0, R1, R2, R3);
- } else {
- __ LoadImmediate(R0, 3 + 7 + 5 * 11);
- __ LoadImmediate(R1, 0);
- }
+ __ umaal(R0, R1, R2, R3);
__ bx(LR);
-#if defined(USING_SIMULATOR)
- HostCPUFeatures::set_arm_version(version);
-#endif
}
@@ -1274,10 +1149,12 @@
ASSEMBLER_TEST_GENERATE(Ldrd, assembler) {
__ mov(IP, Operand(SP));
- __ strd(R2, Address(SP, (-kWordSize * 30), Address::PreIndex));
- __ strd(R0, Address(IP, (-kWordSize * 28)));
- __ ldrd(R2, Address(IP, (-kWordSize * 28)));
- __ ldrd(R0, Address(SP, (kWordSize * 30), Address::PostIndex));
+ __ sub(SP, SP, Operand(kWordSize*30));
+ __ strd(R2, SP, 0);
+ __ strd(R0, IP, (-kWordSize*28));
+ __ ldrd(R2, IP, (-kWordSize*28));
+ __ ldrd(R0, SP, 0);
+ __ add(SP, SP, Operand(kWordSize*30));
__ sub(R0, R0, Operand(R2));
__ add(R1, R1, Operand(R3));
__ bx(LR);
@@ -1476,8 +1353,6 @@
__ vcmpd(D1, D5);
__ vmstat();
__ mov(R0, Operand(0), NE); // Put failure into R0 if NE
- } else {
- __ LoadImmediate(R0, 42);
}
__ bx(LR);
}
@@ -1485,8 +1360,10 @@
ASSEMBLER_TEST_RUN(VstmdVldmd, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::vfp_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1532,8 +1409,6 @@
__ vcmps(S1, S5);
__ vmstat();
__ mov(R0, Operand(0), NE); // Put failure value into R0 if NE
- } else {
- __ LoadImmediate(R0, 42);
}
__ bx(LR);
}
@@ -1541,8 +1416,10 @@
ASSEMBLER_TEST_RUN(VstmsVldms, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::vfp_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1587,8 +1464,6 @@
__ vcmpd(D1, D5);
__ vmstat();
__ mov(R0, Operand(0), NE); // Put failure into R0 if NE
- } else {
- __ LoadImmediate(R0, 42);
}
__ bx(LR);
}
@@ -1596,8 +1471,10 @@
ASSEMBLER_TEST_RUN(VstmdVldmd1, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::vfp_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1641,8 +1518,6 @@
__ vcmps(S1, S5);
__ vmstat();
__ mov(R0, Operand(0), NE); // Put failure value into R0 if NE
- } else {
- __ LoadImmediate(R0, 42);
}
__ bx(LR);
}
@@ -1650,8 +1525,10 @@
ASSEMBLER_TEST_RUN(VstmsVldms1, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::vfp_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1706,8 +1583,6 @@
// Restore used callee-saved FPU registers.
__ vldmd(IA_W, SP, D8, 3);
- } else {
- __ LoadImmediate(R0, 42);
}
__ bx(LR);
}
@@ -1715,8 +1590,10 @@
ASSEMBLER_TEST_RUN(VstmdVldmd_off, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::vfp_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1764,8 +1641,6 @@
__ vcmps(S5, S10);
__ vmstat();
__ mov(R0, Operand(0), NE); // Put failure value into R0 if NE
- } else {
- __ LoadImmediate(R0, 42);
}
__ bx(LR);
}
@@ -1773,8 +1648,10 @@
ASSEMBLER_TEST_RUN(VstmsVldms_off, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::vfp_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1784,8 +1661,6 @@
__ mov(R1, Operand(9));
__ udiv(R2, R0, R1);
__ mov(R0, Operand(R2));
- } else {
- __ mov(R0, Operand(3));
}
__ bx(LR);
}
@@ -1793,8 +1668,10 @@
ASSEMBLER_TEST_RUN(Udiv, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::integer_division_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1804,8 +1681,6 @@
__ LoadImmediate(R1, -9);
__ sdiv(R2, R0, R1);
__ mov(R0, Operand(R2));
- } else {
- __ LoadImmediate(R0, -3);
}
__ bx(LR);
}
@@ -1813,8 +1688,10 @@
ASSEMBLER_TEST_RUN(Sdiv, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::integer_division_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1824,8 +1701,6 @@
__ mov(R1, Operand(0));
__ udiv(R2, R0, R1);
__ mov(R0, Operand(R2));
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -1833,8 +1708,10 @@
ASSEMBLER_TEST_RUN(Udiv_zero, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::integer_division_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1844,8 +1721,6 @@
__ mov(R1, Operand(0));
__ sdiv(R2, R0, R1);
__ mov(R0, Operand(R2));
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -1853,8 +1728,10 @@
ASSEMBLER_TEST_RUN(Sdiv_zero, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::integer_division_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1864,8 +1741,6 @@
__ LoadImmediate(R1, 0xffffffff);
__ udiv(R2, R0, R1);
__ mov(R0, Operand(R2));
- } else {
- __ LoadImmediate(R0, 0);
}
__ bx(LR);
}
@@ -1873,8 +1748,10 @@
ASSEMBLER_TEST_RUN(Udiv_corner, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::integer_division_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1884,8 +1761,6 @@
__ LoadImmediate(R1, 0xffffffff);
__ sdiv(R2, R0, R1);
__ mov(R0, Operand(R2));
- } else {
- __ LoadImmediate(R0, 0x80000000);
}
__ bx(LR);
}
@@ -1893,9 +1768,11 @@
ASSEMBLER_TEST_RUN(Sdiv_corner, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(static_cast<int32_t>(0x80000000),
- EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::integer_division_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(static_cast<int32_t>(0x80000000),
+ EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1909,9 +1786,11 @@
HostCPUFeatures::set_integer_division_supported(orig);
__ bx(LR);
#else
- __ mov(R0, Operand(27));
- __ mov(R1, Operand(9));
- __ IntegerDivide(R0, R0, R1, D0, D1);
+ if (TargetCPUFeatures::can_divide()) {
+ __ mov(R0, Operand(27));
+ __ mov(R1, Operand(9));
+ __ IntegerDivide(R0, R0, R1, D0, D1);
+ }
__ bx(LR);
#endif
}
@@ -1919,8 +1798,10 @@
ASSEMBLER_TEST_RUN(IntDiv_supported, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::can_divide()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1934,9 +1815,11 @@
HostCPUFeatures::set_integer_division_supported(orig);
__ bx(LR);
#else
- __ mov(R0, Operand(27));
- __ mov(R1, Operand(9));
- __ IntegerDivide(R0, R0, R1, D0, D1);
+ if (TargetCPUFeatures::can_divide()) {
+ __ mov(R0, Operand(27));
+ __ mov(R1, Operand(9));
+ __ IntegerDivide(R0, R0, R1, D0, D1);
+ }
__ bx(LR);
#endif
}
@@ -1944,8 +1827,10 @@
ASSEMBLER_TEST_RUN(IntDiv_unsupported, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::can_divide()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -1994,18 +1879,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 36);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vaddqi8, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(36, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(36, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2038,18 +1922,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 36);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vaddqi16, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(36, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(36, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2082,18 +1965,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 36);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vaddqi32, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(36, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(36, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2114,18 +1996,17 @@
__ vmovrs(R2, S10);
__ add(R0, R0, Operand(R2));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 10);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vaddqi64, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2152,18 +2033,17 @@
__ LoadImmediate(R0, 1);
__ Bind(&fail);
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 1);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vshlqu64, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2190,18 +2070,17 @@
__ LoadImmediate(R0, 1);
__ Bind(&fail);
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 1);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vshlqi64, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2248,8 +2127,6 @@
__ Bind(&fail);
__ LoadImmediate(R0, 0);
- } else {
- __ LoadImmediate(R0, 1);
}
__ bx(LR);
}
@@ -2257,8 +2134,10 @@
ASSEMBLER_TEST_RUN(Mint_shl_ok, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2305,8 +2184,6 @@
__ Bind(&fail);
__ LoadImmediate(R0, 1);
- } else {
- __ LoadImmediate(R0, 1);
}
__ bx(LR);
}
@@ -2314,8 +2191,10 @@
ASSEMBLER_TEST_RUN(Mint_shl_overflow, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2348,18 +2227,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 10);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vsubqi8, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2392,18 +2270,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 10);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vsubqi16, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2436,18 +2313,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 10);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vsubqi32, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2468,18 +2344,17 @@
__ vmovrs(R2, S10);
__ add(R0, R0, Operand(R2));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 3);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vsubqi64, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2512,18 +2387,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 70);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vmulqi8, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(70, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(70, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2556,18 +2430,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 70);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vmulqi16, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(70, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(70, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2600,18 +2473,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 70);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vmulqi32, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(70, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(70, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2634,19 +2506,17 @@
__ vcvtis(S0, S8);
__ vmovrs(R0, S0);
-
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 36);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vaddqs, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(36, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(36, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2669,19 +2539,17 @@
__ vcvtis(S0, S8);
__ vmovrs(R0, S0);
-
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 10);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vsubqs, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(10, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2704,19 +2572,17 @@
__ vcvtis(S0, S8);
__ vmovrs(R0, S0);
-
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 70);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vmulqs, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(70, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(70, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2748,18 +2614,17 @@
__ CompareImmediate(R3, 1);
__ bx(LR, NE);
__ LoadImmediate(R0, 42);
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 42);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(VtblX, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2791,18 +2656,17 @@
__ CompareImmediate(R3, 1);
__ bx(LR, NE);
__ LoadImmediate(R0, 42);
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 42);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(VtblY, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2834,18 +2698,17 @@
__ CompareImmediate(R3, 1);
__ bx(LR, NE);
__ LoadImmediate(R0, 42);
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 42);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(VtblZ, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2877,18 +2740,17 @@
__ CompareImmediate(R3, 1);
__ bx(LR, NE);
__ LoadImmediate(R0, 42);
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 42);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(VtblW, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2919,18 +2781,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -8);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Veorq, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-8, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-8, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -2961,18 +2822,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 60);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vornq, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(60, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(60, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3003,18 +2863,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -4);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vorrq, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3045,18 +2904,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 4);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vandq, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3082,19 +2940,17 @@
__ vadds(S4, S4, S7);
__ vcvtis(S0, S4);
__ vmovrs(R0, S0);
-
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 4);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vmovq, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3105,18 +2961,17 @@
__ vmvnq(Q1, Q0); // Q1 <- ~Q0.
__ vmvnq(Q2, Q1); // Q2 <- ~Q1.
__ vmovrs(R0, S10); // Now R0 should be 42 again.
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 42);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vmvnq, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3138,18 +2993,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -4);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vdupb, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3171,18 +3025,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -4);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vduph, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3204,18 +3057,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -4);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vdupw, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-4, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3237,19 +3089,18 @@
__ vadds(S0, S0, S1);
__ vadds(S0, S0, S2);
__ vadds(S0, S0, S3);
- __ bx(LR);
- } else {
- __ LoadSImmediate(S0, 8.0);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vzipqw, test) {
EXPECT(test != NULL);
- typedef float (*Vzipqw)() DART_UNUSED;
- float res = EXECUTE_TEST_CODE_FLOAT(Vzipqw, test->entry());
- EXPECT_FLOAT_EQ(8.0, res, 0.0001f);
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef float (*Vzipqw)() DART_UNUSED;
+ float res = EXECUTE_TEST_CODE_FLOAT(Vzipqw, test->entry());
+ EXPECT_FLOAT_EQ(8.0, res, 0.0001f);
+ }
}
@@ -3282,18 +3133,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -2);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vceqqi32, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3318,18 +3168,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -2);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vceqqs, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3362,18 +3211,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -2);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vcgeqi32, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3406,18 +3254,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -2);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vcugeqi32, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3442,18 +3289,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -2);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vcgeqs, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3486,18 +3332,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -2);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vcgtqi32, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3530,18 +3375,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -2);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vcugtqi32, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3566,18 +3410,17 @@
__ add(R0, R0, Operand(R1));
__ add(R0, R0, Operand(R2));
__ add(R0, R0, Operand(R3));
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, -2);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vcgtqs, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(-2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3601,18 +3444,17 @@
__ vcvtis(S0, S8);
__ vmovrs(R0, S0);
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 8);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vminqs, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(8, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(8, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3636,18 +3478,17 @@
__ vcvtis(S0, S8);
__ vmovrs(R0, S0);
- __ bx(LR);
- } else {
- __ LoadImmediate(R0, 14);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vmaxqs, test) {
EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(14, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef int (*Tst)() DART_UNUSED;
+ EXPECT_EQ(14, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ }
}
@@ -3692,22 +3533,19 @@
__ vmovs(S5, S4);
__ vmovs(S6, S4);
__ vmovs(S7, S4);
-
__ vrecpeqs(Q0, Q1);
-
- __ bx(LR);
- } else {
- __ LoadSImmediate(S0, arm_recip_estimate(147.0));
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vrecpeqs, test) {
EXPECT(test != NULL);
- typedef float (*Vrecpeqs)() DART_UNUSED;
- float res = EXECUTE_TEST_CODE_FLOAT(Vrecpeqs, test->entry());
- EXPECT_FLOAT_EQ(arm_recip_estimate(147.0), res, 0.0001f);
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef float (*Vrecpeqs)() DART_UNUSED;
+ float res = EXECUTE_TEST_CODE_FLOAT(Vrecpeqs, test->entry());
+ EXPECT_FLOAT_EQ(arm_recip_estimate(147.0), res, 0.0001f);
+ }
}
@@ -3724,20 +3562,18 @@
__ LoadSImmediate(S11, 3.0);
__ vrecpsqs(Q0, Q1, Q2);
-
- __ bx(LR);
- } else {
- __ LoadSImmediate(S0, 2.0 - 10.0 * 5.0);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vrecpsqs, test) {
EXPECT(test != NULL);
- typedef float (*Vrecpsqs)() DART_UNUSED;
- float res = EXECUTE_TEST_CODE_FLOAT(Vrecpsqs, test->entry());
- EXPECT_FLOAT_EQ(2.0 - 10.0 * 5.0, res, 0.0001f);
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef float (*Vrecpsqs)() DART_UNUSED;
+ float res = EXECUTE_TEST_CODE_FLOAT(Vrecpsqs, test->entry());
+ EXPECT_FLOAT_EQ(2.0 - 10.0 * 5.0, res, 0.0001f);
+ }
}
@@ -3755,20 +3591,18 @@
__ vmulqs(Q0, Q0, Q2);
__ vrecpsqs(Q2, Q1, Q0);
__ vmulqs(Q0, Q0, Q2);
-
- __ bx(LR);
- } else {
- __ LoadSImmediate(S0, 1.0/147000.0);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Reciprocal, test) {
EXPECT(test != NULL);
- typedef float (*Reciprocal)() DART_UNUSED;
- float res = EXECUTE_TEST_CODE_FLOAT(Reciprocal, test->entry());
- EXPECT_FLOAT_EQ(1.0/147000.0, res, 0.0001f);
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef float (*Reciprocal)() DART_UNUSED;
+ float res = EXECUTE_TEST_CODE_FLOAT(Reciprocal, test->entry());
+ EXPECT_FLOAT_EQ(1.0/147000.0, res, 0.0001f);
+ }
}
@@ -3831,20 +3665,18 @@
__ vmovs(S7, S4);
__ vrsqrteqs(Q0, Q1);
-
- __ bx(LR);
- } else {
- __ LoadSImmediate(S0, arm_reciprocal_sqrt_estimate(147.0));
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vrsqrteqs, test) {
EXPECT(test != NULL);
- typedef float (*Vrsqrteqs)() DART_UNUSED;
- float res = EXECUTE_TEST_CODE_FLOAT(Vrsqrteqs, test->entry());
- EXPECT_FLOAT_EQ(arm_reciprocal_sqrt_estimate(147.0), res, 0.0001f);
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef float (*Vrsqrteqs)() DART_UNUSED;
+ float res = EXECUTE_TEST_CODE_FLOAT(Vrsqrteqs, test->entry());
+ EXPECT_FLOAT_EQ(arm_reciprocal_sqrt_estimate(147.0), res, 0.0001f);
+ }
}
@@ -3861,20 +3693,18 @@
__ LoadSImmediate(S11, 3.0);
__ vrsqrtsqs(Q0, Q1, Q2);
-
- __ bx(LR);
- } else {
- __ LoadSImmediate(S0, (3.0 - 10.0 * 5.0) / 2.0);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vrsqrtsqs, test) {
EXPECT(test != NULL);
- typedef float (*Vrsqrtsqs)() DART_UNUSED;
- float res = EXECUTE_TEST_CODE_FLOAT(Vrsqrtsqs, test->entry());
- EXPECT_FLOAT_EQ((3.0 - 10.0 * 5.0)/2.0, res, 0.0001f);
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef float (*Vrsqrtsqs)() DART_UNUSED;
+ float res = EXECUTE_TEST_CODE_FLOAT(Vrsqrtsqs, test->entry());
+ EXPECT_FLOAT_EQ((3.0 - 10.0 * 5.0)/2.0, res, 0.0001f);
+ }
}
@@ -3896,20 +3726,18 @@
__ vmulqs(Q2, Q0, Q0);
__ vrsqrtsqs(Q2, Q1, Q2);
__ vmulqs(Q0, Q0, Q2);
-
- __ bx(LR);
- } else {
- __ LoadSImmediate(S0, 1.0/sqrt(147000.0));
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(ReciprocalSqrt, test) {
EXPECT(test != NULL);
- typedef float (*ReciprocalSqrt)() DART_UNUSED;
- float res = EXECUTE_TEST_CODE_FLOAT(ReciprocalSqrt, test->entry());
- EXPECT_FLOAT_EQ(1.0/sqrt(147000.0), res, 0.0001f);
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef float (*ReciprocalSqrt)() DART_UNUSED;
+ float res = EXECUTE_TEST_CODE_FLOAT(ReciprocalSqrt, test->entry());
+ EXPECT_FLOAT_EQ(1.0/sqrt(147000.0), res, 0.0001f);
+ }
}
@@ -3941,20 +3769,18 @@
__ vmulqs(Q0, Q0, Q2);
__ vrecpsqs(Q2, Q1, Q0);
__ vmulqs(Q0, Q0, Q2);
-
- __ bx(LR);
- } else {
- __ LoadSImmediate(S0, sqrt(147000.0));
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(SIMDSqrt, test) {
EXPECT(test != NULL);
- typedef float (*SIMDSqrt)() DART_UNUSED;
- float res = EXECUTE_TEST_CODE_FLOAT(SIMDSqrt, test->entry());
- EXPECT_FLOAT_EQ(sqrt(147000.0), res, 0.0001f);
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef float (*SIMDSqrt)() DART_UNUSED;
+ float res = EXECUTE_TEST_CODE_FLOAT(SIMDSqrt, test->entry());
+ EXPECT_FLOAT_EQ(sqrt(147000.0), res, 0.0001f);
+ }
}
@@ -3990,20 +3816,18 @@
__ vadds(S0, S0, S1);
__ vadds(S0, S0, S2);
__ vadds(S0, S0, S3);
-
- __ bx(LR);
- } else {
- __ LoadSImmediate(S0, 10.0);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(SIMDSqrt2, test) {
EXPECT(test != NULL);
- typedef float (*SIMDSqrt2)() DART_UNUSED;
- float res = EXECUTE_TEST_CODE_FLOAT(SIMDSqrt2, test->entry());
- EXPECT_FLOAT_EQ(10.0, res, 0.0001f);
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef float (*SIMDSqrt2)() DART_UNUSED;
+ float res = EXECUTE_TEST_CODE_FLOAT(SIMDSqrt2, test->entry());
+ EXPECT_FLOAT_EQ(10.0, res, 0.0001f);
+ }
}
@@ -4031,20 +3855,18 @@
__ vadds(S0, S0, S1);
__ vadds(S0, S0, S2);
__ vadds(S0, S0, S3);
-
- __ bx(LR);
- } else {
- __ LoadSImmediate(S0, 16.0);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(SIMDDiv, test) {
EXPECT(test != NULL);
- typedef float (*SIMDDiv)() DART_UNUSED;
- float res = EXECUTE_TEST_CODE_FLOAT(SIMDDiv, test->entry());
- EXPECT_FLOAT_EQ(16.0, res, 0.0001f);
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef float (*SIMDDiv)() DART_UNUSED;
+ float res = EXECUTE_TEST_CODE_FLOAT(SIMDDiv, test->entry());
+ EXPECT_FLOAT_EQ(16.0, res, 0.0001f);
+ }
}
@@ -4060,20 +3882,18 @@
__ vadds(S0, S0, S1);
__ vadds(S0, S0, S2);
__ vadds(S0, S0, S3);
-
- __ bx(LR);
- } else {
- __ LoadSImmediate(S0, 4.0);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vabsqs, test) {
EXPECT(test != NULL);
- typedef float (*Vabsqs)() DART_UNUSED;
- float res = EXECUTE_TEST_CODE_FLOAT(Vabsqs, test->entry());
- EXPECT_FLOAT_EQ(4.0, res, 0.0001f);
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef float (*Vabsqs)() DART_UNUSED;
+ float res = EXECUTE_TEST_CODE_FLOAT(Vabsqs, test->entry());
+ EXPECT_FLOAT_EQ(4.0, res, 0.0001f);
+ }
}
@@ -4089,114 +3909,18 @@
__ vadds(S0, S0, S1);
__ vadds(S0, S0, S2);
__ vadds(S0, S0, S3);
-
- __ bx(LR);
- } else {
- __ LoadSImmediate(S0, 2.0);
- __ bx(LR);
}
+ __ bx(LR);
}
ASSEMBLER_TEST_RUN(Vnegqs, test) {
EXPECT(test != NULL);
- typedef float (*Vnegqs)() DART_UNUSED;
- float res = EXECUTE_TEST_CODE_FLOAT(Vnegqs, test->entry());
- EXPECT_FLOAT_EQ(2.0, res, 0.0001f);
-}
-
-
-ASSEMBLER_TEST_GENERATE(MultCheckOverflow, assembler) {
- // Both positive, no overflow
- Label overflow1, test1;
- __ LoadImmediate(R0, 42);
- __ LoadImmediate(R1, 0xff);
- __ LoadImmediate(R2, 0xf0);
- __ CheckMultSignedOverflow(R1, R2, R3, D0, D1, &overflow1);
- __ b(&test1);
- __ Bind(&overflow1);
- __ LoadImmediate(R0, 1);
- __ Ret();
-
-
- // Left negative no overflow.
- __ Bind(&test1);
- Label overflow2, test2;
- __ LoadImmediate(R1, -0xff);
- __ LoadImmediate(R2, 0xf0);
- __ CheckMultSignedOverflow(R1, R2, R3, D0, D1, &overflow2);
- __ b(&test2);
- __ Bind(&overflow2);
- __ LoadImmediate(R0, 2);
- __ Ret();
-
- // Right negative no overflow
- Label overflow3, test3;
- __ Bind(&test2);
- __ LoadImmediate(R1, 0xff);
- __ LoadImmediate(R2, -0xf0);
- __ CheckMultSignedOverflow(R1, R2, R3, D0, D1, &overflow3);
- __ b(&test3);
- __ Bind(&overflow3);
- __ LoadImmediate(R0, 3);
- __ Ret();
-
- // Both negative no overflow.
- Label overflow4, test4;
- __ Bind(&test3);
- __ LoadImmediate(R1, -0xff);
- __ LoadImmediate(R2, -0xf0);
- __ CheckMultSignedOverflow(R1, R2, R3, D0, D1, &overflow4);
- __ b(&test4);
- __ Bind(&overflow4);
- __ LoadImmediate(R0, 4);
- __ Ret();
-
- // Both positive with overflow.
- Label test5;
- __ Bind(&test4);
- __ LoadImmediate(R1, 0x0fffffff);
- __ LoadImmediate(R2, 0xffff);
- __ CheckMultSignedOverflow(R1, R2, R3, D0, D1, &test5);
- __ LoadImmediate(R0, 5);
- __ Ret();
-
- // left negative with overflow.
- Label test6;
- __ Bind(&test5);
- __ LoadImmediate(R1, -0x0fffffff);
- __ LoadImmediate(R2, 0xffff);
- __ CheckMultSignedOverflow(R1, R2, R3, D0, D1, &test6);
- __ LoadImmediate(R0, 6);
- __ Ret();
-
- // right negative with overflow.
- Label test7;
- __ Bind(&test6);
- __ LoadImmediate(R1, 0x0fffffff);
- __ LoadImmediate(R2, -0xffff);
- __ CheckMultSignedOverflow(R1, R2, R3, D0, D1, &test7);
- __ LoadImmediate(R0, 7);
- __ Ret();
-
- // both negative with overflow.
- Label test8;
- __ Bind(&test7);
- __ LoadImmediate(R1, -0x0fffffff);
- __ LoadImmediate(R2, -0xffff);
- __ CheckMultSignedOverflow(R1, R2, R3, D0, D1, &test8);
- __ LoadImmediate(R0, 8);
- __ Ret();
-
- __ Bind(&test8);
- __ Ret();
-}
-
-
-ASSEMBLER_TEST_RUN(MultCheckOverflow, test) {
- EXPECT(test != NULL);
- typedef int (*Tst)() DART_UNUSED;
- EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+ if (TargetCPUFeatures::neon_supported()) {
+ typedef float (*Vnegqs)() DART_UNUSED;
+ float res = EXECUTE_TEST_CODE_FLOAT(Vnegqs, test->entry());
+ EXPECT_FLOAT_EQ(2.0, res, 0.0001f);
+ }
}
@@ -4267,7 +3991,6 @@
#undef RANGE_OF
}
-
} // namespace dart
#endif // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index b6e3a68..4295cb1 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -1067,7 +1067,7 @@
SetPrologueOffset();
- TraceSimMsg("EnterCallRuntimeFrame");
+ Comment("EnterCallRuntimeFrame");
// Save volatile CPU and FPU registers on the stack:
// -------------
@@ -1108,7 +1108,7 @@
2 * kWordSize + // FP and RA.
kDartVolatileFpuRegCount * kWordSize;
- TraceSimMsg("LeaveCallRuntimeFrame");
+ Comment("LeaveCallRuntimeFrame");
// SP might have been modified to reserve space for arguments
// and ensure proper alignment of the stack frame.
@@ -1213,21 +1213,6 @@
break_(Instr::kStopMessageCode);
}
-
-void Assembler::TraceSimMsg(const char* message) {
- // Don't bother adding in the messages unless tracing is enabled, and we are
- // running in the simulator.
-#if defined(USING_SIMULATOR)
- if (FLAG_trace_sim_after != -1) {
- Label msg;
- b(&msg);
- Emit(reinterpret_cast<int32_t>(message));
- Bind(&msg);
- break_(Instr::kSimulatorMessageCode);
- }
-#endif
-}
-
} // namespace dart
#endif // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 86cd17f..62dd303 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -325,10 +325,6 @@
// Debugging and bringup support.
void Stop(const char* message);
-
- // TODO(zra): TraceSimMsg enables printing of helpful messages when
- // --trace_sim is given. Eventually these calls will be changed to Comment.
- void TraceSimMsg(const char* message);
void Unimplemented(const char* message);
void Untested(const char* message);
void Unreachable(const char* message);
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index dcf41c2..7b2d914 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -2299,6 +2299,28 @@
}
+void Assembler::shldq(Register dst, Register src, Register shifter) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ ASSERT(shifter == RCX);
+ Operand operand(src);
+ EmitOperandREX(dst, operand, REX_W);
+ EmitUint8(0x0F);
+ EmitUint8(0xA5);
+ EmitOperand(src & 7, Operand(dst));
+}
+
+
+void Assembler::shrdq(Register dst, Register src, Register shifter) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ ASSERT(shifter == RCX);
+ Operand operand(src);
+ EmitOperandREX(dst, operand, REX_W);
+ EmitUint8(0x0F);
+ EmitUint8(0xAD);
+ EmitOperand(src & 7, Operand(dst));
+}
+
+
void Assembler::incl(const Address& address) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
Operand operand(address);
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 93ddd1f..861ccc5 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -627,6 +627,8 @@
void sarq(Register reg, const Immediate& imm);
void sarq(Register operand, Register shifter);
void shldq(Register dst, Register src, const Immediate& imm);
+ void shldq(Register dst, Register src, Register shifter);
+ void shrdq(Register dst, Register src, Register shifter);
void incl(const Address& address);
void decl(const Address& address);
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index 3a35086..85ee637 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -1389,6 +1389,42 @@
__ Bind(&donetest15b);
}
+ {
+ Label donetest15c;
+ const int64_t left = 0xff00000000000000;
+ const int64_t right = 0xffffffffffffffff;
+ const int64_t shifted = 0xf000000000000003;
+ __ movq(RDX, Immediate(left));
+ __ movq(RAX, Immediate(right));
+ __ movq(RCX, Immediate(2));
+ __ shlq(RDX, RCX); // RDX = 0xff00000000000000 << 2 == 0xfc00000000000000
+ __ shldq(RDX, RAX, RCX);
+ // RDX = high64(0xfc00000000000000:0xffffffffffffffff << 2)
+ // == 0xf000000000000003
+ __ cmpq(RDX, Immediate(shifted));
+ __ j(EQUAL, &donetest15c);
+ __ int3();
+ __ Bind(&donetest15c);
+ }
+
+ {
+ Label donetest15d;
+ const int64_t left = 0xff00000000000000;
+ const int64_t right = 0xffffffffffffffff;
+ const int64_t shifted = 0xcff0000000000000;
+ __ movq(RDX, Immediate(left));
+ __ movq(RAX, Immediate(right));
+ __ movq(RCX, Immediate(2));
+ __ shrq(RDX, RCX); // RDX = 0xff00000000000000 >> 2 == 0x3fc0000000000000
+ __ shrdq(RDX, RAX, RCX);
+ // RDX = low64(0xffffffffffffffff:0x3fc0000000000000 >> 2)
+ // == 0xcff0000000000000
+ __ cmpq(RDX, Immediate(shifted));
+ __ j(EQUAL, &donetest15d);
+ __ int3();
+ __ Bind(&donetest15d);
+ }
+
__ movl(RAX, Immediate(0));
__ ret();
}
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 7527d48..1ac1186 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -60,6 +60,7 @@
const int kNumIterations = 1000;
Timer timer(true, "CorelibIsolateStartup");
Isolate* isolate = Isolate::Current();
+ Thread::ExitIsolate();
for (int i = 0; i < kNumIterations; i++) {
timer.Start();
TestCase::CreateTestIsolate();
@@ -67,7 +68,7 @@
Dart_ShutdownIsolate();
}
benchmark->set_score(timer.TotalElapsedTime() / kNumIterations);
- Isolate::SetCurrent(isolate);
+ Thread::EnterIsolate(isolate);
}
@@ -428,16 +429,19 @@
"\n";
// Start an Isolate, load a script and create a full snapshot.
- uint8_t* buffer;
+ uint8_t* vm_isolate_snapshot_buffer;
+ uint8_t* isolate_snapshot_buffer;
// Need to load the script into the dart: core library due to
// the import of dart:_internal.
TestCase::LoadCoreTestScript(kScriptChars, NULL);
Api::CheckAndFinalizePendingClasses(Isolate::Current());
// Write snapshot with object content.
- FullSnapshotWriter writer(&buffer, &malloc_allocator);
+ FullSnapshotWriter writer(&vm_isolate_snapshot_buffer,
+ &isolate_snapshot_buffer,
+ &malloc_allocator);
writer.WriteFullSnapshot();
- const Snapshot* snapshot = Snapshot::SetupFromBuffer(buffer);
+ const Snapshot* snapshot = Snapshot::SetupFromBuffer(isolate_snapshot_buffer);
ASSERT(snapshot->kind() == Snapshot::kFull);
benchmark->set_score(snapshot->length());
}
@@ -459,16 +463,19 @@
"\n";
// Start an Isolate, load a script and create a full snapshot.
- uint8_t* buffer;
+ uint8_t* vm_isolate_snapshot_buffer;
+ uint8_t* isolate_snapshot_buffer;
// Need to load the script into the dart: core library due to
// the import of dart:_internal.
TestCase::LoadCoreTestScript(kScriptChars, NULL);
Api::CheckAndFinalizePendingClasses(Isolate::Current());
// Write snapshot with object content.
- FullSnapshotWriter writer(&buffer, &malloc_allocator);
+ FullSnapshotWriter writer(&vm_isolate_snapshot_buffer,
+ &isolate_snapshot_buffer,
+ &malloc_allocator);
writer.WriteFullSnapshot();
- const Snapshot* snapshot = Snapshot::SetupFromBuffer(buffer);
+ const Snapshot* snapshot = Snapshot::SetupFromBuffer(isolate_snapshot_buffer);
ASSERT(snapshot->kind() == Snapshot::kFull);
benchmark->set_score(snapshot->length());
}
diff --git a/runtime/vm/benchmark_test.h b/runtime/vm/benchmark_test.h
index 18ea0a5..b26a139 100644
--- a/runtime/vm/benchmark_test.h
+++ b/runtime/vm/benchmark_test.h
@@ -19,10 +19,14 @@
DECLARE_FLAG(int, code_heap_size);
DECLARE_FLAG(int, old_gen_growth_space_ratio);
-// snapshot_buffer points to a snapshot if we link in a snapshot otherwise
-// it is initialized to NULL.
namespace bin {
-extern const uint8_t* snapshot_buffer;
+// vm_isolate_snapshot_buffer points to a snapshot for the vm isolate if we
+// link in a snapshot otherwise it is initialized to NULL.
+extern const uint8_t* vm_isolate_snapshot_buffer;
+
+// isolate_snapshot_buffer points to a snapshot for an isolate if we link in a
+// snapshot otherwise it is initialized to NULL.
+extern const uint8_t* isolate_snapshot_buffer;
}
// The BENCHMARK macros are used for benchmarking a specific functionality
@@ -109,7 +113,7 @@
class BenchmarkIsolateScope {
public:
explicit BenchmarkIsolateScope(Benchmark* benchmark) : benchmark_(benchmark) {
- benchmark_->CreateIsolate(bin::snapshot_buffer);
+ benchmark_->CreateIsolate(bin::isolate_snapshot_buffer);
Dart_EnterScope(); // Create a Dart API scope for unit benchmarks.
}
~BenchmarkIsolateScope() {
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index c33cd26..f0ff462 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -314,8 +314,8 @@
V(ClassMirror_interfaces_instantiated, 1) \
V(ClassMirror_mixin, 1) \
V(ClassMirror_mixin_instantiated, 2) \
- V(ClassMirror_members, 2) \
- V(ClassMirror_constructors, 2) \
+ V(ClassMirror_members, 3) \
+ V(ClassMirror_constructors, 3) \
V(LibraryMirror_members, 2) \
V(LibraryMirror_libraryDependencies, 2) \
V(ClassMirror_invoke, 5) \
@@ -334,7 +334,7 @@
V(FunctionTypeMirror_call_method, 2) \
V(FunctionTypeMirror_parameters, 2) \
V(FunctionTypeMirror_return_type, 2) \
- V(MethodMirror_owner, 1) \
+ V(MethodMirror_owner, 2) \
V(MethodMirror_parameters, 2) \
V(MethodMirror_return_type, 2) \
V(MethodMirror_source, 1) \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index a7468b9..1ea33f3 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -510,6 +510,10 @@
void ClassFinalizer::FinalizeTypeParameters(
const Class& cls,
GrowableObjectArray* pending_types) {
+ if (FLAG_trace_type_finalization) {
+ OS::Print("Finalizing type parameters of '%s'\n",
+ String::Handle(cls.Name()).ToCString());
+ }
if (cls.IsMixinApplication()) {
// Setup the type parameters of the mixin application and finalize the
// mixin type.
@@ -817,6 +821,15 @@
if (error.IsNull() &&
!(type_arg.Equals(type_param) &&
instantiated_bound.Equals(declared_bound))) {
+ // If type_arg is a type parameter, its declared bound may not be
+ // resolved yet.
+ if (type_arg.IsTypeParameter()) {
+ const Class& type_arg_cls = Class::Handle(
+ TypeParameter::Cast(type_arg).parameterized_class());
+ const AbstractType& bound = AbstractType::Handle(
+ TypeParameter::Cast(type_arg).bound());
+ ResolveType(type_arg_cls, bound);
+ }
if (!type_param.CheckBound(type_arg, instantiated_bound, &error) &&
error.IsNull()) {
// The bound cannot be checked at compile time; postpone to run time.
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 1be6b66..aa4671f 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -1436,10 +1436,11 @@
ASSERT(optimized_code.is_optimized());
ICData::DeoptReasonId deopt_reason = ICData::kDeoptUnknown;
uint32_t deopt_flags = 0;
- const DeoptInfo& deopt_info = DeoptInfo::Handle(
+ const TypedData& deopt_info = TypedData::Handle(
optimized_code.GetDeoptInfoAtPc(pc, &deopt_reason, &deopt_flags));
ASSERT(!deopt_info.IsNull());
const Function& function = Function::Handle(optimized_code.function());
+ Compiler::EnsureUnoptimizedCode(Thread::Current(), function);
const Code& unoptimized_code = Code::Handle(function.unoptimized_code());
ASSERT(!unoptimized_code.IsNull());
// The switch to unoptimized code may have already occurred.
@@ -1573,9 +1574,7 @@
ASSERT(code.raw() == optimized_code.raw());
// Some sanity checking of the optimized/unoptimized code.
- const Code& unoptimized_code = Code::Handle(function.unoptimized_code());
ASSERT(!optimized_code.IsNull() && optimized_code.is_optimized());
- ASSERT(!unoptimized_code.IsNull() && !unoptimized_code.is_optimized());
}
#endif
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 77eb89f..47bd2ba 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -178,10 +178,10 @@
RawError* Compiler::Compile(const Library& library, const Script& script) {
- Isolate* volatile isolate = Isolate::Current();
- StackZone zone(isolate);
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
+ Isolate* const isolate = Isolate::Current();
+ StackZone zone(isolate);
if (FLAG_trace_compiler) {
const String& script_url = String::Handle(script.url());
// TODO(iposva): Extract script kind.
@@ -192,6 +192,8 @@
Parser::ParseCompilationUnit(library, script);
return Error::null();
} else {
+ Isolate* const isolate = Isolate::Current();
+ StackZone zone(isolate);
Error& error = Error::Handle();
error = isolate->object_store()->sticky_error();
isolate->object_store()->clear_sticky_error();
@@ -279,7 +281,7 @@
}
}
- Isolate* volatile isolate = Isolate::Current();
+ Isolate* const isolate = Isolate::Current();
// We remember all the classes that are being compiled in these lists. This
// also allows us to reset the marked_for_parsing state in case we see an
// error.
@@ -291,9 +293,9 @@
GrowableObjectArray::Handle(isolate, GrowableObjectArray::New(4));
// Parse the class and all the interfaces it implements and super classes.
- StackZone zone(isolate);
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
+ StackZone zone(isolate);
if (FLAG_trace_compiler) {
ISL_Print("Compiling Class %s '%s'\n", "", cls.ToCString());
}
@@ -352,7 +354,8 @@
parse_class.reset_is_marked_for_parsing();
}
}
-
+ Isolate* const isolate = Isolate::Current();
+ StackZone zone(isolate);
Error& error = Error::Handle(isolate);
error = isolate->object_store()->sticky_error();
isolate->object_store()->clear_sticky_error();
@@ -374,9 +377,9 @@
}
TimerScope timer(FLAG_compiler_stats, &CompilerStats::codegen_timer);
bool is_compiled = false;
- Thread* volatile thread = Thread::Current();
- Zone* volatile zone = thread->zone();
- Isolate* volatile isolate = thread->isolate();
+ Thread* const thread = Thread::Current();
+ Zone* const zone = thread->zone();
+ Isolate* const isolate = thread->isolate();
HANDLESCOPE(isolate);
// We may reattempt compilation if the function needs to be assembled using
@@ -842,7 +845,7 @@
if (deopt_table_length > 0) {
ISL_Print("DeoptInfo: {\n");
Smi& offset = Smi::Handle();
- DeoptInfo& info = DeoptInfo::Handle();
+ TypedData& info = TypedData::Handle();
Smi& reason_and_flags = Smi::Handle();
for (intptr_t i = 0; i < deopt_table_length; ++i) {
DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason_and_flags);
@@ -852,7 +855,7 @@
ISL_Print("%4" Pd ": 0x%" Px " %s (%s)\n",
i,
start + offset.Value(),
- info.ToCString(),
+ DeoptInfo::ToCString(deopt_table, info),
DeoptReasonToCString(
static_cast<ICData::DeoptReasonId>(reason)));
}
@@ -964,12 +967,12 @@
const Function& function,
bool optimized,
intptr_t osr_id) {
- Thread* volatile thread = Thread::Current();
- Isolate* volatile isolate = thread->isolate();
- StackZone stack_zone(isolate);
- Zone* volatile zone = stack_zone.GetZone();
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
+ Thread* const thread = Thread::Current();
+ Isolate* const isolate = thread->isolate();
+ StackZone stack_zone(isolate);
+ Zone* const zone = stack_zone.GetZone();
TIMERSCOPE(isolate, time_compilation);
Timer per_compile_timer(FLAG_trace_compiler, "Compilation time");
per_compile_timer.Start();
@@ -1032,6 +1035,9 @@
}
return Error::null();
} else {
+ Thread* const thread = Thread::Current();
+ Isolate* const isolate = thread->isolate();
+ StackZone stack_zone(isolate);
Error& error = Error::Handle();
// We got an error during compilation.
error = isolate->object_store()->sticky_error();
@@ -1052,6 +1058,35 @@
}
+void Compiler::EnsureUnoptimizedCode(Thread* thread,
+ const Function& function) {
+ if (function.unoptimized_code() != Object::null()) {
+ return;
+ }
+ Code& original_code = Code::ZoneHandle(thread->zone());
+ if (function.HasCode()) {
+ original_code = function.CurrentCode();
+ }
+ CompilationPipeline* pipeline =
+ CompilationPipeline::New(thread->zone(), function);
+ const Error& error = Error::Handle(
+ CompileFunctionHelper(pipeline, function, false, Isolate::kNoDeoptId));
+ if (!error.IsNull()) {
+ Exceptions::PropagateError(error);
+ }
+ // Since CompileFunctionHelper replaces the current code, re-attach the
+ // the original code if the function was already compiled.
+ if (!original_code.IsNull() &&
+ (original_code.raw() != function.CurrentCode())) {
+ function.AttachCode(original_code);
+ }
+ ASSERT(function.unoptimized_code() != Object::null());
+ if (FLAG_trace_compiler) {
+ ISL_Print("Ensure unoptimized code for %s\n", function.ToCString());
+ }
+}
+
+
RawError* Compiler::CompileOptimizedFunction(Thread* thread,
const Function& function,
intptr_t osr_id) {
@@ -1065,7 +1100,6 @@
// This is only used from unit tests.
RawError* Compiler::CompileParsedFunction(
ParsedFunction* parsed_function) {
- Isolate* volatile isolate = Isolate::Current();
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
// Non-optimized code generator.
@@ -1079,6 +1113,7 @@
}
return Error::null();
} else {
+ Isolate* const isolate = Isolate::Current();
Error& error = Error::Handle();
// We got an error during compilation.
error = isolate->object_store()->sticky_error();
@@ -1142,10 +1177,10 @@
// The VM sets the field's value to transiton_sentinel prior to
// evaluating the initializer value.
ASSERT(field.value() == Object::transition_sentinel().raw());
- Isolate* volatile isolate = Isolate::Current();
- StackZone zone(isolate);
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
+ Isolate* const isolate = Isolate::Current();
+ StackZone zone(isolate);
ParsedFunction* parsed_function =
Parser::ParseStaticFieldInitializer(field);
@@ -1163,6 +1198,8 @@
DartEntry::InvokeFunction(initializer, Object::empty_array()));
return result.raw();
} else {
+ Isolate* const isolate = Isolate::Current();
+ StackZone zone(isolate);
const Error& error =
Error::Handle(isolate, isolate->object_store()->sticky_error());
isolate->object_store()->clear_sticky_error();
@@ -1175,10 +1212,9 @@
RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
- Thread* volatile thread = Thread::Current();
- Isolate* volatile isolate = thread->isolate();
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
+ Thread* const thread = Thread::Current();
if (FLAG_trace_compiler) {
ISL_Print("compiling expression: ");
AstPrinter::PrintNode(fragment);
@@ -1228,6 +1264,8 @@
DartEntry::InvokeFunction(func, Object::empty_array()));
return result.raw();
} else {
+ Thread* const thread = Thread::Current();
+ Isolate* const isolate = thread->isolate();
const Object& result =
PassiveObject::Handle(isolate->object_store()->sticky_error());
isolate->object_store()->clear_sticky_error();
diff --git a/runtime/vm/compiler.h b/runtime/vm/compiler.h
index f9cc682..0e1f144 100644
--- a/runtime/vm/compiler.h
+++ b/runtime/vm/compiler.h
@@ -41,6 +41,9 @@
// Returns Error::null() if there is no compilation error.
static RawError* CompileFunction(Thread* thread, const Function& function);
+ // Generates unoptimized code if not present, current code is unchanged.
+ static void EnsureUnoptimizedCode(Thread* thread, const Function& function);
+
// Generates optimized code for function.
//
// Returns Error::null() if there is no compilation error.
diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc
index 62d0164..49af1e6 100644
--- a/runtime/vm/cpu_arm.cc
+++ b/runtime/vm/cpu_arm.cc
@@ -101,7 +101,6 @@
// This is for the DGBox. For the time-being, assume it is similar to the
// Lego Mindstorm.
arm_version_ = ARMv5TE;
- // TODO(zra): Verify with DGLogik that this is correct.
store_pc_read_offset_ = 12;
} else if (CpuInfo::FieldContains(kCpuInfoProcessor, "ARMv6") ||
CpuInfo::FieldContains(kCpuInfoModel, "ARMv6")) {
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index ffae666..a19208a 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -75,7 +75,8 @@
};
-const char* Dart::InitOnce(Dart_IsolateCreateCallback create,
+const char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
+ Dart_IsolateCreateCallback create,
Dart_IsolateInterruptCallback interrupt,
Dart_IsolateUnhandledExceptionCallback unhandled,
Dart_IsolateShutdownCallback shutdown,
@@ -138,6 +139,10 @@
return "SSE2 is required.";
}
#endif
+ if (vm_isolate_snapshot != NULL) {
+ // Initializing the VM isolate from a snapshot is not implemented yet.
+ USE(vm_isolate_snapshot);
+ }
Object::FinalizeVMIsolate(vm_isolate_);
}
// There is a planned and known asymmetry here: We enter one scope for the VM
@@ -146,7 +151,7 @@
Dart_EnterScope();
Api::InitHandles();
- Isolate::SetCurrent(NULL); // Unregister the VM isolate from this thread.
+ Thread::ExitIsolate(); // Unregister the VM isolate from this thread.
Isolate::SetCreateCallback(create);
Isolate::SetInterruptCallback(interrupt);
Isolate::SetUnhandledExceptionCallback(unhandled);
@@ -175,7 +180,7 @@
thread_pool_ = NULL;
// Set the VM isolate as current isolate.
- Isolate::SetCurrent(vm_isolate_);
+ Thread::EnterIsolate(vm_isolate_);
// There is a planned and known asymmetry here: We exit one scope for the VM
// isolate to account for the scope that was entered in Dart_InitOnce.
diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h
index 135c6b0..470b3ff 100644
--- a/runtime/vm/dart.h
+++ b/runtime/vm/dart.h
@@ -20,6 +20,7 @@
class Dart : public AllStatic {
public:
static const char* InitOnce(
+ const uint8_t* vm_isolate_snapshot,
Dart_IsolateCreateCallback create,
Dart_IsolateInterruptCallback interrupt,
Dart_IsolateUnhandledExceptionCallback unhandled,
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 6dd2be2..f30f365 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1200,6 +1200,7 @@
}
DART_EXPORT bool Dart_Initialize(
+ const uint8_t* vm_isolate_snapshot,
Dart_IsolateCreateCallback create,
Dart_IsolateInterruptCallback interrupt,
Dart_IsolateUnhandledExceptionCallback unhandled,
@@ -1209,7 +1210,8 @@
Dart_FileWriteCallback file_write,
Dart_FileCloseCallback file_close,
Dart_EntropySource entropy_source) {
- const char* err_msg = Dart::InitOnce(create, interrupt, unhandled, shutdown,
+ const char* err_msg = Dart::InitOnce(vm_isolate_snapshot,
+ create, interrupt, unhandled, shutdown,
file_open, file_read, file_write,
file_close, entropy_source);
if (err_msg != NULL) {
@@ -1284,7 +1286,7 @@
const uint8_t* snapshot,
void* callback_data,
char** error) {
- TRACE_API_CALL(CURRENT_FUNC);
+ CHECK_NO_ISOLATE(Isolate::Current());
char* isolate_name = BuildIsolateName(script_uri, main);
Isolate* isolate = Dart::CreateIsolate(isolate_name);
free(isolate_name);
@@ -1356,7 +1358,10 @@
CHECK_NO_ISOLATE(Isolate::Current());
// TODO(16615): Validate isolate parameter.
Isolate* iso = reinterpret_cast<Isolate*>(isolate);
- Isolate::SetCurrent(iso);
+ if (iso->mutator_thread() != NULL) {
+ FATAL("Multiple mutators within one isolate is not supported.");
+ }
+ Thread::EnterIsolate(iso);
}
@@ -1384,7 +1389,7 @@
DART_EXPORT void Dart_ExitIsolate() {
CHECK_ISOLATE(Isolate::Current());
- Isolate::SetCurrent(NULL);
+ Thread::ExitIsolate();
}
@@ -1408,16 +1413,25 @@
}
-DART_EXPORT Dart_Handle Dart_CreateSnapshot(uint8_t** buffer,
- intptr_t* size) {
+DART_EXPORT Dart_Handle Dart_CreateSnapshot(
+ uint8_t** vm_isolate_snapshot_buffer,
+ intptr_t* vm_isolate_snapshot_size,
+ uint8_t** isolate_snapshot_buffer,
+ intptr_t* isolate_snapshot_size) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
TIMERSCOPE(isolate, time_creating_snapshot);
- if (buffer == NULL) {
- RETURN_NULL_ERROR(buffer);
+ if (vm_isolate_snapshot_buffer == NULL) {
+ RETURN_NULL_ERROR(vm_isolate_snapshot_buffer);
}
- if (size == NULL) {
- RETURN_NULL_ERROR(size);
+ if (vm_isolate_snapshot_size == NULL) {
+ RETURN_NULL_ERROR(vm_isolate_snapshot_size);
+ }
+ if (isolate_snapshot_buffer == NULL) {
+ RETURN_NULL_ERROR(isolate_snapshot_buffer);
+ }
+ if (isolate_snapshot_size == NULL) {
+ RETURN_NULL_ERROR(isolate_snapshot_size);
}
// Finalize all classes if needed.
Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
@@ -1426,9 +1440,12 @@
}
// Since this is only a snapshot the root library should not be set.
isolate->object_store()->set_root_library(Library::Handle(isolate));
- FullSnapshotWriter writer(buffer, ApiReallocate);
+ FullSnapshotWriter writer(vm_isolate_snapshot_buffer,
+ isolate_snapshot_buffer,
+ ApiReallocate);
writer.WriteFullSnapshot();
- *size = writer.BytesWritten();
+ *vm_isolate_snapshot_size = writer.VmIsolateSnapshotSize();
+ *isolate_snapshot_size = writer.IsolateSnapshotSize();
return Api::Success();
}
@@ -1594,6 +1611,9 @@
DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle handle) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
+ if (port_id == ILLEGAL_PORT) {
+ return false;
+ }
const Object& object = Object::Handle(isolate, Api::UnwrapHandle(handle));
uint8_t* data = NULL;
MessageWriter writer(&data, &allocator, false);
@@ -1608,6 +1628,11 @@
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
CHECK_CALLBACK_STATE(isolate);
+ if (port_id == ILLEGAL_PORT) {
+ return Api::NewError("%s: illegal port_id %" Pd64 ".",
+ CURRENT_FUNC,
+ port_id);
+ }
return Api::NewHandle(isolate, SendPort::New(port_id));
}
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index c3f9fb5..46f85aa 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -291,7 +291,10 @@
: saved_isolate_(current_isolate) {
}
~IsolateSaver() {
- Isolate::SetCurrent(saved_isolate_);
+ // TODO(koda): Audit users; they should know whether they're in an isolate.
+ if (saved_isolate_ != NULL) {
+ Thread::EnterIsolate(saved_isolate_);
+ }
}
private:
Isolate* saved_isolate_;
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index fe7c5ea..c439b41 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -20,6 +20,7 @@
namespace dart {
DECLARE_FLAG(bool, enable_type_checks);
+DECLARE_FLAG(int, optimization_counter_threshold);
DECLARE_FLAG(bool, verify_acquired_data);
TEST_CASE(ErrorHandleBasics) {
@@ -1742,6 +1743,74 @@
}
+static const intptr_t kOptExtLength = 16;
+static int8_t opt_data[kOptExtLength] = { 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x10, };
+
+static void OptExternalByteDataNativeFunction(Dart_NativeArguments args) {
+ Dart_EnterScope();
+ Dart_Handle external_byte_data = Dart_NewExternalTypedData(
+ Dart_TypedData_kByteData, opt_data, 16);
+ EXPECT_VALID(external_byte_data);
+ EXPECT_EQ(Dart_TypedData_kByteData,
+ Dart_GetTypeOfTypedData(external_byte_data));
+ Dart_SetReturnValue(args, external_byte_data);
+ Dart_ExitScope();
+}
+
+
+static Dart_NativeFunction OptExternalByteDataNativeResolver(
+ Dart_Handle name, int arg_count, bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
+ return &OptExternalByteDataNativeFunction;
+}
+
+
+TEST_CASE(OptimizedExternalByteDataAccess) {
+ const char* kScriptChars =
+ "import 'dart:typed_data';\n"
+ "class Expect {\n"
+ " static equals(a, b) {\n"
+ " if (a != b) {\n"
+ " throw 'not equal. expected: $a, got: $b';\n"
+ " }\n"
+ " }\n"
+ "}\n"
+ "ByteData createExternalByteData() native 'CreateExternalByteData';"
+ "access(ByteData a) {"
+ " Expect.equals(0x04030201, a.getUint32(0, Endianness.LITTLE_ENDIAN));"
+ " Expect.equals(0x08070605, a.getUint32(4, Endianness.LITTLE_ENDIAN));"
+ " Expect.equals(0x0c0b0a09, a.getUint32(8, Endianness.LITTLE_ENDIAN));"
+ " Expect.equals(0x100f0e0d, a.getUint32(12, Endianness.LITTLE_ENDIAN));"
+ "}"
+ "ByteData main() {"
+ " var length = 16;"
+ " var a = createExternalByteData();"
+ " Expect.equals(length, a.lengthInBytes);"
+ " for (int i = 0; i < 20; i++) {"
+ " access(a);"
+ " }"
+ " return a;"
+ "}\n";
+ // Create a test library and Load up a test script in it.
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+
+ Dart_Handle result = Dart_SetNativeResolver(
+ lib, &OptExternalByteDataNativeResolver, NULL);
+ EXPECT_VALID(result);
+
+ // Invoke 'main' function.
+ int old_oct = FLAG_optimization_counter_threshold;
+ FLAG_optimization_counter_threshold = 5;
+ result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+ FLAG_optimization_counter_threshold = old_oct;
+}
+
+
static void TestTypedDataDirectAccess() {
Dart_Handle str = Dart_NewStringFromCString("junk");
Dart_Handle byte_array = Dart_NewTypedData(Dart_TypedData_kUint8, 10);
@@ -3619,7 +3688,7 @@
intptr_t mydata = 12345;
char* err;
Dart_Isolate isolate =
- Dart_CreateIsolate(NULL, NULL, bin::snapshot_buffer,
+ Dart_CreateIsolate(NULL, NULL, bin::isolate_snapshot_buffer,
reinterpret_cast<void*>(mydata),
&err);
EXPECT(isolate != NULL);
@@ -7141,6 +7210,20 @@
}
+TEST_CASE(IllegalNewSendPort) {
+ Dart_Handle error = Dart_NewSendPort(ILLEGAL_PORT);
+ EXPECT(Dart_IsError(error));
+ EXPECT(Dart_IsApiError(error));
+}
+
+
+TEST_CASE(IllegalPost) {
+ Dart_Handle message = Dart_True();
+ bool success = Dart_Post(ILLEGAL_PORT, message);
+ EXPECT(!success);
+}
+
+
UNIT_TEST_CASE(NewNativePort) {
// Create a port with a bogus handler.
Dart_Port error_port = Dart_NewNativePort("Foo", NULL, true);
@@ -7378,7 +7461,7 @@
MonitorLocker ml(sync);
char* error = NULL;
shared_isolate = Dart_CreateIsolate(NULL, NULL,
- bin::snapshot_buffer,
+ bin::isolate_snapshot_buffer,
NULL, &error);
EXPECT(shared_isolate != NULL);
Dart_EnterScope();
@@ -7506,7 +7589,7 @@
// Create an isolate.
char* err;
Dart_Isolate isolate = Dart_CreateIsolate(NULL, NULL,
- bin::snapshot_buffer,
+ bin::isolate_snapshot_buffer,
my_data, &err);
if (isolate == NULL) {
OS::Print("Creation of isolate failed '%s'\n", err);
@@ -7556,7 +7639,7 @@
// Create an isolate.
char* err;
Dart_Isolate isolate = Dart_CreateIsolate(NULL, NULL,
- bin::snapshot_buffer,
+ bin::isolate_snapshot_buffer,
NULL, &err);
if (isolate == NULL) {
OS::Print("Creation of isolate failed '%s'\n", err);
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 3ffa06b..75a2b1c 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -221,7 +221,7 @@
bool Debugger::HasEventHandler() {
- return (event_handler_ != NULL) || Service::NeedsDebuggerEvents();
+ return (event_handler_ != NULL) || Service::NeedsEvents();
}
@@ -233,7 +233,7 @@
//
// kBreakpointResolved events are handled differently in the vm
// service, so suppress them here.
- if (Service::NeedsDebuggerEvents() &&
+ if (Service::NeedsEvents() &&
(event->type() != DebuggerEvent::kBreakpointResolved)) {
ServiceEvent service_event(event);
Service::HandleEvent(&service_event);
@@ -243,7 +243,7 @@
(*event_handler_)(event);
}
- if (Service::NeedsDebuggerEvents() && event->IsPauseEvent()) {
+ if (Service::NeedsEvents() && event->IsPauseEvent()) {
// If we were paused, notify the service that we have resumed.
ServiceEvent service_event(event->isolate(), ServiceEvent::kResume);
service_event.set_top_frame(event->top_frame());
@@ -286,7 +286,7 @@
// than the regular debugger breakpoint notifications.
static void SendServiceBreakpointEvent(ServiceEvent::EventType type,
SourceBreakpoint* bpt) {
- if (Service::NeedsDebuggerEvents() /*&& !bpt->IsOneShot()*/) {
+ if (Service::NeedsEvents()) {
ServiceEvent service_event(Isolate::Current(), type);
service_event.set_breakpoint(bpt);
Service::HandleEvent(&service_event);
@@ -1643,8 +1643,7 @@
for (intptr_t pos = 0; pos < num_functions; pos++) {
function ^= functions.At(pos);
ASSERT(!function.IsNull());
- if (function.is_debuggable() &&
- FunctionContains(function, script, token_pos)) {
+ if (FunctionContains(function, script, token_pos)) {
SelectBestFit(&best_fit, &function);
}
}
@@ -1656,8 +1655,7 @@
for (intptr_t pos = 0; pos < num_closures; pos++) {
function ^= closures.At(pos);
ASSERT(!function.IsNull());
- if (function.is_debuggable() &&
- FunctionContains(function, script, token_pos)) {
+ if (FunctionContains(function, script, token_pos)) {
SelectBestFit(&best_fit, &function);
}
}
diff --git a/runtime/vm/deferred_objects.cc b/runtime/vm/deferred_objects.cc
index ef76a00..2727f10 100644
--- a/runtime/vm/deferred_objects.cc
+++ b/runtime/vm/deferred_objects.cc
@@ -4,12 +4,15 @@
#include "vm/deferred_objects.h"
+#include "vm/code_patcher.h"
+#include "vm/compiler.h"
#include "vm/deopt_instructions.h"
#include "vm/flags.h"
#include "vm/object.h"
namespace dart {
+DECLARE_FLAG(bool, trace_deoptimization);
DECLARE_FLAG(bool, trace_deoptimization_verbose);
@@ -97,6 +100,112 @@
}
+void DeferredRetAddr::Materialize(DeoptContext* deopt_context) {
+ Function& function = Function::Handle(deopt_context->zone());
+ function ^= deopt_context->ObjectAt(index_);
+ Compiler::EnsureUnoptimizedCode(deopt_context->thread(), function);
+ const Code& code =
+ Code::Handle(deopt_context->zone(), function.unoptimized_code());
+ // Check that deopt_id exists.
+ // TODO(vegorov): verify after deoptimization targets as well.
+#ifdef DEBUG
+ ASSERT(Isolate::IsDeoptAfter(deopt_id_) ||
+ (code.GetPcForDeoptId(deopt_id_, RawPcDescriptors::kDeopt) != 0));
+#endif
+
+ uword continue_at_pc = code.GetPcForDeoptId(deopt_id_,
+ RawPcDescriptors::kDeopt);
+ ASSERT(continue_at_pc != 0);
+ uword* dest_addr = reinterpret_cast<uword*>(slot());
+ *dest_addr = continue_at_pc;
+
+ if (FLAG_trace_deoptimization_verbose) {
+ OS::PrintErr("materializing return addr at 0x%" Px ": 0x%" Px "\n",
+ reinterpret_cast<uword>(slot()), continue_at_pc);
+ }
+
+ uword pc = code.GetPcForDeoptId(deopt_id_, RawPcDescriptors::kIcCall);
+ if (pc != 0) {
+ // If the deoptimization happened at an IC call, update the IC data
+ // to avoid repeated deoptimization at the same site next time around.
+ ICData& ic_data = ICData::Handle();
+ CodePatcher::GetInstanceCallAt(pc, code, &ic_data);
+ if (!ic_data.IsNull()) {
+ ic_data.AddDeoptReason(deopt_context->deopt_reason());
+ }
+ } else {
+ if (deopt_context->HasDeoptFlag(ICData::kHoisted)) {
+ // Prevent excessive deoptimization.
+ function.set_allows_hoisting_check_class(false);
+ }
+
+ if (deopt_context->HasDeoptFlag(ICData::kGeneralized)) {
+ function.set_allows_bounds_check_generalization(false);
+ }
+ }
+}
+
+
+void DeferredPcMarker::Materialize(DeoptContext* deopt_context) {
+ uword* dest_addr = reinterpret_cast<uword*>(slot());
+ Function& function = Function::Handle(deopt_context->zone());
+ function ^= deopt_context->ObjectAt(index_);
+ if (function.IsNull()) {
+ // Callee's PC marker is not used (pc of Deoptimize stub). Set to 0.
+ *dest_addr = 0;
+ return;
+ }
+ Compiler::EnsureUnoptimizedCode(deopt_context->thread(), function);
+ const Code& code =
+ Code::Handle(deopt_context->zone(), function.unoptimized_code());
+ ASSERT(!code.IsNull());
+ ASSERT(function.HasCode());
+ const intptr_t pc_marker =
+ code.EntryPoint() + Assembler::EntryPointToPcMarkerOffset();
+ *dest_addr = pc_marker;
+
+ if (FLAG_trace_deoptimization_verbose) {
+ OS::PrintErr("materializing pc marker at 0x%" Px ": %s, %s\n",
+ reinterpret_cast<uword>(slot()), code.ToCString(),
+ function.ToCString());
+ }
+
+ // Increment the deoptimization counter. This effectively increments each
+ // function occurring in the optimized frame.
+ function.set_deoptimization_counter(function.deoptimization_counter() + 1);
+ if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
+ OS::PrintErr("Deoptimizing %s (count %d)\n",
+ function.ToFullyQualifiedCString(),
+ function.deoptimization_counter());
+ }
+ // Clear invocation counter so that hopefully the function gets reoptimized
+ // only after more feedback has been collected.
+ function.set_usage_counter(0);
+ if (function.HasOptimizedCode()) {
+ function.SwitchToUnoptimizedCode();
+ }
+}
+
+
+void DeferredPp::Materialize(DeoptContext* deopt_context) {
+ Function& function = Function::Handle(deopt_context->zone());
+ function ^= deopt_context->ObjectAt(index_);
+ ASSERT(!function.IsNull());
+ Compiler::EnsureUnoptimizedCode(deopt_context->thread(), function);
+ const Code& code =
+ Code::Handle(deopt_context->zone(), function.unoptimized_code());
+ ASSERT(!code.IsNull());
+ ASSERT(code.ObjectPool() != Object::null());
+ *slot() = code.ObjectPool();
+
+ if (FLAG_trace_deoptimization_verbose) {
+ OS::PrintErr("materializing pp at 0x%" Px ": 0x%" Px "\n",
+ reinterpret_cast<uword>(slot()),
+ reinterpret_cast<uword>(code.ObjectPool()));
+ }
+}
+
+
RawObject* DeferredObject::object() {
if (object_ == NULL) {
Create();
diff --git a/runtime/vm/deferred_objects.h b/runtime/vm/deferred_objects.h
index 0077388..35556f8 100644
--- a/runtime/vm/deferred_objects.h
+++ b/runtime/vm/deferred_objects.h
@@ -140,6 +140,58 @@
};
+class DeferredRetAddr : public DeferredSlot {
+ public:
+ DeferredRetAddr(intptr_t index,
+ intptr_t deopt_id,
+ RawObject** slot,
+ DeferredSlot* next)
+ : DeferredSlot(slot, next), index_(index), deopt_id_(deopt_id) { }
+
+ virtual void Materialize(DeoptContext* deopt_context);
+
+ intptr_t index() const { return index_; }
+
+ private:
+ const intptr_t index_;
+ const intptr_t deopt_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeferredRetAddr);
+};
+
+
+class DeferredPcMarker : public DeferredSlot {
+ public:
+ DeferredPcMarker(intptr_t index, RawObject** slot, DeferredSlot* next)
+ : DeferredSlot(slot, next), index_(index) { }
+
+ virtual void Materialize(DeoptContext* deopt_context);
+
+ intptr_t index() const { return index_; }
+
+ private:
+ const intptr_t index_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeferredPcMarker);
+};
+
+
+class DeferredPp : public DeferredSlot {
+ public:
+ DeferredPp(intptr_t index, RawObject** slot, DeferredSlot* next)
+ : DeferredSlot(slot, next), index_(index) { }
+
+ virtual void Materialize(DeoptContext* deopt_context);
+
+ intptr_t index() const { return index_; }
+
+ private:
+ const intptr_t index_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeferredPp);
+};
+
+
// Describes an object which allocation was removed by AllocationSinking pass.
// Arguments for materialization are stored as a part of expression stack
// for the bottommost deoptimized frame so that GC could discover them.
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 26b0066..401f2ba 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -6,6 +6,7 @@
#include "vm/assembler.h"
#include "vm/code_patcher.h"
+#include "vm/compiler.h"
#include "vm/intermediate_language.h"
#include "vm/locations.h"
#include "vm/parser.h"
@@ -27,7 +28,7 @@
intptr_t* cpu_registers)
: code_(code.raw()),
object_table_(code.object_table()),
- deopt_info_(DeoptInfo::null()),
+ deopt_info_(TypedData::null()),
dest_frame_is_allocated_(false),
dest_frame_(NULL),
dest_frame_size_(0),
@@ -43,7 +44,7 @@
deferred_slots_(NULL),
deferred_objects_count_(0),
deferred_objects_(NULL) {
- const DeoptInfo& deopt_info = DeoptInfo::Handle(
+ const TypedData& deopt_info = TypedData::Handle(
code.GetDeoptInfoAtPc(frame->pc(), &deopt_reason_, &deopt_flags_));
ASSERT(!deopt_info.IsNull());
deopt_info_ = deopt_info.raw();
@@ -80,7 +81,7 @@
}
caller_fp_ = GetSourceFp();
- dest_frame_size_ = deopt_info.FrameSize();
+ dest_frame_size_ = DeoptInfo::FrameSize(deopt_info);
if (dest_options == kDestIsAllocated) {
dest_frame_ = new intptr_t[dest_frame_size_];
@@ -203,7 +204,6 @@
case DeoptInstr::kCallerPc:
return false;
- case DeoptInstr::kSuffix:
case DeoptInstr::kMaterializeObject:
default:
// We should not encounter these instructions when filling stack slots.
@@ -217,15 +217,15 @@
void DeoptContext::FillDestFrame() {
const Code& code = Code::Handle(code_);
- const DeoptInfo& deopt_info = DeoptInfo::Handle(deopt_info_);
+ const TypedData& deopt_info = TypedData::Handle(deopt_info_);
- const intptr_t len = deopt_info.TranslationLength();
- GrowableArray<DeoptInstr*> deopt_instructions(len);
+ GrowableArray<DeoptInstr*> deopt_instructions;
const Array& deopt_table = Array::Handle(code.deopt_info_array());
ASSERT(!deopt_table.IsNull());
- deopt_info.ToInstructions(deopt_table, &deopt_instructions);
+ DeoptInfo::Unpack(deopt_table, deopt_info, &deopt_instructions);
- const intptr_t frame_size = deopt_info.FrameSize();
+ const intptr_t len = deopt_instructions.length();
+ const intptr_t frame_size = dest_frame_size_;
// For now, we never place non-objects in the deoptimized frame if
// the destination frame is a copy. This allows us to copy the
@@ -240,7 +240,8 @@
// described as part of the expression stack for the bottom-most deoptimized
// frame. They will be used during materialization and removed from the stack
// right before control switches to the unoptimized code.
- const intptr_t num_materializations = deopt_info.NumMaterializations();
+ const intptr_t num_materializations =
+ DeoptInfo::NumMaterializations(deopt_instructions);
PrepareForDeferredMaterialization(num_materializations);
for (intptr_t from_index = 0, to_index = kDartFrameFixedSize;
from_index < num_materializations;
@@ -377,34 +378,9 @@
}
void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
- Code& code = Code::Handle(deopt_context->zone());
- code ^= deopt_context->ObjectAt(object_table_index_);
- ASSERT(!code.IsNull());
- uword continue_at_pc = code.GetPcForDeoptId(deopt_id_,
- RawPcDescriptors::kDeopt);
- ASSERT(continue_at_pc != 0);
- *dest_addr = continue_at_pc;
-
- uword pc = code.GetPcForDeoptId(deopt_id_, RawPcDescriptors::kIcCall);
- if (pc != 0) {
- // If the deoptimization happened at an IC call, update the IC data
- // to avoid repeated deoptimization at the same site next time around.
- ICData& ic_data = ICData::Handle();
- CodePatcher::GetInstanceCallAt(pc, code, &ic_data);
- if (!ic_data.IsNull()) {
- ic_data.AddDeoptReason(deopt_context->deopt_reason());
- }
- } else {
- const Function& function = Function::Handle(code.function());
- if (deopt_context->HasDeoptFlag(ICData::kHoisted)) {
- // Prevent excessive deoptimization.
- function.set_allows_hoisting_check_class(false);
- }
-
- if (deopt_context->HasDeoptFlag(ICData::kGeneralized)) {
- function.set_allows_bounds_check_generalization(false);
- }
- }
+ *dest_addr = Smi::RawValue(0);
+ deopt_context->DeferRetAddrMaterialization(
+ object_table_index_, deopt_id_, dest_addr);
}
intptr_t object_table_index() const { return object_table_index_; }
@@ -641,33 +617,9 @@
}
void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
- Code& code = Code::Handle(deopt_context->zone());
- code ^= deopt_context->ObjectAt(object_table_index_);
- if (code.IsNull()) {
- // Callee's PC marker is not used (pc of Deoptimize stub). Set to 0.
- *dest_addr = 0;
- return;
- }
- const Function& function =
- Function::Handle(deopt_context->zone(), code.function());
- ASSERT(function.HasCode());
- const intptr_t pc_marker =
- code.EntryPoint() + Assembler::EntryPointToPcMarkerOffset();
- *dest_addr = pc_marker;
- // Increment the deoptimization counter. This effectively increments each
- // function occurring in the optimized frame.
- function.set_deoptimization_counter(function.deoptimization_counter() + 1);
- if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
- OS::PrintErr("Deoptimizing %s (count %d)\n",
- function.ToFullyQualifiedCString(),
- function.deoptimization_counter());
- }
- // Clear invocation counter so that hopefully the function gets reoptimized
- // only after more feedback has been collected.
- function.set_usage_counter(0);
- if (function.HasOptimizedCode()) {
- function.SwitchToUnoptimizedCode();
- }
+ *dest_addr = Smi::RawValue(0);
+ deopt_context->DeferPcMarkerMaterialization(
+ object_table_index_, dest_addr);
}
private:
@@ -695,11 +647,9 @@
}
void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
- Code& code = Code::Handle(deopt_context->zone());
- code ^= deopt_context->ObjectAt(object_table_index_);
- ASSERT(!code.IsNull());
- const intptr_t pp = reinterpret_cast<intptr_t>(code.ObjectPool());
- *dest_addr = pp;
+ *dest_addr = Smi::RawValue(0);
+ deopt_context->DeferPpMaterialization(object_table_index_,
+ reinterpret_cast<RawObject**>(dest_addr));
}
private:
@@ -763,56 +713,6 @@
};
-// Deoptimization instruction that indicates the rest of this DeoptInfo is a
-// suffix of another one. The suffix contains the info number (0 based
-// index in the deopt table of the DeoptInfo to share) and the length of the
-// suffix.
-class DeoptSuffixInstr : public DeoptInstr {
- public:
- DeoptSuffixInstr(intptr_t info_number, intptr_t suffix_length)
- : info_number_(info_number), suffix_length_(suffix_length) {
- ASSERT(info_number >= 0);
- ASSERT(suffix_length >= 0);
- }
-
- explicit DeoptSuffixInstr(intptr_t source_index)
- : info_number_(InfoNumber::decode(source_index)),
- suffix_length_(SuffixLength::decode(source_index)) {
- }
-
- virtual intptr_t source_index() const {
- return InfoNumber::encode(info_number_) |
- SuffixLength::encode(suffix_length_);
- }
- virtual DeoptInstr::Kind kind() const { return kSuffix; }
-
- virtual const char* ArgumentsToCString() const {
- return Thread::Current()->zone()->PrintToString(
- "%" Pd ":%" Pd, info_number_, suffix_length_);
- }
-
- void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
- // The deoptimization info is uncompressed by translating away suffixes
- // before executing the instructions.
- UNREACHABLE();
- }
-
- private:
- // Static decoder functions in DeoptInstr have access to the bitfield
- // definitions.
- friend class DeoptInstr;
-
- static const intptr_t kFieldWidth = kBitsPerWord / 2;
- class InfoNumber : public BitField<intptr_t, 0, kFieldWidth> { };
- class SuffixLength : public BitField<intptr_t, kFieldWidth, kFieldWidth> { };
-
- const intptr_t info_number_;
- const intptr_t suffix_length_;
-
- DISALLOW_COPY_AND_ASSIGN(DeoptSuffixInstr);
-};
-
-
// Write reference to a materialized object with the given index into the
// stack slot.
class DeoptMaterializedObjectRefInstr : public DeoptInstr {
@@ -873,13 +773,6 @@
};
-intptr_t DeoptInstr::DecodeSuffix(intptr_t source_index,
- intptr_t* info_number) {
- *info_number = DeoptSuffixInstr::InfoNumber::decode(source_index);
- return DeoptSuffixInstr::SuffixLength::decode(source_index);
-}
-
-
uword DeoptInstr::GetRetAddress(DeoptInstr* instr,
const Array& object_table,
Code* code) {
@@ -890,8 +783,11 @@
// from the simulator.
ASSERT(Isolate::IsDeoptAfter(ret_address_instr->deopt_id()));
ASSERT(!object_table.IsNull());
+ Function& function = Function::Handle();
+ function ^= object_table.At(ret_address_instr->object_table_index());
ASSERT(code != NULL);
- *code ^= object_table.At(ret_address_instr->object_table_index());
+ Compiler::EnsureUnoptimizedCode(Thread::Current(), function);
+ *code ^= function.unoptimized_code();
ASSERT(!code->IsNull());
uword res = code->GetPcForDeoptId(ret_address_instr->deopt_id(),
RawPcDescriptors::kDeopt);
@@ -935,8 +831,6 @@
return new DeoptCallerPpInstr();
case kCallerPc:
return new DeoptCallerPcInstr();
- case kSuffix:
- return new DeoptSuffixInstr(source_index);
case kMaterializedObjectRef:
return new DeoptMaterializedObjectRefInstr(source_index);
case kMaterializeObject:
@@ -980,8 +874,6 @@
return "callerpp";
case kCallerPc:
return "callerpc";
- case kSuffix:
- return "suffix";
case kMaterializedObjectRef:
return "ref";
case kMaterializeObject:
@@ -1083,33 +975,27 @@
}
}
-void DeoptInfoBuilder::AddReturnAddress(const Code& code,
+void DeoptInfoBuilder::AddReturnAddress(const Function& function,
intptr_t deopt_id,
intptr_t dest_index) {
- // Check that deopt_id exists.
- // TODO(vegorov): verify after deoptimization targets as well.
-#ifdef DEBUG
- ASSERT(Isolate::IsDeoptAfter(deopt_id) ||
- (code.GetPcForDeoptId(deopt_id, RawPcDescriptors::kDeopt) != 0));
-#endif
- const intptr_t object_table_index = FindOrAddObjectInTable(code);
+ const intptr_t object_table_index = FindOrAddObjectInTable(function);
ASSERT(dest_index == FrameSize());
instructions_.Add(
new(zone()) DeoptRetAddressInstr(object_table_index, deopt_id));
}
-void DeoptInfoBuilder::AddPcMarker(const Code& code,
+void DeoptInfoBuilder::AddPcMarker(const Function& function,
intptr_t dest_index) {
- intptr_t object_table_index = FindOrAddObjectInTable(code);
+ intptr_t object_table_index = FindOrAddObjectInTable(function);
ASSERT(dest_index == FrameSize());
instructions_.Add(new(zone()) DeoptPcMarkerInstr(object_table_index));
}
-void DeoptInfoBuilder::AddPp(const Code& code,
+void DeoptInfoBuilder::AddPp(const Function& function,
intptr_t dest_index) {
- intptr_t object_table_index = FindOrAddObjectInTable(code);
+ intptr_t object_table_index = FindOrAddObjectInTable(function);
ASSERT(dest_index == FrameSize());
instructions_.Add(new(zone()) DeoptPpInstr(object_table_index));
}
@@ -1269,19 +1155,22 @@
}
-RawDeoptInfo* DeoptInfoBuilder::CreateDeoptInfo(const Array& deopt_table) {
- // TODO(vegorov): enable compression of deoptimization info containing object
- // materialization instructions.
- const bool disable_compression =
- (instructions_[0]->kind() == DeoptInstr::kMaterializeObject);
+static uint8_t* ZoneReAlloc(uint8_t* ptr,
+ intptr_t old_size,
+ intptr_t new_size) {
+ return Isolate::Current()->current_zone()->Realloc<uint8_t>(
+ ptr, old_size, new_size);
+}
+
+RawTypedData* DeoptInfoBuilder::CreateDeoptInfo(const Array& deopt_table) {
intptr_t length = instructions_.length();
// Count the number of instructions that are a shared suffix of some deopt
// info already written.
TrieNode* suffix = trie_root_;
intptr_t suffix_length = 0;
- if (FLAG_compress_deopt_info && !disable_compression) {
+ if (FLAG_compress_deopt_info) {
for (intptr_t i = length - 1; i >= 0; --i) {
TrieNode* node = suffix->FindChild(*instructions_[i]);
if (node == NULL) break;
@@ -1290,33 +1179,51 @@
}
}
+
// Allocate space for the translation. If the shared suffix is longer
// than one instruction, we replace it with a single suffix instruction.
- if (suffix_length > 1) length -= (suffix_length - 1);
- const DeoptInfo& deopt_info =
- DeoptInfo::Handle(zone(), DeoptInfo::New(length));
+ const bool use_suffix = suffix_length > 1;
+ if (use_suffix) {
+ length -= (suffix_length - 1);
+ }
+
+ uint8_t* buffer;
+ typedef WriteStream::Raw<sizeof(intptr_t), intptr_t> Writer;
+ WriteStream stream(&buffer, ZoneReAlloc, 2 * length * kWordSize);
+
+ Writer::Write(&stream, FrameSize());
+
+ if (use_suffix) {
+ Writer::Write(&stream, suffix_length);
+ Writer::Write(&stream, suffix->info_number());
+ } else {
+ Writer::Write(&stream, 0);
+ }
// Write the unshared instructions and build their sub-tree.
- TrieNode* node = NULL;
- intptr_t write_count = (suffix_length > 1) ? length - 1 : length;
- for (intptr_t i = 0; i < write_count; ++i) {
+ TrieNode* node = use_suffix ? suffix : trie_root_;
+ const intptr_t write_count = use_suffix ? length - 1 : length;
+ for (intptr_t i = write_count - 1; i >= 0; --i) {
DeoptInstr* instr = instructions_[i];
- deopt_info.SetAt(i, instr->kind(), instr->source_index());
- TrieNode* child = node;
- node = new(zone()) TrieNode(instr, current_info_number_);
+ Writer::Write(&stream, instr->kind());
+ Writer::Write(&stream, instr->source_index());
+
+ TrieNode* child = new(zone()) TrieNode(instr, current_info_number_);
node->AddChild(child);
+ node = child;
}
- if (suffix_length > 1) {
- suffix->AddChild(node);
- DeoptInstr* instr =
- new(zone()) DeoptSuffixInstr(suffix->info_number(), suffix_length);
- deopt_info.SetAt(length - 1, instr->kind(), instr->source_index());
- } else {
- trie_root_->AddChild(node);
+ const TypedData& deopt_info = TypedData::Handle(zone(), TypedData::New(
+ kTypedDataUint8ArrayCid, stream.bytes_written(), Heap::kOld));
+ {
+ NoSafepointScope no_safepoint;
+ memmove(deopt_info.DataAddr(0),
+ stream.buffer(),
+ stream.bytes_written());
}
- ASSERT(deopt_info.VerifyDecompression(instructions_, deopt_table));
+ ASSERT(DeoptInfo::VerifyDecompression(
+ instructions_, deopt_table, deopt_info));
instructions_.Clear();
materializations_.Clear();
frame_start_ = -1;
@@ -1333,7 +1240,7 @@
void DeoptTable::SetEntry(const Array& table,
intptr_t index,
const Smi& offset,
- const DeoptInfo& info,
+ const TypedData& info,
const Smi& reason) {
ASSERT((table.Length() % kEntrySize) == 0);
intptr_t i = index * kEntrySize;
@@ -1352,7 +1259,7 @@
void DeoptTable::GetEntry(const Array& table,
intptr_t index,
Smi* offset,
- DeoptInfo* info,
+ TypedData* info,
Smi* reason) {
intptr_t i = index * kEntrySize;
*offset ^= table.At(i);
diff --git a/runtime/vm/deopt_instructions.h b/runtime/vm/deopt_instructions.h
index 6154e06..f2927f5 100644
--- a/runtime/vm/deopt_instructions.h
+++ b/runtime/vm/deopt_instructions.h
@@ -85,6 +85,7 @@
dest_frame_ = dest_frame;
}
+ Thread* thread() const { return thread_; }
Zone* zone() const { return thread_->zone(); }
intptr_t source_frame_size() const { return source_frame_size_; }
@@ -97,7 +98,7 @@
return (deopt_flags_ & flag) != 0;
}
- RawDeoptInfo* deopt_info() const { return deopt_info_; }
+ RawTypedData* deopt_info() const { return deopt_info_; }
// Fills the destination frame but defers materialization of
// objects.
@@ -153,6 +154,27 @@
deferred_slots_);
}
+ void DeferRetAddrMaterialization(intptr_t index,
+ intptr_t deopt_id,
+ intptr_t* slot) {
+ deferred_slots_ = new DeferredRetAddr(
+ index,
+ deopt_id,
+ reinterpret_cast<RawObject**>(slot),
+ deferred_slots_);
+ }
+
+ void DeferPcMarkerMaterialization(intptr_t index, intptr_t* slot) {
+ deferred_slots_ = new DeferredPcMarker(
+ index,
+ reinterpret_cast<RawObject**>(slot),
+ deferred_slots_);
+ }
+
+ void DeferPpMaterialization(intptr_t index, RawObject** slot) {
+ deferred_slots_ = new DeferredPp(index, slot, deferred_slots_);
+ }
+
DeferredObject* GetDeferredObject(intptr_t idx) const {
return deferred_objects_[idx];
}
@@ -184,7 +206,7 @@
RawCode* code_;
RawArray* object_table_;
- RawDeoptInfo* deopt_info_;
+ RawTypedData* deopt_info_;
bool dest_frame_is_allocated_;
intptr_t* dest_frame_;
intptr_t dest_frame_size_;
@@ -235,7 +257,6 @@
kCallerFp,
kCallerPp,
kCallerPc,
- kSuffix,
kMaterializedObjectRef,
kMaterializeObject
};
@@ -263,10 +284,6 @@
return (kind() == other.kind()) && (source_index() == other.source_index());
}
- // Decode the payload of a suffix command. Return the suffix length and
- // set the output parameter info_number to the index of the shared suffix.
- static intptr_t DecodeSuffix(intptr_t source_index, intptr_t* info_number);
-
// Get the code and return address which is encoded in this
// kRetAfterAddress deopt instruction.
static uword GetRetAddress(DeoptInstr* instr,
@@ -409,14 +426,14 @@
const GrowableObjectArray& object_table() { return object_table_; }
// Return address before instruction.
- void AddReturnAddress(const Code& code,
+ void AddReturnAddress(const Function& function,
intptr_t deopt_id,
intptr_t dest_index);
// Copy from optimized frame to unoptimized.
void AddCopy(Value* value, const Location& source_loc, intptr_t dest_index);
- void AddPcMarker(const Code& code, intptr_t dest_index);
- void AddPp(const Code& code, intptr_t dest_index);
+ void AddPcMarker(const Function& function, intptr_t dest_index);
+ void AddPp(const Function& function, intptr_t dest_index);
void AddCallerFp(intptr_t dest_index);
void AddCallerPp(intptr_t dest_index);
void AddCallerPc(intptr_t dest_index);
@@ -435,7 +452,7 @@
// Returns the index of the next stack slot. Used for verification.
intptr_t EmitMaterializationArguments(intptr_t dest_index);
- RawDeoptInfo* CreateDeoptInfo(const Array& deopt_table);
+ RawTypedData* CreateDeoptInfo(const Array& deopt_table);
// Mark the actual start of the frame description after all materialization
// instructions were emitted. Used for verification purposes.
@@ -486,6 +503,8 @@
// stored in an Array in the heap. It consists of triples of (PC offset,
// info, reason). Elements of each entry are stored consecutively in the
// array.
+// TODO(vegorov): consider compressing the whole table into a single TypedData
+// object.
class DeoptTable : public AllStatic {
public:
// Return the array size in elements for a given number of table entries.
@@ -495,7 +514,7 @@
static void SetEntry(const Array& table,
intptr_t index,
const Smi& offset,
- const DeoptInfo& info,
+ const TypedData& info,
const Smi& reason_and_flags);
// Return the length of the table in entries.
@@ -506,7 +525,7 @@
static void GetEntry(const Array& table,
intptr_t index,
Smi* offset,
- DeoptInfo* info,
+ TypedData* info,
Smi* reason_and_flags);
static RawSmi* EncodeReasonAndFlags(ICData::DeoptReasonId reason,
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index 5e95d92..7ab11d4 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -696,12 +696,6 @@
}
} else if (instr->IsMultiplyOrSyncPrimitive()) {
if (instr->Bit(24) == 0) {
- if ((TargetCPUFeatures::arm_version() != ARMv7) &&
- (instr->Bits(21, 3) != 0)) {
- // mla ... smlal only supported on armv7.
- Unknown(instr);
- return;
- }
// multiply instructions
switch (instr->Bits(21, 3)) {
case 0: {
@@ -715,11 +709,19 @@
break;
}
case 2: {
+ if (TargetCPUFeatures::arm_version() == ARMv5TE) {
+ Unknown(instr);
+ return;
+ }
// Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
Format(instr, "umaal'cond's 'rd, 'rn, 'rm, 'rs");
break;
}
case 3: {
+ if (TargetCPUFeatures::arm_version() != ARMv7) {
+ Unknown(instr);
+ return;
+ }
// Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
break;
@@ -739,17 +741,17 @@
Format(instr, "smull'cond's 'rd, 'rn, 'rm, 'rs");
break;
}
- case 7: {
- // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
- Format(instr, "smlal'cond's 'rd, 'rn, 'rm, 'rs");
- break;
- }
default: {
Unknown(instr); // Not used.
break;
}
}
} else {
+ if (TargetCPUFeatures::arm_version() == ARMv5TE) {
+ // strex and ldrex are only supported after ARMv6.
+ Unknown(instr);
+ return;
+ }
// synchronization primitives
switch (instr->Bits(20, 4)) {
case 8: {
@@ -1470,7 +1472,8 @@
Instr* instr = Instr::At(pc);
if (instr->ConditionField() == kSpecialCondition) {
- if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) {
+ if ((instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) &&
+ (TargetCPUFeatures::arm_version() != ARMv5TE)) {
Format(instr, "clrex");
} else {
if (instr->IsSIMDDataProcessing()) {
diff --git a/runtime/vm/flags.cc b/runtime/vm/flags.cc
index c305ad1..6aec343 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -463,8 +463,6 @@
void Flags::PrintJSON(JSONStream* js) {
JSONObject jsobj(js);
jsobj.AddProperty("type", "FlagList");
- jsobj.AddProperty("id", "flags");
-
{
JSONArray jsarr(&jsobj, "unmodifiedFlags");
for (intptr_t i = 0; i < num_flags_; ++i) {
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index db4b32e..616807c 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -2382,6 +2382,8 @@
node->InitializerAt(i)->Visit(&for_value);
Append(for_value);
Value* temp_val = for_value.value();
+ ASSERT(!node->TempAt(i)->HasIndex() ||
+ (node->TempAt(i)->index() == GetCurrentTempLocalIndex()));
node->TempAt(i)->set_index(GetCurrentTempLocalIndex());
Do(new(Z) PushTempInstr(temp_val));
owner()->AllocateTemp();
@@ -3436,10 +3438,11 @@
void EffectGraphVisitor::VisitStoreLocalNode(StoreLocalNode* node) {
// If the right hand side is an expression that does not contain
// a safe point for the debugger to stop, add an explicit stub
- // call. Exception: don't do this when assigning to internal variables,
- // or for generated code that has no source position.
+ // call. Exception: don't do this when assigning to or from internal
+ // variables, or for generated code that has no source position.
if ((node->value()->IsLiteralNode() ||
- node->value()->IsLoadLocalNode() ||
+ (node->value()->IsLoadLocalNode() &&
+ !node->value()->AsLoadLocalNode()->local().IsInternal()) ||
node->value()->IsClosureNode()) &&
!node->local().IsInternal() &&
(node->token_pos() != Scanner::kNoSourcePos)) {
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 146b2ec..04141c1 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -862,7 +862,7 @@
const Array& array =
Array::Handle(Array::New(deopt_info_table_size, Heap::kOld));
Smi& offset = Smi::Handle();
- DeoptInfo& info = DeoptInfo::Handle();
+ TypedData& info = TypedData::Handle();
Smi& reason_and_flags = Smi::Handle();
for (intptr_t i = 0; i < deopt_infos_.length(); i++) {
offset = Smi::New(deopt_infos_[i]->pc_offset());
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 31b6176..9fa51ad 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -126,7 +126,7 @@
}
virtual ~CompilerDeoptInfo() { }
- RawDeoptInfo* CreateDeoptInfo(FlowGraphCompiler* compiler,
+ RawTypedData* CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder,
const Array& deopt_table);
@@ -279,6 +279,7 @@
static bool SupportsUnboxedMints();
static bool SupportsSinCos();
static bool SupportsUnboxedSimd128();
+ static bool SupportsHardwareDivision();
// Accessors.
Assembler* assembler() const { return assembler_; }
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 8f93df9..5ea34ba 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -59,6 +59,11 @@
}
+bool FlowGraphCompiler::SupportsHardwareDivision() {
+ return TargetCPUFeatures::can_divide();
+}
+
+
void FlowGraphCompiler::EnterIntrinsicMode() {
ASSERT(!intrinsic_mode());
intrinsic_mode_ = true;
@@ -73,12 +78,12 @@
}
-RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
+RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder,
const Array& deopt_table) {
if (deopt_env_ == NULL) {
++builder->current_info_number_;
- return DeoptInfo::null();
+ return TypedData::null();
}
intptr_t stack_height = compiler->StackSize();
@@ -95,12 +100,14 @@
builder->MarkFrameStart();
// Current PP, FP, and PC.
- builder->AddPp(current->code(), slot_ix++);
+ builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
builder->AddCallerFp(slot_ix++);
- builder->AddReturnAddress(current->code(), deopt_id(), slot_ix++);
+ builder->AddReturnAddress(Function::Handle(current->code().function()),
+ deopt_id(),
+ slot_ix++);
// Callee's PC marker is not used anymore. Pass Function::null() to set to 0.
- builder->AddPcMarker(Code::Handle(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(), slot_ix++);
// Emit all values that are needed for materialization as a part of the
// expression stack for the bottom-most frame. This guarantees that GC
@@ -118,17 +125,18 @@
current = current->outer();
while (current != NULL) {
// PP, FP, and PC.
- builder->AddPp(current->code(), slot_ix++);
+ builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
builder->AddCallerFp(slot_ix++);
// For any outer environment the deopt id is that of the call instruction
// which is recorded in the outer environment.
- builder->AddReturnAddress(current->code(),
+ builder->AddReturnAddress(Function::Handle(current->code().function()),
Isolate::ToDeoptAfter(current->deopt_id()),
slot_ix++);
// PC marker.
- builder->AddPcMarker(previous->code(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(previous->code().function()),
+ slot_ix++);
// The values of outgoing arguments can be changed from the inlined call so
// we must read them from the previous environment.
@@ -160,7 +168,8 @@
builder->AddCallerPc(slot_ix++);
// PC marker.
- builder->AddPcMarker(previous->code(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(previous->code().function()),
+ slot_ix++);
// For the outermost environment, set the incoming arguments.
for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) {
@@ -1263,9 +1272,6 @@
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count);
-#if defined(DEBUG)
- __ LoadImmediate(R4, kInvalidObjectPointer);
-#endif
}
@@ -1348,10 +1354,6 @@
RawPcDescriptors::kUnoptStaticCall,
locs);
__ Drop(argument_count);
-#if defined(DEBUG)
- __ LoadImmediate(R4, kInvalidObjectPointer);
- __ LoadImmediate(R5, kInvalidObjectPointer);
-#endif
}
@@ -1428,13 +1430,6 @@
Isolate::kNoDeoptId,
token_pos);
}
-#if defined(DEBUG)
- if (!is_optimizing()) {
- // Do this *after* adding the pc descriptor!
- __ LoadImmediate(R4, kInvalidObjectPointer);
- __ LoadImmediate(R5, kInvalidObjectPointer);
- }
-#endif
// Stub returns result in flags (result of a cmp, we need Z computed).
__ Pop(right);
__ Pop(left);
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 1e1bb66..1d684f6 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -55,6 +55,11 @@
}
+bool FlowGraphCompiler::SupportsHardwareDivision() {
+ return true;
+}
+
+
void FlowGraphCompiler::EnterIntrinsicMode() {
ASSERT(!intrinsic_mode());
intrinsic_mode_ = true;
@@ -69,12 +74,12 @@
}
-RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
+RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder,
const Array& deopt_table) {
if (deopt_env_ == NULL) {
++builder->current_info_number_;
- return DeoptInfo::null();
+ return TypedData::null();
}
intptr_t stack_height = compiler->StackSize();
@@ -91,10 +96,12 @@
builder->MarkFrameStart();
// Current PP, FP, and PC.
- builder->AddPp(current->code(), slot_ix++);
- builder->AddPcMarker(Code::Handle(), slot_ix++);
+ builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
+ builder->AddPcMarker(Function::Handle(), slot_ix++);
builder->AddCallerFp(slot_ix++);
- builder->AddReturnAddress(current->code(), deopt_id(), slot_ix++);
+ builder->AddReturnAddress(Function::Handle(current->code().function()),
+ deopt_id(),
+ slot_ix++);
// Emit all values that are needed for materialization as a part of the
// expression stack for the bottom-most frame. This guarantees that GC
@@ -112,13 +119,14 @@
current = current->outer();
while (current != NULL) {
// PP, FP, and PC.
- builder->AddPp(current->code(), slot_ix++);
- builder->AddPcMarker(previous->code(), slot_ix++);
+ builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
+ builder->AddPcMarker(Function::Handle(previous->code().function()),
+ slot_ix++);
builder->AddCallerFp(slot_ix++);
// For any outer environment the deopt id is that of the call instruction
// which is recorded in the outer environment.
- builder->AddReturnAddress(current->code(),
+ builder->AddReturnAddress(Function::Handle(current->code().function()),
Isolate::ToDeoptAfter(current->deopt_id()),
slot_ix++);
@@ -149,7 +157,8 @@
// For the outermost environment, set caller PC, caller PP, and caller FP.
builder->AddCallerPp(slot_ix++);
// PC marker.
- builder->AddPcMarker(previous->code(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(previous->code().function()),
+ slot_ix++);
builder->AddCallerFp(slot_ix++);
builder->AddCallerPc(slot_ix++);
@@ -1244,9 +1253,6 @@
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count);
-#if defined(DEBUG)
- __ LoadImmediate(R4, kInvalidObjectPointer, kNoPP);
-#endif
}
@@ -1328,10 +1334,6 @@
&target_label,
RawPcDescriptors::kUnoptStaticCall,
locs);
-#if defined(DEBUG)
- __ LoadImmediate(R4, kInvalidObjectPointer, kNoPP);
- __ LoadImmediate(R5, kInvalidObjectPointer, kNoPP);
-#endif
__ Drop(argument_count);
}
@@ -1409,13 +1411,6 @@
Isolate::kNoDeoptId,
token_pos);
}
-#if defined(DEBUG)
- if (!is_optimizing()) {
- // Do this *after* adding the pc descriptor!
- __ LoadImmediate(R4, kInvalidObjectPointer, kNoPP);
- __ LoadImmediate(R5, kInvalidObjectPointer, kNoPP);
- }
-#endif
// Stub returns result in flags (result of a cmp, we need Z computed).
__ Pop(right);
__ Pop(left);
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index b6a6b94..1193e78 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -61,6 +61,11 @@
}
+bool FlowGraphCompiler::SupportsHardwareDivision() {
+ return true;
+}
+
+
void FlowGraphCompiler::EnterIntrinsicMode() {
ASSERT(!intrinsic_mode());
intrinsic_mode_ = true;
@@ -73,12 +78,12 @@
}
-RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
+RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder,
const Array& deopt_table) {
if (deopt_env_ == NULL) {
++builder->current_info_number_;
- return DeoptInfo::null();
+ return TypedData::null();
}
intptr_t stack_height = compiler->StackSize();
@@ -95,11 +100,13 @@
builder->MarkFrameStart();
// Callee's PC marker is not used anymore. Pass Code::null() to set to 0.
- builder->AddPcMarker(Code::Handle(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(), slot_ix++);
// Current FP and PC.
builder->AddCallerFp(slot_ix++);
- builder->AddReturnAddress(current->code(), deopt_id(), slot_ix++);
+ builder->AddReturnAddress(Function::Handle(current->code().function()),
+ deopt_id(),
+ slot_ix++);
// Emit all values that are needed for materialization as a part of the
// expression stack for the bottom-most frame. This guarantees that GC
@@ -114,7 +121,7 @@
}
// Current PC marker and caller FP.
- builder->AddPcMarker(current->code(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(current->code().function()), slot_ix++);
builder->AddCallerFp(slot_ix++);
Environment* previous = current;
@@ -122,7 +129,7 @@
while (current != NULL) {
// For any outer environment the deopt id is that of the call instruction
// which is recorded in the outer environment.
- builder->AddReturnAddress(current->code(),
+ builder->AddReturnAddress(Function::Handle(current->code().function()),
Isolate::ToDeoptAfter(current->deopt_id()),
slot_ix++);
@@ -144,7 +151,8 @@
}
// PC marker and caller FP.
- builder->AddPcMarker(current->code(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(current->code().function()),
+ slot_ix++);
builder->AddCallerFp(slot_ix++);
// Iterate on the outer environment.
@@ -1216,10 +1224,6 @@
RawPcDescriptors::kUnoptStaticCall,
locs);
__ Drop(argument_count);
-#if defined(DEBUG)
- __ movl(ECX, Immediate(kInvalidObjectPointer));
- __ movl(EDX, Immediate(kInvalidObjectPointer));
-#endif
}
@@ -1290,9 +1294,6 @@
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count);
-#if defined(DEBUG)
- __ movl(EDX, Immediate(kInvalidObjectPointer));
-#endif
}
@@ -1435,13 +1436,6 @@
Isolate::kNoDeoptId,
token_pos);
}
-#if defined(DEBUG)
- if (!is_optimizing()) {
- // Do this *after* adding the pc descriptor!
- __ movl(EDX, Immediate(kInvalidObjectPointer));
- __ movl(ECX, Immediate(kInvalidObjectPointer));
- }
-#endif
// Stub returns result in flags (result of a cmpl, we need ZF computed).
__ popl(right);
__ popl(left);
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 1f09dc0..c7ebddf 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -54,6 +54,11 @@
}
+bool FlowGraphCompiler::SupportsHardwareDivision() {
+ return true;
+}
+
+
void FlowGraphCompiler::EnterIntrinsicMode() {
ASSERT(!intrinsic_mode());
intrinsic_mode_ = true;
@@ -68,12 +73,12 @@
}
-RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
+RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder,
const Array& deopt_table) {
if (deopt_env_ == NULL) {
++builder->current_info_number_;
- return DeoptInfo::null();
+ return TypedData::null();
}
intptr_t stack_height = compiler->StackSize();
@@ -90,12 +95,14 @@
builder->MarkFrameStart();
// Current PP, FP, and PC.
- builder->AddPp(current->code(), slot_ix++);
+ builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
builder->AddCallerFp(slot_ix++);
- builder->AddReturnAddress(current->code(), deopt_id(), slot_ix++);
+ builder->AddReturnAddress(Function::Handle(current->code().function()),
+ deopt_id(),
+ slot_ix++);
// Callee's PC marker is not used anymore. Pass Code::null() to set to 0.
- builder->AddPcMarker(Code::Handle(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(), slot_ix++);
// Emit all values that are needed for materialization as a part of the
// expression stack for the bottom-most frame. This guarantees that GC
@@ -113,17 +120,18 @@
current = current->outer();
while (current != NULL) {
// PP, FP, and PC.
- builder->AddPp(current->code(), slot_ix++);
+ builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
builder->AddCallerFp(slot_ix++);
// For any outer environment the deopt id is that of the call instruction
// which is recorded in the outer environment.
- builder->AddReturnAddress(current->code(),
+ builder->AddReturnAddress(Function::Handle(current->code().function()),
Isolate::ToDeoptAfter(current->deopt_id()),
slot_ix++);
// PC marker.
- builder->AddPcMarker(previous->code(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(previous->code().function()),
+ slot_ix++);
// The values of outgoing arguments can be changed from the inlined call so
// we must read them from the previous environment.
@@ -155,7 +163,8 @@
builder->AddCallerPc(slot_ix++);
// PC marker.
- builder->AddPcMarker(previous->code(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(previous->code().function()),
+ slot_ix++);
// For the outermost environment, set the incoming arguments.
for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) {
@@ -194,7 +203,7 @@
void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
Label* is_true,
Label* is_false) {
- __ TraceSimMsg("BoolToJump");
+ __ Comment("BoolToJump");
Label fall_through;
__ BranchEqual(bool_register, Object::null_object(), &fall_through);
__ BranchEqual(bool_register, Bool::True(), is_true);
@@ -212,7 +221,7 @@
Register temp_reg,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
- __ TraceSimMsg("CallSubtypeTestStub");
+ __ Comment("CallSubtypeTestStub");
ASSERT(instance_reg == A0);
ASSERT(temp_reg == kNoRegister); // Unused on MIPS.
const SubtypeTestCache& type_test_cache =
@@ -321,7 +330,7 @@
const GrowableArray<intptr_t>& class_ids,
Label* is_equal_lbl,
Label* is_not_equal_lbl) {
- __ TraceSimMsg("CheckClassIds");
+ __ Comment("CheckClassIds");
for (intptr_t i = 0; i < class_ids.length(); i++) {
__ BranchEqual(class_id_reg, Immediate(class_ids[i]), is_equal_lbl);
}
@@ -339,7 +348,6 @@
const AbstractType& type,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
- __ TraceSimMsg("InstantiatedTypeNoArgumentsTest");
__ Comment("InstantiatedTypeNoArgumentsTest");
ASSERT(type.IsInstantiated());
const Class& type_class = Class::Handle(type.type_class());
@@ -404,7 +412,6 @@
const Class& type_class,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
- __ TraceSimMsg("Subtype1TestCacheLookup");
__ Comment("Subtype1TestCacheLookup");
const Register kInstanceReg = A0;
__ LoadClass(T0, kInstanceReg);
@@ -432,7 +439,6 @@
const AbstractType& type,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
- __ TraceSimMsg("UninstantiatedTypeTest");
__ Comment("UninstantiatedTypeTest");
ASSERT(!type.IsInstantiated());
// Skip check if destination is a dynamic type.
@@ -512,7 +518,6 @@
const AbstractType& type,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
- __ TraceSimMsg("InlineInstanceof");
__ Comment("InlineInstanceof");
if (type.IsVoidType()) {
// A non-null value is returned from a void function, which will result in a
@@ -656,7 +661,7 @@
const AbstractType& dst_type,
const String& dst_name,
LocationSummary* locs) {
- __ TraceSimMsg("AssertAssignable");
+ __ Comment("AssertAssignable");
ASSERT(token_pos >= 0);
ASSERT(!dst_type.IsNull());
ASSERT(dst_type.IsFinalized());
@@ -749,7 +754,6 @@
// Input parameters:
// S4: arguments descriptor array.
void FlowGraphCompiler::CopyParameters() {
- __ TraceSimMsg("CopyParameters");
__ Comment("Copy parameters");
const Function& function = parsed_function().function();
LocalScope* scope = parsed_function().node_sequence()->scope();
@@ -1078,7 +1082,6 @@
function.IsClosureFunction() && !flow_graph().IsCompiledForOsr();
#endif
if (check_arguments) {
- __ TraceSimMsg("Check argument count");
__ Comment("Check argument count");
// Check that exactly num_fixed arguments are passed in.
Label correct_num_arguments, wrong_num_arguments;
@@ -1115,7 +1118,6 @@
// null.
if (!is_optimizing()) {
ASSERT(num_locals > 0); // There is always at least context_var.
- __ TraceSimMsg("Initialize spill slots");
__ Comment("Initialize spill slots");
const intptr_t slot_base = parsed_function().first_stack_local_index();
const intptr_t context_index =
@@ -1245,7 +1247,7 @@
// top-level function (parsed_function().function()) which could be
// reoptimized and which counter needs to be incremented.
// Pass the function explicitly, it is used in IC stub.
- __ TraceSimMsg("OptimizedInstanceCall");
+ __ Comment("OptimizedInstanceCall");
__ LoadObject(T0, parsed_function().function());
__ LoadObject(S5, ic_data);
GenerateDartCall(deopt_id,
@@ -1264,18 +1266,15 @@
intptr_t token_pos,
LocationSummary* locs) {
ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
- __ TraceSimMsg("InstanceCall");
+ __ Comment("InstanceCall");
__ LoadObject(S5, ic_data);
GenerateDartCall(deopt_id,
token_pos,
target_label,
RawPcDescriptors::kIcCall,
locs);
- __ TraceSimMsg("InstanceCall return");
+ __ Comment("InstanceCall return");
__ Drop(argument_count);
-#if defined(DEBUG)
- __ LoadImmediate(S4, kInvalidObjectPointer);
-#endif
}
@@ -1292,7 +1291,7 @@
ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
const MegamorphicCache& cache =
MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor));
- __ TraceSimMsg("MegamorphicInstanceCall");
+ __ Comment("MegamorphicInstanceCall");
__ lw(T0, Address(SP, (argument_count - 1) * kWordSize));
__ LoadTaggedClassIdMayBeSmi(T0, T0);
@@ -1359,10 +1358,6 @@
&target_label,
RawPcDescriptors::kUnoptStaticCall,
locs);
-#if defined(DEBUG)
- __ LoadImmediate(S4, kInvalidObjectPointer);
- __ LoadImmediate(S5, kInvalidObjectPointer);
-#endif
__ Drop(argument_count);
}
@@ -1375,7 +1370,7 @@
intptr_t token_pos,
LocationSummary* locs) {
StubCode* stub_code = isolate()->stub_code();
- __ TraceSimMsg("StaticCall");
+ __ Comment("StaticCall");
__ LoadObject(S4, arguments_descriptor);
// Do not use the code from the function, but let the code be patched so that
// we can record the outgoing edges to other code.
@@ -1394,7 +1389,7 @@
const Object& obj,
bool needs_number_check,
intptr_t token_pos) {
- __ TraceSimMsg("EqualityRegConstCompare");
+ __ Comment("EqualityRegConstCompare");
ASSERT(!needs_number_check ||
(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()));
if (needs_number_check) {
@@ -1416,7 +1411,7 @@
Isolate::kNoDeoptId,
token_pos);
}
- __ TraceSimMsg("EqualityRegConstCompare return");
+ __ Comment("EqualityRegConstCompare return");
// Stub returns result in CMPRES1 (if it is 0, then reg and obj are equal).
__ lw(reg, Address(SP, 1 * kWordSize)); // Restore 'reg'.
__ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant.
@@ -1433,7 +1428,6 @@
Register right,
bool needs_number_check,
intptr_t token_pos) {
- __ TraceSimMsg("EqualityRegRegCompare");
__ Comment("EqualityRegRegCompare");
if (needs_number_check) {
StubCode* stub_code = isolate()->stub_code();
@@ -1452,14 +1446,7 @@
Isolate::kNoDeoptId,
token_pos);
}
-#if defined(DEBUG)
- if (!is_optimizing()) {
- // Do this *after* adding the pc descriptor!
- __ LoadImmediate(S4, kInvalidObjectPointer);
- __ LoadImmediate(S5, kInvalidObjectPointer);
- }
-#endif
- __ TraceSimMsg("EqualityRegRegCompare return");
+ __ Comment("EqualityRegRegCompare return");
// Stub returns result in CMPRES1 (if it is 0, then left and right are
// equal).
__ lw(right, Address(SP, 0 * kWordSize));
@@ -1480,7 +1467,7 @@
ClobberDeadTempRegisters(locs);
#endif
- __ TraceSimMsg("SaveLiveRegisters");
+ __ Comment("SaveLiveRegisters");
// TODO(vegorov): consider saving only caller save (volatile) registers.
const intptr_t fpu_regs_count = locs->live_registers()->FpuRegisterCount();
if (fpu_regs_count > 0) {
@@ -1522,7 +1509,7 @@
void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) {
// General purpose registers have the highest register number at the
// lowest address.
- __ TraceSimMsg("RestoreLiveRegisters");
+ __ Comment("RestoreLiveRegisters");
const intptr_t cpu_registers = locs->live_registers()->cpu_registers();
ASSERT((cpu_registers & ~kAllCpuRegistersList) == 0);
const int register_count = Utils::CountOneBits(cpu_registers);
@@ -1592,7 +1579,6 @@
argument_names));
StubCode* stub_code = isolate()->stub_code();
- __ TraceSimMsg("EmitTestAndCall");
__ Comment("EmitTestAndCall");
__ LoadObject(S4, arguments_descriptor);
for (intptr_t i = 0; i < len; i++) {
@@ -1630,7 +1616,7 @@
MoveOperands* move = moves_[index];
const Location source = move->src();
const Location destination = move->dest();
- __ TraceSimMsg("ParallelMoveResolver::EmitMove");
+ __ Comment("ParallelMoveResolver::EmitMove");
if (source.IsRegister()) {
if (destination.IsRegister()) {
@@ -1785,14 +1771,14 @@
void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst,
const Address& src) {
- __ TraceSimMsg("ParallelMoveResolver::MoveMemoryToMemory");
+ __ Comment("ParallelMoveResolver::MoveMemoryToMemory");
__ lw(TMP, src);
__ sw(TMP, dst);
}
void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) {
- __ TraceSimMsg("ParallelMoveResolver::StoreObject");
+ __ Comment("ParallelMoveResolver::StoreObject");
__ LoadObject(TMP, obj);
__ sw(TMP, dst);
}
@@ -1836,26 +1822,26 @@
void ParallelMoveResolver::SpillScratch(Register reg) {
- __ TraceSimMsg("ParallelMoveResolver::SpillScratch");
+ __ Comment("ParallelMoveResolver::SpillScratch");
__ Push(reg);
}
void ParallelMoveResolver::RestoreScratch(Register reg) {
- __ TraceSimMsg("ParallelMoveResolver::RestoreScratch");
+ __ Comment("ParallelMoveResolver::RestoreScratch");
__ Pop(reg);
}
void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) {
- __ TraceSimMsg("ParallelMoveResolver::SpillFpuScratch");
+ __ Comment("ParallelMoveResolver::SpillFpuScratch");
__ AddImmediate(SP, -kDoubleSize);
__ StoreDToOffset(reg, SP, 0);
}
void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) {
- __ TraceSimMsg("ParallelMoveResolver::RestoreFpuScratch");
+ __ Comment("ParallelMoveResolver::RestoreFpuScratch");
__ LoadDFromOffset(reg, SP, 0);
__ AddImmediate(SP, kDoubleSize);
}
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index c24d2ef..562f0c3 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -59,6 +59,11 @@
}
+bool FlowGraphCompiler::SupportsHardwareDivision() {
+ return true;
+}
+
+
void FlowGraphCompiler::EnterIntrinsicMode() {
ASSERT(!intrinsic_mode());
intrinsic_mode_ = true;
@@ -73,12 +78,12 @@
}
-RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
+RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
DeoptInfoBuilder* builder,
const Array& deopt_table) {
if (deopt_env_ == NULL) {
++builder->current_info_number_;
- return DeoptInfo::null();
+ return TypedData::null();
}
intptr_t stack_height = compiler->StackSize();
@@ -95,10 +100,12 @@
builder->MarkFrameStart();
// Current PP, FP, and PC.
- builder->AddPp(current->code(), slot_ix++);
- builder->AddPcMarker(Code::Handle(), slot_ix++);
+ builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
+ builder->AddPcMarker(Function::Handle(), slot_ix++);
builder->AddCallerFp(slot_ix++);
- builder->AddReturnAddress(current->code(), deopt_id(), slot_ix++);
+ builder->AddReturnAddress(Function::Handle(current->code().function()),
+ deopt_id(),
+ slot_ix++);
// Emit all values that are needed for materialization as a part of the
// expression stack for the bottom-most frame. This guarantees that GC
@@ -116,13 +123,14 @@
current = current->outer();
while (current != NULL) {
// PP, FP, and PC.
- builder->AddPp(current->code(), slot_ix++);
- builder->AddPcMarker(previous->code(), slot_ix++);
+ builder->AddPp(Function::Handle(current->code().function()), slot_ix++);
+ builder->AddPcMarker(Function::Handle(previous->code().function()),
+ slot_ix++);
builder->AddCallerFp(slot_ix++);
// For any outer environment the deopt id is that of the call instruction
// which is recorded in the outer environment.
- builder->AddReturnAddress(current->code(),
+ builder->AddReturnAddress(Function::Handle(current->code().function()),
Isolate::ToDeoptAfter(current->deopt_id()),
slot_ix++);
@@ -153,7 +161,8 @@
// For the outermost environment, set caller PC, caller PP, and caller FP.
builder->AddCallerPp(slot_ix++);
// PC marker.
- builder->AddPcMarker(previous->code(), slot_ix++);
+ builder->AddPcMarker(Function::Handle(previous->code().function()),
+ slot_ix++);
builder->AddCallerFp(slot_ix++);
builder->AddCallerPc(slot_ix++);
@@ -1223,10 +1232,6 @@
RawPcDescriptors::kUnoptStaticCall,
locs);
__ Drop(argument_count, RCX);
-#if defined(DEBUG)
- __ movq(RBX, Immediate(kInvalidObjectPointer));
- __ movq(R10, Immediate(kInvalidObjectPointer));
-#endif
}
@@ -1297,9 +1302,6 @@
RawPcDescriptors::kIcCall,
locs);
__ Drop(argument_count, RCX);
-#if defined(DEBUG)
- __ movq(R10, Immediate(kInvalidObjectPointer));
-#endif
}
@@ -1441,13 +1443,6 @@
Isolate::kNoDeoptId,
token_pos);
}
-#if defined(DEBUG)
- // Do this *after* adding the pc descriptor!
- if (!is_optimizing()) {
- __ movq(R10, Immediate(kInvalidObjectPointer));
- __ movq(RBX, Immediate(kInvalidObjectPointer));
- }
-#endif
// Stub returns result in flags (result of a cmpq, we need ZF computed).
__ popq(right);
__ popq(left);
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 04bb036..1b33345 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -2035,6 +2035,7 @@
}
break;
case Token::kDIV:
+ if (!FlowGraphCompiler::SupportsHardwareDivision()) return false;
if (ShouldSpecializeForDouble(ic_data) ||
HasOnlyTwoOf(ic_data, kSmiCid)) {
operands_type = kDoubleCid;
@@ -2087,6 +2088,7 @@
break;
case Token::kMOD:
case Token::kTRUNCDIV:
+ if (!FlowGraphCompiler::SupportsHardwareDivision()) return false;
if (HasOnlyTwoOf(ic_data, kSmiCid)) {
if (ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)) {
return false;
diff --git a/runtime/vm/freelist.cc b/runtime/vm/freelist.cc
index 00a4691..b8df851 100644
--- a/runtime/vm/freelist.cc
+++ b/runtime/vm/freelist.cc
@@ -70,7 +70,7 @@
uword FreeList::TryAllocateLocked(intptr_t size, bool is_protected) {
- DEBUG_ASSERT(mutex_->Owner() == Isolate::Current());
+ DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread());
// Precondition: is_protected is false or else all free list elements are
// in non-writable pages.
@@ -183,7 +183,7 @@
void FreeList::FreeLocked(uword addr, intptr_t size) {
- DEBUG_ASSERT(mutex_->Owner() == Isolate::Current());
+ DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread());
// Precondition required by AsElement and EnqueueElement: the (page
// containing the) header of the freed block should be writable. This is
// the case when called for newly allocated pages because they are
@@ -249,7 +249,7 @@
intptr_t FreeList::LengthLocked(int index) const {
- DEBUG_ASSERT(mutex_->Owner() == Isolate::Current());
+ DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread());
ASSERT(index >= 0);
ASSERT(index < kNumLists);
intptr_t result = 0;
@@ -362,7 +362,7 @@
FreeListElement* FreeList::TryAllocateLargeLocked(intptr_t minimum_size) {
- DEBUG_ASSERT(mutex_->Owner() == Isolate::Current());
+ DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread());
FreeListElement* previous = NULL;
FreeListElement* current = free_lists_[kNumLists];
// TODO(koda): Find largest.
@@ -384,7 +384,7 @@
uword FreeList::TryAllocateSmallLocked(intptr_t size) {
- DEBUG_ASSERT(mutex_->Owner() == Isolate::Current());
+ DEBUG_ASSERT(mutex_->IsOwnedByCurrentThread());
if (size > last_free_small_size_) {
return 0;
}
diff --git a/runtime/vm/gc_sweeper.cc b/runtime/vm/gc_sweeper.cc
index 270c9cc..b9b5835 100644
--- a/runtime/vm/gc_sweeper.cc
+++ b/runtime/vm/gc_sweeper.cc
@@ -113,7 +113,7 @@
}
virtual void Run() {
- Isolate::SetCurrent(task_isolate_);
+ Thread::EnterIsolate(task_isolate_);
GCSweeper sweeper;
HeapPage* page = first_;
@@ -143,7 +143,7 @@
old_space_->set_tasks(old_space_->tasks() - 1);
ml.Notify();
}
- Isolate::SetCurrent(NULL);
+ Thread::ExitIsolate();
delete task_isolate_;
}
diff --git a/runtime/vm/growable_array.h b/runtime/vm/growable_array.h
index 81a946b..ba6f807 100644
--- a/runtime/vm/growable_array.h
+++ b/runtime/vm/growable_array.h
@@ -90,6 +90,15 @@
data_[idx] = value;
}
+ void Reverse() {
+ for (intptr_t i = 0; i < length_ / 2; i++) {
+ const intptr_t j = length_ - 1 - i;
+ T temp = data_[i];
+ data_[i] = data_[j];
+ data_[j] = temp;
+ }
+ }
+
// The content is uninitialized after calling it.
void SetLength(intptr_t new_length);
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index a8f35f4..2443369 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -639,7 +639,7 @@
stats_.after_.old_ = old_space_->GetCurrentUsage();
ASSERT(gc_in_progress_);
gc_in_progress_ = false;
- if (Service::NeedsGCEvents()) {
+ if (Service::NeedsEvents()) {
GCEvent event(stats_);
Service::HandleGCEvent(&event);
}
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 840b45e..eea43c4 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -191,7 +191,7 @@
}
-bool CheckClassInstr::IsNullCheck() const {
+bool CheckClassInstr::DeoptIfNull() const {
if (unary_checks().NumberOfChecks() != 1) {
return false;
}
@@ -203,6 +203,19 @@
}
+// Null object is a singleton of null-class (except for some sentinel,
+// transitional temporaries). Instead of checking against the null class only
+// we can check against null instance instead.
+bool CheckClassInstr::DeoptIfNotNull() const {
+ if (unary_checks().NumberOfChecks() != 1) {
+ return false;
+ }
+ const intptr_t cid = unary_checks().GetCidAt(0);
+ return cid == kNullCid;
+}
+
+
+
bool CheckClassInstr::IsDenseSwitch() const {
if (unary_checks().GetReceiverClassIdAt(0) == kSmiCid) return false;
if (cids_.length() > 2 &&
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index b8bf6dd..72ebed1 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -7592,7 +7592,12 @@
virtual void PrintOperandsTo(BufferFormatter* f) const;
- bool IsNullCheck() const;
+ bool IsNullCheck() const {
+ return DeoptIfNull() || DeoptIfNotNull();
+ }
+
+ bool DeoptIfNull() const;
+ bool DeoptIfNotNull() const;
bool IsDenseSwitch() const;
intptr_t ComputeCidMask() const;
@@ -8015,7 +8020,9 @@
fixed_parameter_count_(fixed_parameter_count),
deopt_id_(deopt_id),
parsed_function_(parsed_function),
- outer_(outer) { }
+ outer_(outer) {
+ ASSERT(!parsed_function_.code().IsNull());
+ }
GrowableArray<Value*> values_;
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 6dc5ac0..f576dc8 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1283,9 +1283,6 @@
if ((representation() == kUnboxedUint32) ||
(representation() == kUnboxedInt32)) {
Register result = locs()->out(0).reg();
- if ((index_scale() == 1) && index.IsRegister()) {
- __ SmiUntag(index.reg());
- }
switch (class_id()) {
case kTypedDataInt32ArrayCid:
ASSERT(representation() == kUnboxedInt32);
@@ -3054,9 +3051,6 @@
} else if (((op_kind() == Token::kSHL) && can_overflow()) ||
(op_kind() == Token::kSHR)) {
num_temps = 1;
- } else if ((op_kind() == Token::kMUL) &&
- (TargetCPUFeatures::arm_version() != ARMv7)) {
- num_temps = 1;
}
LocationSummary* summary = new(zone) LocationSummary(
zone, kNumInputs, num_temps, LocationSummary::kNoCall);
@@ -3088,11 +3082,6 @@
(op_kind() == Token::kSHR)) {
summary->set_temp(0, Location::RequiresRegister());
}
- if (op_kind() == Token::kMUL) {
- if (TargetCPUFeatures::arm_version() != ARMv7) {
- summary->set_temp(0, Location::RequiresFpuRegister());
- }
- }
// We make use of 3-operand instructions by not requiring result register
// to be identical to first input register as on Intel.
summary->set_out(0, Location::RequiresRegister());
@@ -3145,24 +3134,11 @@
__ LoadImmediate(IP, value);
__ mul(result, left, IP);
} else {
- if (TargetCPUFeatures::arm_version() == ARMv7) {
- __ LoadImmediate(IP, value);
- __ smull(result, IP, left, IP);
- // IP: result bits 32..63.
- __ cmp(IP, Operand(result, ASR, 31));
- __ b(deopt, NE);
- } else if (TargetCPUFeatures::can_divide()) {
- const QRegister qtmp = locs()->temp(0).fpu_reg();
- const DRegister dtmp0 = EvenDRegisterOf(qtmp);
- const DRegister dtmp1 = OddDRegisterOf(qtmp);
- __ LoadImmediate(IP, value);
- __ CheckMultSignedOverflow(left, IP, result, dtmp0, dtmp1, deopt);
- __ mul(result, left, IP);
- } else {
- // TODO(vegorov): never emit this instruction if hardware does not
- // support it! This will lead to deopt cycle penalizing the code.
- __ b(deopt);
- }
+ __ LoadImmediate(IP, value);
+ __ smull(result, IP, left, IP);
+ // IP: result bits 32..63.
+ __ cmp(IP, Operand(result, ASR, 31));
+ __ b(deopt, NE);
}
break;
}
@@ -3262,22 +3238,10 @@
if (deopt == NULL) {
__ mul(result, IP, right);
} else {
- if (TargetCPUFeatures::arm_version() == ARMv7) {
- __ smull(result, IP, IP, right);
- // IP: result bits 32..63.
- __ cmp(IP, Operand(result, ASR, 31));
- __ b(deopt, NE);
- } else if (TargetCPUFeatures::can_divide()) {
- const QRegister qtmp = locs()->temp(0).fpu_reg();
- const DRegister dtmp0 = EvenDRegisterOf(qtmp);
- const DRegister dtmp1 = OddDRegisterOf(qtmp);
- __ CheckMultSignedOverflow(IP, right, result, dtmp0, dtmp1, deopt);
- __ mul(result, IP, right);
- } else {
- // TODO(vegorov): never emit this instruction if hardware does not
- // support it! This will lead to deopt cycle penalizing the code.
- __ b(deopt);
- }
+ __ smull(result, IP, IP, right);
+ // IP: result bits 32..63.
+ __ cmp(IP, Operand(result, ASR, 31));
+ __ b(deopt, NE);
}
break;
}
@@ -3297,22 +3261,17 @@
break;
}
case Token::kTRUNCDIV: {
+ ASSERT(TargetCPUFeatures::can_divide());
if ((right_range == NULL) || right_range->Overlaps(0, 0)) {
// Handle divide by zero in runtime.
__ cmp(right, Operand(0));
__ b(deopt, EQ);
}
const Register temp = locs()->temp(0).reg();
- if (TargetCPUFeatures::can_divide()) {
- const DRegister dtemp = EvenDRegisterOf(locs()->temp(1).fpu_reg());
- __ SmiUntag(temp, left);
- __ SmiUntag(IP, right);
- __ IntegerDivide(result, temp, IP, dtemp, DTMP);
- } else {
- // TODO(vegorov): never emit this instruction if hardware does not
- // support it! This will lead to deopt cycle penalizing the code.
- __ b(deopt);
- }
+ const DRegister dtemp = EvenDRegisterOf(locs()->temp(1).fpu_reg());
+ __ SmiUntag(temp, left);
+ __ SmiUntag(IP, right);
+ __ IntegerDivide(result, temp, IP, dtemp, DTMP);
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
// case we cannot tag the result.
@@ -3322,22 +3281,17 @@
break;
}
case Token::kMOD: {
+ ASSERT(TargetCPUFeatures::can_divide());
if ((right_range == NULL) || right_range->Overlaps(0, 0)) {
// Handle divide by zero in runtime.
__ cmp(right, Operand(0));
__ b(deopt, EQ);
}
const Register temp = locs()->temp(0).reg();
- if (TargetCPUFeatures::can_divide()) {
- const DRegister dtemp = EvenDRegisterOf(locs()->temp(1).fpu_reg());
- __ SmiUntag(temp, left);
- __ SmiUntag(IP, right);
- __ IntegerDivide(result, temp, IP, dtemp, DTMP);
- } else {
- // TODO(vegorov): never emit this instruction if hardware does not
- // support it! This will lead to deopt cycle penalizing the code.
- __ b(deopt);
- }
+ const DRegister dtemp = EvenDRegisterOf(locs()->temp(1).fpu_reg());
+ __ SmiUntag(temp, left);
+ __ SmiUntag(IP, right);
+ __ IntegerDivide(result, temp, IP, dtemp, DTMP);
__ SmiUntag(IP, right);
__ mls(result, IP, result, temp); // result <- left - right * result
__ SmiTag(result);
@@ -3432,9 +3386,6 @@
if (((op_kind() == Token::kSHL) && can_overflow()) ||
(op_kind() == Token::kSHR)) {
num_temps = 1;
- } else if ((op_kind() == Token::kMUL) &&
- (TargetCPUFeatures::arm_version() != ARMv7)) {
- num_temps = 1;
}
LocationSummary* summary = new(zone) LocationSummary(
zone, kNumInputs, num_temps, LocationSummary::kNoCall);
@@ -3444,11 +3395,6 @@
(op_kind() == Token::kSHR)) {
summary->set_temp(0, Location::RequiresRegister());
}
- if (op_kind() == Token::kMUL) {
- if (TargetCPUFeatures::arm_version() != ARMv7) {
- summary->set_temp(0, Location::RequiresFpuRegister());
- }
- }
// We make use of 3-operand instructions by not requiring result register
// to be identical to first input register as on Intel.
summary->set_out(0, Location::RequiresRegister());
@@ -3499,24 +3445,11 @@
__ LoadImmediate(IP, value);
__ mul(result, left, IP);
} else {
- if (TargetCPUFeatures::arm_version() == ARMv7) {
- __ LoadImmediate(IP, value);
- __ smull(result, IP, left, IP);
- // IP: result bits 32..63.
- __ cmp(IP, Operand(result, ASR, 31));
- __ b(deopt, NE);
- } else if (TargetCPUFeatures::can_divide()) {
- const QRegister qtmp = locs()->temp(0).fpu_reg();
- const DRegister dtmp0 = EvenDRegisterOf(qtmp);
- const DRegister dtmp1 = OddDRegisterOf(qtmp);
- __ LoadImmediate(IP, value);
- __ CheckMultSignedOverflow(left, IP, result, dtmp0, dtmp1, deopt);
- __ mul(result, left, IP);
- } else {
- // TODO(vegorov): never emit this instruction if hardware does not
- // support it! This will lead to deopt cycle penalizing the code.
- __ b(deopt);
- }
+ __ LoadImmediate(IP, value);
+ __ smull(result, IP, left, IP);
+ // IP: result bits 32..63.
+ __ cmp(IP, Operand(result, ASR, 31));
+ __ b(deopt, NE);
}
break;
}
@@ -3593,22 +3526,10 @@
if (deopt == NULL) {
__ mul(result, left, right);
} else {
- if (TargetCPUFeatures::arm_version() == ARMv7) {
- __ smull(result, IP, left, right);
- // IP: result bits 32..63.
- __ cmp(IP, Operand(result, ASR, 31));
- __ b(deopt, NE);
- } else if (TargetCPUFeatures::can_divide()) {
- const QRegister qtmp = locs()->temp(0).fpu_reg();
- const DRegister dtmp0 = EvenDRegisterOf(qtmp);
- const DRegister dtmp1 = OddDRegisterOf(qtmp);
- __ CheckMultSignedOverflow(left, right, result, dtmp0, dtmp1, deopt);
- __ mul(result, left, right);
- } else {
- // TODO(vegorov): never emit this instruction if hardware does not
- // support it! This will lead to deopt cycle penalizing the code.
- __ b(deopt);
- }
+ __ smull(result, IP, left, right);
+ // IP: result bits 32..63.
+ __ cmp(IP, Operand(result, ASR, 31));
+ __ b(deopt, NE);
}
break;
}
@@ -5880,6 +5801,7 @@
deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp);
}
if (kind() == MergedMathInstr::kTruncDivMod) {
+ ASSERT(TargetCPUFeatures::can_divide());
const Register left = locs()->in(0).reg();
const Register right = locs()->in(1).reg();
ASSERT(locs()->out(0).IsPairLocation());
@@ -5893,16 +5815,10 @@
__ b(deopt, EQ);
}
const Register temp = locs()->temp(0).reg();
- if (TargetCPUFeatures::can_divide()) {
- const DRegister dtemp = EvenDRegisterOf(locs()->temp(1).fpu_reg());
- __ SmiUntag(temp, left);
- __ SmiUntag(IP, right);
- __ IntegerDivide(result_div, temp, IP, dtemp, DTMP);
- } else {
- // TODO(vegorov): never emit this instruction if hardware does not
- // support it! This will lead to deopt cycle penalizing the code.
- __ b(deopt);
- }
+ const DRegister dtemp = EvenDRegisterOf(locs()->temp(1).fpu_reg());
+ __ SmiUntag(temp, left);
+ __ SmiUntag(IP, right);
+ __ IntegerDivide(result_div, temp, IP, dtemp, DTMP);
// Check the corner case of dividing the 'MIN_SMI' with -1, in which
// case we cannot tag the result.
@@ -6020,7 +5936,9 @@
if (IsNullCheck()) {
__ CompareImmediate(locs()->in(0).reg(),
reinterpret_cast<intptr_t>(Object::null()));
- __ b(deopt, EQ);
+ ASSERT(DeoptIfNull() || DeoptIfNotNull());
+ Condition cond = DeoptIfNull() ? EQ : NE;
+ __ b(deopt, cond);
return;
}
@@ -6261,16 +6179,10 @@
// result without causing overflow.
// We deopt on larger inputs.
// TODO(regis): Range analysis may eliminate the deopt check.
- if (TargetCPUFeatures::arm_version() == ARMv7) {
- __ cmp(left_hi, Operand(left_lo, ASR, 31));
- __ cmp(right_hi, Operand(right_lo, ASR, 31), EQ);
- __ b(deopt, NE);
- __ smull(out_lo, out_hi, left_lo, right_lo);
- } else {
- // TODO(vegorov): never emit this instruction if hardware does not
- // support it! This will lead to deopt cycle penalizing the code.
- __ b(deopt);
- }
+ __ cmp(left_hi, Operand(left_lo, ASR, 31));
+ __ cmp(right_hi, Operand(right_lo, ASR, 31), EQ);
+ __ b(deopt, NE);
+ __ smull(out_lo, out_hi, left_lo, right_lo);
break;
}
default:
@@ -6935,10 +6847,6 @@
StubCode* stub_code = compiler->isolate()->stub_code();
const ExternalLabel label(stub_code->DebugStepCheckEntryPoint());
compiler->GenerateCall(token_pos(), &label, stub_kind_, locs());
-#if defined(DEBUG)
- __ LoadImmediate(R4, kInvalidObjectPointer);
- __ LoadImmediate(R5, kInvalidObjectPointer);
-#endif
}
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 846414a..3956689 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -5090,7 +5090,9 @@
licm_hoisted_ ? ICData::kHoisted : 0);
if (IsNullCheck()) {
__ CompareObject(locs()->in(0).reg(), Object::null_object(), PP);
- __ b(deopt, EQ);
+ ASSERT(DeoptIfNull() || DeoptIfNotNull());
+ Condition cond = DeoptIfNull() ? EQ : NE;
+ __ b(deopt, cond);
return;
}
@@ -5607,10 +5609,6 @@
StubCode* stub_code = compiler->isolate()->stub_code();
const ExternalLabel label(stub_code->DebugStepCheckEntryPoint());
compiler->GenerateCall(token_pos(), &label, stub_kind_, locs());
-#if defined(DEBUG)
- __ LoadImmediate(R4, kInvalidObjectPointer, kNoPP);
- __ LoadImmediate(R5, kInvalidObjectPointer, kNoPP);
-#endif
}
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index d9e565a..6d70aa4 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -5763,7 +5763,9 @@
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ cmpl(locs()->in(0).reg(), raw_null);
- __ j(EQUAL, deopt);
+ ASSERT(DeoptIfNull() || DeoptIfNotNull());
+ Condition cond = DeoptIfNull() ? EQUAL : NOT_EQUAL;
+ __ j(cond, deopt);
return;
}
@@ -6843,9 +6845,6 @@
StubCode* stub_code = compiler->isolate()->stub_code();
const ExternalLabel label(stub_code->DebugStepCheckEntryPoint());
compiler->GenerateCall(token_pos(), &label, stub_kind_, locs());
-#if defined(DEBUG)
- __ movl(EDX, Immediate(kInvalidObjectPointer));
-#endif
}
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 5bf3c7d..2274bf8 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -54,7 +54,7 @@
void PushArgumentInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// In SSA mode, we need an explicit push. Nothing to do in non-SSA mode
// where PushArgument is handled by BindInstr::EmitNativeCode.
- __ TraceSimMsg("PushArgumentInstr");
+ __ Comment("PushArgumentInstr");
if (compiler->is_optimizing()) {
Location value = locs()->in(0);
if (value.IsRegister()) {
@@ -86,7 +86,7 @@
// The entry needs to be patchable, no inlined objects are allowed in the area
// that will be overwritten by the patch instructions: a branch macro sequence.
void ReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("ReturnInstr");
+ __ Comment("ReturnInstr");
Register result = locs()->in(0).reg();
ASSERT(result == V0);
@@ -99,7 +99,6 @@
#if defined(DEBUG)
Label stack_ok;
__ Comment("Stack Check");
- __ TraceSimMsg("Stack Check");
const intptr_t fp_sp_dist =
(kFirstLocalSlotFromFp + 1 - compiler->StackSize()) * kWordSize;
ASSERT(fp_sp_dist <= 0);
@@ -309,7 +308,7 @@
void LoadLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("LoadLocalInstr");
+ __ Comment("LoadLocalInstr");
Register result = locs()->out(0).reg();
__ LoadFromOffset(result, FP, local().index() * kWordSize);
}
@@ -325,7 +324,7 @@
void StoreLocalInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("StoreLocalInstr");
+ __ Comment("StoreLocalInstr");
Register value = locs()->in(0).reg();
Register result = locs()->out(0).reg();
ASSERT(result == value); // Assert that register assignment is correct.
@@ -345,7 +344,7 @@
void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// The register allocator drops constant definitions that have no uses.
if (!locs()->out(0).IsInvalid()) {
- __ TraceSimMsg("ConstantInstr");
+ __ Comment("ConstantInstr");
Register result = locs()->out(0).reg();
__ LoadObject(result, value());
}
@@ -457,7 +456,7 @@
Register obj = locs()->in(0).reg();
Register result = locs()->out(0).reg();
- __ TraceSimMsg("AssertBooleanInstr");
+ __ Comment("AssertBooleanInstr");
EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
ASSERT(obj == result);
}
@@ -508,7 +507,7 @@
Register value_cid_reg,
Register value_reg,
Label* value_is_smi = NULL) {
- __ TraceSimMsg("LoadValueCid");
+ __ Comment("LoadValueCid");
Label done;
if (value_is_smi == NULL) {
__ LoadImmediate(value_cid_reg, kSmiCid);
@@ -558,7 +557,7 @@
static void EmitBranchOnCondition(FlowGraphCompiler* compiler,
Condition true_condition,
BranchLabels labels) {
- __ TraceSimMsg("ControlInstruction::EmitBranchOnCondition");
+ __ Comment("ControlInstruction::EmitBranchOnCondition");
if (labels.fall_through == labels.false_label) {
// If the next block is the false successor, fall through to it.
__ BranchOnCondition(true_condition, labels.true_label);
@@ -577,7 +576,6 @@
static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler,
const LocationSummary& locs,
Token::Kind kind) {
- __ TraceSimMsg("EmitSmiComparisonOp");
__ Comment("EmitSmiComparisonOp");
const Location left = locs.in(0);
const Location right = locs.in(1);
@@ -598,7 +596,6 @@
const LocationSummary& locs,
Token::Kind kind,
BranchLabels labels) {
- __ TraceSimMsg("EmitUnboxedMintEqualityOp");
__ Comment("EmitUnboxedMintEqualityOp");
ASSERT(Token::IsEqualityOperator(kind));
PairLocation* left_pair = locs.in(0).AsPairLocation();
@@ -630,7 +627,6 @@
const LocationSummary& locs,
Token::Kind kind,
BranchLabels labels) {
- __ TraceSimMsg("EmitUnboxedMintComparisonOp");
__ Comment("EmitUnboxedMintComparisonOp");
PairLocation* left_pair = locs.in(0).AsPairLocation();
Register left_lo = left_pair->At(0).reg();
@@ -773,8 +769,7 @@
void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
- __ TraceSimMsg("EqualityCompareInstr");
- __ Comment("EqualityCompareInstr:BranchCode");
+ __ Comment("EqualityCompareInstr::EmitBranchCode");
ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
BranchLabels labels = compiler->CreateBranchLabels(branch);
@@ -950,7 +945,7 @@
void RelationalOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("RelationalOpInstr");
+ __ Comment("RelationalOpInstr");
Label is_true, is_false;
BranchLabels labels = { &is_true, &is_false, &is_false };
@@ -970,7 +965,7 @@
void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
- __ TraceSimMsg("RelationalOpInstr");
+ __ Comment("RelationalOpInstr");
BranchLabels labels = compiler->CreateBranchLabels(branch);
Condition true_condition = EmitComparisonCode(compiler, labels);
@@ -985,7 +980,7 @@
void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("NativeCallInstr");
+ __ Comment("NativeCallInstr");
Register result = locs()->out(0).reg();
// Push the result place holder initialized to NULL.
@@ -1049,7 +1044,7 @@
Register char_code = locs()->in(0).reg();
Register result = locs()->out(0).reg();
- __ TraceSimMsg("StringFromCharCodeInstr");
+ __ Comment("StringFromCharCodeInstr");
__ LoadImmediate(result,
reinterpret_cast<uword>(Symbols::PredefinedAddress()));
@@ -1071,7 +1066,7 @@
void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("StringToCharCodeInstr");
+ __ Comment("StringToCharCodeInstr");
ASSERT(cid_ == kOneByteStringCid);
Register str = locs()->in(0).reg();
@@ -1262,7 +1257,7 @@
void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("LoadIndexedInstr");
+ __ Comment("LoadIndexedInstr");
// The array register points to the backing store for external arrays.
const Register array = locs()->in(0).reg();
const Location index = locs()->in(1);
@@ -1300,9 +1295,6 @@
if ((representation() == kUnboxedUint32) ||
(representation() == kUnboxedInt32)) {
const Register result = locs()->out(0).reg();
- if ((index_scale() == 1) && index.IsRegister()) {
- __ SmiUntag(index.reg());
- }
switch (class_id()) {
case kTypedDataInt32ArrayCid:
ASSERT(representation() == kUnboxedInt32);
@@ -1488,7 +1480,7 @@
void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("StoreIndexedInstr");
+ __ Comment("StoreIndexedInstr");
// The array register points to the backing store for external arrays.
const Register array = locs()->in(0).reg();
const Location index = locs()->in(1);
@@ -1620,7 +1612,7 @@
void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("GuardFieldClassInstr");
+ __ Comment("GuardFieldClassInstr");
const intptr_t value_cid = value()->Type()->ToCid();
const intptr_t field_cid = field().guarded_cid();
@@ -2093,7 +2085,7 @@
//
// This is safe only so long as LoadStaticFieldInstr cannot deoptimize.
void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("LoadStaticFieldInstr");
+ __ Comment("LoadStaticFieldInstr");
Register field = locs()->in(0).reg();
Register result = locs()->out(0).reg();
__ LoadFromOffset(result, field, Field::value_offset() - kHeapObjectTag);
@@ -2112,7 +2104,7 @@
void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("StoreStaticFieldInstr");
+ __ Comment("StoreStaticFieldInstr");
Register value = locs()->in(0).reg();
Register temp = locs()->temp(0).reg();
@@ -2226,7 +2218,7 @@
void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("CreateArrayInstr");
+ __ Comment("CreateArrayInstr");
const Register kLengthReg = A1;
const Register kElemTypeReg = A0;
const Register kResultReg = V0;
@@ -2375,7 +2367,7 @@
void InstantiateTypeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("InstantiateTypeInstr");
+ __ Comment("InstantiateTypeInstr");
Register instantiator_reg = locs()->in(0).reg();
Register result_reg = locs()->out(0).reg();
@@ -2416,7 +2408,7 @@
void InstantiateTypeArgumentsInstr::EmitNativeCode(
FlowGraphCompiler* compiler) {
- __ TraceSimMsg("InstantiateTypeArgumentsInstr");
+ __ Comment("InstantiateTypeArgumentsInstr");
Register instantiator_reg = locs()->in(0).reg();
Register result_reg = locs()->out(0).reg();
ASSERT(instantiator_reg == T0);
@@ -2566,7 +2558,7 @@
ASSERT(locs()->temp(0).reg() == T1);
ASSERT(locs()->out(0).reg() == V0);
- __ TraceSimMsg("AllocateContextInstr");
+ __ Comment("AllocateContextInstr");
__ LoadImmediate(T1, num_context_variables());
StubCode* stub_code = compiler->isolate()->stub_code();
const ExternalLabel label(stub_code->AllocateContextEntryPoint());
@@ -2594,7 +2586,7 @@
Register temp = locs()->temp(0).reg();
Label call_runtime, no_call;
- __ TraceSimMsg("InitStaticFieldInstr");
+ __ Comment("InitStaticFieldInstr");
__ lw(temp, FieldAddress(field, Field::value_offset()));
__ BranchEqual(temp, Object::sentinel(), &call_runtime);
@@ -2634,7 +2626,7 @@
Register context_value = locs()->in(0).reg();
Register result = locs()->out(0).reg();
- __ TraceSimMsg("CloneContextInstr");
+ __ Comment("CloneContextInstr");
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ LoadObject(TMP, Object::null_object()); // Make room for the result.
@@ -2714,14 +2706,12 @@
if (FLAG_use_osr) {
uword flags_address = Isolate::Current()->stack_overflow_flags_address();
Register value = instruction_->locs()->temp(0).reg();
- __ TraceSimMsg("CheckStackOverflowSlowPathOsr");
__ Comment("CheckStackOverflowSlowPathOsr");
__ Bind(osr_entry_label());
__ LoadImmediate(TMP, flags_address);
__ LoadImmediate(value, Isolate::kOsrRequest);
__ sw(value, Address(TMP));
}
- __ TraceSimMsg("CheckStackOverflowSlowPath");
__ Comment("CheckStackOverflowSlowPath");
__ Bind(entry_label());
compiler->SaveLiveRegisters(instruction_->locs());
@@ -2759,7 +2749,7 @@
void CheckStackOverflowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("CheckStackOverflowInstr");
+ __ Comment("CheckStackOverflowInstr");
CheckStackOverflowSlowPath* slow_path = new CheckStackOverflowSlowPath(this);
compiler->AddSlowPathCode(slow_path);
@@ -2794,7 +2784,7 @@
compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp)
: NULL;
- __ TraceSimMsg("EmitSmiShiftLeft");
+ __ Comment("EmitSmiShiftLeft");
if (locs.in(1).IsConstant()) {
const Object& constant = locs.in(1).constant();
@@ -2933,7 +2923,7 @@
void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("BinarySmiOpInstr");
+ __ Comment("BinarySmiOpInstr");
if (op_kind() == Token::kSHL) {
EmitSmiShiftLeft(compiler, this);
return;
@@ -2962,7 +2952,7 @@
break;
}
case Token::kSUB: {
- __ TraceSimMsg("kSUB imm");
+ __ Comment("kSUB imm");
if (deopt == NULL) {
__ AddImmediate(result, left, -imm);
} else {
@@ -3022,7 +3012,7 @@
// sarl operation masks the count to 5 bits.
const intptr_t kCountLimit = 0x1F;
const intptr_t value = Smi::Cast(constant).Value();
- __ TraceSimMsg("kSHR");
+ __ Comment("kSHR");
__ sra(result, left, Utils::Minimum(value + kSmiTagSize, kCountLimit));
__ SmiTag(result);
break;
@@ -3049,7 +3039,7 @@
break;
}
case Token::kSUB: {
- __ TraceSimMsg("kSUB");
+ __ Comment("kSUB");
if (deopt == NULL) {
__ subu(result, left, right);
} else {
@@ -3059,7 +3049,7 @@
break;
}
case Token::kMUL: {
- __ TraceSimMsg("kMUL");
+ __ Comment("kMUL");
__ sra(TMP, left, kSmiTagSize);
__ mult(TMP, right);
__ mflo(result);
@@ -4598,7 +4588,7 @@
void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("PolymorphicInstanceCallInstr");
+ __ Comment("PolymorphicInstanceCallInstr");
ASSERT(ic_data().NumArgsTested() == 1);
if (!with_checks()) {
ASSERT(ic_data().HasOneTarget());
@@ -4642,7 +4632,7 @@
void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("BranchInstr");
+ __ Comment("BranchInstr");
comparison()->EmitBranchCode(compiler, this);
}
@@ -4670,7 +4660,12 @@
ICData::kDeoptCheckClass,
licm_hoisted_ ? ICData::kHoisted : 0);
if (IsNullCheck()) {
- __ BranchEqual(locs()->in(0).reg(), Object::null_object(), deopt);
+ if (DeoptIfNull()) {
+ __ BranchEqual(locs()->in(0).reg(), Object::null_object(), deopt);
+ } else {
+ ASSERT(DeoptIfNotNull());
+ __ BranchNotEqual(locs()->in(0).reg(), Object::null_object(), deopt);
+ }
return;
}
@@ -4739,7 +4734,7 @@
void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("CheckSmiInstr");
+ __ Comment("CheckSmiInstr");
Register value = locs()->in(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(),
ICData::kDeoptCheckSmi,
@@ -5004,6 +4999,14 @@
// Code for a variable shift amount.
Register shift = locs()->in(1).reg();
+ // Code below assumes shift amount is not 0 (cannot shift by 32 - 0).
+ Label non_zero_shift, done;
+ __ bne(shift, ZR, &non_zero_shift);
+ __ delay_slot()->mov(out_lo, left_lo);
+ __ b(&done);
+ __ delay_slot()->mov(out_hi, left_hi);
+ __ Bind(&non_zero_shift);
+
// Deopt if shift is larger than 63 or less than 0.
if (has_shift_count_check()) {
__ sltiu(CMPRES1, shift, Immediate(2*(kMintShiftCountLimit + 1)));
@@ -5017,11 +5020,11 @@
switch (op_kind()) {
case Token::kSHR: {
- Label large_shift, done;
+ Label large_shift;
__ sltiu(CMPRES1, shift, Immediate(32));
__ beq(CMPRES1, ZR, &large_shift);
- // shift < 32.
+ // 0 < shift < 32.
__ delay_slot()->ori(TMP, ZR, Immediate(32));
__ subu(TMP, TMP, shift); // TMP = 32 - shift; 0 < TMP <= 31.
__ sllv(out_lo, left_hi, TMP);
@@ -5035,15 +5038,14 @@
__ sra(out_hi, left_hi, 31);
__ srav(out_lo, left_hi, shift); // Only 5 low bits of shift used.
- __ Bind(&done);
break;
}
case Token::kSHL: {
- Label large_shift, done;
+ Label large_shift;
__ sltiu(CMPRES1, shift, Immediate(32));
__ beq(CMPRES1, ZR, &large_shift);
- // shift < 32.
+ // 0 < shift < 32.
__ delay_slot()->ori(TMP, ZR, Immediate(32));
__ subu(TMP, TMP, shift); // TMP = 32 - shift; 0 < TMP <= 31.
__ srlv(out_hi, left_lo, TMP);
@@ -5077,12 +5079,12 @@
} else {
__ mov(out_lo, ZR);
}
- __ Bind(&done);
break;
}
default:
UNREACHABLE();
}
+ __ Bind(&done);
}
}
@@ -5393,7 +5395,7 @@
void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("GotoInstr");
+ __ Comment("GotoInstr");
if (!compiler->is_optimizing()) {
if (FLAG_emit_edge_counters) {
compiler->EmitEdgeCounter();
@@ -5508,7 +5510,6 @@
void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("StrictCompareInstr");
__ Comment("StrictCompareInstr");
ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
@@ -5530,7 +5531,7 @@
void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch) {
- __ TraceSimMsg("StrictCompareInstr::EmitBranchCode");
+ __ Comment("StrictCompareInstr::EmitBranchCode");
ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT);
BranchLabels labels = compiler->CreateBranchLabels(branch);
@@ -5566,7 +5567,6 @@
void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- __ TraceSimMsg("AllocateObjectInstr");
__ Comment("AllocateObjectInstr");
Isolate* isolate = compiler->isolate();
StubCode* stub_code = isolate->stub_code();
@@ -5587,10 +5587,6 @@
StubCode* stub_code = compiler->isolate()->stub_code();
const ExternalLabel label(stub_code->DebugStepCheckEntryPoint());
compiler->GenerateCall(token_pos(), &label, stub_kind_, locs());
-#if defined(DEBUG)
- __ LoadImmediate(S4, kInvalidObjectPointer);
- __ LoadImmediate(S5, kInvalidObjectPointer);
-#endif
}
@@ -5609,7 +5605,7 @@
void GrowRegExpStackInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Register typed_data = locs()->in(0).reg();
const Register result = locs()->out(0).reg();
- __ TraceSimMsg("GrowRegExpStackInstr");
+ __ Comment("GrowRegExpStackInstr");
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ LoadObject(TMP, Object::null_object());
__ sw(TMP, Address(SP, 1 * kWordSize));
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index ee1a43b..9e81b43 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -5503,7 +5503,8 @@
if (IsNullCheck()) {
__ CompareObject(locs()->in(0).reg(),
Object::null_object(), PP);
- __ j(EQUAL, deopt);
+ Condition cond = DeoptIfNull() ? EQUAL : NOT_EQUAL;
+ __ j(cond, deopt);
return;
}
@@ -6410,10 +6411,6 @@
StubCode* stub_code = compiler->isolate()->stub_code();
const ExternalLabel label(stub_code->DebugStepCheckEntryPoint());
compiler->GenerateCall(token_pos(), &label, stub_kind_, locs());
-#if defined(DEBUG)
- __ movq(R10, Immediate(kInvalidObjectPointer));
- __ movq(RBX, Immediate(kInvalidObjectPointer));
-#endif
}
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index b5b3ccf..5705f29 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -261,7 +261,7 @@
__ Bind(&init_loop); \
__ AddImmediate(R3, 2 * kWordSize); \
__ cmp(R3, Operand(R1)); \
- __ strd(R6, Address(R3, -2 * kWordSize), LS); \
+ __ strd(R6, R3, -2 * kWordSize, LS); \
__ b(&init_loop, CC); \
__ str(R6, Address(R3, -2 * kWordSize), HI); \
\
@@ -348,23 +348,13 @@
void Intrinsifier::Integer_mulFromInteger(Assembler* assembler) {
- if (TargetCPUFeatures::arm_version() == ARMv7) {
- Label fall_through;
- TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
- __ SmiUntag(R0); // Untags R6. We only want result shifted by one.
- __ smull(R0, IP, R0, R1); // IP:R0 <- R0 * R1.
- __ cmp(IP, Operand(R0, ASR, 31));
- __ bx(LR, EQ);
- __ Bind(&fall_through); // Fall through on overflow.
- } else if (TargetCPUFeatures::can_divide()) {
- Label fall_through;
- TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
- __ SmiUntag(R0); // Untags R6. We only want result shifted by one.
- __ CheckMultSignedOverflow(R0, R1, IP, D0, D1, &fall_through);
- __ mul(R0, R0, R1);
- __ Ret();
- __ Bind(&fall_through); // Fall through on overflow.
- }
+ Label fall_through;
+ TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
+ __ SmiUntag(R0); // Untags R6. We only want result shifted by one.
+ __ smull(R0, IP, R0, R1); // IP:R0 <- R0 * R1.
+ __ cmp(IP, Operand(R0, ASR, 31));
+ __ bx(LR, EQ);
+ __ Bind(&fall_through); // Fall through on overflow.
}
@@ -800,18 +790,28 @@
}
+void Intrinsifier::Bigint_lsh(Assembler* assembler) {
+ // TODO(regis): Implement.
+}
+
+
+void Intrinsifier::Bigint_rsh(Assembler* assembler) {
+ // TODO(regis): Implement.
+}
+
+
void Intrinsifier::Bigint_absAdd(Assembler* assembler) {
// static void _absAdd(Uint32List digits, int used,
// Uint32List a_digits, int a_used,
// Uint32List r_digits)
// R2 = used, R3 = digits
- __ ldrd(R2, Address(SP, 3 * kWordSize));
+ __ ldrd(R2, SP, 3 * kWordSize);
// R3 = &digits[0]
__ add(R3, R3, Operand(TypedData::data_offset() - kHeapObjectTag));
// R4 = a_used, R5 = a_digits
- __ ldrd(R4, Address(SP, 1 * kWordSize));
+ __ ldrd(R4, SP, 1 * kWordSize);
// R5 = &a_digits[0]
__ add(R5, R5, Operand(TypedData::data_offset() - kHeapObjectTag));
@@ -866,12 +866,12 @@
// Uint32List r_digits)
// R2 = used, R3 = digits
- __ ldrd(R2, Address(SP, 3 * kWordSize));
+ __ ldrd(R2, SP, 3 * kWordSize);
// R3 = &digits[0]
__ add(R3, R3, Operand(TypedData::data_offset() - kHeapObjectTag));
// R4 = a_used, R5 = a_digits
- __ ldrd(R4, Address(SP, 1 * kWordSize));
+ __ ldrd(R4, SP, 1 * kWordSize);
// R5 = &a_digits[0]
__ add(R5, R5, Operand(TypedData::data_offset() - kHeapObjectTag));
@@ -917,9 +917,6 @@
void Intrinsifier::Bigint_mulAdd(Assembler* assembler) {
- if (TargetCPUFeatures::arm_version() != ARMv7) {
- return;
- }
// Pseudo code:
// static int _mulAdd(Uint32List x_digits, int xi,
// Uint32List m_digits, int i,
@@ -949,7 +946,7 @@
Label done;
// R3 = x, no_op if x == 0
- __ ldrd(R0, Address(SP, 5 * kWordSize)); // R0 = xi as Smi, R1 = x_digits.
+ __ ldrd(R0, SP, 5 * kWordSize); // R0 = xi as Smi, R1 = x_digits.
__ add(R1, R1, Operand(R0, LSL, 1));
__ ldr(R3, FieldAddress(R1, TypedData::data_offset()));
__ tst(R3, Operand(R3));
@@ -961,12 +958,12 @@
__ b(&done, EQ);
// R4 = mip = &m_digits[i >> 1]
- __ ldrd(R0, Address(SP, 3 * kWordSize)); // R0 = i as Smi, R1 = m_digits.
+ __ ldrd(R0, SP, 3 * kWordSize); // R0 = i as Smi, R1 = m_digits.
__ add(R1, R1, Operand(R0, LSL, 1));
__ add(R4, R1, Operand(TypedData::data_offset() - kHeapObjectTag));
// R5 = ajp = &a_digits[j >> 1]
- __ ldrd(R0, Address(SP, 1 * kWordSize)); // R0 = j as Smi, R1 = a_digits.
+ __ ldrd(R0, SP, 1 * kWordSize); // R0 = j as Smi, R1 = a_digits.
__ add(R1, R1, Operand(R0, LSL, 1));
__ add(R5, R1, Operand(TypedData::data_offset() - kHeapObjectTag));
@@ -1022,9 +1019,6 @@
void Intrinsifier::Bigint_sqrAdd(Assembler* assembler) {
- if (TargetCPUFeatures::arm_version() != ARMv7) {
- return;
- }
// Pseudo code:
// static int _sqrAdd(Uint32List x_digits, int i,
// Uint32List a_digits, int used) {
@@ -1052,7 +1046,7 @@
// }
// R4 = xip = &x_digits[i >> 1]
- __ ldrd(R2, Address(SP, 2 * kWordSize)); // R2 = i as Smi, R3 = x_digits
+ __ ldrd(R2, SP, 2 * kWordSize); // R2 = i as Smi, R3 = x_digits
__ add(R3, R3, Operand(R2, LSL, 1));
__ add(R4, R3, Operand(TypedData::data_offset() - kHeapObjectTag));
@@ -1130,7 +1124,7 @@
// *ajp = low32(t) = R6
// *(ajp + 1) = high32(t) = R7
- __ strd(R6, Address(R5, 0));
+ __ strd(R6, R5, 0);
__ Bind(&x_zero);
__ mov(R0, Operand(Smi::RawValue(1))); // One digit processed.
@@ -1144,9 +1138,6 @@
void Intrinsifier::Montgomery_mulMod(Assembler* assembler) {
- if (TargetCPUFeatures::arm_version() != ARMv7) {
- return;
- }
// Pseudo code:
// static int _mulMod(Uint32List args, Uint32List digits, int i) {
// uint32_t rho = args[_RHO]; // _RHO == 2.
@@ -1164,7 +1155,7 @@
TypedData::data_offset() + 2*Bigint::kBytesPerDigit));
// R2 = digits[i >> 1]
- __ ldrd(R0, Address(SP, 0 * kWordSize)); // R0 = i as Smi, R1 = digits
+ __ ldrd(R0, SP, 0 * kWordSize); // R0 = i as Smi, R1 = digits
__ add(R1, R1, Operand(R0, LSL, 1));
__ ldr(R2, FieldAddress(R1, TypedData::data_offset()));
@@ -1444,44 +1435,41 @@
// _state[kSTATE_LO] = state & _MASK_32;
// _state[kSTATE_HI] = state >> 32;
void Intrinsifier::Random_nextState(Assembler* assembler) {
- // No 32x32 -> 64 bit multiply/accumulate on ARMv5 or ARMv6.
- if (TargetCPUFeatures::arm_version() == ARMv7) {
- const Library& math_lib = Library::Handle(Library::MathLibrary());
- ASSERT(!math_lib.IsNull());
- const Class& random_class = Class::Handle(
- math_lib.LookupClassAllowPrivate(Symbols::_Random()));
- ASSERT(!random_class.IsNull());
- const Field& state_field = Field::ZoneHandle(
- random_class.LookupInstanceField(Symbols::_state()));
- ASSERT(!state_field.IsNull());
- const Field& random_A_field = Field::ZoneHandle(
- random_class.LookupStaticField(Symbols::_A()));
- ASSERT(!random_A_field.IsNull());
- ASSERT(random_A_field.is_const());
- const Instance& a_value = Instance::Handle(random_A_field.value());
- const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
- // 'a_int_value' is a mask.
- ASSERT(Utils::IsUint(32, a_int_value));
- int32_t a_int32_value = static_cast<int32_t>(a_int_value);
+ const Library& math_lib = Library::Handle(Library::MathLibrary());
+ ASSERT(!math_lib.IsNull());
+ const Class& random_class = Class::Handle(
+ math_lib.LookupClassAllowPrivate(Symbols::_Random()));
+ ASSERT(!random_class.IsNull());
+ const Field& state_field = Field::ZoneHandle(
+ random_class.LookupInstanceField(Symbols::_state()));
+ ASSERT(!state_field.IsNull());
+ const Field& random_A_field = Field::ZoneHandle(
+ random_class.LookupStaticField(Symbols::_A()));
+ ASSERT(!random_A_field.IsNull());
+ ASSERT(random_A_field.is_const());
+ const Instance& a_value = Instance::Handle(random_A_field.value());
+ const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
+ // 'a_int_value' is a mask.
+ ASSERT(Utils::IsUint(32, a_int_value));
+ int32_t a_int32_value = static_cast<int32_t>(a_int_value);
- __ ldr(R0, Address(SP, 0 * kWordSize)); // Receiver.
- __ ldr(R1, FieldAddress(R0, state_field.Offset())); // Field '_state'.
- // Addresses of _state[0] and _state[1].
+ __ ldr(R0, Address(SP, 0 * kWordSize)); // Receiver.
+ __ ldr(R1, FieldAddress(R0, state_field.Offset())); // Field '_state'.
+ // Addresses of _state[0] and _state[1].
- const int64_t disp_0 = Instance::DataOffsetFor(kTypedDataUint32ArrayCid);
- const int64_t disp_1 = disp_0 +
- Instance::ElementSizeFor(kTypedDataUint32ArrayCid);
+ const int64_t disp_0 = Instance::DataOffsetFor(kTypedDataUint32ArrayCid);
+ const int64_t disp_1 = disp_0 +
+ Instance::ElementSizeFor(kTypedDataUint32ArrayCid);
- __ LoadImmediate(R0, a_int32_value);
- __ LoadFromOffset(kWord, R2, R1, disp_0 - kHeapObjectTag);
- __ LoadFromOffset(kWord, R3, R1, disp_1 - kHeapObjectTag);
- __ mov(R6, Operand(0)); // Zero extend unsigned _state[kSTATE_HI].
- // Unsigned 32-bit multiply and 64-bit accumulate into R6:R3.
- __ umlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2.
- __ StoreToOffset(kWord, R3, R1, disp_0 - kHeapObjectTag);
- __ StoreToOffset(kWord, R6, R1, disp_1 - kHeapObjectTag);
- __ Ret();
- }
+ __ LoadImmediate(R0, a_int32_value);
+ __ LoadFromOffset(kWord, R2, R1, disp_0 - kHeapObjectTag);
+ __ LoadFromOffset(kWord, R3, R1, disp_1 - kHeapObjectTag);
+ __ mov(R6, Operand(0)); // Zero extend unsigned _state[kSTATE_HI].
+ // Unsigned 32-bit multiply and 64-bit accumulate into R6:R3.
+ __ umlal(R3, R6, R0, R2); // R6:R3 <- R6:R3 + R0 * R2.
+ __ StoreToOffset(kWord, R3, R1, disp_0 - kHeapObjectTag);
+ __ StoreToOffset(kWord, R6, R1, disp_1 - kHeapObjectTag);
+ __ Ret();
}
@@ -1886,9 +1874,6 @@
void Intrinsifier::JSRegExp_ExecuteMatch(Assembler* assembler) {
- if (FLAG_use_jscre) {
- return;
- }
static const intptr_t kRegExpParamOffset = 2 * kWordSize;
static const intptr_t kStringParamOffset = 1 * kWordSize;
// start_index smi is located at offset 0.
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index f85b09b..baf7a66 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -689,6 +689,16 @@
}
+void Intrinsifier::Bigint_lsh(Assembler* assembler) {
+ // TODO(regis): Implement.
+}
+
+
+void Intrinsifier::Bigint_rsh(Assembler* assembler) {
+ // TODO(regis): Implement.
+}
+
+
void Intrinsifier::Bigint_absAdd(Assembler* assembler) {
// static void _absAdd(Uint32List digits, int used,
// Uint32List a_digits, int a_used,
@@ -1937,9 +1947,6 @@
void Intrinsifier::JSRegExp_ExecuteMatch(Assembler* assembler) {
- if (FLAG_use_jscre) {
- return;
- }
static const intptr_t kRegExpParamOffset = 2 * kWordSize;
static const intptr_t kStringParamOffset = 1 * kWordSize;
// start_index smi is located at offset 0.
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index bd4ee51..a73612d 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -805,6 +805,16 @@
}
+void Intrinsifier::Bigint_lsh(Assembler* assembler) {
+ // TODO(regis): Implement.
+}
+
+
+void Intrinsifier::Bigint_rsh(Assembler* assembler) {
+ // TODO(regis): Implement.
+}
+
+
void Intrinsifier::Bigint_absAdd(Assembler* assembler) {
// static void _absAdd(Uint32List digits, int used,
// Uint32List a_digits, int a_used,
@@ -1931,9 +1941,6 @@
void Intrinsifier::JSRegExp_ExecuteMatch(Assembler* assembler) {
- if (FLAG_use_jscre) {
- return;
- }
static const intptr_t kRegExpParamOffset = 3 * kWordSize;
static const intptr_t kStringParamOffset = 2 * kWordSize;
// start_index smi is located at offset 1.
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 61d2799..63c7ac0 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -783,6 +783,16 @@
}
+void Intrinsifier::Bigint_lsh(Assembler* assembler) {
+ // TODO(regis): Implement.
+}
+
+
+void Intrinsifier::Bigint_rsh(Assembler* assembler) {
+ // TODO(regis): Implement.
+}
+
+
void Intrinsifier::Bigint_absAdd(Assembler* assembler) {
// static void _absAdd(Uint32List digits, int used,
// Uint32List a_digits, int a_used,
@@ -1959,9 +1969,6 @@
void Intrinsifier::JSRegExp_ExecuteMatch(Assembler* assembler) {
- if (FLAG_use_jscre) {
- return;
- }
static const intptr_t kRegExpParamOffset = 2 * kWordSize;
static const intptr_t kStringParamOffset = 1 * kWordSize;
// start_index smi is located at 0.
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index c1d8171..9a5baf3 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -725,6 +725,84 @@
}
+void Intrinsifier::Bigint_lsh(Assembler* assembler) {
+ // static void _lsh(Uint32List x_digits, int x_used, int n,
+ // Uint32List r_digits)
+
+ __ movq(RDI, Address(RSP, 4 * kWordSize)); // x_digits
+ __ movq(R8, Address(RSP, 3 * kWordSize)); // x_used is Smi
+ __ subq(R8, Immediate(2)); // x_used > 0, Smi. R8 = x_used - 1, round up.
+ __ sarq(R8, Immediate(2)); // R8 + 1 = number of digit pairs to read.
+ __ movq(RCX, Address(RSP, 2 * kWordSize)); // n is Smi
+ __ SmiUntag(RCX);
+ __ movq(RBX, Address(RSP, 1 * kWordSize)); // r_digits
+ __ movq(RSI, RCX);
+ __ sarq(RSI, Immediate(6)); // RSI = n ~/ (2*_DIGIT_BITS).
+ __ leaq(RBX, FieldAddress(RBX, RSI, TIMES_8, TypedData::data_offset()));
+ __ xorq(RAX, RAX); // RAX = 0.
+ __ movq(RDX, FieldAddress(RDI, R8, TIMES_8, TypedData::data_offset()));
+ __ shldq(RAX, RDX, RCX);
+ __ movq(Address(RBX, R8, TIMES_8, 2 * Bigint::kBytesPerDigit), RAX);
+ Label last;
+ __ cmpq(R8, Immediate(0));
+ __ j(EQUAL, &last, Assembler::kNearJump);
+ Label loop;
+ __ Bind(&loop);
+ __ movq(RAX, RDX);
+ __ movq(RDX,
+ FieldAddress(RDI, R8, TIMES_8,
+ TypedData::data_offset() - 2 * Bigint::kBytesPerDigit));
+ __ shldq(RAX, RDX, RCX);
+ __ movq(Address(RBX, R8, TIMES_8, 0), RAX);
+ __ decq(R8);
+ __ j(NOT_ZERO, &loop, Assembler::kNearJump);
+ __ Bind(&last);
+ __ xorq(RAX, RAX); // RAX = 0.
+ __ shldq(RDX, RAX, RCX);
+ __ movq(Address(RBX, 0), RDX);
+ // Returning Object::null() is not required, since this method is private.
+ __ ret();
+}
+
+
+void Intrinsifier::Bigint_rsh(Assembler* assembler) {
+ // static void _rsh(Uint32List x_digits, int x_used, int n,
+ // Uint32List r_digits)
+
+ __ movq(RDI, Address(RSP, 4 * kWordSize)); // x_digits
+ __ movq(R8, Address(RSP, 3 * kWordSize)); // x_used is Smi
+ __ subq(R8, Immediate(2)); // x_used > 0, Smi. R8 = x_used - 1, round up.
+ __ sarq(R8, Immediate(2));
+ __ movq(RCX, Address(RSP, 2 * kWordSize)); // n is Smi
+ __ SmiUntag(RCX);
+ __ movq(RBX, Address(RSP, 1 * kWordSize)); // r_digits
+ __ movq(RSI, RCX);
+ __ sarq(RSI, Immediate(6)); // RSI = n ~/ (2*_DIGIT_BITS).
+ __ leaq(RDI, FieldAddress(RDI, RSI, TIMES_8, TypedData::data_offset()));
+ __ movq(RDX, Address(RDI, 0));
+ __ subq(R8, RSI); // R8 + 1 = number of digit pairs to read.
+ Label last;
+ __ cmpq(R8, Immediate(0));
+ __ j(EQUAL, &last, Assembler::kNearJump);
+ __ xorq(R9, R9); // R9 = 0.
+ Label loop;
+ __ Bind(&loop);
+ __ movq(RAX, RDX);
+ __ movq(RDX, Address(RDI, R9, TIMES_8, 2 * Bigint::kBytesPerDigit));
+ __ shrdq(RAX, RDX, RCX);
+ __ movq(FieldAddress(RBX, R9, TIMES_8, TypedData::data_offset()), RAX);
+ __ incq(R9);
+ __ cmpq(R9, R8);
+ __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
+ __ Bind(&last);
+ __ xorq(RAX, RAX); // RAX = 0.
+ __ shrdq(RDX, RAX, RCX);
+ __ movq(FieldAddress(RBX, R8, TIMES_8, TypedData::data_offset()), RDX);
+ // Returning Object::null() is not required, since this method is private.
+ __ ret();
+}
+
+
void Intrinsifier::Bigint_absAdd(Assembler* assembler) {
// static void _absAdd(Uint32List digits, int used,
// Uint32List a_digits, int a_used,
@@ -1836,9 +1914,6 @@
void Intrinsifier::JSRegExp_ExecuteMatch(Assembler* assembler) {
- if (FLAG_use_jscre) {
- return;
- }
static const intptr_t kRegExpParamOffset = 3 * kWordSize;
static const intptr_t kStringParamOffset = 2 * kWordSize;
// start_index smi is located at offset 1.
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 806c712..abc5343 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -536,11 +536,12 @@
object##_handle_(NULL),
Isolate::Isolate()
- : mutator_thread_(new Thread(this)),
+ : mutator_thread_(NULL),
vm_tag_(0),
store_buffer_(),
message_notify_callback_(NULL),
name_(NULL),
+ debugger_name_(NULL),
start_time_(OS::GetCurrentTimeMicros()),
main_port_(0),
origin_id_(0),
@@ -603,12 +604,13 @@
}
Isolate::Isolate(Isolate* original)
- : mutator_thread_(new Thread(this)),
+ : mutator_thread_(NULL),
vm_tag_(0),
store_buffer_(true),
class_table_(original->class_table()),
message_notify_callback_(NULL),
name_(NULL),
+ debugger_name_(NULL),
start_time_(OS::GetCurrentTimeMicros()),
main_port_(0),
pause_capability_(0),
@@ -666,6 +668,7 @@
Isolate::~Isolate() {
free(name_);
+ free(debugger_name_);
delete heap_;
delete object_store_;
delete api_state_;
@@ -682,7 +685,6 @@
delete spawn_state_;
delete log_;
log_ = NULL;
- delete mutator_thread_;
}
@@ -693,31 +695,6 @@
#endif // DEBUG
-void Isolate::SetCurrent(Isolate* current) {
- Isolate* old_current = Current();
- if (old_current != NULL) {
- old_current->set_vm_tag(VMTag::kIdleTagId);
- old_current->set_thread_state(NULL);
- Profiler::EndExecution(old_current);
- }
- if (current != NULL) {
- Thread::SetCurrent(current->mutator_thread());
- ASSERT(current->thread_state() == NULL);
- InterruptableThreadState* thread_state =
- ThreadInterrupter::GetCurrentThreadState();
-#if defined(DEBUG)
- CheckForDuplicateThreadState(thread_state);
-#endif
- ASSERT(thread_state != NULL);
- Profiler::BeginExecution(current);
- current->set_thread_state(thread_state);
- current->set_vm_tag(VMTag::kVMTagId);
- } else {
- Thread::SetCurrent(NULL);
- }
-}
-
-
void Isolate::InitOnce() {
create_callback_ = NULL;
isolates_list_monitor_ = new Monitor();
@@ -737,7 +714,7 @@
// TODO(5411455): For now just set the recently created isolate as
// the current isolate.
- SetCurrent(result);
+ Thread::EnterIsolate(result);
// Setup the isolate specific resuable handles.
#define REUSABLE_HANDLE_ALLOCATION(object) \
@@ -771,7 +748,6 @@
result->set_terminate_capability(result->random()->NextUInt64());
result->BuildName(name_prefix);
-
result->debugger_ = new Debugger();
result->debugger_->Initialize(result);
if (FLAG_trace_isolates) {
@@ -815,11 +791,18 @@
}
+void Isolate::set_debugger_name(const char* name) {
+ free(debugger_name_);
+ debugger_name_ = strdup(name);
+}
+
+
void Isolate::BuildName(const char* name_prefix) {
ASSERT(name_ == NULL);
if (name_prefix == NULL) {
name_prefix = "isolate";
}
+ set_debugger_name(name_prefix);
if (ServiceIsolate::NameEquals(name_prefix)) {
name_ = strdup(name_prefix);
return;
@@ -931,6 +914,7 @@
bool Isolate::MakeRunnable() {
ASSERT(Isolate::Current() == NULL);
+
MutexLocker ml(mutex_);
// Check if we are in a valid state to make the isolate runnable.
if (is_runnable_ == true) {
@@ -1191,16 +1175,19 @@
ASSERT(result.IsFunction());
Function& func = Function::Handle(isolate);
func ^= result.raw();
- func = func.ImplicitClosureFunction();
// TODO(turnidge): Currently we need a way to force a one-time
// breakpoint for all spawned isolates to support isolate
// debugging. Remove this once the vmservice becomes the standard
- // way to debug.
+ // way to debug. Set the breakpoint on the static function instead
+ // of its implicit closure function because that latter is merely
+ // a dispatcher that is marked as undebuggable.
if (FLAG_break_at_isolate_spawn) {
isolate->debugger()->OneTimeBreakAtEntry(func);
}
+ func = func.ImplicitClosureFunction();
+
const Array& capabilities = Array::Handle(Array::New(2));
Capability& capability = Capability::Handle();
capability = Capability::New(isolate->pause_capability());
@@ -1428,7 +1415,7 @@
// TODO(5411455): For now just make sure there are no current isolates
// as we are shutting down the isolate.
- SetCurrent(NULL);
+ Thread::ExitIsolate();
Profiler::ShutdownProfilingForIsolate(this);
}
@@ -1532,23 +1519,16 @@
jsobj.AddProperty("type", (ref ? "@Isolate" : "Isolate"));
jsobj.AddPropertyF("id", "isolates/%" Pd "",
static_cast<intptr_t>(main_port()));
- jsobj.AddPropertyF("mainPort", "%" Pd "",
- static_cast<intptr_t>(main_port()));
- // Assign an isolate name based on the entry function.
- IsolateSpawnState* state = spawn_state();
- if (state == NULL) {
- jsobj.AddPropertyF("name", "root");
- } else if (state->class_name() != NULL) {
- jsobj.AddPropertyF("name", "%s.%s",
- state->class_name(),
- state->function_name());
- } else {
- jsobj.AddPropertyF("name", "%s", state->function_name());
- }
+ jsobj.AddProperty("name", debugger_name());
+ jsobj.AddPropertyF("number", "%" Pd "",
+ static_cast<intptr_t>(main_port()));
if (ref) {
return;
}
+ int64_t start_time_millis = start_time() / kMicrosecondsPerMillisecond;
+ jsobj.AddProperty64("startTime", start_time_millis);
+ IsolateSpawnState* state = spawn_state();
if (state != NULL) {
const Object& entry = Object::Handle(this, state->ResolveFunction());
if (!entry.IsNull() && entry.IsFunction()) {
@@ -1603,12 +1583,6 @@
jsobj.AddProperty("error", error, false);
}
- {
- JSONObject typeargsRef(&jsobj, "canonicalTypeArguments");
- typeargsRef.AddProperty("type", "@TypeArgumentsList");
- typeargsRef.AddProperty("id", "typearguments");
- typeargsRef.AddProperty("name", "canonical type arguments");
- }
bool is_io_enabled = false;
{
const GrowableObjectArray& libs =
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 54c92fe..beafd96 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -122,7 +122,6 @@
Thread* thread = Thread::Current();
return thread == NULL ? NULL : thread->isolate();
}
- static void SetCurrent(Isolate* isolate);
static void InitOnce();
static Isolate* Init(const char* name_prefix, bool is_vm_isolate = false);
@@ -170,7 +169,7 @@
// No other threads operating on this isolate may execute Dart code.
// TODO(koda): Remove after caching current thread in generated code.
Thread* mutator_thread() {
- DEBUG_ASSERT(IsIsolateOf(mutator_thread_));
+ DEBUG_ASSERT(mutator_thread_ == NULL || IsIsolateOf(mutator_thread_));
return mutator_thread_;
}
#if defined(DEBUG)
@@ -178,6 +177,9 @@
#endif // DEBUG
const char* name() const { return name_; }
+ const char* debugger_name() const { return debugger_name_; }
+ void set_debugger_name(const char* name);
+
// TODO(koda): Move to Thread.
class Log* Log() const;
@@ -680,6 +682,10 @@
user_tag_ = tag;
}
+ void set_mutator_thread(Thread* thread) {
+ mutator_thread_ = thread;
+ }
+
template<class T> T* AllocateReusableHandle();
Thread* mutator_thread_;
@@ -689,6 +695,7 @@
MegamorphicCacheTable megamorphic_cache_table_;
Dart_MessageNotifyCallback message_notify_callback_;
char* name_;
+ char* debugger_name_;
int64_t start_time_;
Dart_Port main_port_;
Dart_Port origin_id_; // Isolates created by spawnFunc have some origin id.
@@ -799,7 +806,8 @@
static void AddIsolateTolist(Isolate* isolate);
static void RemoveIsolateFromList(Isolate* isolate);
static void CheckForDuplicateThreadState(InterruptableThreadState* state);
- static Monitor* isolates_list_monitor_;
+
+ static Monitor* isolates_list_monitor_; // Protects isolates_list_head_
static Isolate* isolates_list_head_;
#define REUSABLE_FRIEND_DECLARATION(name) \
@@ -820,13 +828,14 @@
public:
explicit StartIsolateScope(Isolate* new_isolate)
: new_isolate_(new_isolate), saved_isolate_(Isolate::Current()) {
+ // TODO(koda): Audit users; passing NULL goes against naming of this class.
if (new_isolate_ == NULL) {
// Do nothing.
return;
}
if (saved_isolate_ != new_isolate_) {
ASSERT(Isolate::Current() == NULL);
- Isolate::SetCurrent(new_isolate_);
+ Thread::EnterIsolate(new_isolate_);
new_isolate_->SetStackLimitFromStackBase(
Isolate::GetCurrentStackPointer());
}
@@ -839,7 +848,10 @@
}
if (saved_isolate_ != new_isolate_) {
new_isolate_->ClearStackLimit();
- Isolate::SetCurrent(saved_isolate_);
+ Thread::ExitIsolate();
+ if (saved_isolate_ != NULL) {
+ Thread::EnterIsolate(saved_isolate_);
+ }
}
}
@@ -860,9 +872,12 @@
saved_isolate_(Isolate::Current()),
saved_stack_limit_(saved_isolate_
? saved_isolate_->saved_stack_limit() : 0) {
+ // TODO(koda): Audit users; why would these two ever be equal?
if (saved_isolate_ != new_isolate_) {
- Isolate::SetCurrent(new_isolate_);
- if (new_isolate_ != NULL) {
+ if (new_isolate_ == NULL) {
+ Thread::ExitIsolate();
+ } else {
+ Thread::EnterIsolate(new_isolate_);
// Don't allow dart code to execute.
new_isolate_->SetStackLimit(~static_cast<uword>(0));
}
@@ -871,8 +886,11 @@
~SwitchIsolateScope() {
if (saved_isolate_ != new_isolate_) {
- Isolate::SetCurrent(saved_isolate_);
+ if (new_isolate_ != NULL) {
+ Thread::ExitIsolate();
+ }
if (saved_isolate_ != NULL) {
+ Thread::EnterIsolate(saved_isolate_);
saved_isolate_->SetStackLimit(saved_stack_limit_);
}
}
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index 388c0d3..06c13fc 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -274,12 +274,14 @@
void JSONStream::PrintProperty(const char* name, intptr_t i) {
+ ASSERT(Utils::IsJavascriptInt(i));
PrintPropertyName(name);
PrintValue(i);
}
void JSONStream::PrintProperty64(const char* name, int64_t i) {
+ ASSERT(Utils::IsJavascriptInt64(i));
PrintPropertyName(name);
PrintValue64(i);
}
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index 08260c3..d62c588 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -155,6 +155,8 @@
#define CORE_LIB_INTRINSIC_LIST(V) \
V(_Smi, ~, Smi_bitNegate, 134149043) \
V(_Smi, get:bitLength, Smi_bitLength, 869986288) \
+ V(_Bigint, _lsh, Bigint_lsh, 1318834243) \
+ V(_Bigint, _rsh, Bigint_rsh, 1239668932) \
V(_Bigint, _absAdd, Bigint_absAdd, 222437051) \
V(_Bigint, _absSub, Bigint_absSub, 599465997) \
V(_Bigint, _mulAdd, Bigint_mulAdd, 1696801459) \
@@ -367,8 +369,8 @@
V(_ByteDataView, setUint32, ByteDataViewSetUint32, 284405389) \
V(_ByteDataView, setInt64, ByteDataViewSetInt64, 486916661) \
V(_ByteDataView, setUint64, ByteDataViewSetUint64, 1432663320) \
- V(_ByteDataView, setFloat32, ByteDataViewSetFloat32, 733187060) \
- V(_ByteDataView, setFloat64, ByteDataViewSetFloat64, 1138577739) \
+ V(_ByteDataView, setFloat32, ByteDataViewSetFloat32, 344976311) \
+ V(_ByteDataView, setFloat64, ByteDataViewSetFloat64, 1480166018) \
V(_ByteDataView, getInt8, ByteDataViewGetInt8, 1383732403) \
V(_ByteDataView, getUint8, ByteDataViewGetUint8, 806641537) \
V(_ByteDataView, getInt16, ByteDataViewGetInt16, 76281079) \
@@ -377,8 +379,8 @@
V(_ByteDataView, getUint32, ByteDataViewGetUint32, 760435927) \
V(_ByteDataView, getInt64, ByteDataViewGetInt64, 364361487) \
V(_ByteDataView, getUint64, ByteDataViewGetUint64, 565678407) \
- V(_ByteDataView, getFloat32, ByteDataViewGetFloat32, 924006540) \
- V(_ByteDataView, getFloat64, ByteDataViewGetFloat64, 1863927528) \
+ V(_ByteDataView, getFloat32, ByteDataViewGetFloat32, 1979131043) \
+ V(_ByteDataView, getFloat64, ByteDataViewGetFloat64, 164756117) \
V(::, asin, MathASin, 1651042633) \
V(::, acos, MathACos, 1139647090) \
V(::, atan, MathATan, 1668754384) \
@@ -399,6 +401,8 @@
// A list of core function that should never be inlined.
#define INLINE_BLACK_LIST(V) \
+ V(_Bigint, _lsh, Bigint_lsh, 1318834243) \
+ V(_Bigint, _rsh, Bigint_rsh, 1239668932) \
V(_Bigint, _absAdd, Bigint_absAdd, 222437051) \
V(_Bigint, _absSub, Bigint_absSub, 599465997) \
V(_Bigint, _mulAdd, Bigint_mulAdd, 1696801459) \
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index f7ff985..a3cd5c1 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -48,7 +48,7 @@
}
// Start the native port without a current isolate.
IsolateSaver saver(Isolate::Current());
- Isolate::SetCurrent(NULL);
+ Thread::ExitIsolate();
NativeMessageHandler* nmh = new NativeMessageHandler(name, handler);
Dart_Port port_id = PortMap::CreatePort(nmh);
@@ -60,7 +60,7 @@
DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id) {
// Close the native port without a current isolate.
IsolateSaver saver(Isolate::Current());
- Isolate::SetCurrent(NULL);
+ Thread::ExitIsolate();
// TODO(turnidge): Check that the port is native before trying to close.
return PortMap::ClosePort(native_port_id);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 103a394..f80f10b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -142,7 +142,6 @@
reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::exception_handlers_class_ =
reinterpret_cast<RawClass*>(RAW_NULL);
-RawClass* Object::deopt_info_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::context_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::context_scope_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::icdata_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
@@ -559,9 +558,6 @@
cls = Class::New<ExceptionHandlers>();
exception_handlers_class_ = cls.raw();
- cls = Class::New<DeoptInfo>();
- deopt_info_class_ = cls.raw();
-
cls = Class::New<Context>();
context_class_ = cls.raw();
@@ -816,7 +812,6 @@
SET_CLASS_NAME(stackmap, Stackmap);
SET_CLASS_NAME(var_descriptors, LocalVarDescriptors);
SET_CLASS_NAME(exception_handlers, ExceptionHandlers);
- SET_CLASS_NAME(deopt_info, DeoptInfo);
SET_CLASS_NAME(context, Context);
SET_CLASS_NAME(context_scope, ContextScope);
SET_CLASS_NAME(icdata, ICData);
@@ -2817,7 +2812,9 @@
const String& func_src =
String::Handle(BuildClosureSource(param_names, expr));
Script& script = Script::Handle();
- script = Script::New(Symbols::Empty(), func_src, RawScript::kSourceTag);
+ script = Script::New(Symbols::EvalSourceUri(),
+ func_src,
+ RawScript::kSourceTag);
// In order to tokenize the source, we need to get the key to mangle
// private names from the library from which the class originates.
const Library& lib = Library::Handle(cls.library());
@@ -3207,8 +3204,6 @@
return Symbols::LocalVarDescriptors().raw();
case kExceptionHandlersCid:
return Symbols::ExceptionHandlers().raw();
- case kDeoptInfoCid:
- return Symbols::DeoptInfo().raw();
case kContextCid:
return Symbols::Context().raw();
case kContextScopeCid:
@@ -4120,16 +4115,10 @@
JSONArray interfaces_array(&jsobj, "interfaces");
const Array& interface_array = Array::Handle(interfaces());
Type& interface_type = Type::Handle();
- Class& interface_cls = Class::Handle();
if (!interface_array.IsNull()) {
for (intptr_t i = 0; i < interface_array.Length(); ++i) {
- // TODO(turnidge): Use the Type directly once regis has added
- // types to the vmservice.
interface_type ^= interface_array.At(i);
- if (interface_type.HasResolvedTypeClass()) {
- interface_cls = interface_type.type_class();
- interfaces_array.AddValue(interface_cls);
- }
+ interfaces_array.AddValue(interface_type);
}
}
}
@@ -4430,8 +4419,6 @@
const String& user_name = String::Handle(PrettyName());
const String& vm_name = String::Handle(Name());
AddNameProperties(&jsobj, user_name, vm_name);
- jsobj.AddProperty("length", Length());
- jsobj.AddProperty("numInstantiations", NumInstantiations());
if (ref) {
return;
}
@@ -4444,7 +4431,7 @@
}
}
if (!IsInstantiated()) {
- JSONArray jsarr(&jsobj, "instantiations");
+ JSONArray jsarr(&jsobj, "_instantiations");
Array& prior_instantiations = Array::Handle(instantiations());
ASSERT(prior_instantiations.Length() > 0); // Always at least a sentinel.
TypeArguments& type_args = TypeArguments::Handle();
@@ -5107,7 +5094,7 @@
Isolate* isolate = Isolate::Current();
const Code& current_code = Code::Handle(isolate, CurrentCode());
- if (FLAG_trace_disabling_optimized_code) {
+ if (FLAG_trace_deoptimization) {
OS::Print("Disabling optimized code: '%s' entry: %#" Px "\n",
ToFullyQualifiedCString(),
current_code.EntryPoint());
@@ -5308,43 +5295,43 @@
const char* Function::KindToCString(RawFunction::Kind kind) {
switch (kind) {
case RawFunction::kRegularFunction:
- return "kRegularFunction";
+ return "RegularFunction";
break;
case RawFunction::kClosureFunction:
- return "kClosureFunction";
+ return "ClosureFunction";
break;
case RawFunction::kSignatureFunction:
- return "kSignatureFunction";
+ return "SignatureFunction";
break;
case RawFunction::kGetterFunction:
- return "kGetterFunction";
+ return "GetterFunction";
break;
case RawFunction::kSetterFunction:
- return "kSetterFunction";
+ return "SetterFunction";
break;
case RawFunction::kConstructor:
- return "kConstructor";
+ return "Constructor";
break;
case RawFunction::kImplicitGetter:
- return "kImplicitGetter";
+ return "ImplicitGetter";
break;
case RawFunction::kImplicitSetter:
- return "kImplicitSetter";
+ return "ImplicitSetter";
break;
case RawFunction::kImplicitStaticFinalGetter:
- return "kImplicitStaticFinalGetter";
+ return "ImplicitStaticFinalGetter";
break;
case RawFunction::kMethodExtractor:
- return "kMethodExtractor";
+ return "MethodExtractor";
break;
case RawFunction::kNoSuchMethodDispatcher:
- return "kNoSuchMethodDispatcher";
+ return "NoSuchMethodDispatcher";
break;
case RawFunction::kInvokeFieldDispatcher:
- return "kInvokeFieldDispatcher";
+ return "InvokeFieldDispatcher";
break;
case RawFunction::kIrregexpFunction:
- return "kIrregexpFunction";
+ return "IrregexpFunction";
break;
default:
UNREACHABLE();
@@ -6824,16 +6811,16 @@
const String& user_name = String::Handle(PrettyName());
const String& vm_name = String::Handle(name());
AddNameProperties(&jsobj, user_name, vm_name);
- if (cls.IsTopLevel()) {
- const Library& library = Library::Handle(cls.library());
- jsobj.AddProperty("owningLibrary", library);
- } else {
- jsobj.AddProperty("owningClass", cls);
- }
const Function& parent = Function::Handle(parent_function());
if (!parent.IsNull()) {
- jsobj.AddProperty("parent", parent);
+ jsobj.AddProperty("owner", parent);
+ } else if (cls.IsTopLevel()) {
+ const Library& library = Library::Handle(cls.library());
+ jsobj.AddProperty("owner", library);
+ } else {
+ jsobj.AddProperty("owner", cls);
}
+
const char* kind_string = Function::KindToCString(kind());
jsobj.AddProperty("kind", kind_string);
if (ref) {
@@ -6841,13 +6828,19 @@
}
jsobj.AddProperty("static", is_static());
jsobj.AddProperty("const", is_const());
- jsobj.AddProperty("optimizable", is_optimizable());
- jsobj.AddProperty("inlinable", CanBeInlined());
- jsobj.AddProperty("unoptimizedCode", Object::Handle(unoptimized_code()));
- jsobj.AddProperty("usageCounter", usage_counter());
- jsobj.AddProperty("optimizedCallSiteCount", optimized_call_site_count());
- jsobj.AddProperty("code", Object::Handle(CurrentCode()));
- jsobj.AddProperty("deoptimizations",
+ Code& code = Code::Handle(CurrentCode());
+ if (!code.IsNull()) {
+ jsobj.AddProperty("code", code);
+ }
+ jsobj.AddProperty("_optimizable", is_optimizable());
+ jsobj.AddProperty("_inlinable", CanBeInlined());
+ code = unoptimized_code();
+ if (!code.IsNull()) {
+ jsobj.AddProperty("_unoptimizedCode", code);
+ }
+ jsobj.AddProperty("_usageCounter", usage_counter());
+ jsobj.AddProperty("_optimizedCallSiteCount", optimized_call_site_count());
+ jsobj.AddProperty("_deoptimizations",
static_cast<intptr_t>(deoptimization_counter()));
const Script& script = Script::Handle(this->script());
@@ -7196,23 +7189,23 @@
if (ref) {
return;
}
- jsobj.AddProperty("guardNullable", is_nullable());
+ jsobj.AddProperty("_guardNullable", is_nullable());
if (guarded_cid() == kIllegalCid) {
- jsobj.AddProperty("guardClass", "unknown");
+ jsobj.AddProperty("_guardClass", "unknown");
} else if (guarded_cid() == kDynamicCid) {
- jsobj.AddProperty("guardClass", "dynamic");
+ jsobj.AddProperty("_guardClass", "dynamic");
} else {
ClassTable* table = Isolate::Current()->class_table();
ASSERT(table->IsValidIndex(guarded_cid()));
cls ^= table->At(guarded_cid());
- jsobj.AddProperty("guardClass", cls);
+ jsobj.AddProperty("_guardClass", cls);
}
if (guarded_list_length() == kUnknownFixedLength) {
- jsobj.AddProperty("guardLength", "unknown");
+ jsobj.AddProperty("_guardLength", "unknown");
} else if (guarded_list_length() == kNoFixedLength) {
- jsobj.AddProperty("guardLength", "variable");
+ jsobj.AddProperty("_guardLength", "variable");
} else {
- jsobj.AddProperty("guardLength", guarded_list_length());
+ jsobj.AddProperty("_guardLength", guarded_list_length());
}
const Class& origin_cls = Class::Handle(origin());
const Script& script = Script::Handle(origin_cls.script());
@@ -8427,6 +8420,12 @@
}
while (scan_position != length) {
+ if (snippet_start == -1) {
+ if ((line == from_line) && (column == from_column)) {
+ snippet_start = scan_position;
+ }
+ }
+
char c = src.CharAt(scan_position);
if (c == '\n') {
line++;
@@ -8442,11 +8441,7 @@
scan_position++;
column++;
- if (snippet_start == -1) {
- if ((line == from_line) && (column == from_column)) {
- snippet_start = scan_position;
- }
- } else if ((line == to_line) && (column == to_column)) {
+ if ((line == to_line) && (column == to_column)) {
snippet_end = scan_position;
break;
}
@@ -8522,7 +8517,7 @@
if (ref) {
return;
}
- jsobj.AddProperty("owningLibrary", lib);
+ jsobj.AddProperty("library", lib);
const String& source = String::Handle(Source());
jsobj.AddPropertyStr("source", source);
@@ -8750,7 +8745,7 @@
static RawString* MakeFunctionMetaName(const Function& func) {
const String& cname =
String::Handle(MakeClassMetaName(Class::Handle(func.origin())));
- String& fname = String::Handle(func.name());
+ String& fname = String::Handle(func.QualifiedPrettyName());
fname = String::Concat(Symbols::At(), fname);
return String::Concat(cname, fname);
}
@@ -11140,113 +11135,104 @@
}
-intptr_t DeoptInfo::Length() const {
- return Smi::Value(raw_ptr()->length_);
-}
-
-
-intptr_t DeoptInfo::FromIndex(intptr_t index) const {
+intptr_t DeoptInfo::FrameSize(const TypedData& packed) {
NoSafepointScope no_safepoint;
- return *(EntryAddr(index, kFromIndex));
+ typedef ReadStream::Raw<sizeof(intptr_t), intptr_t> Reader;
+ ReadStream read_stream(reinterpret_cast<uint8_t*>(packed.DataAddr(0)),
+ packed.LengthInBytes());
+ return Reader::Read(&read_stream);
}
-intptr_t DeoptInfo::Instruction(intptr_t index) const {
+intptr_t DeoptInfo::NumMaterializations(
+ const GrowableArray<DeoptInstr*>& unpacked) {
+ intptr_t num = 0;
+ while (unpacked[num]->kind() == DeoptInstr::kMaterializeObject) {
+ num++;
+ }
+ return num;
+}
+
+
+void DeoptInfo::UnpackInto(const Array& table,
+ const TypedData& packed,
+ GrowableArray<DeoptInstr*>* unpacked,
+ intptr_t length) {
NoSafepointScope no_safepoint;
- return *(EntryAddr(index, kInstruction));
-}
+ typedef ReadStream::Raw<sizeof(intptr_t), intptr_t> Reader;
+ ReadStream read_stream(reinterpret_cast<uint8_t*>(packed.DataAddr(0)),
+ packed.LengthInBytes());
+ const intptr_t frame_size = Reader::Read(&read_stream); // Skip frame size.
+ USE(frame_size);
+ const intptr_t suffix_length = Reader::Read(&read_stream);
+ if (suffix_length != 0) {
+ ASSERT(suffix_length > 1);
+ const intptr_t info_number = Reader::Read(&read_stream);
-intptr_t DeoptInfo::FrameSize() const {
- return TranslationLength() - NumMaterializations();
-}
-
-
-intptr_t DeoptInfo::TranslationLength() const {
- intptr_t length = Length();
- if (Instruction(length - 1) != DeoptInstr::kSuffix) return length;
-
- // If the last command is a suffix, add in the length of the suffix and
- // do not count the suffix command as a translation command.
- intptr_t ignored = 0;
- intptr_t suffix_length =
- DeoptInstr::DecodeSuffix(FromIndex(length - 1), &ignored);
- return length + suffix_length - 1;
-}
-
-
-intptr_t DeoptInfo::NumMaterializations() const {
- intptr_t pos = 0;
- while (Instruction(pos) == DeoptInstr::kMaterializeObject) {
- pos++;
+ TypedData& suffix = TypedData::Handle();
+ Smi& offset = Smi::Handle();
+ Smi& reason_and_flags = Smi::Handle();
+ DeoptTable::GetEntry(
+ table, info_number, &offset, &suffix, &reason_and_flags);
+ UnpackInto(table, suffix, unpacked, suffix_length);
}
- return pos;
-}
-
-void DeoptInfo::ToInstructions(const Array& table,
- GrowableArray<DeoptInstr*>* instructions) const {
- ASSERT(instructions->is_empty());
- Smi& offset = Smi::Handle();
- DeoptInfo& info = DeoptInfo::Handle(raw());
- Smi& reason_and_flags = Smi::Handle();
- intptr_t index = 0;
- intptr_t length = TranslationLength();
- while (index < length) {
- intptr_t instruction = info.Instruction(index);
- intptr_t from_index = info.FromIndex(index);
- if (instruction == DeoptInstr::kSuffix) {
- // Suffix instructions cause us to 'jump' to another translation,
- // changing info, length and index.
- intptr_t info_number = 0;
- intptr_t suffix_length =
- DeoptInstr::DecodeSuffix(from_index, &info_number);
- DeoptTable::GetEntry(
- table, info_number, &offset, &info, &reason_and_flags);
- length = info.TranslationLength();
- index = length - suffix_length;
- } else {
- instructions->Add(DeoptInstr::Create(instruction, from_index));
- ++index;
- }
+ while ((read_stream.PendingBytes() > 0) &&
+ (unpacked->length() < length)) {
+ const intptr_t instruction = Reader::Read(&read_stream);
+ const intptr_t from_index = Reader::Read(&read_stream);
+ unpacked->Add(DeoptInstr::Create(instruction, from_index));
}
}
-const char* DeoptInfo::ToCString() const {
- if (Length() == 0) {
- return "No DeoptInfo";
- }
- // Convert to DeoptInstr.
- GrowableArray<DeoptInstr*> deopt_instrs(Length());
- for (intptr_t i = 0; i < Length(); i++) {
- deopt_instrs.Add(DeoptInstr::Create(Instruction(i), FromIndex(i)));
- }
+void DeoptInfo::Unpack(const Array& table,
+ const TypedData& packed,
+ GrowableArray<DeoptInstr*>* unpacked) {
+ ASSERT(unpacked->is_empty());
+
+ // Pass kMaxInt32 as the length to unpack all instructions from the
+ // packed stream.
+ UnpackInto(table, packed, unpacked, kMaxInt32);
+
+ unpacked->Reverse();
+}
+
+
+const char* DeoptInfo::ToCString(const Array& deopt_table,
+ const TypedData& packed) {
+ GrowableArray<DeoptInstr*> deopt_instrs;
+ Unpack(deopt_table, packed, &deopt_instrs);
+
// Compute the buffer size required.
intptr_t len = 1; // Trailing '\0'.
- for (intptr_t i = 0; i < Length(); i++) {
+ for (intptr_t i = 0; i < deopt_instrs.length(); i++) {
len += OS::SNPrint(NULL, 0, "[%s]", deopt_instrs[i]->ToCString());
}
+
// Allocate the buffer.
char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len);
+
// Layout the fields in the buffer.
intptr_t index = 0;
- for (intptr_t i = 0; i < Length(); i++) {
+ for (intptr_t i = 0; i < deopt_instrs.length(); i++) {
index += OS::SNPrint((buffer + index),
(len - index),
"[%s]",
deopt_instrs[i]->ToCString());
}
+
return buffer;
}
// Returns a bool so it can be asserted.
bool DeoptInfo::VerifyDecompression(const GrowableArray<DeoptInstr*>& original,
- const Array& deopt_table) const {
- intptr_t length = TranslationLength();
- GrowableArray<DeoptInstr*> unpacked(length);
- ToInstructions(deopt_table, &unpacked);
+ const Array& deopt_table,
+ const TypedData& packed) {
+ GrowableArray<DeoptInstr*> unpacked;
+ Unpack(deopt_table, packed, &unpacked);
ASSERT(unpacked.length() == original.length());
for (intptr_t i = 0; i < unpacked.length(); ++i) {
ASSERT(unpacked[i]->Equals(*original[i]));
@@ -11255,47 +11241,6 @@
}
-void DeoptInfo::PrintJSONImpl(JSONStream* stream, bool ref) const {
- Object::PrintJSONImpl(stream, ref);
-}
-
-
-RawDeoptInfo* DeoptInfo::New(intptr_t num_commands) {
- ASSERT(Object::deopt_info_class() != Class::null());
- if ((num_commands < 0) || (num_commands > kMaxElements)) {
- FATAL1("Fatal error in DeoptInfo::New(): invalid num_commands %" Pd "\n",
- num_commands);
- }
- DeoptInfo& result = DeoptInfo::Handle();
- {
- uword size = DeoptInfo::InstanceSize(num_commands);
- RawObject* raw = Object::Allocate(DeoptInfo::kClassId,
- size,
- Heap::kOld);
- NoSafepointScope no_safepoint;
- result ^= raw;
- result.SetLength(num_commands);
- }
- return result.raw();
-}
-
-
-void DeoptInfo::SetLength(intptr_t value) const {
- // This is only safe because we create a new Smi, which does not cause
- // heap allocation.
- StoreSmi(&raw_ptr()->length_, Smi::New(value));
-}
-
-
-void DeoptInfo::SetAt(intptr_t index,
- intptr_t instr_kind,
- intptr_t from_index) const {
- NoSafepointScope no_safepoint;
- *(EntryAddr(index, kInstruction)) = instr_kind;
- *(EntryAddr(index, kFromIndex)) = from_index;
-}
-
-
const char* ICData::ToCString() const {
const char* kFormat = "ICData target:'%s' num-args: %" Pd
" num-checks: %" Pd "";
@@ -12108,7 +12053,7 @@
}
-RawDeoptInfo* Code::GetDeoptInfoAtPc(uword pc,
+RawTypedData* Code::GetDeoptInfoAtPc(uword pc,
ICData::DeoptReasonId* deopt_reason,
uint32_t* deopt_flags) const {
ASSERT(is_optimized());
@@ -12120,7 +12065,7 @@
intptr_t length = DeoptTable::GetLength(table);
Smi& offset = Smi::Handle();
Smi& reason_and_flags = Smi::Handle();
- DeoptInfo& info = DeoptInfo::Handle();
+ TypedData& info = TypedData::Handle();
for (intptr_t i = 0; i < length; ++i) {
DeoptTable::GetEntry(table, i, &offset, &info, &reason_and_flags);
if (pc == (code_entry + offset.Value())) {
@@ -12131,7 +12076,7 @@
}
}
*deopt_reason = ICData::kDeoptUnknown;
- return DeoptInfo::null();
+ return TypedData::null();
}
@@ -12542,20 +12487,20 @@
AddTypeProperties(&jsobj, "Code", JSONType(), ref);
jsobj.AddPropertyF("id", "code/%" Px64"-%" Px "", compile_timestamp(),
EntryPoint());
- jsobj.AddPropertyF("start", "%" Px "", EntryPoint());
- jsobj.AddPropertyF("end", "%" Px "", EntryPoint() + Size());
- jsobj.AddProperty("optimized", is_optimized());
- jsobj.AddProperty("alive", is_alive());
- const Object& obj = Object::Handle(owner());
+ const String& user_name = String::Handle(PrettyName());
+ const String& vm_name = String::Handle(Name());
+ AddNameProperties(&jsobj, user_name, vm_name);
const bool is_stub = IsStubCode() || IsAllocationStubCode();
if (is_stub) {
jsobj.AddProperty("kind", "Stub");
} else {
jsobj.AddProperty("kind", "Dart");
}
- const String& user_name = String::Handle(PrettyName());
- const String& vm_name = String::Handle(Name());
- AddNameProperties(&jsobj, user_name, vm_name);
+ jsobj.AddProperty("_optimized", is_optimized());
+ if (ref) {
+ return;
+ }
+ const Object& obj = Object::Handle(owner());
if (obj.IsFunction()) {
jsobj.AddProperty("function", obj);
} else {
@@ -12566,13 +12511,13 @@
func.AddProperty("name", user_name.ToCString());
AddNameProperties(&func, user_name, vm_name);
}
- if (ref) {
- return;
- }
+ jsobj.AddPropertyF("_startAddress", "%" Px "", EntryPoint());
+ jsobj.AddPropertyF("_endAddress", "%" Px "", EntryPoint() + Size());
+ jsobj.AddProperty("_alive", is_alive());
const Array& array = Array::Handle(ObjectPool());
- jsobj.AddProperty("objectPool", array);
+ jsobj.AddProperty("_objectPool", array);
{
- JSONArray jsarr(&jsobj, "disassembly");
+ JSONArray jsarr(&jsobj, "_disassembly");
if (is_alive()) {
// Only disassemble alive code objects.
DisassembleToJSONStream formatter(jsarr);
@@ -12581,12 +12526,12 @@
}
const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
if (!descriptors.IsNull()) {
- JSONObject desc(&jsobj, "descriptors");
+ JSONObject desc(&jsobj, "_descriptors");
descriptors.PrintToJSONObject(&desc, false);
}
const Array& inlined_function_table = Array::Handle(inlined_id_to_function());
if (!inlined_function_table.IsNull()) {
- JSONArray inlined_functions(&jsobj, "inlinedFunctions");
+ JSONArray inlined_functions(&jsobj, "_inlinedFunctions");
Function& function = Function::Handle();
for (intptr_t i = 0; i < inlined_function_table.Length(); i++) {
function ^= inlined_function_table.At(i);
@@ -12599,7 +12544,7 @@
Smi& start = Smi::Handle();
Smi& end = Smi::Handle();
Smi& temp_smi = Smi::Handle();
- JSONArray inline_intervals(&jsobj, "inlinedIntervals");
+ JSONArray inline_intervals(&jsobj, "_inlinedIntervals");
for (intptr_t i = 0; i < intervals.Length() - Code::kInlIntNumEntries;
i += Code::kInlIntNumEntries) {
start ^= intervals.At(i + Code::kInlIntStart);
@@ -15946,18 +15891,11 @@
}
-// dart2js represents integers as double precision floats, which can represent
-// anything in the range -2^53 ... 2^53.
-static bool IsJavascriptInt(int64_t value) {
- return ((-0x20000000000000LL <= value) && (value <= 0x20000000000000LL));
-}
-
-
RawInteger* Integer::New(int64_t value, Heap::Space space, const bool silent) {
const bool is_smi = Smi::IsValid(value);
if (!silent &&
FLAG_throw_on_javascript_int_overflow &&
- !IsJavascriptInt(value)) {
+ !Utils::IsJavascriptInt64(value)) {
const Integer& i = is_smi ?
Integer::Handle(Smi::New(static_cast<intptr_t>(value))) :
Integer::Handle(Mint::New(value, space));
@@ -16055,7 +15993,7 @@
value = AsInt64Value();
}
}
- return !IsJavascriptInt(value);
+ return !Utils::IsJavascriptInt64(value);
}
@@ -20083,6 +20021,7 @@
RawReceivePort* ReceivePort::New(Dart_Port id,
bool is_control_port,
Heap::Space space) {
+ ASSERT(id != ILLEGAL_PORT);
Isolate* isolate = Isolate::Current();
const SendPort& send_port =
SendPort::Handle(isolate, SendPort::New(id, isolate->origin_id()));
@@ -20123,6 +20062,7 @@
RawSendPort* SendPort::New(Dart_Port id,
Dart_Port origin_id,
Heap::Space space) {
+ ASSERT(id != ILLEGAL_PORT);
SendPort& result = SendPort::Handle();
{
RawObject* raw = Object::Allocate(SendPort::kClassId,
@@ -20406,21 +20346,16 @@
}
-RawJSRegExp* JSRegExp::New(intptr_t len, Heap::Space space) {
- if (len < 0 || len > kMaxElements) {
- // This should be caught before we reach here.
- FATAL1("Fatal error in JSRegexp::New: invalid len %" Pd "\n", len);
- }
+RawJSRegExp* JSRegExp::New(Heap::Space space) {
JSRegExp& result = JSRegExp::Handle();
{
RawObject* raw = Object::Allocate(JSRegExp::kClassId,
- JSRegExp::InstanceSize(len),
+ JSRegExp::InstanceSize(),
space);
NoSafepointScope no_safepoint;
result ^= raw;
result.set_type(kUnitialized);
result.set_flags(0);
- result.SetLength(len);
}
return result.raw();
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 4ca6980..289cceb 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1797,9 +1797,6 @@
RawCode* unoptimized_code() const { return raw_ptr()->unoptimized_code_; }
void set_unoptimized_code(const Code& value) const;
- static intptr_t unoptimized_code_offset() {
- return OFFSET_OF(RawFunction, unoptimized_code_);
- }
bool HasCode() const;
static intptr_t instructions_offset() {
@@ -3545,81 +3542,38 @@
// field-value pairs) are added as artificial slots to the expression stack
// of the bottom-most frame. They are removed from the stack at the very end
// of deoptimization by the deoptimization stub.
-class DeoptInfo : public Object {
- private:
- // Describes the layout of deopt info data. The index of a deopt-info entry
- // is implicitly the target slot in which the value is written into.
- enum {
- kInstruction = 0,
- kFromIndex,
- kNumberOfEntries,
- };
-
+class DeoptInfo : public AllStatic {
public:
- // The number of instructions.
- intptr_t Length() const;
-
- // The number of real (non-suffix) instructions needed to execute the
- // deoptimization translation.
- intptr_t TranslationLength() const;
-
// Size of the frame part of the translation not counting kMaterializeObject
// instructions in the prefix.
- intptr_t FrameSize() const;
+ static intptr_t FrameSize(const TypedData& packed);
// Returns the number of kMaterializeObject instructions in the prefix.
- intptr_t NumMaterializations() const;
-
- static RawDeoptInfo* New(intptr_t num_commands);
-
- static const intptr_t kBytesPerElement = (kNumberOfEntries * kWordSize);
- static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
-
- static intptr_t InstanceSize() {
- ASSERT(sizeof(RawDeoptInfo) ==
- OFFSET_OF_RETURNED_VALUE(RawDeoptInfo, data));
- return 0;
- }
-
- static intptr_t InstanceSize(intptr_t len) {
- ASSERT(0 <= len && len <= kMaxElements);
- return RoundedAllocationSize(sizeof(RawDeoptInfo) +
- (len * kBytesPerElement));
- }
-
- // 'index' corresponds to target, to-index.
- void SetAt(intptr_t index,
- intptr_t instr_kind,
- intptr_t from_index) const;
-
- intptr_t Instruction(intptr_t index) const;
- intptr_t FromIndex(intptr_t index) const;
- intptr_t ToIndex(intptr_t index) const {
- return index;
- }
+ static intptr_t NumMaterializations(const GrowableArray<DeoptInstr*>&);
// Unpack the entire translation into an array of deoptimization
// instructions. This copies any shared suffixes into the array.
- void ToInstructions(const Array& table,
- GrowableArray<DeoptInstr*>* instructions) const;
+ static void Unpack(const Array& table,
+ const TypedData& packed,
+ GrowableArray<DeoptInstr*>* instructions);
+ // Size of the frame part of the translation not counting kMaterializeObject
+ // instructions in the prefix.
+ static const char* ToCString(const Array& table,
+ const TypedData& packed);
// Returns true iff decompression yields the same instructions as the
// original.
- bool VerifyDecompression(const GrowableArray<DeoptInstr*>& original,
- const Array& deopt_table) const;
+ static bool VerifyDecompression(const GrowableArray<DeoptInstr*>& original,
+ const Array& deopt_table,
+ const TypedData& packed);
+
private:
- intptr_t* EntryAddr(intptr_t index, intptr_t entry_offset) const {
- ASSERT((index >=0) && (index < Length()));
- intptr_t data_index = (index * kNumberOfEntries) + entry_offset;
- return &UnsafeMutableNonPointer(raw_ptr()->data())[data_index];
- }
-
- void SetLength(intptr_t value) const;
-
- FINAL_HEAP_OBJECT_IMPLEMENTATION(DeoptInfo, Object);
- friend class Class;
+ static void UnpackInto(const Array& table,
+ const TypedData& packed,
+ GrowableArray<DeoptInstr*>* instructions,
+ intptr_t length);
};
@@ -4015,7 +3969,7 @@
return raw_ptr()->static_calls_target_table_;
}
- RawDeoptInfo* GetDeoptInfoAtPc(uword pc,
+ RawTypedData* GetDeoptInfoAtPc(uword pc,
ICData::DeoptReasonId* deopt_reason,
uint32_t* deopt_flags) const;
@@ -7542,24 +7496,11 @@
virtual bool CanonicalizeEquals(const Instance& other) const;
- static const intptr_t kBytesPerElement = 1;
- static const intptr_t kMaxElements = kSmiMax / kBytesPerElement;
-
static intptr_t InstanceSize() {
- ASSERT(sizeof(RawJSRegExp) == OFFSET_OF_RETURNED_VALUE(RawJSRegExp, data));
- if (FLAG_use_jscre) {
- return 0;
- }
return RoundedAllocationSize(sizeof(RawJSRegExp));
}
- static intptr_t InstanceSize(intptr_t len) {
- ASSERT(0 <= len && len <= kMaxElements);
- return RoundedAllocationSize(
- sizeof(RawJSRegExp) + (len * kBytesPerElement));
- }
-
- static RawJSRegExp* New(intptr_t length, Heap::Space space = Heap::kNew);
+ static RawJSRegExp* New(Heap::Space space = Heap::kNew);
private:
void set_type(RegExType type) const {
@@ -7578,12 +7519,6 @@
return FlagsBits::decode(raw_ptr()->type_flags_);
}
- void SetLength(intptr_t value) const {
- // This is only safe because we create a new Smi, which does not cause
- // heap allocation.
- StoreSmi(&raw_ptr()->data_length_, Smi::New(value));
- }
-
FINAL_HEAP_OBJECT_IMPLEMENTATION(JSRegExp, Instance);
friend class Class;
};
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 1a349ed..7b23600 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -2645,6 +2645,7 @@
if (!FLAG_write_protect_code) {
// Since this test is expected to crash, crash if write protection of code
// is switched off.
+ // TODO(regis, fschneider): Should this be FATAL() instead?
OS::DebugBreak();
}
}
@@ -4209,8 +4210,8 @@
elideSubstring("classes", js.ToCString(), buffer);
EXPECT_STREQ(
"{\"type\":\"@Function\",\"id\":\"\",\"name\":\"toString\","
- "\"owningClass\":{\"type\":\"@Class\",\"id\":\"\",\"name\":\"bool\"},"
- "\"kind\":\"kRegularFunction\"}",
+ "\"owner\":{\"type\":\"@Class\",\"id\":\"\",\"name\":\"bool\"},"
+ "\"kind\":\"RegularFunction\"}",
buffer);
}
// Library reference
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index 3d513ec..55c6c36 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -504,11 +504,16 @@
}
+// TODO(regis, iposva): When this function is no longer called from the
+// CodeImmutability test in object_test.cc, it will be called only from the
+// simulator, which means that only the Intel implementation is needed.
void OS::DebugBreak() {
#if defined(HOST_ARCH_X64) || defined(HOST_ARCH_IA32)
asm("int $3");
-#elif defined(HOST_ARCH_ARM)
+#elif defined(HOST_ARCH_ARM) && !defined(__THUMBEL__)
asm("svc #0x9f0001"); // __ARM_NR_breakpoint
+#elif defined(HOST_ARCH_ARM) && defined(__THUMBEL__)
+ UNIMPLEMENTED();
#elif defined(HOST_ARCH_MIPS) || defined(HOST_ARCH_ARM64)
UNIMPLEMENTED();
#else
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index 457f06e..e55380c 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -23,8 +23,6 @@
namespace dart {
-class Isolate;
-
// Low-level operations on OS platform threads.
class OSThread : AllStatic {
public:
@@ -63,13 +61,15 @@
void Unlock();
#if defined(DEBUG)
- Isolate* Owner() const { return owner_; }
+ bool IsOwnedByCurrentThread() const {
+ return owner_ == OSThread::GetCurrentThreadId();
+ }
#endif // defined(DEBUG)
private:
MutexData data_;
#if defined(DEBUG)
- Isolate* owner_;
+ ThreadId owner_;
#endif // defined(DEBUG)
DISALLOW_COPY_AND_ASSIGN(Mutex);
diff --git a/runtime/vm/os_thread_android.cc b/runtime/vm/os_thread_android.cc
index f4b5233..57de1b0 100644
--- a/runtime/vm/os_thread_android.cc
+++ b/runtime/vm/os_thread_android.cc
@@ -11,7 +11,6 @@
#include <sys/time.h> // NOLINT
#include "platform/assert.h"
-#include "vm/isolate.h"
namespace dart {
@@ -197,7 +196,7 @@
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- owner_ = NULL;
+ owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
}
@@ -209,7 +208,7 @@
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- ASSERT(owner_ == NULL);
+ ASSERT(owner_ == OSThread::kInvalidThreadId);
#endif // defined(DEBUG)
}
@@ -221,7 +220,7 @@
ASSERT(result == 0); // Verify no other errors.
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- owner_ = Isolate::Current();
+ owner_ = OSThread::GetCurrentThreadId();
#endif // defined(DEBUG)
}
@@ -235,7 +234,7 @@
ASSERT(result == 0); // Verify no other errors.
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- owner_ = Isolate::Current();
+ owner_ = OSThread::GetCurrentThreadId();
#endif // defined(DEBUG)
return true;
}
@@ -244,8 +243,8 @@
void Mutex::Unlock() {
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- ASSERT(owner_ == Isolate::Current());
- owner_ = NULL;
+ ASSERT(IsOwnedByCurrentThread());
+ owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
int result = pthread_mutex_unlock(data_.mutex());
// Specifically check for wrong thread unlocking to aid debugging.
diff --git a/runtime/vm/os_thread_linux.cc b/runtime/vm/os_thread_linux.cc
index a2b3cff..b1b97fd 100644
--- a/runtime/vm/os_thread_linux.cc
+++ b/runtime/vm/os_thread_linux.cc
@@ -12,7 +12,6 @@
#include <sys/time.h> // NOLINT
#include "platform/assert.h"
-#include "vm/isolate.h"
namespace dart {
@@ -198,7 +197,7 @@
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- owner_ = NULL;
+ owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
}
@@ -210,7 +209,7 @@
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- ASSERT(owner_ == NULL);
+ ASSERT(owner_ == OSThread::kInvalidThreadId);
#endif // defined(DEBUG)
}
@@ -222,7 +221,7 @@
ASSERT(result == 0); // Verify no other errors.
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- owner_ = Isolate::Current();
+ owner_ = OSThread::GetCurrentThreadId();
#endif // defined(DEBUG)
}
@@ -236,7 +235,7 @@
ASSERT(result == 0); // Verify no other errors.
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- owner_ = Isolate::Current();
+ owner_ = OSThread::GetCurrentThreadId();
#endif // defined(DEBUG)
return true;
}
@@ -245,8 +244,8 @@
void Mutex::Unlock() {
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- ASSERT(owner_ == Isolate::Current());
- owner_ = NULL;
+ ASSERT(IsOwnedByCurrentThread());
+ owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
int result = pthread_mutex_unlock(data_.mutex());
// Specifically check for wrong thread unlocking to aid debugging.
diff --git a/runtime/vm/os_thread_macos.cc b/runtime/vm/os_thread_macos.cc
index 279425a..2102887 100644
--- a/runtime/vm/os_thread_macos.cc
+++ b/runtime/vm/os_thread_macos.cc
@@ -19,7 +19,6 @@
#include <mach/thread_act.h> // NOLINT
#include "platform/assert.h"
-#include "vm/isolate.h"
namespace dart {
@@ -203,7 +202,7 @@
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- owner_ = NULL;
+ owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
}
@@ -215,7 +214,7 @@
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- ASSERT(owner_ == NULL);
+ ASSERT(owner_ == OSThread::kInvalidThreadId);
#endif // defined(DEBUG)
}
@@ -227,7 +226,7 @@
ASSERT(result == 0); // Verify no other errors.
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- owner_ = Isolate::Current();
+ owner_ = OSThread::GetCurrentThreadId();
#endif // defined(DEBUG)
}
@@ -241,7 +240,7 @@
ASSERT(result == 0); // Verify no other errors.
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- owner_ = Isolate::Current();
+ owner_ = OSThread::GetCurrentThreadId();
#endif // defined(DEBUG)
return true;
}
@@ -250,8 +249,8 @@
void Mutex::Unlock() {
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- ASSERT(owner_ == Isolate::Current());
- owner_ = NULL;
+ ASSERT(IsOwnedByCurrentThread());
+ owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
int result = pthread_mutex_unlock(data_.mutex());
// Specifically check for wrong thread unlocking to aid debugging.
diff --git a/runtime/vm/os_thread_win.cc b/runtime/vm/os_thread_win.cc
index e240b50..ff6ced0 100644
--- a/runtime/vm/os_thread_win.cc
+++ b/runtime/vm/os_thread_win.cc
@@ -10,7 +10,6 @@
#include <process.h> // NOLINT
#include "platform/assert.h"
-#include "vm/isolate.h"
namespace dart {
@@ -173,7 +172,7 @@
}
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- owner_ = NULL;
+ owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
}
@@ -182,7 +181,7 @@
CloseHandle(data_.semaphore_);
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- ASSERT(owner_ == NULL);
+ ASSERT(owner_ == OSThread::kInvalidThreadId);
#endif // defined(DEBUG)
}
@@ -194,7 +193,7 @@
}
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- owner_ = Isolate::Current();
+ owner_ = OSThread::GetCurrentThreadId();
#endif // defined(DEBUG)
}
@@ -205,7 +204,7 @@
if (result == WAIT_OBJECT_0) {
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- owner_ = Isolate::Current();
+ owner_ = OSThread::GetCurrentThreadId();
#endif // defined(DEBUG)
return true;
}
@@ -220,8 +219,8 @@
void Mutex::Unlock() {
// When running with assertions enabled we do track the owner.
#if defined(DEBUG)
- ASSERT(owner_ == Isolate::Current());
- owner_ = NULL;
+ ASSERT(IsOwnedByCurrentThread());
+ owner_ = OSThread::kInvalidThreadId;
#endif // defined(DEBUG)
BOOL result = ReleaseSemaphore(data_.semaphore_, 1, NULL);
if (result == 0) {
diff --git a/runtime/vm/pages.h b/runtime/vm/pages.h
index 06abc31..c6b4f38 100644
--- a/runtime/vm/pages.h
+++ b/runtime/vm/pages.h
@@ -10,6 +10,7 @@
#include "vm/lockers.h"
#include "vm/ring_buffer.h"
#include "vm/spaces.h"
+#include "vm/thread.h"
#include "vm/virtual_memory.h"
namespace dart {
@@ -226,7 +227,7 @@
IncreaseCapacityInWordsLocked(increase_in_words);
}
void IncreaseCapacityInWordsLocked(intptr_t increase_in_words) {
- DEBUG_ASSERT(pages_lock_->Owner() == Isolate::Current());
+ DEBUG_ASSERT(pages_lock_->IsOwnedByCurrentThread());
usage_.capacity_in_words += increase_in_words;
}
intptr_t ExternalInWords() const {
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 0a2b0fb..6bfd9c8 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -62,7 +62,7 @@
// Quick access to the current isolate and zone.
-#define I (thread()->isolate())
+#define I (isolate())
#define Z (zone())
@@ -318,7 +318,7 @@
// For parsing a compilation unit.
Parser::Parser(const Script& script, const Library& library, intptr_t token_pos)
- : thread_(Thread::Current()),
+ : isolate_(Thread::Current()->isolate()),
script_(Script::Handle(zone(), script.raw())),
tokens_iterator_(TokenStream::Handle(zone(), script.tokens()),
token_pos),
@@ -347,7 +347,7 @@
Parser::Parser(const Script& script,
ParsedFunction* parsed_function,
intptr_t token_position)
- : thread_(Thread::Current()),
+ : isolate_(Thread::Current()->isolate()),
script_(Script::Handle(zone(), script.raw())),
tokens_iterator_(TokenStream::Handle(zone(), script.tokens()),
token_position),
@@ -764,18 +764,6 @@
};
-static bool HasReturnNode(SequenceNode* seq) {
- if (seq->length() == 0) {
- return false;
- } else if ((seq->length()) == 1 &&
- (seq->NodeAt(seq->length() - 1)->IsSequenceNode())) {
- return HasReturnNode(seq->NodeAt(seq->length() - 1)->AsSequenceNode());
- } else {
- return seq->NodeAt(seq->length() - 1)->IsReturnNode();
- }
-}
-
-
void Parser::ParseClass(const Class& cls) {
if (!cls.is_synthesized_class()) {
Isolate* isolate = Isolate::Current();
@@ -906,16 +894,6 @@
UNREACHABLE();
}
- if (!HasReturnNode(node_sequence)) {
- // Add implicit return node. The implicit return value of synchronous
- // generator closures is false, to indicate that there are no more
- // elements in the iterable. In other cases the implicit return value
- // is null.
- AstNode* return_value = func.IsSyncGenClosure()
- ? new LiteralNode(func.end_token_pos(), Bool::False())
- : new LiteralNode(func.end_token_pos(), Instance::ZoneHandle());
- node_sequence->Add(new ReturnNode(func.end_token_pos(), return_value));
- }
if (parsed_function->has_expression_temp_var()) {
node_sequence->scope()->AddVariable(parsed_function->expression_temp_var());
}
@@ -1566,16 +1544,21 @@
}
-void Parser::SkipBlock() {
- ASSERT(CurrentToken() == Token::kLBRACE);
+void Parser::SkipToMatching() {
+ Token::Kind opening_token = CurrentToken();
+ ASSERT((opening_token == Token::kLBRACE) ||
+ (opening_token == Token::kLPAREN));
GrowableArray<Token::Kind> token_stack(8);
- // Adding the first kLBRACE here, because it will be consumed in the loop
- // right away.
- token_stack.Add(CurrentToken());
- const intptr_t block_start_pos = TokenPos();
+ GrowableArray<intptr_t> token_pos_stack(8);
+ // Adding the first opening brace here, because it will be consumed
+ // in the loop right away.
+ token_stack.Add(opening_token);
+ const intptr_t start_pos = TokenPos();
+ intptr_t opening_pos = start_pos;
+ token_pos_stack.Add(start_pos);
bool is_match = true;
bool unexpected_token_found = false;
- Token::Kind token;
+ Token::Kind token = opening_token;
intptr_t token_pos;
do {
ConsumeToken();
@@ -1586,15 +1569,22 @@
case Token::kLPAREN:
case Token::kLBRACK:
token_stack.Add(token);
+ token_pos_stack.Add(token_pos);
break;
case Token::kRBRACE:
- is_match = token_stack.RemoveLast() == Token::kLBRACE;
+ opening_token = token_stack.RemoveLast();
+ opening_pos = token_pos_stack.RemoveLast();
+ is_match = opening_token == Token::kLBRACE;
break;
case Token::kRPAREN:
- is_match = token_stack.RemoveLast() == Token::kLPAREN;
+ opening_token = token_stack.RemoveLast();
+ opening_pos = token_pos_stack.RemoveLast();
+ is_match = opening_token == Token::kLPAREN;
break;
case Token::kRBRACK:
- is_match = token_stack.RemoveLast() == Token::kLBRACK;
+ opening_token = token_stack.RemoveLast();
+ opening_pos = token_pos_stack.RemoveLast();
+ is_match = opening_token == Token::kLBRACK;
break;
case Token::kEOS:
unexpected_token_found = true;
@@ -1605,13 +1595,34 @@
}
} while (!token_stack.is_empty() && is_match && !unexpected_token_found);
if (!is_match) {
- ReportError(token_pos, "unbalanced '%s'", Token::Str(token));
+ const Error& error = Error::Handle(
+ LanguageError::NewFormatted(Error::Handle(),
+ script_, opening_pos, Report::kWarning, Heap::kNew,
+ "unbalanced '%s' opens here", Token::Str(opening_token)));
+ ReportErrors(error, script_, token_pos,
+ "unbalanced '%s'", Token::Str(token));
} else if (unexpected_token_found) {
- ReportError(block_start_pos, "unterminated block");
+ ReportError(start_pos, "unterminated '%s'", Token::Str(opening_token));
}
}
+
+void Parser::SkipBlock() {
+ ASSERT(CurrentToken() == Token::kLBRACE);
+ SkipToMatching();
+}
+
+
+// Skips tokens up to and including matching closing parenthesis.
+void Parser::SkipToMatchingParenthesis() {
+ ASSERT(CurrentToken() == Token::kLPAREN);
+ SkipToMatching();
+ ASSERT(CurrentToken() == Token::kRPAREN);
+ ConsumeToken();
+}
+
+
void Parser::ParseFormalParameter(bool allow_explicit_default_value,
bool evaluate_metadata,
ParamList* params) {
@@ -3346,6 +3357,7 @@
} else if (func.IsAsyncGenClosure()) {
body = CloseAsyncGeneratorClosure(body);
}
+ EnsureHasReturnStatement(body, end_token_pos);
current_block_->statements->Add(body);
innermost_function_ = saved_innermost_function.raw();
last_used_try_index_ = saved_try_index;
@@ -3388,23 +3400,6 @@
}
-// Skips tokens up to matching closing parenthesis.
-void Parser::SkipToMatchingParenthesis() {
- Token::Kind current_token = CurrentToken();
- ASSERT(current_token == Token::kLPAREN);
- int level = 0;
- do {
- if (current_token == Token::kLPAREN) {
- level++;
- } else if (current_token == Token::kRPAREN) {
- level--;
- }
- ConsumeToken();
- current_token = CurrentToken();
- } while ((level > 0) && (current_token != Token::kEOS));
-}
-
-
void Parser::SkipInitializers() {
ASSERT(CurrentToken() == Token::kCOLON);
do {
@@ -6837,6 +6832,22 @@
}
+// Add a return node to the sequence if necessary.
+void Parser::EnsureHasReturnStatement(SequenceNode* seq, intptr_t return_pos) {
+ if ((seq->length() == 0) ||
+ !seq->NodeAt(seq->length() - 1)->IsReturnNode()) {
+ const Function& func = innermost_function();
+ // The implicit return value of synchronous generator closures is false,
+ // to indicate that there are no more elements in the iterable.
+ // In other cases the implicit return value is null.
+ AstNode* return_value = func.IsSyncGenClosure()
+ ? new LiteralNode(return_pos, Bool::False())
+ : new LiteralNode(return_pos, Instance::ZoneHandle());
+ seq->Add(new ReturnNode(return_pos, return_value));
+ }
+}
+
+
SequenceNode* Parser::CloseBlock() {
SequenceNode* statements = current_block_->statements;
if (current_block_->scope != NULL) {
@@ -7306,10 +7317,12 @@
result_type = Type::DynamicType();
const intptr_t function_pos = TokenPos();
+ intptr_t metadata_pos = -1;
if (is_literal) {
ASSERT(CurrentToken() == Token::kLPAREN);
function_name = &Symbols::AnonymousClosure();
} else {
+ metadata_pos = SkipMetadata();
if (CurrentToken() == Token::kVOID) {
ConsumeToken();
result_type = Type::VoidType();
@@ -7359,6 +7372,9 @@
innermost_function(),
function_pos);
function.set_result_type(result_type);
+ if (metadata_pos >= 0) {
+ library_.AddFunctionMetadata(function, metadata_pos);
+ }
}
// The function type needs to be finalized at compile time, since the closure
@@ -7722,6 +7738,7 @@
bool Parser::IsFunctionDeclaration() {
const intptr_t saved_pos = TokenPos();
bool is_external = false;
+ SkipMetadata();
if (is_top_level_) {
if (is_patch_source() &&
(CurrentToken() == Token::kIDENT) &&
@@ -8293,6 +8310,23 @@
}
+// Build an AST node for static call to Dart function print(str).
+// Used during debugging to insert print in generated dart code.
+AstNode* Parser::DartPrint(const char* str) {
+ const Library& lib = Library::Handle(Library::CoreLibrary());
+ const Function& print_fn = Function::ZoneHandle(
+ Z, lib.LookupFunctionAllowPrivate(Symbols::print()));
+ ASSERT(!print_fn.IsNull());
+ ArgumentListNode* one_arg = new(Z) ArgumentListNode(Scanner::kNoSourcePos);
+ String& msg = String::Handle(String::NewFormatted("%s", str));
+ one_arg->Add(new(Z) LiteralNode(Scanner::kNoSourcePos,
+ String::ZoneHandle(Symbols::New(msg))));
+ AstNode* print_call =
+ new(Z) StaticCallNode(Scanner::kNoSourcePos, print_fn, one_arg);
+ return print_call;
+}
+
+
AstNode* Parser::ParseAwaitForStatement(String* label_name) {
TRACE_PARSER("ParseAwaitForStatement");
ASSERT(IsAwaitKeyword());
@@ -8460,7 +8494,6 @@
loop_var_assignment_pos);
ASSERT(loop_var_assignment != NULL);
}
-
current_block_->statements->Add(loop_var_assignment);
// Now parse the for-in loop statement or block.
@@ -10621,8 +10654,8 @@
} else {
arguments = implicit_arguments;
}
- const GrowableObjectArray& names = GrowableObjectArray::Handle(Z,
- GrowableObjectArray::New(Heap::kOld));
+ const GrowableObjectArray& names =
+ GrowableObjectArray::Handle(Z, GrowableObjectArray::New(Heap::kOld));
bool named_argument_seen = false;
if (LookaheadToken(1) != Token::kRPAREN) {
String& arg_name = String::Handle(Z);
@@ -10642,7 +10675,7 @@
ReportError("duplicate named argument");
}
}
- names.Add(*CurrentLiteral());
+ names.Add(*CurrentLiteral(), Heap::kOld);
ConsumeToken(); // ident.
ConsumeToken(); // colon.
} else if (named_argument_seen) {
@@ -11040,16 +11073,11 @@
if (primary_node->IsSuper()) {
ReportError(primary_pos, "illegal use of super");
}
- String& name = String::CheckedZoneHandle(
- primary_node->primary().raw());
+ String& name =
+ String::CheckedZoneHandle(primary_node->primary().raw());
if (current_function().is_static()) {
- selector = ThrowNoSuchMethodError(primary_pos,
- current_class(),
- name,
- NULL, // No arguments.
- InvocationMirror::kStatic,
- InvocationMirror::kMethod,
- NULL); // No existing function.
+ // The static call will be converted to throwing a NSM error.
+ selector = ParseStaticCall(current_class(), name, primary_pos);
} else {
// Treat as call to unresolved (instance) method.
selector = ParseInstanceCall(LoadReceiver(primary_pos),
@@ -11904,15 +11932,28 @@
"using '%s' in this context is invalid",
type_name.ToCString());
}
- if (!prefix.IsNull() && prefix.is_deferred_load() && !allow_deferred_type) {
- ParseTypeArguments(ClassFinalizer::kIgnore);
- return ClassFinalizer::NewFinalizedMalformedType(
- Error::Handle(Z), // No previous error.
- script_,
- ident_pos,
- "using deferred type '%s.%s' is invalid",
- String::Handle(Z, prefix.name()).ToCString(),
- type_name.ToCString());
+ if (!prefix.IsNull() && prefix.is_deferred_load()) {
+ // If deferred prefixes are allowed but it is not yet loaded,
+ // remember that this function depends on the prefix.
+ if (allow_deferred_type && !prefix.is_loaded()) {
+ ASSERT(parsed_function() != NULL);
+ parsed_function()->AddDeferredPrefix(prefix);
+ }
+ // If the deferred prefixes are not allowed, or if the prefix
+ // is not yet loaded, return a malformed type. Otherwise, handle
+ // resolution below, as needed.
+ if (!prefix.is_loaded() || !allow_deferred_type) {
+ ParseTypeArguments(ClassFinalizer::kIgnore);
+ return ClassFinalizer::NewFinalizedMalformedType(
+ Error::Handle(Z), // No previous error.
+ script_,
+ ident_pos,
+ !prefix.is_loaded()
+ ? "deferred type '%s.%s' is not yet loaded"
+ : "using deferred type '%s.%s' is invalid",
+ String::Handle(Z, prefix.name()).ToCString(),
+ type_name.ToCString());
+ }
}
}
Object& type_class = Object::Handle(Z);
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index cfb6a76..3b81d0b 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -41,7 +41,7 @@
class ParsedFunction : public ZoneAllocated {
public:
ParsedFunction(Thread* thread, const Function& function)
- : thread_(thread),
+ : isolate_(thread->isolate()),
function_(function),
code_(Code::Handle(zone(), function.unoptimized_code())),
node_sequence_(NULL),
@@ -150,12 +150,11 @@
void record_await() { have_seen_await_expr_ = true; }
bool have_seen_await() const { return have_seen_await_expr_; }
- Thread* thread() const { return thread_; }
- Isolate* isolate() const { return thread()->isolate(); }
- Zone* zone() const { return thread()->zone(); }
+ Isolate* isolate() const { return isolate_; }
+ Zone* zone() const { return isolate()->current_zone(); }
private:
- Thread* thread_;
+ Isolate* isolate_;
const Function& function_;
Code& code_;
SequenceNode* node_sequence_;
@@ -325,9 +324,10 @@
bool IsYieldKeyword();
void SkipIf(Token::Kind);
+ void SkipToMatching();
+ void SkipToMatchingParenthesis();
void SkipBlock();
intptr_t SkipMetadata();
- void SkipToMatchingParenthesis();
void SkipTypeArguments();
void SkipType(bool allow_void);
void SkipInitializers();
@@ -350,6 +350,8 @@
void SkipQualIdent();
void SkipFunctionPreamble();
+ AstNode* DartPrint(const char* str);
+
void CheckConstructorCallTypeArguments(intptr_t pos,
const Function& constructor,
const TypeArguments& type_arguments);
@@ -533,6 +535,7 @@
const ArgumentsDescriptor& desc,
Array* default_values);
+ void EnsureHasReturnStatement(SequenceNode* seq, intptr_t return_pos);
void ChainNewBlock(LocalScope* outer_scope);
void OpenBlock();
void OpenLoopBlock();
@@ -796,11 +799,10 @@
RawInstance* TryCanonicalize(const Instance& instance, intptr_t token_pos);
- Thread* thread() const { return thread_; }
- Isolate* isolate() const { return thread()->isolate(); }
- Zone* zone() const { return thread()->zone(); }
+ Isolate* isolate() const { return isolate_; }
+ Zone* zone() const { return isolate()->current_zone(); }
- Thread* thread_; // Cached current thread.
+ Isolate* isolate_; // Cached current isolate.
Script& script_;
TokenStream::Iterator tokens_iterator_;
diff --git a/runtime/vm/port.cc b/runtime/vm/port.cc
index cfb9ac8..5a75068 100644
--- a/runtime/vm/port.cc
+++ b/runtime/vm/port.cc
@@ -25,6 +25,14 @@
intptr_t PortMap::FindPort(Dart_Port port) {
+ // ILLEGAL_PORT (0) is used as a sentinel value in Entry.port. The loop below
+ // could return the index to a deleted port when we are searching for
+ // port id ILLEGAL_PORT. Return -1 immediately to indicate the port
+ // does not exist.
+ if (port == ILLEGAL_PORT) {
+ return -1;
+ }
+ ASSERT(port != ILLEGAL_PORT);
intptr_t index = port % capacity_;
intptr_t start_index = index;
Entry entry = map_[index];
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 0ef0d80a..d0b327e 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -169,20 +169,6 @@
instance_size = ExceptionHandlers::InstanceSize(num_handlers);
break;
}
- case kDeoptInfoCid: {
- const RawDeoptInfo* raw_deopt_info =
- reinterpret_cast<const RawDeoptInfo*>(this);
- intptr_t num_entries = Smi::Value(raw_deopt_info->ptr()->length_);
- instance_size = DeoptInfo::InstanceSize(num_entries);
- break;
- }
- case kJSRegExpCid: {
- const RawJSRegExp* raw_jsregexp =
- reinterpret_cast<const RawJSRegExp*>(this);
- intptr_t data_length = Smi::Value(raw_jsregexp->ptr()->data_length_);
- instance_size = JSRegExp::InstanceSize(data_length);
- break;
- }
case kFreeListElement: {
uword addr = RawObject::ToAddr(const_cast<RawObject*>(this));
FreeListElement* element = reinterpret_cast<FreeListElement*>(addr);
@@ -586,15 +572,6 @@
}
-intptr_t RawDeoptInfo::VisitDeoptInfoPointers(
- RawDeoptInfo* raw_obj, ObjectPointerVisitor* visitor) {
- RawDeoptInfo* obj = raw_obj->ptr();
- intptr_t length = Smi::Value(obj->length_);
- visitor->VisitPointer(reinterpret_cast<RawObject**>(&obj->length_));
- return DeoptInfo::InstanceSize(length);
-}
-
-
intptr_t RawContext::VisitContextPointers(RawContext* raw_obj,
ObjectPointerVisitor* visitor) {
intptr_t num_variables = raw_obj->ptr()->num_variables_;
@@ -904,9 +881,8 @@
ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
- intptr_t length = Smi::Value(raw_obj->ptr()->data_length_);
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
- return JSRegExp::InstanceSize(length);
+ return JSRegExp::InstanceSize();
}
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index f4a537f..b0ace7c 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -35,7 +35,6 @@
V(Stackmap) \
V(LocalVarDescriptors) \
V(ExceptionHandlers) \
- V(DeoptInfo) \
V(Context) \
V(ContextScope) \
V(ICData) \
@@ -186,10 +185,6 @@
kSmiTagShift = 1,
};
-enum {
- kInvalidObjectPointer = kHeapObjectTag,
-};
-
enum TypedDataElementType {
#define V(name) k##name##Element,
CLASS_LIST_TYPED_DATA(V)
@@ -1244,19 +1239,6 @@
};
-// Contains an array of deoptimization commands, e.g., move a specific register
-// into a specific slot of unoptimized frame.
-class RawDeoptInfo : public RawObject {
- RAW_HEAP_OBJECT_IMPLEMENTATION(DeoptInfo);
-
- RawSmi* length_; // Number of deoptimization commands
-
- // Variable length data follows here.
- intptr_t* data() { OPEN_ARRAY_START(intptr_t, intptr_t); }
- const intptr_t* data() const { OPEN_ARRAY_START(intptr_t, intptr_t); }
-};
-
-
class RawContext : public RawObject {
RAW_HEAP_OBJECT_IMPLEMENTATION(Context);
@@ -1886,9 +1868,8 @@
RAW_HEAP_OBJECT_IMPLEMENTATION(JSRegExp);
RawObject** from() {
- return reinterpret_cast<RawObject**>(&ptr()->data_length_);
+ return reinterpret_cast<RawObject**>(&ptr()->num_bracket_expressions_);
}
- RawSmi* data_length_;
RawSmi* num_bracket_expressions_;
RawString* pattern_; // Pattern to be used for matching.
RawFunction* one_byte_function_;
@@ -1903,9 +1884,6 @@
// type: Uninitialized, simple or complex.
// flags: Represents global/local, case insensitive, multiline.
int8_t type_flags_;
-
- // Variable length data follows here.
- uint8_t* data() { OPEN_ARRAY_START(uint8_t, uint8_t); }
};
@@ -2154,7 +2132,6 @@
(index == kStackmapCid) ||
(index == kLocalVarDescriptorsCid) ||
(index == kExceptionHandlersCid) ||
- (index == kDeoptInfoCid) ||
(index == kCodeCid) ||
(index == kContextScopeCid) ||
(index == kInstanceCid) ||
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 6a9c490..838145c 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -1342,22 +1342,6 @@
}
-RawDeoptInfo* DeoptInfo::ReadFrom(SnapshotReader* reader,
- intptr_t object_id,
- intptr_t tags,
- Snapshot::Kind kind) {
- UNREACHABLE();
- return DeoptInfo::null();
-}
-
-
-void RawDeoptInfo::WriteTo(SnapshotWriter* writer,
- intptr_t object_id,
- Snapshot::Kind kind) {
- UNREACHABLE();
-}
-
-
RawContext* Context::ReadFrom(SnapshotReader* reader,
intptr_t object_id,
intptr_t tags,
@@ -2767,12 +2751,9 @@
ASSERT(reader != NULL);
ASSERT(kind == Snapshot::kMessage);
- // Read the length so that we can determine instance size to allocate.
- intptr_t len = reader->ReadSmiValue();
-
// Allocate JSRegExp object.
JSRegExp& regex = JSRegExp::ZoneHandle(
- reader->zone(), JSRegExp::New(len, HEAP_SPACE(kind)));
+ reader->zone(), JSRegExp::New(HEAP_SPACE(kind)));
reader->AddBackRef(object_id, ®ex, kIsDeserialized);
// Set the object tags.
@@ -2786,8 +2767,7 @@
regex.StoreNonPointer(®ex.raw_ptr()->type_flags_,
reader->Read<int8_t>());
- // TODO(5411462): Need to implement a way of recompiling the regex.
-
+ // TODO(18854): Need to implement a way of recreating the irrexp functions.
return regex.raw();
}
@@ -2805,15 +2785,10 @@
writer->WriteIndexedObject(kJSRegExpCid);
writer->WriteTags(writer->GetObjectTags(this));
- // Write out the data length field.
- writer->Write<RawObject*>(ptr()->data_length_);
-
// Write out all the other fields.
writer->Write<RawObject*>(ptr()->num_bracket_expressions_);
writer->WriteObjectImpl(ptr()->pattern_);
writer->Write<int8_t>(ptr()->type_flags_);
-
- // Do not write out the data part which is native.
}
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index d251935..47e296d 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -5148,7 +5148,7 @@
const String& pattern,
bool multi_line,
bool ignore_case) {
- const JSRegExp& regexp = JSRegExp::Handle(JSRegExp::New(0));
+ const JSRegExp& regexp = JSRegExp::Handle(JSRegExp::New());
regexp.set_pattern(pattern);
diff --git a/runtime/vm/regexp_parser.cc b/runtime/vm/regexp_parser.cc
index 9db51dd..03abf5a 100644
--- a/runtime/vm/regexp_parser.cc
+++ b/runtime/vm/regexp_parser.cc
@@ -673,7 +673,7 @@
// Start with captures started previous to current position
intptr_t capture_count = captures_started();
// Add count of captures after this position.
- intptr_t n;
+ uintptr_t n;
while ((n = current()) != kEndMarker) {
Advance();
switch (n) {
@@ -681,7 +681,7 @@
Advance();
break;
case '[': {
- intptr_t c;
+ uintptr_t c;
while ((c = current()) != kEndMarker) {
Advance();
if (c == '\\') {
diff --git a/runtime/vm/regexp_test.cc b/runtime/vm/regexp_test.cc
index b8b962f..a0f5621 100644
--- a/runtime/vm/regexp_test.cc
+++ b/runtime/vm/regexp_test.cc
@@ -25,9 +25,6 @@
}
TEST_CASE(RegExp_OneByteString) {
- if (FLAG_use_jscre)
- return;
-
uint8_t chars[] = { 'a', 'b', 'c', 'b', 'a' };
intptr_t len = ARRAY_SIZE(chars);
const String& str = String::Handle(
@@ -49,9 +46,6 @@
}
TEST_CASE(RegExp_TwoByteString) {
- if (FLAG_use_jscre)
- return;
-
uint16_t chars[] = { 'a', 'b', 'c', 'b', 'a' };
intptr_t len = ARRAY_SIZE(chars);
const String& str = String::Handle(
@@ -73,9 +67,6 @@
}
TEST_CASE(RegExp_ExternalOneByteString) {
- if (FLAG_use_jscre)
- return;
-
uint8_t chars[] = { 'a', 'b', 'c', 'b', 'a' };
intptr_t len = ARRAY_SIZE(chars);
const String& str = String::Handle(
@@ -97,9 +88,6 @@
}
TEST_CASE(RegExp_ExternalTwoByteString) {
- if (FLAG_use_jscre)
- return;
-
uint16_t chars[] = { 'a', 'b', 'c', 'b', 'a' };
intptr_t len = ARRAY_SIZE(chars);
const String& str = String::Handle(
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 5cb1721..e120572 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -44,7 +44,6 @@
// TODO(johnmccutchan): Unify embedder service handler lists and their APIs.
EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL;
EmbedderServiceHandler* Service::root_service_handler_head_ = NULL;
-uint32_t Service::event_mask_ = 0;
struct ServiceMethodDescriptor;
ServiceMethodDescriptor* FindMethod(const char* method_name);
@@ -501,34 +500,14 @@
}
-bool Service::EventMaskHas(uint32_t mask) {
- return (event_mask_ & mask) != 0;
-}
-
-
bool Service::NeedsEvents() {
return ServiceIsolate::IsRunning();
}
-bool Service::NeedsDebuggerEvents() {
- return NeedsEvents() && EventMaskHas(kEventFamilyDebugMask);
-}
-
-
-bool Service::NeedsGCEvents() {
- return NeedsEvents() && EventMaskHas(kEventFamilyGCMask);
-}
-
-
-void Service::SetEventMask(uint32_t mask) {
- event_mask_ = mask;
-}
-
-
-void Service::SendEvent(intptr_t eventFamilyId,
- intptr_t eventType,
+void Service::SendEvent(intptr_t eventType,
const Object& eventMessage) {
+ ASSERT(!ServiceIsolate::IsServiceIsolateDescendant(Isolate::Current()));
if (!ServiceIsolate::IsRunning()) {
return;
}
@@ -536,18 +515,10 @@
ASSERT(isolate != NULL);
HANDLESCOPE(isolate);
- // Construct a list of the form [eventFamilyId, eventMessage].
- //
- // TODO(turnidge): Revisit passing the eventFamilyId here at all.
- const Array& list = Array::Handle(Array::New(2));
- ASSERT(!list.IsNull());
- list.SetAt(0, Integer::Handle(Integer::New(eventFamilyId)));
- list.SetAt(1, eventMessage);
-
// Push the event to port_.
uint8_t* data = NULL;
MessageWriter writer(&data, &allocator, false);
- writer.WriteMessage(list);
+ writer.WriteMessage(eventMessage);
intptr_t len = writer.BytesWritten();
if (FLAG_trace_service) {
OS::Print("vm-service: Pushing event of type %" Pd ", len %" Pd "\n",
@@ -559,8 +530,7 @@
}
-void Service::SendEvent(intptr_t eventFamilyId,
- const String& meta,
+void Service::SendEvent(const String& meta,
const uint8_t* data,
intptr_t size) {
// Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data]
@@ -586,16 +556,19 @@
}
ASSERT(offset == total_bytes);
// TODO(turnidge): Pass the real eventType here.
- SendEvent(eventFamilyId, 0, message);
+ SendEvent(0, message);
}
void Service::HandleGCEvent(GCEvent* event) {
+ if (ServiceIsolate::IsServiceIsolateDescendant(Isolate::Current())) {
+ return;
+ }
JSONStream js;
event->PrintJSON(&js);
const String& message = String::Handle(String::New(js.ToCString()));
// TODO(turnidge): Pass the real eventType here.
- SendEvent(kEventFamilyGC, 0, message);
+ SendEvent(0, message);
}
@@ -603,7 +576,7 @@
JSONStream js;
event->PrintJSON(&js);
const String& message = String::Handle(String::New(js.ToCString()));
- SendEvent(kEventFamilyDebug, event->type(), message);
+ SendEvent(event->type(), message);
}
@@ -798,8 +771,7 @@
}
const String& message = String::Handle(String::New(js.ToCString()));
uint8_t data[] = {0, 128, 255};
- // TODO(koda): Add 'testing' event family.
- SendEvent(kEventFamilyDebug, message, data, sizeof(data));
+ SendEvent(message, data, sizeof(data));
}
@@ -2232,12 +2204,11 @@
{
JSONObject jsobj(&js);
jsobj.AddProperty("type", "ServiceEvent");
- jsobj.AddPropertyF("id", "_graphEvent");
jsobj.AddProperty("eventType", "_Graph");
jsobj.AddProperty("isolate", isolate);
}
const String& message = String::Handle(String::New(js.ToCString()));
- SendEvent(kEventFamilyDebug, message, buffer, stream.bytes_written());
+ SendEvent(message, buffer, stream.bytes_written());
}
@@ -2415,7 +2386,7 @@
void VisitIsolate(Isolate* isolate) {
if ((isolate != Dart::vm_isolate()) &&
- !ServiceIsolate::IsServiceIsolate(isolate)) {
+ !ServiceIsolate::IsServiceIsolateDescendant(isolate)) {
jsarr_->AddValue(isolate);
}
}
@@ -2434,24 +2405,19 @@
static bool GetVM(Isolate* isolate, JSONStream* js) {
JSONObject jsobj(js);
jsobj.AddProperty("type", "VM");
- jsobj.AddProperty("id", "vm");
jsobj.AddProperty("architectureBits", static_cast<intptr_t>(kBitsPerWord));
jsobj.AddProperty("targetCPU", CPU::Id());
jsobj.AddProperty("hostCPU", HostCPUFeatures::hardware());
- jsobj.AddPropertyF("date", "%" Pd64 "", OS::GetCurrentTimeMillis());
jsobj.AddProperty("version", Version::String());
// Send pid as a string because it allows us to avoid any issues with
// pids > 53-bits (when consumed by JavaScript).
// TODO(johnmccutchan): Codify how integers are sent across the service.
jsobj.AddPropertyF("pid", "%" Pd "", OS::ProcessId());
- jsobj.AddProperty("assertsEnabled", isolate->AssertsEnabled());
- jsobj.AddProperty("typeChecksEnabled", isolate->TypeChecksEnabled());
- int64_t start_time_micros = Dart::vm_isolate()->start_time();
- int64_t uptime_micros = (OS::GetCurrentTimeMicros() - start_time_micros);
- double seconds = (static_cast<double>(uptime_micros) /
- static_cast<double>(kMicrosecondsPerSecond));
- jsobj.AddProperty("uptime", seconds);
-
+ jsobj.AddProperty("_assertsEnabled", isolate->AssertsEnabled());
+ jsobj.AddProperty("_typeChecksEnabled", isolate->TypeChecksEnabled());
+ int64_t start_time_millis = (Dart::vm_isolate()->start_time() /
+ kMicrosecondsPerMillisecond);
+ jsobj.AddProperty64("startTime", start_time_millis);
// Construct the isolate list.
{
JSONArray jsarr(&jsobj, "isolates");
@@ -2506,6 +2472,25 @@
}
+static const MethodParameter* set_name_params[] = {
+ ISOLATE_PARAMETER,
+ new MethodParameter("name", true),
+ NULL,
+};
+
+
+static bool SetName(Isolate* isolate, JSONStream* js) {
+ isolate->set_debugger_name(js->LookupParam("name"));
+ {
+ ServiceEvent event(isolate, ServiceEvent::kIsolateUpdate);
+ Service::HandleEvent(&event);
+ }
+ JSONObject jsobj(js);
+ jsobj.AddProperty("type", "Success");
+ return true;
+}
+
+
static ServiceMethodDescriptor service_methods_[] = {
{ "_echo", _Echo,
NULL },
@@ -2527,7 +2512,7 @@
eval_frame_params },
{ "getAllocationProfile", GetAllocationProfile,
get_allocation_profile_params },
- { "getCallSiteData", GetCallSiteData,
+ { "_getCallSiteData", GetCallSiteData,
get_call_site_data_params },
{ "getClassList", GetClassList,
get_class_list_params },
@@ -2577,8 +2562,10 @@
resume_params },
{ "requestHeapSnapshot", RequestHeapSnapshot,
request_heap_snapshot_params },
- { "setFlag", SetFlag ,
+ { "setFlag", SetFlag,
set_flags_params },
+ { "setName", SetName,
+ set_name_params },
};
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index c63f15d..28e02a6 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -31,11 +31,7 @@
// Handles a message which is directed to a particular isolate.
static void HandleIsolateMessage(Isolate* isolate, const Array& message);
- static bool EventMaskHas(uint32_t mask);
- static void SetEventMask(uint32_t mask);
static bool NeedsEvents();
- static bool NeedsDebuggerEvents();
- static bool NeedsGCEvents();
static void HandleEvent(ServiceEvent* event);
static void HandleGCEvent(GCEvent* event);
@@ -56,31 +52,21 @@
private:
static void InvokeMethod(Isolate* isolate, const Array& message);
- // These must be kept in sync with service/constants.dart
- static const int kEventFamilyDebug = 0;
- static const int kEventFamilyGC = 1;
- static const uint32_t kEventFamilyDebugMask = (1 << kEventFamilyDebug);
- static const uint32_t kEventFamilyGCMask = (1 << kEventFamilyGC);
-
static void EmbedderHandleMessage(EmbedderServiceHandler* handler,
JSONStream* js);
static EmbedderServiceHandler* FindIsolateEmbedderHandler(const char* name);
static EmbedderServiceHandler* FindRootEmbedderHandler(const char* name);
- static void SendEvent(intptr_t eventFamilyId,
- intptr_t eventType,
+ static void SendEvent(intptr_t eventType,
const Object& eventMessage);
// Does not take ownership of 'data'.
- static void SendEvent(intptr_t eventId,
- const String& meta,
+ static void SendEvent(const String& meta,
const uint8_t* data,
intptr_t size);
static EmbedderServiceHandler* isolate_service_handler_head_;
static EmbedderServiceHandler* root_service_handler_head_;
-
- static uint32_t event_mask_;
};
} // namespace dart
diff --git a/runtime/vm/service/client.dart b/runtime/vm/service/client.dart
index 1fd4f44..0d0b253 100644
--- a/runtime/vm/service/client.dart
+++ b/runtime/vm/service/client.dart
@@ -6,20 +6,16 @@
// A service client.
abstract class Client {
- /// A port for receipt of asynchronous service events.
- final RawReceivePort eventPort = new RawReceivePort();
final VMService service;
+ final bool sendEvents;
- Client(this.service) {
- eventPort.handler = (response) {
- post(null, response);
- };
+ Client(this.service, { bool sendEvents: true })
+ : this.sendEvents = sendEvents {
service._addClient(this);
}
/// When implementing, call [close] when the network connection closes.
void close() {
- eventPort.close();
service._removeClient(this);
}
@@ -37,8 +33,8 @@
}
}
- /// When implementing, responsible for sending [response] to the client.
- void post(var seq, dynamic response);
+ // Sends a result to the client. Implemented in subclasses.
+ void post(var seq, dynamic result);
dynamic toJson() {
return {
diff --git a/runtime/vm/service/constants.dart b/runtime/vm/service/constants.dart
index 8804863..92390e6 100644
--- a/runtime/vm/service/constants.dart
+++ b/runtime/vm/service/constants.dart
@@ -9,12 +9,4 @@
static const int SERVICE_EXIT_MESSAGE_ID = 0;
static const int ISOLATE_STARTUP_MESSAGE_ID = 1;
static const int ISOLATE_SHUTDOWN_MESSAGE_ID = 2;
-
- // Event family ids.
- static const int EVENT_FAMILY_DEBUG = 0;
- static const int EVENT_FAMILY_GC = 1;
-
- // Event family masks.
- static const int EVENT_FAMILY_DEBUG_MASK = (1 << EVENT_FAMILY_DEBUG);
- static const int EVENT_FAMILY_DEBUG_GC = (1 << EVENT_FAMILY_GC);
}
diff --git a/runtime/vm/service/service.idl b/runtime/vm/service/service.idl
index 1b825a19..4850a1c 100644
--- a/runtime/vm/service/service.idl
+++ b/runtime/vm/service/service.idl
@@ -1,14 +1,100 @@
+// <h2>Connecting to the VM Service</h2>
//
-// TODO(turnidge): Finish writing an idl description of the service protocol.
+// TODO(turnidge): Describe how to connect, etc.
//
+// <h2>Types</h2>
+//
+// Every non-error response returned by the VM Service has the
+// <code>type</code> property. This allows the client distinguish
+// between different kinds of responses.
+//
+// If the type name of a response begins with an <code>@</code>
+// character then that response is a _reference_. If the type name of
+// a response does not begin with an <code>@</code> character then
+// that response is an _object_ (or sometimes _full object_). A
+// reference is meant to be a subset of a full object with just enough
+// information for the client to generate a reasonable-looking link.
+//
+// For example, an isolate reference may look like this...
+//
+// {
+// type: "@Isolate",
+// id: "isolates/123",
+// name: "worker"
+// }
+//
+// ... and a full isolate object would have additional properties:
+//
+// {
+// type: "Isolate",
+// id: "isolates/123",
+// name: "worker"
+// entry: ...
+// heaps: ...
+// topFrame: ...
+// ...
+// }
+//
+// <h2>IDs and Names</h2>
+//
+// Many responses returned by the VM Service have an <code>id</code>
+// property. This is an identifier used to request an object from an
+// isolate using the <code>getObject</code> rpc. If two responses
+// have the same id then they refer to the same object. The converse
+// is not true: the same object may occasionally be returned with two
+// different ids.
+//
+// The client must not parse ids -- they must be treated as opaque
+// strings. We reserve the right to change the ids of objects.
+//
+// TODO(turnidge): Describe id/handle expiration. Provide guidance on
+// which responses are cacheable/constant. Perhaps this needs to be
+// signaled in the Response itself.
+//
+// Many responses have the <code>name</code> property. Names are
+// provided so that objects can be displayed in a way that a Dart
+// language programmer would find sensible.
+//
+// Note that names are not unique. Many objects will have the same
+// name.
+//
+// <h2>Private Properties</h2>
+//
+// Some properties returned by the VM Service begin with an underscore
+// (_) character. These properties are called _private
+// properties_. Private properties provide private information
+// specific to the VM's implementation. Private properties may be
+// added, removed, or changed at any time with any release of the VM.
+// They are provided for those tools that need this level of internal
+// access, such as the Observatory.
+//
+// For example, some responses will have the <code>_vmType</code>
+// property. This provides the VM-internal type name of an object,
+// and is provided only when this type name differs from the
+// <code>type</code> property.
+//
+// <b>If your application relies on private properties, you should expect
+// to update it when new versions of the VM are released.</b>
+//
+// <hr>
interface Service {
+ // Returns global information about the Dart VM.
getVM() VM
+ // Changes the debugging name for some isolate.
+ setName(isolateId string, name string) Response
+
+ // Returns information about an isolate.
+ getIsolate(isolateId string) Isolate
+
+ // Returns a list of vm flags and their values.
getFlagList() FlagList
+ // Sets the value of a vm flag
setFlag(name string, value string) Response
+ // Loads an object by id from an isolate.
getObject(isolateId string, objectId string) Object
// The response is a subtype of Object or ObjectRef.
@@ -48,7 +134,7 @@
getCoverage(isolateId string, targetId string) CodeCoverage
// Returns call site cache information for a function.
- getCallSiteData(isolateId string, targetId string) _CallSiteData
+ _getCallSiteData(isolateId string, targetId string) _CallSiteData
// Returns a full cpu profile for an isolate.
//
@@ -97,21 +183,27 @@
getTypeArgumentsList(isolateId string,
onlyWithInstantiations bool) TypeArgumentsList
+ // Gets a list of isolate metrics.
getIsolateMetricList(isolateId string,
type MetricSelector) MetricList
+ // Gets a specific isolate metric by id.
getIsolateMetric(isolateId string,
metricId string) Metric
+ // Gets a list of vm metrics.
getVMMetricList() MetricList
+ // Gets a specific vm metric by id.
getVMMetric(metricId string) Metric
+ // A test rpc for vm requests.
+ _echoVM(text string) _EchoResponse
+
+ // A test rpc for isolate requests.
_echo(isolateId string,
text string) _EchoResponse
- _echoVM(text string) _EchoResponse
-
// Triggers a ServiceEvent with EventType '_Echo'.
_triggerEchoEvent(isolateId string,
text string) _EchoResponse
@@ -124,10 +216,10 @@
}
-// Every top level response returned by the Service interface extends
-// <code>Response</code>. This allows the client to distinguish
-// between different kinds of responses by using the <code>type</code>
-// property.
+// Every non-error top level response returned by the Service
+// interface extends <code>Response</code>. This allows the client to
+// distinguish between different kinds of responses by using the
+// <code>type</code> property.
struct Response {
// Every response returned by the VM Service has the
// <code>type</code> property. This allows the client distinguish
@@ -142,32 +234,683 @@
}
+// An asynchronous notification from the VM Service.
+struct ServiceEvent extends Response {
+ // What kind of event is this?
+ eventType ServiceEventType
+
+ // The isolate with which this event is associated.
+ isolate IsolateRef
+
+ // The breakpoint associated with this event, if applicable.
+ //
+ // This is provided for the events:
+ // <code>PauseBreakpoint</code>
+ // <code>BreakpointAdded</code>
+ // <code>BreakpointRemoved</code>
+ // <code>BreakpointResolved</code>
+ breakpoint Breakpoint [optional]
+
+ // The top stack frame associated with this event, if applicable.
+ //
+ // This is provided for the events:
+ // <code>PauseBreakpoint</code>
+ // <code>PauseInterrupted</code>
+ // <code>PauseException</code>
+ //
+ // For the <code>Resume</code> event, the top frame is provided at
+ // all times except for the initial resume event that is delivered
+ // when an isolate begins execution.
+ topFrame Frame [optional]
+
+ // The exception associated with this event, if this is a
+ // <code>PauseException</code> event.
+ exception InstanceRef [optional]
+}
+
+
+// The type of a service event.
+enum ServiceEventType {
+ // Notification that a new isolate has started.
+ IsolateStart
+
+ // Notification that an isolate has exited.
+ IsolateExit
+
+ // Notification that isolate identifying information has changed.
+ // Currently used to notify of changes to the isolate debugging name
+ // via <code>setName</code>.
+ IsolateUpdate
+
+ // An isolate has paused at start, before executing code.
+ PauseStart
+
+ // An isolate has paused at exit, before terminating.
+ PauseExit
+
+ // An isolate has paused at a breakpoint or due to stepping.
+ PauseBreakpoint
+
+ // An isolate has paused due to interruption via <code>pause</code>.
+ PauseInterrupted
+
+ // An isolate has paused due to an exception.
+ //
+ // TODO(turnidge): Allow user to toggle pause-on-exceptions.
+ PauseException
+
+ // An isolate has started or resumed execution.
+ Resume
+
+ // A breakpoint has been added for an isolate.
+ BreakpointAdded
+
+ // An unresolved breakpoint has been resolved for an isolate.
+ BreakpointResolved
+
+ // A breakpoint has been removed.
+ BreakpointRemoved
+
+ // A garbage collection event.
+ GC
+
+ // The object graph is being delivered. This is triggered via
+ // <code>requestHeapSnapshot</code>.
+ _Graph
+}
+
+
struct VM extends Response {
- placeholder int
+ // Word length on target architecture (e.g. 32, 64).
+ architectureBits int
+
+ // The CPU we are generating code for.
+ targetCPU string
+
+ // The CPU we are actually running on.
+ hostCPU string
+
+ // The Dart VM version string.
+ version string
+
+ // The process id for the VM.
+ pid string
+
+ // The time that the VM started in milliseconds since the epoch.
+ //
+ // Suitable to pass to DateTime.fromMillisecondsSinceEpoch.
+ startTime int
+
+ // A list of isolates running in the VM.
+ isolates []IsolateRef
+
+ // Are assertions enabled in the VM?
+ //
+ // TODO(turnidge): Move to some sort of general settings list?
+ _assertsEnabled bool
+
+ // Are type checks enabled in the VM?
+ //
+ // TODO(turnidge): Move to some sort of general settings list?
+ _typeChecksEnabled bool
}
+// A reference to an an isolate.
+struct IsolateRef extends Object {
+ // A numeric id for this isolate, represented as a string. Unique.
+ number string
+
+ // A name identifying this isolate. Not guaranteed to be unique.
+ name string
+}
+
+
+// An isolate running in the VM.
+struct Isolate {
+ // A numeric id for this isolate, represented as a string. Unique.
+ number string
+
+ // A name identifying this isolate. Not guaranteed to be unique.
+ name string
+
+ // The time that the VM started in milliseconds since the epoch.
+ //
+ // Suitable to pass to DateTime.fromMillisecondsSinceEpoch.
+ startTime int
+
+ // The entry function for this isolate.
+ entry FunctionRef [optional]
+
+ // The number of live ports for this isolate.
+ livePorts int
+
+ // Will this isolate pause when exiting?
+ pauseOnExit bool
+
+ // The last pause event delivered to the isolate. If the isolate is
+ // running, this will be a resume event.
+ pauseEvent ServiceEvent
+
+ // The error that is causing this isolate to exit, if applicable.
+ error Error [optional]
+
+ // The root library for this isolate.
+ rootLib LibraryRef
+
+ // A list of all libraries for this isolate.
+ libraries []LibraryRef
+
+ // A list of all breakpoints for this isolate.
+ breakpoints []Breakpoint
+
+ // A list of features enabled for this isolate.
+ features []string
+
+ // TODO
+ heaps int
+
+ // TODO
+ tagCounters int
+}
+
+
+// A list of flags.
struct FlagList extends Response {
- placeholder int
+ // A list of all flags which are set to default values.
+ unmodifiedFlags []Flag
+
+ // A list of all flags which have been modified by the user.
+ modifiedFlags []Flag
}
-struct _EchoResponse extends Response {
- text string
+// A single flag.
+struct Flag {
+ // The name of the flag.
+ name string
+
+ // A description of the flag.
+ comment string
+
+ // The type of the flag.
+ flagType FlagType
}
-// Persistent objects in the vm are returned as subclasses of Object.
+// The type of a flag.
+enum FlagType {
+ bool
+ int
+ uint64_t
+ string
+}
+
+
+// A reference to a persistent object that lives in some isolate.
+struct ObjectRef extends Response {
+ // A unique identifier for an object. Passed to
+ // <code>getObject</code> to load the full object.
+ id string
+}
+
+
+// A persistent object that lives in some isolate.
struct Object extends Response {
- // The object <code>id</code> can be used to refer to a persistent
- // object inside the vm or an isolate.
- id string
+ // A unique identifier for this object.
+ id string
+}
+
+
+// TODO(turnidge): null type
+// TODO(turnidge): VMObject.
+
+
+// A reference to a Dart language library.
+struct LibraryRef extends ObjectRef {
+ // The name of this library.
+ name string
+
+ // The url of this library.
+ url string
+}
+
+
+// A Dart language library.
+struct Library extends Object {
+ // The name of this library.
+ name string
+
+ // The url of this library.
+ url string
+
+ // A list of the imports for this library.
+ imports []LibraryRef
+
+ // A list of the scripts which constitute this library.
+ scripts []ScriptRef
+
+ // A list of the top-level variables in this library.
+ variables []FieldRef
+
+ // A list of the top-level functions in this library.
+ functions []FunctionRef
+
+ // A list of all classes in this library.
+ classes []ClassRef
+}
+
+
+// A reference to a Dart language script.
+struct ScriptRef extends ObjectRef {
+ // A name for this script.
+ name string
+
+ // What kind of script is this?
+ kind ScriptKind
+}
+
+
+// A Dart language script.
+struct Script extends Object {
+ // A name for this script.
+ name string
+
+ // What kind of script is this?
+ kind ScriptKind
+
+ // The library which owns this script.
+ library LibraryRef
+
+ // The source code for this script. For certain built-in scripts,
+ // this may be reconstructed without source comments.
+ source string
+
+ // A table encoding a mapping from token position to line and column.
+ //
+ // Each entry in the array consists of a line number followed by
+ // (tokenPos, columnNumber) pairs:
+ //
+ // [lineNumber, (tokenPos, columnNumber)*]
+ //
+ // For example, the following table:
+ //
+ // [[1, 100, 5, 101, 8],[2, 102, 7]]
+ //
+ // Encodes the following mapping:
+ //
+ // tokenPos line column
+ // -------- ------ ------
+ // 100 1 5
+ // 101 1 8
+ // 102 2 7
+ //
+ // TODO(turnidge): The tool I'm using does not support [][].
+ // tokenPosTable [][]int
+ tokenPosTable int
+}
+
+
+enum ScriptKind {
+ script
+ library
+ source
+ patch
+}
+
+
+// A reference to a Dart language class.
+struct ClassRef extends ObjectRef {
+ // The name of this class.
+ name string
+
+ // A vm internal name, provided only when it is different than name.
+ _vmName string [optional]
+}
+
+
+// A Dart language class.
+struct Class extends Object {
+ // The name of this class.
+ name string
+
+ // A vm internal name, provided only when it is different than name.
+ _vmName string [optional]
+
+ // The error which occurred during class finalization, if it exists.
+ error InstanceRef [optional]
+
+ // Is this an abstract class?
+ abstract bool
+
+ // Is this a const class?
+ const bool
+
+ // Has this class been finalized?
+ finalized bool
+
+ // Is this class implemented?
+ implemented bool
+
+ // Is this a vm patch class?
+ patch bool
+
+ // The library which contains this class.
+ library LibraryRef
+
+ // The script which defines this class. May be missing for some
+ // classes.
+ script ScriptRef
+
+ // The superclass of this class, if any.
+ super ClassRef [optional]
+
+ // A list of interface types for this class.
+ interfaces []TypeRef
+
+ // A list of fields in this class. Does not include fields from
+ // superclasses.
+ fields []FieldRef
+
+ // A list of functions in this class. Does not include functions
+ // from superclasses.
+ functions []FunctionRef
+
+ // A list of subclasses of this class.
+ subclasses []ClassRef
+
+ // Allocation statistics for this class, if available.
+ allocationStats ClassHeapStats [optional]
+}
+
+
+struct ClassHeapStats extends Response {
+ TODO int
+}
+
+
+// A reference to a Dart language field or variable.
+struct FieldRef extends ObjectRef {
+ // The name of this field.
+ name string
+
+ // A vm internal name, provided only when it is different than name.
+ _vmName string [optional]
+
+ // The value of this field, if the field is static.
+ value InstanceRef [optional]
+
+ // The owner of this field, which can be either a LibraryRef for a
+ // ClassRef.
+ owner ObjectRef
+
+ // The declared type of this field.
+ declaredType TypeRef
+
+ // Is this field const?
+ const bool
+
+ // Is this field final?
+ final bool
+
+ // Is this field static?
+ static bool
+}
+
+
+// A Dart language field or variable.
+struct Field extends ObjectRef {
+ // The name of this field.
+ name string
+
+ // A vm internal name, provided only when it is different than name.
+ _vmName string [optional]
+
+ // The value of this field, if the field is static.
+ value InstanceRef [optional]
+
+ // The owner of this field, which can be either a LibraryRef for a
+ // ClassRef.
+ owner ObjectRef
+
+ // The declared type of this field.
+ declaredType TypeRef
+
+ // Is this field const?
+ const bool
+
+ // Is this field final?
+ final bool
+
+ // Is this field static?
+ static bool
+
+ // The script containing this feild.
+ script ScriptRef [optional]
+
+ // The token position of this field.
+ tokenPos int [optional]
+
+ // Have we seen null assigned to this field?
+ _guardNullable bool
+
+ // Have we seen a single class assigned to this field?
+ //
+ // TODO(johnmccutchan): This can actually be a string 'unknown' or
+ // 'dynamic' or a ClassRef. Change how this is encoded.
+ _guardClass string
+
+ // Have we seen a fixed length list assigned to this field?
+ //
+ // TODO(johnmccutchan): This can actually be a string 'unknown' or
+ // 'dynamic' or a ClassRef. Change how this is encoded.
+ _guardLength string
+}
+
+
+// A reference to a Dart language function.
+struct FunctionRef extends ObjectRef {
+ // The name of this function.
+ name string
+
+ // A vm internal name, provided only when it is different than name.
+ _vmName string [optional]
+
+ // The owner of this field, which can be a LibraryRef, ClassRef, or
+ // a FunctionRef.
+ owner ObjectRef
+
+ // What kind of function is this?
+ kind FunctionKind
+}
+
+
+// A Dart language function.
+struct Function extends ObjectRef {
+ // The name of this function.
+ name string
+
+ // A vm internal name, provided only when it is different than name.
+ _vmName string [optional]
+
+ // What kind of function is this?
+ kind FunctionKind
+
+ // The owner of this field, which can be a LibraryRef, ClassRef, or
+ // a FunctionRef.
+ owner ObjectRef
+
+ // Is this function static?
+ //
+ // TODO(turnidge): This is inconsistent with FieldRef.
+ static bool
+
+ // Is this function const?
+ const bool
+
+ // The script containing this function.
+ script ScriptRef [optional]
+
+ // The first token position of this function.
+ tokenPos int [optional]
+
+ // The last token position of this function.
+ endTokenPos int [optional]
+
+ // The compiled code associated with this function.
+ code CodeRef [optional]
+
+ // Are we able to generate optimized code for this function?
+ _optimizable bool
+
+ // Are we able to inline this function?
+ _inlinable bool
+
+ // The unoptimized version of this function, if retained.
+ _unoptimizedCode CodeRef [optional]
+
+ // An indicator of how actively this function is used.
+ _usageCounter int
+
+ // TODO(johnmccutchan): Document.
+ _optimizedCallSiteCount int
+
+ // How many times has this function been deoptimized?
+ _deoptimizations int
+}
+
+
+enum FunctionKind {
+ RegularFunction
+ ClosureFunction
+ GetterFunction
+ SetterFunction
+ Constructor
+ ImplicitGetter
+ ImplicitSetter
+ ImplicitStaticFinalGetter
+ IrregexpFunction
+ StaticInitializer
+ MethodExtractor
+ NoSuchMethodDispatcher
+ InvokeFieldDispatcher
+ Collected
+ Native
+ Stub
+ Tag
+}
+
+
+// A reference to a compiled code object in the Dart VM.
+struct CodeRef extends ObjectRef {
+ // A name for this code object
+ name string
+
+ // A vm internal name, provided only when it is different than name.
+ _vmName string [optional]
+
+ // What kind of code object is this?
+ kind CodeKind
+
+ // Was this code generated using the optimizing compiler?
+ _optimized bool
+}
+
+
+// A compiled code object in the Dart VM.
+struct Code extends Object {
+ // A name for this code object
+ name string
+
+ // A vm internal name, provided only when it is different than name.
+ _vmName string [optional]
+
+ // What kind of code object is this?
+ kind CodeKind
+
+ // Was this code generated using the optimizing compiler?
+ _optimized bool
+
+ // The function which corresponds to this compiled code.
+ function FunctionRef
+
+ // The start address of the generated code as a hex string.
+ _startAddress string
+
+ // The end address of the generated code as a hex string.
+ _endAddress string
+
+ // The object pool associated with this code object.
+ _objectPool UNDOCUMENTED [optional]
+
+ // The disassembly of this code object.
+ _disassembly UNDOCUMENTED [optional]
+
+ // The pc descriptor table for this code object.
+ _descriptors UNDOCUMENTED [optional]
+
+ // The inlined function table for this code object.
+ _inlinedFunctions UNDOCUMENTED [optional]
+
+ // Inline interval information for this code object.
+ _inlinedIntervals UNDOCUMENTED [optional]
+}
+
+
+enum CodeKind {
+ Dart
+ Native
+ Stub
+ Tag
+ Collected
+}
+
+
+// A reference to a type arguments vector.
+struct TypeArgumentsRef extends ObjectRef {
+ // A name for this type argument list.
+ name string
+
+ // A vm internal name, provided only when it is different than name.
+ _vmName string
+}
+
+
+// The type argument vector for some instantiated generic type.
+struct TypeArguments extends Object {
+ // A name for this type argument list.
+ name string
+
+ // A vm internal name, provided only when it is different than name.
+ _vmName string
+
+ // A list of types.
+ types []TypeRef
+}
+
+
+// Represents an error object inside the VM.
+struct Error extends Object {
+ // An error message
+ message string
+}
+
+
+// A <code>InstanceRef</code> encodes a reference to a
+// <code>Instance</code> object.
+struct InstanceRef extends ObjectRef {
+ TODO int
+}
+
+
+struct TypeRef extends InstanceRef {
+ TODO2 int
}
// An <code>Instance</code> represents a Dart-language object.
struct Instance extends Object {
- placeholder int
+ TODO int
}
@@ -179,65 +922,6 @@
}
-// References to persistent objects in the vm are returned as
-// subclasses of ObjectRef.
-struct ObjectRef extends Response {
- // The object <code>id</code> can be used to refer to a persistent
- // object inside the vm or an isolate.
- id string
-}
-
-
-// A <code>CodeRef</code> encodes a reference to a <code>Code</code> object.
-struct CodeRef extends ObjectRef {
- placeholder int
-}
-
-
-struct ClassRef extends ObjectRef {
- placeholder int
-}
-
-
-struct TypeArgumentsRef extends ObjectRef {
- placeholder int
-}
-
-
-// A <code>FunctionRef</code> encodes a reference to a <code>Function</code> object.
-struct FunctionRef extends ObjectRef {
- placeholder int
-}
-
-
-// A <code>FieldRef</code> encodes a reference to a <code>Field</code> object.
-struct FieldRef extends ObjectRef {
- placeholder int
-}
-
-
-// A <code>InstanceRef</code> encodes a reference to a <code>Instance</code> object.
-struct InstanceRef extends ObjectRef {
- placeholder int
-}
-
-
-// A <code>ScriptRef</code> encodes a reference to a <code>Script</code> object.
-struct ScriptRef extends ObjectRef {
- placeholder int
-}
-
-
-struct Class extends Object {
- placeholder int
-}
-
-
-struct TypeArguments extends Object {
- placeholder int
-}
-
-
// A <code>Location</code> encodes a location withing a dart script.
//
// TODO(turnidge): Should this really be broken out as its own type?
@@ -273,7 +957,7 @@
struct CodeCoverage extends Response {
- placeholder int
+ TODO int
}
@@ -392,14 +1076,14 @@
struct Gauge extends Metric {
- value double
- min double
- max double
+ value float
+ min float
+ max float
}
struct Counter extends Metric {
- value double
+ value float
}
@@ -430,6 +1114,16 @@
// A <code>MetricSelector</code> is used to indicate which list of metrics
// should be retrieved from an isolate.
enum MetricSelector {
- Dart,
- Native,
+ Dart
+ Native
}
+
+
+struct _EchoResponse extends Response {
+ text string
+}
+
+
+struct UNDOCUMENTED {
+ TODO int
+}
\ No newline at end of file
diff --git a/runtime/vm/service/vmservice.dart b/runtime/vm/service/vmservice.dart
index 934bd6f..95254a3 100644
--- a/runtime/vm/service/vmservice.dart
+++ b/runtime/vm/service/vmservice.dart
@@ -7,6 +7,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:isolate';
+import 'dart:typed_data';
part 'client.dart';
part 'constants.dart';
@@ -22,12 +23,10 @@
class VMService extends MessageRouter {
static VMService _instance;
+
/// Collection of currently connected clients.
final Set<Client> clients = new Set<Client>();
- // A map encoding which clients are interested in which kinds of events.
- final Map<int, Set<Client>> eventMap = new Map<int, Set<Client>>();
-
/// Collection of currently running isolates.
RunningIsolates runningIsolates = new RunningIsolates();
@@ -44,85 +43,71 @@
clients.remove(client);
}
- int eventTypeCode(String eventType) {
- switch(eventType) {
- case 'debug':
- return Constants.EVENT_FAMILY_DEBUG;
- case 'gc':
- return Constants.EVENT_FAMILY_GC;
- default:
- return -1;
- }
- }
-
- void _updateEventMask() {
- int mask = 0;
- for (var key in eventMap.keys) {
- var subscribers = eventMap[key];
- if (subscribers.isNotEmpty) {
- mask |= (1 << key);
+ void _eventMessageHandler(dynamic eventMessage) {
+ for (var client in clients) {
+ if (client.sendEvents) {
+ client.post(null, eventMessage);
}
}
- _setEventMask(mask);
- }
-
- void subscribe(String eventType, Client client) {
- int eventCode = eventTypeCode(eventType);
- assert(eventCode >= 0);
- var subscribers = eventMap.putIfAbsent(eventCode, () => new Set<Client>());
- subscribers.add(client);
- _updateEventMask();
}
void _controlMessageHandler(int code,
- int port_id,
+ int portId,
SendPort sp,
String name) {
switch (code) {
case Constants.ISOLATE_STARTUP_MESSAGE_ID:
- runningIsolates.isolateStartup(port_id, sp, name);
+ runningIsolates.isolateStartup(portId, sp, name);
break;
case Constants.ISOLATE_SHUTDOWN_MESSAGE_ID:
- runningIsolates.isolateShutdown(port_id, sp);
+ runningIsolates.isolateShutdown(portId, sp);
break;
}
}
- void _eventMessageHandler(int eventType, dynamic eventMessage) {
- var subscribers = eventMap[eventType];
- if (subscribers == null) {
- return;
- }
- for (var subscriber in subscribers) {
- subscriber.post(null, eventMessage);
- }
- }
-
void _exit() {
if (onShutdown != null) {
onShutdown();
}
isolateLifecyclePort.close();
scriptLoadPort.close();
- var clientList = clients.toList();
- for (var client in clientList) {
+ for (var client in clients) {
client.close();
}
_onExit();
}
void messageHandler(message) {
- assert(message is List);
- if (message is List && (message.length == 4)) {
- _controlMessageHandler(message[0], message[1], message[2], message[3]);
- } else if (message is List && (message.length == 2)) {
- _eventMessageHandler(message[0], message[1]);
- } else if (message is List && (message.length == 1)) {
- assert(message[0] == Constants.SERVICE_EXIT_MESSAGE_ID);
- _exit();
- } else {
- Logger.root.severe('Unexpected message: $message');
+ if (message is String) {
+ // This is an event intended for all clients.
+ _eventMessageHandler(message);
+ return;
}
+ if (message is Uint8List) {
+ // This is "raw" data intended for a specific client.
+ //
+ // TODO(turnidge): Do not broadcast this data to all clients.
+ _eventMessageHandler(message);
+ return;
+ }
+ if (message is List) {
+ // This is an internal vm service event.
+ if (message.length == 1) {
+ // This is a control message directing the vm service to exit.
+ assert(message[0] == Constants.SERVICE_EXIT_MESSAGE_ID);
+ _exit();
+ return;
+ }
+ if (message.length == 4) {
+ // This is a message informing us of the birth or death of an
+ // isolate.
+ _controlMessageHandler(message[0], message[1], message[2], message[3]);
+ return;
+ }
+ }
+
+ Logger.root.severe(
+ 'Internal vm-service error: ignoring illegal message: $message');
}
void _notSupported(_) {
@@ -180,9 +165,6 @@
service.runningIsolates.isolateStartup(port_id, sp, name);
}
-void _setEventMask(int mask)
- native "VMService_SetEventMask";
-
void _onStart() native "VMService_OnStart";
void _onExit() native "VMService_OnExit";
diff --git a/runtime/vm/service_event.cc b/runtime/vm/service_event.cc
index 9f7c63d..3dfe66b 100644
--- a/runtime/vm/service_event.cc
+++ b/runtime/vm/service_event.cc
@@ -58,6 +58,8 @@
return "IsolateStart";
case kIsolateExit:
return "IsolateExit";
+ case kIsolateUpdate:
+ return "IsolateUpdate";
case kPauseStart:
return "PauseStart";
case kPauseExit:
diff --git a/runtime/vm/service_event.h b/runtime/vm/service_event.h
index b55d0a8..c7f41e8 100644
--- a/runtime/vm/service_event.h
+++ b/runtime/vm/service_event.h
@@ -16,6 +16,7 @@
enum EventType {
kIsolateStart, // New isolate has started
kIsolateExit, // Isolate has exited
+ kIsolateUpdate, // Isolate identity information has changed
kPauseStart, // --pause-isolates-on-start
kPauseExit, // --pause-isolates-on-exit
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index c9a47c2..3494b12 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -149,6 +149,7 @@
Isolate* ServiceIsolate::isolate_ = NULL;
Dart_Port ServiceIsolate::port_ = ILLEGAL_PORT;
Dart_Port ServiceIsolate::load_port_ = ILLEGAL_PORT;
+Dart_Port ServiceIsolate::origin_ = ILLEGAL_PORT;
Dart_IsolateCreateCallback ServiceIsolate::create_callback_ = NULL;
uint8_t* ServiceIsolate::exit_message_ = NULL;
intptr_t ServiceIsolate::exit_message_length_ = 0;
@@ -180,9 +181,9 @@
virtual void VisitIsolate(Isolate* isolate) {
ASSERT(ServiceIsolate::IsServiceIsolate(Isolate::Current()));
- if (ServiceIsolate::IsServiceIsolate(isolate) ||
+ if (ServiceIsolate::IsServiceIsolateDescendant(isolate) ||
(isolate == Dart::vm_isolate())) {
- // We do not register the service or vm isolate.
+ // We do not register the service (and descendants) or the vm-isolate.
return;
}
// Setup arguments for call.
@@ -250,16 +251,6 @@
Service::HandleRootMessage(message);
}
- static void SetEventMask(Dart_NativeArguments args) {
- NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
- Isolate* isolate = arguments->isolate();
- StackZone stack_zone(isolate);
- Zone* zone = stack_zone.GetZone(); // Used by GET_NON_NULL_NATIVE_ARGUMENT.
- HANDLESCOPE(isolate);
- GET_NON_NULL_NATIVE_ARGUMENT(Integer, mask, arguments->NativeArgAt(0));
- Service::SetEventMask(mask.AsTruncatedUint32Value());
- }
-
static void OnStart(Dart_NativeArguments args) {
NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
Isolate* isolate = arguments->isolate();
@@ -320,8 +311,6 @@
ServiceIsolateNatives::SendIsolateServiceMessage},
{"VMService_SendRootServiceMessage", 1,
ServiceIsolateNatives::SendRootServiceMessage},
- {"VMService_SetEventMask", 1,
- ServiceIsolateNatives::SetEventMask},
{"VMService_OnStart", 0,
ServiceIsolateNatives::OnStart },
{"VMService_OnExit", 0,
@@ -377,6 +366,12 @@
}
+bool ServiceIsolate::IsServiceIsolateDescendant(Isolate* isolate) {
+ MonitorLocker ml(monitor_);
+ return isolate->origin_id() == origin_;
+}
+
+
Dart_Port ServiceIsolate::Port() {
MonitorLocker ml(monitor_);
return port_;
@@ -405,7 +400,7 @@
return false;
}
Isolate* isolate = Isolate::Current();
- if (IsServiceIsolate(isolate)) {
+ if (IsServiceIsolateDescendant(isolate)) {
return false;
}
ASSERT(isolate != NULL);
@@ -436,7 +431,7 @@
return false;
}
Isolate* isolate = Isolate::Current();
- if (IsServiceIsolate(isolate)) {
+ if (IsServiceIsolateDescendant(isolate)) {
return false;
}
ASSERT(isolate != NULL);
@@ -490,6 +485,9 @@
isolate_ = isolate;
if (isolate_ != NULL) {
isolate_->is_service_isolate_ = true;
+ origin_ = isolate_->origin_id();
+ } else {
+ origin_ = ILLEGAL_PORT;
}
}
@@ -611,7 +609,7 @@
return;
}
- Isolate::SetCurrent(NULL);
+ Thread::ExitIsolate();
ServiceIsolate::ConstructExitMessageAndCache(isolate);
diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h
index e71027f..fbcd136 100644
--- a/runtime/vm/service_isolate.h
+++ b/runtime/vm/service_isolate.h
@@ -20,6 +20,7 @@
static bool Exists();
static bool IsRunning();
static bool IsServiceIsolate(Isolate* isolate);
+ static bool IsServiceIsolateDescendant(Isolate* isolate);
static Dart_Port Port();
static Dart_Port WaitForLoadPort();
@@ -56,6 +57,7 @@
static Isolate* isolate_;
static Dart_Port port_;
static Dart_Port load_port_;
+ static Dart_Port origin_;
friend class Dart;
friend class RunServiceTask;
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index eadd7fa..b3a70f4 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -290,7 +290,7 @@
handler.filterMsg("size");
EXPECT_STREQ(
"{\"type\":\"bool\","
- "\"class\":{\"type\":\"@Class\",\"id\":\"classes\\/46\","
+ "\"class\":{\"type\":\"@Class\",\"id\":\"classes\\/45\","
"\"name\":\"bool\"},"
"\"fields\":[],\"id\":\"objects\\/bool-true\","
"\"valueAsString\":\"true\"}",
@@ -304,7 +304,7 @@
handler.filterMsg("_vmName");
EXPECT_STREQ(
"{\"type\":\"int\",\"_vmType\":\"Smi\","
- "\"class\":{\"type\":\"@Class\",\"id\":\"classes\\/42\","
+ "\"class\":{\"type\":\"@Class\",\"id\":\"classes\\/41\","
"\"name\":\"_Smi\",},"
"\"fields\":[],"
"\"id\":\"objects\\/int-123\","
@@ -1079,11 +1079,11 @@
Service::HandleRootMessage(service_msg);
handler.HandleNextMessage();
- EXPECT_SUBSTRING("\"type\":\"VM\",\"id\":\"vm\"", handler.msg());
+ EXPECT_SUBSTRING("\"type\":\"VM\"", handler.msg());
EXPECT_SUBSTRING("\"targetCPU\"", handler.msg());
EXPECT_SUBSTRING("\"hostCPU\"", handler.msg());
EXPECT_SUBSTRING("\"version\"", handler.msg());
- EXPECT_SUBSTRING("\"uptime\"", handler.msg());
+ EXPECT_SUBSTRING("\"startTime\"", handler.msg());
EXPECT_SUBSTRING("\"isolates\"", handler.msg());
}
@@ -1112,7 +1112,7 @@
// Make sure we can get the FlagList.
Service::HandleRootMessage(service_msg);
handler.HandleNextMessage();
- EXPECT_SUBSTRING("\"type\":\"FlagList\",\"id\":\"flags\"", handler.msg());
+ EXPECT_SUBSTRING("\"type\":\"FlagList\"", handler.msg());
EXPECT_SUBSTRING(
"\"name\":\"service_testing_flag\",\"comment\":\"Comment\","
"\"flagType\":\"bool\",\"valueAsString\":\"false\"",
@@ -1173,7 +1173,7 @@
"\"id\":\"libraries\\/%" Pd "\\/scripts\\/test-lib\","
"\"name\":\"test-lib\","
"\"kind\":\"script\","
- "\"owningLibrary\":{\"type\":\"@Library\","
+ "\"library\":{\"type\":\"@Library\","
"\"id\":\"libraries\\/%" Pd "\",\"name\":\"\","
"\"url\":\"test-lib\"},"
"\"source\":\"var port;\\n\\nmain() {\\n}\","
diff --git a/runtime/vm/signal_handler.h b/runtime/vm/signal_handler.h
index b5329bc..b204c55 100644
--- a/runtime/vm/signal_handler.h
+++ b/runtime/vm/signal_handler.h
@@ -44,6 +44,7 @@
class SignalHandler : public AllStatic {
public:
static void Install(SignalAction action);
+ static void Remove();
static uintptr_t GetProgramCounter(const mcontext_t& mcontext);
static uintptr_t GetFramePointer(const mcontext_t& mcontext);
static uintptr_t GetCStackPointer(const mcontext_t& mcontext);
diff --git a/runtime/vm/signal_handler_android.cc b/runtime/vm/signal_handler_android.cc
index d8ea14e..1ac0b8c 100644
--- a/runtime/vm/signal_handler_android.cc
+++ b/runtime/vm/signal_handler_android.cc
@@ -84,11 +84,21 @@
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_sigaction = action;
- act.sa_flags = SA_RESTART | SA_SIGINFO;
sigemptyset(&act.sa_mask);
- // TODO(johnmccutchan): Do we care about restoring the signal handler?
- struct sigaction old_act;
- int r = sigaction(SIGPROF, &act, &old_act);
+ act.sa_flags = SA_RESTART | SA_SIGINFO;
+ int r = sigaction(SIGPROF, &act, NULL);
+ ASSERT(r == 0);
+}
+
+
+void SignalHandler::Remove() {
+ // Ignore future SIGPROF signals because by default SIGPROF will terminate
+ // the process and we may have some signals in flight.
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_IGN;
+ sigemptyset(&act.sa_mask);
+ int r = sigaction(SIGPROF, &act, NULL);
ASSERT(r == 0);
}
diff --git a/runtime/vm/signal_handler_linux.cc b/runtime/vm/signal_handler_linux.cc
index 957edda..960b417 100644
--- a/runtime/vm/signal_handler_linux.cc
+++ b/runtime/vm/signal_handler_linux.cc
@@ -129,9 +129,19 @@
act.sa_sigaction = action;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART | SA_SIGINFO;
- // TODO(johnmccutchan): Do we care about restoring the signal handler?
- struct sigaction old_act;
- int r = sigaction(SIGPROF, &act, &old_act);
+ int r = sigaction(SIGPROF, &act, NULL);
+ ASSERT(r == 0);
+}
+
+
+void SignalHandler::Remove() {
+ // Ignore future SIGPROF signals because by default SIGPROF will terminate
+ // the process and we may have some signals in flight.
+ struct sigaction act;
+ act.sa_handler = SIG_IGN;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ int r = sigaction(SIGPROF, &act, NULL);
ASSERT(r == 0);
}
diff --git a/runtime/vm/signal_handler_macos.cc b/runtime/vm/signal_handler_macos.cc
index 3bb6101..79117c2 100644
--- a/runtime/vm/signal_handler_macos.cc
+++ b/runtime/vm/signal_handler_macos.cc
@@ -110,9 +110,19 @@
act.sa_sigaction = action;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART | SA_SIGINFO;
- // TODO(johnmccutchan): Do we care about restoring the signal handler?
- struct sigaction old_act;
- int r = sigaction(SIGPROF, &act, &old_act);
+ int r = sigaction(SIGPROF, &act, NULL);
+ ASSERT(r == 0);
+}
+
+
+void SignalHandler::Remove() {
+ // Ignore future SIGPROF signals because by default SIGPROF will terminate
+ // the process and we may have some signals in flight.
+ struct sigaction act;
+ act.sa_handler = SIG_IGN;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ int r = sigaction(SIGPROF, &act, NULL);
ASSERT(r == 0);
}
diff --git a/runtime/vm/signal_handler_win.cc b/runtime/vm/signal_handler_win.cc
index a1f8fe0..e3164f4 100644
--- a/runtime/vm/signal_handler_win.cc
+++ b/runtime/vm/signal_handler_win.cc
@@ -43,6 +43,11 @@
}
+void SignalHandler::Remove() {
+ UNIMPLEMENTED();
+}
+
+
} // namespace dart
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 477ee78..30e70f8 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -1082,13 +1082,13 @@
// Synchronization primitives support.
void Simulator::SetExclusiveAccess(uword addr) {
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate != NULL);
- DEBUG_ASSERT(exclusive_access_lock_->Owner() == isolate);
+ Thread* thread = Thread::Current();
+ ASSERT(thread != NULL);
+ DEBUG_ASSERT(exclusive_access_lock_->IsOwnedByCurrentThread());
int i = 0;
- // Find an entry for this isolate in the exclusive access state.
+ // Find an entry for this thread in the exclusive access state.
while ((i < kNumAddressTags) &&
- (exclusive_access_state_[i].isolate != isolate)) {
+ (exclusive_access_state_[i].thread != thread)) {
i++;
}
// Round-robin replacement of previously used entries.
@@ -1097,7 +1097,7 @@
if (++next_address_tag_ == kNumAddressTags) {
next_address_tag_ = 0;
}
- exclusive_access_state_[i].isolate = isolate;
+ exclusive_access_state_[i].thread = thread;
}
// Remember the address being reserved.
exclusive_access_state_[i].addr = addr;
@@ -1105,20 +1105,20 @@
bool Simulator::HasExclusiveAccessAndOpen(uword addr) {
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate != NULL);
+ Thread* thread = Thread::Current();
+ ASSERT(thread != NULL);
ASSERT(addr != 0);
- DEBUG_ASSERT(exclusive_access_lock_->Owner() == isolate);
+ DEBUG_ASSERT(exclusive_access_lock_->IsOwnedByCurrentThread());
bool result = false;
for (int i = 0; i < kNumAddressTags; i++) {
- if (exclusive_access_state_[i].isolate == isolate) {
- // Check whether the current isolate's address reservation matches.
+ if (exclusive_access_state_[i].thread == thread) {
+ // Check whether the current thread's address reservation matches.
if (exclusive_access_state_[i].addr == addr) {
result = true;
}
exclusive_access_state_[i].addr = 0;
} else if (exclusive_access_state_[i].addr == addr) {
- // Other isolates with matching address lose their reservations.
+ // Other threads with matching address lose their reservations.
exclusive_access_state_[i].addr = 0;
}
}
@@ -1128,7 +1128,7 @@
void Simulator::ClearExclusive() {
MutexLocker ml(exclusive_access_lock_);
- // Remove the reservation for this isolate.
+ // Remove the reservation for this thread.
SetExclusiveAccess(NULL);
}
@@ -1156,7 +1156,7 @@
uword new_value) {
MutexLocker ml(exclusive_access_lock_);
// We do not get a reservation as it would be guaranteed to be found when
- // writing below. No other isolate is able to make a reservation while we
+ // writing below. No other thread is able to make a reservation while we
// hold the lock.
uword value = *address;
if (value == compare_value) {
@@ -1713,12 +1713,6 @@
}
} else if (instr->IsMultiplyOrSyncPrimitive()) {
if (instr->Bit(24) == 0) {
- if ((TargetCPUFeatures::arm_version() != ARMv7) &&
- (instr->Bits(21, 3) != 0)) {
- // mla ... smlal only supported on armv7.
- UnimplementedInstruction(instr);
- return;
- }
// multiply instructions.
Register rn = instr->RnField();
Register rd = instr->RdField();
@@ -1734,6 +1728,10 @@
case 3: {
// Registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
// Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
+ if (TargetCPUFeatures::arm_version() != ARMv7) {
+ UnimplementedInstruction(instr);
+ break;
+ }
rd_val = get_register(rd);
// fall through
}
@@ -1785,6 +1783,10 @@
case 2:
// Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
// Format(instr, "umaal'cond's 'rd, 'rn, 'rm, 'rs");
+ if (TargetCPUFeatures::arm_version() == ARMv5TE) {
+ // umaal is only in ARMv6 and above.
+ UnimplementedInstruction(instr);
+ }
case 5:
// Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
// Format(instr, "umlal'cond's 'rd, 'rn, 'rm, 'rs");
@@ -3584,7 +3586,7 @@
void Simulator::InstructionDecode(Instr* instr) {
pc_modified_ = false;
if (IsTracingExecution()) {
- OS::Print("%"Pu64, icount_);
+ OS::Print("%" Pu64 " ", icount_);
const uword start = reinterpret_cast<uword>(instr);
const uword end = start + Instr::kInstrSize;
Disassembler::Disassemble(start, end);
diff --git a/runtime/vm/simulator_arm.h b/runtime/vm/simulator_arm.h
index a846d60..250ac5d 100644
--- a/runtime/vm/simulator_arm.h
+++ b/runtime/vm/simulator_arm.h
@@ -24,6 +24,7 @@
class Mutex;
class RawObject;
class SimulatorSetjmpBuffer;
+class Thread;
typedef struct {
union {
@@ -216,31 +217,30 @@
intptr_t ReadExclusiveW(uword addr, Instr* instr);
intptr_t WriteExclusiveW(uword addr, intptr_t value, Instr* instr);
- // In Dart, there is at most one thread per isolate.
- // We keep track of 16 exclusive access address tags across all isolates.
+ // We keep track of 16 exclusive access address tags across all threads.
// Since we cannot simulate a native context switch, which clears
// the exclusive access state of the local monitor (using the CLREX
- // instruction), we associate the isolate requesting exclusive access to the
- // address tag. Multiple isolates requesting exclusive access (using the LDREX
+ // instruction), we associate the thread requesting exclusive access to the
+ // address tag. Multiple threads requesting exclusive access (using the LDREX
// instruction) to the same address will result in multiple address tags being
- // created for the same address, one per isolate.
- // At any given time, each isolate is associated to at most one address tag.
+ // created for the same address, one per thread.
+ // At any given time, each thread is associated to at most one address tag.
static Mutex* exclusive_access_lock_;
static const int kNumAddressTags = 16;
static struct AddressTag {
- Isolate* isolate;
+ Thread* thread;
uword addr;
} exclusive_access_state_[kNumAddressTags];
static int next_address_tag_;
- // Set access to given address to 'exclusive state' for current isolate.
+ // Set access to given address to 'exclusive state' for current thread.
static void SetExclusiveAccess(uword addr);
- // Returns true if the current isolate has exclusive access to given address,
+ // Returns true if the current thread has exclusive access to given address,
// returns false otherwise. In either case, set access to given address to
- // 'open state' for all isolates.
+ // 'open state' for all threads.
// If given addr is NULL, set access to 'open state' for current
- // isolate (CLREX).
+ // thread (CLREX).
static bool HasExclusiveAccessAndOpen(uword addr);
// Executing is handled based on the instruction type.
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index 763bc75..4acdce0 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -1164,13 +1164,13 @@
// Synchronization primitives support.
void Simulator::SetExclusiveAccess(uword addr) {
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate != NULL);
- DEBUG_ASSERT(exclusive_access_lock_->Owner() == isolate);
+ Thread* thread = Thread::Current();
+ ASSERT(thread != NULL);
+ DEBUG_ASSERT(exclusive_access_lock_->IsOwnedByCurrentThread());
int i = 0;
- // Find an entry for this isolate in the exclusive access state.
+ // Find an entry for this thread in the exclusive access state.
while ((i < kNumAddressTags) &&
- (exclusive_access_state_[i].isolate != isolate)) {
+ (exclusive_access_state_[i].thread != thread)) {
i++;
}
// Round-robin replacement of previously used entries.
@@ -1179,7 +1179,7 @@
if (++next_address_tag_ == kNumAddressTags) {
next_address_tag_ = 0;
}
- exclusive_access_state_[i].isolate = isolate;
+ exclusive_access_state_[i].thread = thread;
}
// Remember the address being reserved.
exclusive_access_state_[i].addr = addr;
@@ -1187,20 +1187,20 @@
bool Simulator::HasExclusiveAccessAndOpen(uword addr) {
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate != NULL);
+ Thread* thread = Thread::Current();
+ ASSERT(thread != NULL);
ASSERT(addr != 0);
- DEBUG_ASSERT(exclusive_access_lock_->Owner() == isolate);
+ DEBUG_ASSERT(exclusive_access_lock_->IsOwnedByCurrentThread());
bool result = false;
for (int i = 0; i < kNumAddressTags; i++) {
- if (exclusive_access_state_[i].isolate == isolate) {
- // Check whether the current isolates address reservation matches.
+ if (exclusive_access_state_[i].thread == thread) {
+ // Check whether the current threads address reservation matches.
if (exclusive_access_state_[i].addr == addr) {
result = true;
}
exclusive_access_state_[i].addr = 0;
} else if (exclusive_access_state_[i].addr == addr) {
- // Other isolates with matching address lose their reservations.
+ // Other threads with matching address lose their reservations.
exclusive_access_state_[i].addr = 0;
}
}
@@ -1210,7 +1210,7 @@
void Simulator::ClearExclusive() {
MutexLocker ml(exclusive_access_lock_);
- // Remove the reservation for this isolate.
+ // Remove the reservation for this thread.
SetExclusiveAccess(NULL);
}
@@ -1238,7 +1238,7 @@
uword new_value) {
MutexLocker ml(exclusive_access_lock_);
// We do not get a reservation as it would be guaranteed to be found when
- // writing below. No other isolate is able to make a reservation while we
+ // writing below. No other thread is able to make a reservation while we
// hold the lock.
uword value = *address;
if (value == compare_value) {
@@ -3300,7 +3300,7 @@
void Simulator::InstructionDecode(Instr* instr) {
pc_modified_ = false;
if (IsTracingExecution()) {
- OS::Print("%" Pu64, icount_);
+ OS::Print("%" Pu64 " ", icount_);
const uword start = reinterpret_cast<uword>(instr);
const uword end = start + Instr::kInstrSize;
Disassembler::Disassemble(start, end);
diff --git a/runtime/vm/simulator_arm64.h b/runtime/vm/simulator_arm64.h
index 83459bb..97e40c4 100644
--- a/runtime/vm/simulator_arm64.h
+++ b/runtime/vm/simulator_arm64.h
@@ -24,6 +24,7 @@
class Mutex;
class RawObject;
class SimulatorSetjmpBuffer;
+class Thread;
typedef struct {
union {
@@ -185,19 +186,18 @@
inline intptr_t ReadX(uword addr, Instr* instr);
inline void WriteX(uword addr, intptr_t value, Instr* instr);
- // In Dart, there is at most one thread per isolate.
- // We keep track of 16 exclusive access address tags across all isolates.
+ // We keep track of 16 exclusive access address tags across all threads.
// Since we cannot simulate a native context switch, which clears
// the exclusive access state of the local monitor (using the CLREX
- // instruction), we associate the isolate requesting exclusive access to the
- // address tag. Multiple isolates requesting exclusive access (using the LDREX
+ // instruction), we associate the thread requesting exclusive access to the
+ // address tag. Multiple threads requesting exclusive access (using the LDREX
// instruction) to the same address will result in multiple address tags being
- // created for the same address, one per isolate.
- // At any given time, each isolate is associated to at most one address tag.
+ // created for the same address, one per thread.
+ // At any given time, each thread is associated to at most one address tag.
static Mutex* exclusive_access_lock_;
static const int kNumAddressTags = 16;
static struct AddressTag {
- Isolate* isolate;
+ Thread* thread;
uword addr;
} exclusive_access_state_[kNumAddressTags];
static int next_address_tag_;
@@ -207,14 +207,14 @@
intptr_t ReadExclusiveW(uword addr, Instr* instr);
intptr_t WriteExclusiveW(uword addr, intptr_t value, Instr* instr);
- // Set access to given address to 'exclusive state' for current isolate.
+ // Set access to given address to 'exclusive state' for current thread.
static void SetExclusiveAccess(uword addr);
- // Returns true if the current isolate has exclusive access to given address,
+ // Returns true if the current thread has exclusive access to given address,
// returns false otherwise. In either case, set access to given address to
- // 'open state' for all isolates.
+ // 'open state' for all threads.
// If given addr is NULL, set access to 'open state' for current
- // isolate (CLREX).
+ // thread (CLREX).
static bool HasExclusiveAccessAndOpen(uword addr);
// Helper functions to set the conditional flags in the architecture state.
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index 634eed1..1cc6487 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -1102,13 +1102,13 @@
// Synchronization primitives support.
void Simulator::SetExclusiveAccess(uword addr) {
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate != NULL);
- DEBUG_ASSERT(exclusive_access_lock_->Owner() == isolate);
+ Thread* thread = Thread::Current();
+ ASSERT(thread != NULL);
+ DEBUG_ASSERT(exclusive_access_lock_->IsOwnedByCurrentThread());
int i = 0;
- // Find an entry for this isolate in the exclusive access state.
+ // Find an entry for this thread in the exclusive access state.
while ((i < kNumAddressTags) &&
- (exclusive_access_state_[i].isolate != isolate)) {
+ (exclusive_access_state_[i].thread != thread)) {
i++;
}
// Round-robin replacement of previously used entries.
@@ -1117,7 +1117,7 @@
if (++next_address_tag_ == kNumAddressTags) {
next_address_tag_ = 0;
}
- exclusive_access_state_[i].isolate = isolate;
+ exclusive_access_state_[i].thread = thread;
}
// Remember the address being reserved.
exclusive_access_state_[i].addr = addr;
@@ -1125,20 +1125,20 @@
bool Simulator::HasExclusiveAccessAndOpen(uword addr) {
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate != NULL);
+ Thread* thread = Thread::Current();
+ ASSERT(thread != NULL);
ASSERT(addr != 0);
- DEBUG_ASSERT(exclusive_access_lock_->Owner() == isolate);
+ DEBUG_ASSERT(exclusive_access_lock_->IsOwnedByCurrentThread());
bool result = false;
for (int i = 0; i < kNumAddressTags; i++) {
- if (exclusive_access_state_[i].isolate == isolate) {
- // Check whether the current isolate's address reservation matches.
+ if (exclusive_access_state_[i].thread == thread) {
+ // Check whether the current thread's address reservation matches.
if (exclusive_access_state_[i].addr == addr) {
result = true;
}
exclusive_access_state_[i].addr = 0;
} else if (exclusive_access_state_[i].addr == addr) {
- // Other isolates with matching address lose their reservations.
+ // Other threads with matching address lose their reservations.
exclusive_access_state_[i].addr = 0;
}
}
@@ -1148,7 +1148,7 @@
void Simulator::ClearExclusive() {
MutexLocker ml(exclusive_access_lock_);
- // Remove the reservation for this isolate.
+ // Remove the reservation for this thread.
SetExclusiveAccess(NULL);
}
@@ -1176,7 +1176,7 @@
uword new_value) {
MutexLocker ml(exclusive_access_lock_);
// We do not get a reservation as it would be guaranteed to be found when
- // writing below. No other isolate is able to make a reservation while we
+ // writing below. No other thread is able to make a reservation while we
// hold the lock.
uword value = *address;
if (value == compare_value) {
@@ -1982,7 +1982,7 @@
void Simulator::InstructionDecode(Instr* instr) {
if (IsTracingExecution()) {
- OS::Print("%" Pu64, icount_);
+ OS::Print("%" Pu64 " ", icount_);
const uword start = reinterpret_cast<uword>(instr);
const uword end = start + Instr::kInstrSize;
Disassembler::Disassemble(start, end);
diff --git a/runtime/vm/simulator_mips.h b/runtime/vm/simulator_mips.h
index 901059dc..16e4728 100644
--- a/runtime/vm/simulator_mips.h
+++ b/runtime/vm/simulator_mips.h
@@ -24,6 +24,7 @@
class Mutex;
class RawObject;
class SimulatorSetjmpBuffer;
+class Thread;
class Simulator {
public:
@@ -197,19 +198,18 @@
inline double ReadD(uword addr, Instr* instr);
inline void WriteD(uword addr, double value, Instr* instr);
- // In Dart, there is at most one thread per isolate.
- // We keep track of 16 exclusive access address tags across all isolates.
+ // We keep track of 16 exclusive access address tags across all threads.
// Since we cannot simulate a native context switch, which clears
- // the exclusive access state of the local monitor, we associate the isolate
+ // the exclusive access state of the local monitor, we associate the thread
// requesting exclusive access to the address tag.
- // Multiple isolates requesting exclusive access (using the LL instruction)
+ // Multiple threads requesting exclusive access (using the LL instruction)
// to the same address will result in multiple address tags being created for
- // the same address, one per isolate.
- // At any given time, each isolate is associated to at most one address tag.
+ // the same address, one per thread.
+ // At any given time, each thread is associated to at most one address tag.
static Mutex* exclusive_access_lock_;
static const int kNumAddressTags = 16;
static struct AddressTag {
- Isolate* isolate;
+ Thread* thread;
uword addr;
} exclusive_access_state_[kNumAddressTags];
static int next_address_tag_;
@@ -219,14 +219,14 @@
intptr_t ReadExclusiveW(uword addr, Instr* instr);
intptr_t WriteExclusiveW(uword addr, intptr_t value, Instr* instr);
- // Set access to given address to 'exclusive state' for current isolate.
+ // Set access to given address to 'exclusive state' for current thread.
static void SetExclusiveAccess(uword addr);
- // Returns true if the current isolate has exclusive access to given address,
+ // Returns true if the current thread has exclusive access to given address,
// returns false otherwise. In either case, set access to given address to
- // 'open state' for all isolates.
+ // 'open state' for all threads.
// If given addr is NULL, set access to 'open state' for current
- // isolate (CLREX).
+ // thread (CLREX).
static bool HasExclusiveAccessAndOpen(uword addr);
void DoBranch(Instr* instr, bool taken, bool likely);
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 37a6d1e..9539362 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -677,9 +677,16 @@
class FullSnapshotWriter : public SnapshotWriter {
public:
static const intptr_t kInitialSize = 64 * KB;
- FullSnapshotWriter(uint8_t** buffer, ReAlloc alloc)
- : SnapshotWriter(Snapshot::kFull, buffer, alloc, kInitialSize, true) {
- ASSERT(buffer != NULL);
+ FullSnapshotWriter(uint8_t** vm_isolate_snapshot_buffer,
+ uint8_t** isolate_snapshot_buffer,
+ ReAlloc alloc)
+ : SnapshotWriter(Snapshot::kFull,
+ isolate_snapshot_buffer,
+ alloc,
+ kInitialSize,
+ true) {
+ ASSERT(vm_isolate_snapshot_buffer != NULL);
+ ASSERT(isolate_snapshot_buffer != NULL);
ASSERT(alloc != NULL);
}
~FullSnapshotWriter() { }
@@ -687,6 +694,9 @@
// Writes a full snapshot of the Isolate.
void WriteFullSnapshot();
+ intptr_t VmIsolateSnapshotSize() const { return 0; }
+ intptr_t IsolateSnapshotSize() const { return BytesWritten(); }
+
private:
DISALLOW_COPY_AND_ASSIGN(FullSnapshotWriter);
};
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 94d6d08..965772a 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -1029,7 +1029,8 @@
"}\n";
Dart_Handle result;
- uint8_t* buffer;
+ uint8_t* vm_isolate_snapshot_buffer;
+ uint8_t* isolate_snapshot_buffer;
// Start an Isolate, load a script and create a full snapshot.
Timer timer1(true, "Snapshot_test");
@@ -1048,7 +1049,9 @@
OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
// Write snapshot with object content.
- FullSnapshotWriter writer(&buffer, &malloc_allocator);
+ FullSnapshotWriter writer(&vm_isolate_snapshot_buffer,
+ &isolate_snapshot_buffer,
+ &malloc_allocator);
writer.WriteFullSnapshot();
}
@@ -1056,7 +1059,7 @@
// from the script.
Timer timer2(true, "Snapshot_test");
timer2.Start();
- TestCase::CreateTestIsolateFromSnapshot(buffer);
+ TestCase::CreateTestIsolateFromSnapshot(isolate_snapshot_buffer);
{
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
timer2.Stop();
@@ -1070,7 +1073,7 @@
Dart_ExitScope();
}
Dart_ShutdownIsolate();
- free(buffer);
+ free(isolate_snapshot_buffer);
}
@@ -1083,7 +1086,8 @@
};
const char* kScriptChars = kFullSnapshotScriptChars;
- uint8_t* buffer;
+ uint8_t* vm_isolate_snapshot_buffer;
+ uint8_t* isolate_snapshot_buffer;
// Start an Isolate, load a script and create a full snapshot.
Timer timer1(true, "Snapshot_test");
@@ -1102,7 +1106,9 @@
OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
// Write snapshot with object content.
- FullSnapshotWriter writer(&buffer, &malloc_allocator);
+ FullSnapshotWriter writer(&vm_isolate_snapshot_buffer,
+ &isolate_snapshot_buffer,
+ &malloc_allocator);
writer.WriteFullSnapshot();
// Invoke a function which returns an object.
@@ -1115,7 +1121,7 @@
// from the script.
Timer timer2(true, "Snapshot_test");
timer2.Start();
- TestCase::CreateTestIsolateFromSnapshot(buffer);
+ TestCase::CreateTestIsolateFromSnapshot(isolate_snapshot_buffer);
{
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
timer2.Stop();
@@ -1133,7 +1139,7 @@
Dart_ExitScope();
}
Dart_ShutdownIsolate();
- free(buffer);
+ free(isolate_snapshot_buffer);
}
@@ -1183,6 +1189,10 @@
uint8_t* buffer;
intptr_t size;
+ uint8_t* vm_isolate_snapshot = NULL;
+ intptr_t vm_isolate_snapshot_size;
+ uint8_t* isolate_snapshot = NULL;
+ intptr_t isolate_snapshot_size;
uint8_t* full_snapshot = NULL;
uint8_t* script_snapshot = NULL;
intptr_t expected_num_libs;
@@ -1194,10 +1204,13 @@
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
// Write out the script snapshot.
- result = Dart_CreateSnapshot(&buffer, &size);
+ result = Dart_CreateSnapshot(&vm_isolate_snapshot,
+ &vm_isolate_snapshot_size,
+ &isolate_snapshot,
+ &isolate_snapshot_size);
EXPECT_VALID(result);
- full_snapshot = reinterpret_cast<uint8_t*>(malloc(size));
- memmove(full_snapshot, buffer, size);
+ full_snapshot = reinterpret_cast<uint8_t*>(malloc(isolate_snapshot_size));
+ memmove(full_snapshot, isolate_snapshot, isolate_snapshot_size);
Dart_ExitScope();
}
@@ -1275,6 +1288,10 @@
Dart_Handle result;
uint8_t* buffer;
intptr_t size;
+ uint8_t* vm_isolate_snapshot = NULL;
+ intptr_t vm_isolate_snapshot_size;
+ uint8_t* isolate_snapshot = NULL;
+ intptr_t isolate_snapshot_size;
uint8_t* full_snapshot = NULL;
uint8_t* script_snapshot = NULL;
@@ -1284,10 +1301,13 @@
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
// Write out the script snapshot.
- result = Dart_CreateSnapshot(&buffer, &size);
+ result = Dart_CreateSnapshot(&vm_isolate_snapshot,
+ &vm_isolate_snapshot_size,
+ &isolate_snapshot,
+ &isolate_snapshot_size);
EXPECT_VALID(result);
- full_snapshot = reinterpret_cast<uint8_t*>(malloc(size));
- memmove(full_snapshot, buffer, size);
+ full_snapshot = reinterpret_cast<uint8_t*>(malloc(isolate_snapshot_size));
+ memmove(full_snapshot, isolate_snapshot, isolate_snapshot_size);
Dart_ExitScope();
}
@@ -1352,6 +1372,10 @@
uint8_t* buffer;
intptr_t size;
+ uint8_t* vm_isolate_snapshot = NULL;
+ intptr_t vm_isolate_snapshot_size;
+ uint8_t* isolate_snapshot = NULL;
+ intptr_t isolate_snapshot_size;
uint8_t* full_snapshot = NULL;
uint8_t* script_snapshot = NULL;
@@ -1365,10 +1389,13 @@
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
// Write out the script snapshot.
- result = Dart_CreateSnapshot(&buffer, &size);
+ result = Dart_CreateSnapshot(&vm_isolate_snapshot,
+ &vm_isolate_snapshot_size,
+ &isolate_snapshot,
+ &isolate_snapshot_size);
EXPECT_VALID(result);
- full_snapshot = reinterpret_cast<uint8_t*>(malloc(size));
- memmove(full_snapshot, buffer, size);
+ full_snapshot = reinterpret_cast<uint8_t*>(malloc(isolate_snapshot_size));
+ memmove(full_snapshot, isolate_snapshot, isolate_snapshot_size);
Dart_ExitScope();
}
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index f8537c3..8e3806c 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -430,7 +430,7 @@
: index_(0),
num_materializations_(0),
code_(Code::Handle(code.raw())),
- deopt_info_(DeoptInfo::Handle()),
+ deopt_info_(TypedData::Handle()),
function_(Function::Handle()),
pc_(pc),
deopt_instructions_(),
@@ -450,8 +450,8 @@
// Unpack deopt info into instructions (translate away suffixes).
const Array& deopt_table = Array::Handle(code_.deopt_info_array());
ASSERT(!deopt_table.IsNull());
- deopt_info_.ToInstructions(deopt_table, &deopt_instructions_);
- num_materializations_ = deopt_info_.NumMaterializations();
+ DeoptInfo::Unpack(deopt_table, deopt_info_, &deopt_instructions_);
+ num_materializations_ = DeoptInfo::NumMaterializations(deopt_instructions_);
object_table_ = code_.object_table();
Advance();
}
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index 2195d81..a3cc4a0 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -319,7 +319,7 @@
intptr_t index_;
intptr_t num_materializations_;
Code& code_;
- DeoptInfo& deopt_info_;
+ TypedData& deopt_info_;
Function& function_;
uword pc_;
GrowableArray<DeoptInstr*> deopt_instructions_;
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index d8d9371..01a07c7 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -531,7 +531,8 @@
// Frame is fully rewritten at this point and it is safe to perform a GC.
// Materialize any objects that were deferred by FillFrame because they
// require allocation.
- __ EnterStubFrame();
+ // Enter stub frame with loading PP. The caller's PP is not materialized yet.
+ __ EnterStubFrame(true);
if (preserve_result) {
__ Push(R1); // Preserve result, it will be GC-d here.
}
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 6621689..033ef48 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -539,7 +539,8 @@
// Frame is fully rewritten at this point and it is safe to perform a GC.
// Materialize any objects that were deferred by FillFrame because they
// require allocation.
- __ EnterStubFrame();
+ // Enter stub frame with loading PP. The caller's PP is not materialized yet.
+ __ EnterStubFrame(true);
if (preserve_result) {
__ Push(ZR); // Workaround for dropped stack slot during GC.
__ Push(R1); // Preserve result, it will be GC-d here.
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index a00fd1f..bab5cdf 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -41,7 +41,7 @@
const intptr_t exitframe_last_param_slot_from_fp = 2;
__ SetPrologueOffset();
- __ TraceSimMsg("CallToRuntimeStub");
+ __ Comment("CallToRuntimeStub");
__ addiu(SP, SP, Immediate(-3 * kWordSize));
__ sw(ZR, Address(SP, 2 * kWordSize)); // Push 0 for the PC marker
__ sw(RA, Address(SP, 1 * kWordSize));
@@ -101,7 +101,7 @@
ASSERT(retval_offset == 3 * kWordSize);
// Retval is next to 1st argument.
__ delay_slot()->addiu(A3, A2, Immediate(kWordSize));
- __ TraceSimMsg("CallToRuntimeStub return");
+ __ Comment("CallToRuntimeStub return");
// Mark that the isolate is executing Dart code.
__ LoadImmediate(A2, VMTag::kDartTagId);
@@ -150,7 +150,7 @@
const intptr_t retval_offset = NativeArguments::retval_offset();
__ SetPrologueOffset();
- __ TraceSimMsg("CallNativeCFunctionStub");
+ __ Comment("CallNativeCFunctionStub");
__ addiu(SP, SP, Immediate(-3 * kWordSize));
__ sw(ZR, Address(SP, 2 * kWordSize)); // Push 0 for the PC marker
__ sw(RA, Address(SP, 1 * kWordSize));
@@ -218,7 +218,7 @@
#else
__ BranchLink(&NativeEntry::NativeCallWrapperLabel());
#endif
- __ TraceSimMsg("CallNativeCFunctionStub return");
+ __ Comment("CallNativeCFunctionStub return");
// Mark that the isolate is executing Dart code.
__ LoadImmediate(A2, VMTag::kDartTagId);
@@ -248,7 +248,7 @@
const intptr_t retval_offset = NativeArguments::retval_offset();
__ SetPrologueOffset();
- __ TraceSimMsg("CallNativeCFunctionStub");
+ __ Comment("CallNativeCFunctionStub");
__ addiu(SP, SP, Immediate(-3 * kWordSize));
__ sw(ZR, Address(SP, 2 * kWordSize)); // Push 0 for the PC marker
__ sw(RA, Address(SP, 1 * kWordSize));
@@ -311,7 +311,7 @@
// the MIPS ABI.
__ mov(T9, T5);
__ jalr(T9);
- __ TraceSimMsg("CallNativeCFunctionStub return");
+ __ Comment("CallNativeCFunctionStub return");
// Mark that the isolate is executing Dart code.
__ LoadImmediate(A2, VMTag::kDartTagId);
@@ -331,7 +331,7 @@
// Input parameters:
// S4: arguments descriptor array.
void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
- __ TraceSimMsg("CallStaticFunctionStub");
+ __ Comment("CallStaticFunctionStub");
__ EnterStubFrame();
// Setup space on stack for return value and preserve arguments descriptor.
@@ -341,7 +341,7 @@
__ sw(TMP, Address(SP, 0 * kWordSize));
__ CallRuntime(kPatchStaticCallRuntimeEntry, 0);
- __ TraceSimMsg("CallStaticFunctionStub return");
+ __ Comment("CallStaticFunctionStub return");
// Get Code object result and restore arguments descriptor array.
__ lw(T0, Address(SP, 0 * kWordSize));
@@ -362,7 +362,7 @@
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
- __ TraceSimMsg("FixCallersTarget");
+ __ Comment("FixCallersTarget");
__ EnterStubFrame();
// Setup space on stack for return value and preserve arguments descriptor.
__ addiu(SP, SP, Immediate(-2 * kWordSize));
@@ -387,7 +387,7 @@
// Called from object allocate instruction when the allocation stub has been
// disabled.
void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) {
- __ TraceSimMsg("FixAllocationStubTarget");
+ __ Comment("FixAllocationStubTarget");
__ EnterStubFrame();
// Setup space on stack for return value.
__ addiu(SP, SP, Immediate(-1 * kWordSize));
@@ -412,7 +412,7 @@
// A0: element type (preserved).
// A1: length (preserved).
void StubCode::GenerateFixAllocateArrayStubTargetStub(Assembler* assembler) {
- __ TraceSimMsg("FixAllocationStubTarget");
+ __ Comment("FixAllocationStubTarget");
__ EnterStubFrame();
// Setup space on stack for return value.
__ addiu(SP, SP, Immediate(-3 * kWordSize));
@@ -441,7 +441,7 @@
// FP[kParamEndSlotFromFp + 1]: Last argument.
static void PushArgumentsArray(Assembler* assembler) {
StubCode* stub_code = Isolate::Current()->stub_code();
- __ TraceSimMsg("PushArgumentsArray");
+ __ Comment("PushArgumentsArray");
// Allocate array to store arguments of caller.
__ LoadImmediate(A0, reinterpret_cast<intptr_t>(Object::null()));
// A0: Null element type for raw Array.
@@ -449,7 +449,7 @@
const Code& array_stub = Code::Handle(stub_code->GetAllocateArrayStub());
const ExternalLabel array_label(array_stub.EntryPoint());
__ BranchLink(&array_label);
- __ TraceSimMsg("PushArgumentsArray return");
+ __ Comment("PushArgumentsArray return");
// V0: newly allocated array.
// A1: Smi-tagged argument count, may be zero (was preserved by the stub).
__ Push(V0); // Array is in V0 and on top of stack.
@@ -513,7 +513,7 @@
kNumberOfFRegisters * kWordSize;
__ SetPrologueOffset();
- __ TraceSimMsg("GenerateDeoptimizationSequence");
+ __ Comment("GenerateDeoptimizationSequence");
// DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there
// is no need to set the correct PC marker or load PP, since they get patched.
__ addiu(SP, SP, Immediate(-kPushedRegistersSize * kWordSize));
@@ -588,7 +588,8 @@
// Frame is fully rewritten at this point and it is safe to perform a GC.
// Materialize any objects that were deferred by FillFrame because they
// require allocation.
- __ EnterStubFrame();
+ // Enter stub frame with loading PP. The caller's PP is not materialized yet.
+ __ EnterStubFrame(true);
if (preserve_result) {
__ Push(T1); // Preserve result, it will be GC-d here.
}
@@ -669,7 +670,7 @@
// The newly allocated object is returned in V0.
void StubCode::GeneratePatchableAllocateArrayStub(Assembler* assembler,
uword* entry_patch_offset, uword* patch_code_pc_offset) {
- __ TraceSimMsg("AllocateArrayStub");
+ __ Comment("AllocateArrayStub");
*entry_patch_offset = assembler->CodeSize();
Label slow_case;
@@ -792,7 +793,7 @@
__ sw(A1, Address(SP, 1 * kWordSize));
__ sw(A0, Address(SP, 0 * kWordSize));
__ CallRuntime(kAllocateArrayRuntimeEntry, 2);
- __ TraceSimMsg("AllocateArrayStub return");
+ __ Comment("AllocateArrayStub return");
// Pop arguments; result is popped in IP.
__ lw(V0, Address(SP, 2 * kWordSize));
__ lw(A1, Address(SP, 1 * kWordSize));
@@ -814,7 +815,7 @@
// A2 : arguments array.
void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
// Save frame pointer coming in.
- __ TraceSimMsg("InvokeDartCodeStub");
+ __ Comment("InvokeDartCodeStub");
__ EnterFrame();
// Save new context and C++ ABI callee-saved registers.
@@ -900,7 +901,7 @@
// We are calling into Dart code, here, so there is no need to call through
// T9 to match the ABI.
__ jalr(A0); // S4 is the arguments descriptor array.
- __ TraceSimMsg("InvokeDartCodeStub return");
+ __ Comment("InvokeDartCodeStub return");
// Get rid of arguments pushed on the stack.
__ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize);
@@ -947,7 +948,7 @@
// Output:
// V0: new allocated RawContext object.
void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
- __ TraceSimMsg("AllocateContext");
+ __ Comment("AllocateContext");
if (FLAG_inline_alloc) {
Label slow_case;
Heap* heap = Isolate::Current()->heap();
@@ -1066,7 +1067,7 @@
// T0: Address (i.e. object) being stored into.
void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) {
// Save values being destroyed.
- __ TraceSimMsg("UpdateStoreBufferStub");
+ __ Comment("UpdateStoreBufferStub");
__ addiu(SP, SP, Immediate(-3 * kWordSize));
__ sw(T3, Address(SP, 2 * kWordSize));
__ sw(T2, Address(SP, 1 * kWordSize));
@@ -1126,7 +1127,7 @@
__ EnterCallRuntimeFrame(1 * kWordSize);
__ LoadIsolate(A0);
__ CallRuntime(kStoreBufferBlockProcessRuntimeEntry, 1);
- __ TraceSimMsg("UpdateStoreBufferStub return");
+ __ Comment("UpdateStoreBufferStub return");
// Restore callee-saved registers, tear down frame.
__ LeaveCallRuntimeFrame();
__ Ret();
@@ -1142,7 +1143,7 @@
void StubCode::GenerateAllocationStubForClass(
Assembler* assembler, const Class& cls,
uword* entry_patch_offset, uword* patch_code_pc_offset) {
- __ TraceSimMsg("AllocationStubForClass");
+ __ Comment("AllocationStubForClass");
*entry_patch_offset = assembler->CodeSize();
// The generated code is different if the class is parameterized.
const bool is_cls_parameterized = cls.NumTypeArguments() > 0;
@@ -1258,7 +1259,7 @@
__ sw(T7, Address(SP, 0 * kWordSize));
}
__ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object.
- __ TraceSimMsg("AllocationStubForClass return");
+ __ Comment("AllocationStubForClass return");
// Pop result (newly allocated object).
__ lw(V0, Address(SP, 2 * kWordSize));
__ addiu(SP, SP, Immediate(3 * kWordSize)); // Pop arguments.
@@ -1311,7 +1312,7 @@
// Cannot use function object from ICData as it may be the inlined
// function and not the top-scope function.
void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) {
- __ TraceSimMsg("OptimizedUsageCounterIncrement");
+ __ Comment("OptimizedUsageCounterIncrement");
Register ic_reg = S5;
Register func_reg = T0;
if (FLAG_trace_optimized_ic_calls) {
@@ -1336,7 +1337,7 @@
// Loads function into 'temp_reg'.
void StubCode::GenerateUsageCounterIncrement(Assembler* assembler,
Register temp_reg) {
- __ TraceSimMsg("UsageCounterIncrement");
+ __ Comment("UsageCounterIncrement");
Register ic_reg = S5;
Register func_reg = temp_reg;
ASSERT(temp_reg == T0);
@@ -1432,7 +1433,7 @@
const RuntimeEntry& handle_ic_miss,
Token::Kind kind,
RangeCollectionMode range_collection_mode) {
- __ TraceSimMsg("NArgsCheckInlineCacheStub");
+ __ Comment("NArgsCheckInlineCacheStub");
ASSERT(num_args > 0);
#if defined(DEBUG)
{ Label ok;
@@ -1571,7 +1572,7 @@
// Pass IC data object.
__ sw(S5, Address(SP, (num_slots - num_args - 4) * kWordSize));
__ CallRuntime(handle_ic_miss, num_args + 1);
- __ TraceSimMsg("NArgsCheckInlineCacheStub return");
+ __ Comment("NArgsCheckInlineCacheStub return");
// Pop returned function object into T3.
// Restore arguments descriptor array and IC data array.
__ lw(T3, Address(SP, (num_slots - 3) * kWordSize));
@@ -1759,7 +1760,7 @@
// S5: ICData
void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, T0);
- __ TraceSimMsg("UnoptimizedStaticCallStub");
+ __ Comment("UnoptimizedStaticCallStub");
#if defined(DEBUG)
{ Label ok;
// Check that the IC data array has NumArgsTested() == 0.
@@ -1951,7 +1952,7 @@
// A2: cache array.
// Result in V0: null -> not found, otherwise result (true or false).
static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
- __ TraceSimMsg("SubtypeNTestCacheStub");
+ __ Comment("SubtypeNTestCacheStub");
ASSERT((1 <= n) && (n <= 3));
if (n > 1) {
// Get instance type arguments.
@@ -2094,7 +2095,7 @@
// T0: function to be reoptimized.
// S4: argument descriptor (preserved).
void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
- __ TraceSimMsg("OptimizeFunctionStub");
+ __ Comment("OptimizeFunctionStub");
__ EnterStubFrame();
__ addiu(SP, SP, Immediate(-3 * kWordSize));
__ sw(S4, Address(SP, 2 * kWordSize));
@@ -2103,7 +2104,7 @@
__ sw(TMP, Address(SP, 1 * kWordSize));
__ sw(T0, Address(SP, 0 * kWordSize));
__ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1);
- __ TraceSimMsg("OptimizeFunctionStub return");
+ __ Comment("OptimizeFunctionStub return");
__ lw(T0, Address(SP, 1 * kWordSize)); // Get Code object
__ lw(S4, Address(SP, 2 * kWordSize)); // Restore argument descriptor.
__ addiu(SP, SP, Immediate(3 * kWordSize)); // Discard argument.
@@ -2131,7 +2132,6 @@
const Register right,
const Register temp1,
const Register temp2) {
- __ TraceSimMsg("IdenticalWithNumberCheckStub");
__ Comment("IdenticalWithNumberCheckStub");
Label reference_compare, done, check_mint, check_bigint;
// If any of the arguments is Smi do reference compare.
@@ -2190,7 +2190,7 @@
__ mov(A0, left);
__ mov(A1, right);
__ CallRuntime(kBigintCompareRuntimeEntry, 2);
- __ TraceSimMsg("IdenticalWithNumberCheckStub return");
+ __ Comment("IdenticalWithNumberCheckStub return");
// Result in V0, 0 means equal.
__ LeaveStubFrame();
__ b(&done);
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 8132e99..4be0ca2 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -483,7 +483,8 @@
// Frame is fully rewritten at this point and it is safe to perform a GC.
// Materialize any objects that were deferred by FillFrame because they
// require allocation.
- __ EnterStubFrame();
+ // Enter stub frame with loading PP. The caller's PP is not materialized yet.
+ __ EnterStubFrame(true);
if (preserve_result) {
__ pushq(Immediate(0)); // Workaround for dropped stack slot during GC.
__ pushq(RBX); // Preserve result, it will be GC-d here.
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index a55bcfb..f52e20a 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -16,7 +16,6 @@
// One-character symbols are added implicitly.
#define PREDEFINED_SYMBOLS_LIST(V) \
- V(Empty, "") \
V(EqualOperator, "==") \
V(GreaterEqualOperator, ">=") \
V(LessEqualOperator, "<=") \
@@ -31,9 +30,7 @@
V(AssignIndexToken, "[]=") \
V(TopLevel, "::") \
V(DefaultLabel, ":L") \
- V(This, "this") \
V(Other, "other") \
- V(Super, "super") \
V(Call, "call") \
V(Current, "current") \
V(MoveNext, "moveNext") \
@@ -57,6 +54,7 @@
V(_EnumNames, "_enum_names") \
V(ExprTemp, ":expr_temp") \
V(AnonymousClosure, "<anonymous closure>") \
+ V(ImplicitClosure, "<implicit closure>") \
V(ClosureParameter, ":closure") \
V(PhaseParameter, ":phase") \
V(TypeArgumentsParameter, ":type_arguments") \
@@ -92,7 +90,6 @@
V(SavedStackTraceVar, ":saved_stack_trace_var") \
V(ListLiteralElement, "list literal element") \
V(ForInIter, ":for-in-iter") \
- V(Library, "library") \
V(LoadLibrary, "loadLibrary") \
V(_LibraryPrefix, "_LibraryPrefix") \
V(On, "on") \
@@ -129,7 +126,6 @@
V(Class, "Class") \
V(Null, "Null") \
V(Dynamic, "dynamic") \
- V(Void, "void") \
V(UnresolvedClass, "UnresolvedClass") \
V(Type, "_Type") \
V(TypeRef, "_TypeRef") \
@@ -176,8 +172,6 @@
V(_Bigint, "_Bigint") \
V(_Double, "_Double") \
V(Bool, "bool") \
- V(True, "true") \
- V(False, "false") \
V(_List, "_List") \
V(_ListFactory, "_List.") \
V(_GrowableList, "_GrowableList") \
@@ -334,6 +328,7 @@
V(DartVMService, "dart:vmservice") \
V(DartProfiler, "dart:profiler") \
V(DartIOLibName, "dart.io") \
+ V(EvalSourceUri, "evaluate:source") \
V(_Random, "_Random") \
V(_state, "_state") \
V(_A, "_A") \
@@ -511,6 +506,14 @@
return *(symbol_handles_[kNullCharId + '~']);
}
+ static const String& Empty() { return *(symbol_handles_[kKwTableStart]); }
+ static const String& False() { return *(symbol_handles_[kFALSEId]); }
+ static const String& Library() { return *(symbol_handles_[kLIBRARYId]); }
+ static const String& Super() { return *(symbol_handles_[kSUPERId]); }
+ static const String& This() { return *(symbol_handles_[kTHISId]); }
+ static const String& True() { return *(symbol_handles_[kTRUEId]); }
+ static const String& Void() { return *(symbol_handles_[kVOIDId]); }
+
// Access methods for symbol handles stored in the vm isolate.
#define DEFINE_SYMBOL_HANDLE_ACCESSOR(symbol, literal) \
static const String& symbol() { return *(symbol_handles_[k##symbol##Id]); }
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 199fd78..c319b51 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -6,6 +6,8 @@
#include "vm/isolate.h"
#include "vm/os_thread.h"
+#include "vm/profiler.h"
+#include "vm/thread_interrupter.h"
namespace dart {
@@ -13,18 +15,76 @@
// The single thread local key which stores all the thread local data
// for a thread.
// TODO(koda): Can we merge this with ThreadInterrupter::thread_state_key_?
-ThreadLocalKey Thread::thread_key = OSThread::kUnsetThreadLocalKey;
+ThreadLocalKey Thread::thread_key_ = OSThread::kUnsetThreadLocalKey;
void Thread::InitOnce() {
- ASSERT(thread_key == OSThread::kUnsetThreadLocalKey);
- thread_key = OSThread::CreateThreadLocal();
- ASSERT(thread_key != OSThread::kUnsetThreadLocalKey);
+ ASSERT(thread_key_ == OSThread::kUnsetThreadLocalKey);
+ thread_key_ = OSThread::CreateThreadLocal();
+ ASSERT(thread_key_ != OSThread::kUnsetThreadLocalKey);
}
void Thread::SetCurrent(Thread* current) {
- OSThread::SetThreadLocal(thread_key, reinterpret_cast<uword>(current));
+ OSThread::SetThreadLocal(thread_key_, reinterpret_cast<uword>(current));
}
+
+void Thread::EnsureInit() {
+ if (Thread::Current() == NULL) {
+ SetCurrent(new Thread());
+ }
+}
+
+
+void Thread::CleanUp() {
+ // We currently deallocate the Thread, to ensure that embedder threads don't
+ // leak the Thread structure. An alternative approach would be to clear and
+ // reuse it, but register a destructor at the OS level.
+ Thread* current = Current();
+ if (current != NULL) {
+ delete current;
+ }
+ SetCurrent(NULL);
+}
+
+
+void Thread::EnterIsolate(Isolate* isolate) {
+ EnsureInit();
+ Thread* thread = Thread::Current();
+ ASSERT(thread->isolate() == NULL);
+ ASSERT(isolate->mutator_thread() == NULL);
+ isolate->set_mutator_thread(thread);
+ // TODO(koda): Migrate thread_state_ and profile_data_ to Thread, to allow
+ // helper threads concurrent with mutator.
+ ASSERT(isolate->thread_state() == NULL);
+ InterruptableThreadState* thread_state =
+ ThreadInterrupter::GetCurrentThreadState();
+#if defined(DEBUG)
+ Isolate::CheckForDuplicateThreadState(thread_state);
+#endif
+ ASSERT(thread_state != NULL);
+ Profiler::BeginExecution(isolate);
+ isolate->set_thread_state(thread_state);
+ isolate->set_vm_tag(VMTag::kVMTagId);
+ thread->isolate_ = isolate;
+}
+
+
+void Thread::ExitIsolate() {
+ Thread* thread = Thread::Current();
+ // TODO(koda): Audit callers; they should know whether they're in an isolate.
+ if (thread == NULL) return;
+ Isolate* isolate = thread->isolate();
+ ASSERT(isolate != NULL);
+ isolate->set_vm_tag(VMTag::kIdleTagId);
+ isolate->set_thread_state(NULL);
+ Profiler::EndExecution(isolate);
+ isolate->set_mutator_thread(NULL);
+ thread->isolate_ = NULL;
+ ASSERT(Isolate::Current() == NULL);
+ CleanUp();
+}
+
+
} // namespace dart
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index bc5c998..8218fba 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -15,19 +15,28 @@
class Isolate;
// A VM thread; may be executing Dart code or performing helper tasks like
-// garbage collection or compilation.
+// garbage collection or compilation. The Thread structure associated with
+// a thread is allocated when the thread enters an isolate, and destroyed
+// upon exiting an isolate or an explicit call to CleanUp.
class Thread {
public:
- explicit Thread(Isolate* isolate)
- : isolate_(isolate),
- cha_(NULL) {}
-
- static void InitOnce();
-
+ // The currently executing thread, or NULL if not yet initialized.
static Thread* Current() {
- return reinterpret_cast<Thread*>(OSThread::GetThreadLocal(thread_key));
+ return reinterpret_cast<Thread*>(OSThread::GetThreadLocal(thread_key_));
}
- static void SetCurrent(Thread* current);
+
+ // Makes the current thread enter 'isolate'. Also calls EnsureInit.
+ static void EnterIsolate(Isolate* isolate);
+ // Makes the current thread exit its isolate. Also calls CleanUp.
+ static void ExitIsolate();
+
+ // Initializes the current thread as a VM thread, if not already done.
+ static void EnsureInit();
+ // Clears the state of the current thread.
+ static void CleanUp();
+
+ // Called at VM startup.
+ static void InitOnce();
// The topmost zone used for allocation in this thread.
Zone* zone() {
@@ -42,11 +51,17 @@
void set_cha(CHA* value) { cha_ = value; }
private:
- static ThreadLocalKey thread_key;
+ static ThreadLocalKey thread_key_;
Isolate* isolate_;
CHA* cha_;
+ Thread()
+ : isolate_(NULL),
+ cha_(NULL) {}
+
+ static void SetCurrent(Thread* current);
+
DISALLOW_COPY_AND_ASSIGN(Thread);
};
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
index b2f5f1c..10cff89 100644
--- a/runtime/vm/thread_interrupter.cc
+++ b/runtime/vm/thread_interrupter.cc
@@ -314,6 +314,7 @@
ASSERT(current_wait_time_ != Monitor::kNoTimeout);
}
}
+ RemoveSignalHandler();
if (FLAG_trace_thread_interrupter) {
OS::Print("ThreadInterrupter thread exiting.\n");
}
diff --git a/runtime/vm/thread_interrupter.h b/runtime/vm/thread_interrupter.h
index 2d9e336..2d3d1b3 100644
--- a/runtime/vm/thread_interrupter.h
+++ b/runtime/vm/thread_interrupter.h
@@ -92,6 +92,8 @@
static void InstallSignalHandler();
+ static void RemoveSignalHandler();
+
friend class ThreadInterrupterVisitIsolates;
};
diff --git a/runtime/vm/thread_interrupter_android.cc b/runtime/vm/thread_interrupter_android.cc
index 237d783..fd27d53 100644
--- a/runtime/vm/thread_interrupter_android.cc
+++ b/runtime/vm/thread_interrupter_android.cc
@@ -59,6 +59,11 @@
ThreadInterrupterAndroid::ThreadInterruptSignalHandler);
}
+
+void ThreadInterrupter::RemoveSignalHandler() {
+ SignalHandler::Remove();
+}
+
} // namespace dart
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/vm/thread_interrupter_linux.cc b/runtime/vm/thread_interrupter_linux.cc
index 67eee89..5ff3c92 100644
--- a/runtime/vm/thread_interrupter_linux.cc
+++ b/runtime/vm/thread_interrupter_linux.cc
@@ -56,6 +56,12 @@
SignalHandler::Install(ThreadInterrupterLinux::ThreadInterruptSignalHandler);
}
+
+void ThreadInterrupter::RemoveSignalHandler() {
+ SignalHandler::Remove();
+}
+
+
} // namespace dart
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/vm/thread_interrupter_macos.cc b/runtime/vm/thread_interrupter_macos.cc
index 4d72afa..b5beeeb 100644
--- a/runtime/vm/thread_interrupter_macos.cc
+++ b/runtime/vm/thread_interrupter_macos.cc
@@ -55,6 +55,11 @@
SignalHandler::Install(ThreadInterrupterMacOS::ThreadInterruptSignalHandler);
}
+
+void ThreadInterrupter::RemoveSignalHandler() {
+ SignalHandler::Remove();
+}
+
} // namespace dart
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/vm/thread_interrupter_win.cc b/runtime/vm/thread_interrupter_win.cc
index 8f0ed95..07feed0 100644
--- a/runtime/vm/thread_interrupter_win.cc
+++ b/runtime/vm/thread_interrupter_win.cc
@@ -110,6 +110,12 @@
// Nothing to do on Windows.
}
+
+void ThreadInterrupter::RemoveSignalHandler() {
+ // Nothing to do on Windows.
+}
+
+
} // namespace dart
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/vm/thread_pool.cc b/runtime/vm/thread_pool.cc
index 9e819b9..f81f99a 100644
--- a/runtime/vm/thread_pool.cc
+++ b/runtime/vm/thread_pool.cc
@@ -274,7 +274,11 @@
// Release monitor while handling the task.
monitor_.Exit();
+ Thread::EnsureInit();
task->Run();
+ ASSERT(Isolate::Current() == NULL);
+ // Prevent unintended sharing of state between tasks.
+ Thread::CleanUp();
delete task;
monitor_.Enter();
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 41695ed..e554b5a 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -217,10 +217,14 @@
class VirtualMemory;
-// snapshot_buffer points to a snapshot if we link in a snapshot otherwise
-// it is initialized to NULL.
namespace bin {
-extern const uint8_t* snapshot_buffer;
+// vm_isolate_snapshot_buffer points to a snapshot for the vm isolate if we
+// link in a snapshot otherwise it is initialized to NULL.
+extern const uint8_t* vm_isolate_snapshot_buffer;
+
+// isolate_snapshot_buffer points to a snapshot for an isolate if we link in a
+// snapshot otherwise it is initialized to NULL.
+extern const uint8_t* isolate_snapshot_buffer;
}
@@ -269,7 +273,7 @@
return CreateIsolate(buffer, name);
}
static Dart_Isolate CreateTestIsolate(const char* name = NULL) {
- return CreateIsolate(bin::snapshot_buffer, name);
+ return CreateIsolate(bin::isolate_snapshot_buffer, name);
}
static Dart_Handle library_handler(Dart_LibraryTag tag,
Dart_Handle library,
diff --git a/sdk/api_readme.md b/sdk/api_readme.md
new file mode 100644
index 0000000..e11030d
--- /dev/null
+++ b/sdk/api_readme.md
@@ -0,0 +1,42 @@
+Welcome to the Dart API reference documentation,
+covering the official Dart API libraries.
+Some of the most fundamental Dart libraries include:
+
+ * [dart:core](./dart_core/index.html):
+ Core functionality such as strings, numbers, collections, errors,
+ dates, and URIs.
+ * [dart:html](./dart_html/index.html):
+ DOM manipulation for web apps.
+ * [dart:io](./dart_io/index.html):
+ I/O for command-line apps.
+
+Except for dart:core, you must import a library before you can use it.
+Here's an example of importing dart:html, dart:math, and a
+third popular library called [polymer.dart](https://www.dartlang.org/polymer-dart/):
+
+ import 'dart:html';
+ import 'dart:math';
+ import 'package:polymer/polymer.dart';
+
+Polymer.dart is an example of a library that isn't
+included in the Dart download,
+but is easy to get and update using the _pub package manager_.
+For information on finding, using, and publishing libraries (and more)
+with pub, see [pub.dartlang.org](https://pub.dartlang.org).
+
+The main site for learning and using Dart is
+[www.dartlang.org](https://www.dartlang.org).
+Check out these pages:
+
+ * [Dart homepage](https://www.dartlang.org)
+ * [Tutorials](https://www.dartlang.org/docs/tutorials/)
+ * [Programmer's Guide](https://www.dartlang.org/docs/)
+ * [Samples](https://www.dartlang.org/samples/)
+ * [A Tour of the Dart Libraries](https://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html)
+
+This API reference is automatically generated from the source code in the
+[Dart project](https://code.google.com/p/dart/).
+If you'd like to contribute to this documentation, see
+[Contributing](https://code.google.com/p/dart/wiki/Contributing)
+and
+[Writing API Documentation](https://code.google.com/p/dart/wiki/WritingApiDocumentation).
\ No newline at end of file
diff --git a/sdk/lib/_internal/compiler/js_lib/js_array.dart b/sdk/lib/_internal/compiler/js_lib/js_array.dart
index 981cbd2..5763242 100644
--- a/sdk/lib/_internal/compiler/js_lib/js_array.dart
+++ b/sdk/lib/_internal/compiler/js_lib/js_array.dart
@@ -544,13 +544,16 @@
String toString() => ListBase.listToString(this);
- List<E> toList({ bool growable: true }) {
- if (growable) {
- return new JSArray<E>.markGrowable(JS('', '#.slice()', this));
- } else {
- return new JSArray<E>.markFixed(JS('', '#.slice()', this));
- }
- }
+ List<E> toList({ bool growable: true }) =>
+ growable
+ ? _toListGrowable()
+ : _toListFixed();
+
+ List<E> _toListGrowable() =>
+ new JSArray<E>.markGrowable(JS('', '#.slice()', this));
+
+ List<E> _toListFixed() =>
+ new JSArray<E>.markFixed(JS('', '#.slice()', this));
Set<E> toSet() => new Set<E>.from(this);
diff --git a/sdk/lib/_internal/compiler/js_lib/js_helper.dart b/sdk/lib/_internal/compiler/js_lib/js_helper.dart
index 1e83b62..163833b 100644
--- a/sdk/lib/_internal/compiler/js_lib/js_helper.dart
+++ b/sdk/lib/_internal/compiler/js_lib/js_helper.dart
@@ -673,7 +673,9 @@
@NoInline()
static double _parseDoubleError(String source,
double handleError(String source)) {
- if (handleError == null) throw new FormatException(source);
+ if (handleError == null) {
+ throw new FormatException("Invalid double", source);
+ }
return handleError(source);
}
diff --git a/sdk/lib/_internal/compiler/js_lib/js_mirrors.dart b/sdk/lib/_internal/compiler/js_lib/js_mirrors.dart
index 9fc50b7..c69e159 100644
--- a/sdk/lib/_internal/compiler/js_lib/js_mirrors.dart
+++ b/sdk/lib/_internal/compiler/js_lib/js_mirrors.dart
@@ -991,7 +991,7 @@
case JSInvocationMirror.METHOD:
if (namedArguments.isNotEmpty) return '$name*';
int nbArgs = positionalArguments.length as int;
- return "$name:$nbArgs:0";
+ return "$name:$nbArgs";
}
throw new RuntimeError("Could not compute reflective name for $name");
}
@@ -1685,7 +1685,7 @@
// reflection with metadata.
if (simpleName == null) continue;
var function = JS('', '#[#]', prototype, key);
- if (isNoSuchMethodStub(function)) continue;
+ if (!isOrdinaryReflectableMethod(function)) continue;
if (isAliasedSuperMethod(function, key)) continue;
var mirror =
new JsMethodMirror.fromUnmangledName(
@@ -2331,8 +2331,11 @@
requiredParameterCount = 0;
}
} else {
- requiredParameterCount = int.parse(info[1]);
- optionalParameterCount = int.parse(info[2]);
+ ReflectionInfo reflectionInfo = new ReflectionInfo(jsFunction);
+ requiredParameterCount = reflectionInfo.requiredParameterCount;
+ optionalParameterCount = reflectionInfo.optionalParameterCount;
+ assert(int.parse(info[1]) == requiredParameterCount
+ + optionalParameterCount);
}
return new JsMethodMirror(
s(name), jsFunction, requiredParameterCount, optionalParameterCount,
@@ -2959,8 +2962,10 @@
return firstChar == '*' || firstChar == '+';
}
-bool isNoSuchMethodStub(var jsFunction) {
- return JS('bool', r'#.$reflectable == 2', jsFunction);
+/// Returns `true` if [jsFunction] is an ordinary reflectable method and
+/// not a (potentially reflectable) stub or otherwise non-reflectable method.
+bool isOrdinaryReflectableMethod(var jsFunction) {
+ return JS('bool', r'#.$reflectable === 1', jsFunction);
}
/// Returns true if [key] is only an aliased entry for [function] in the
diff --git a/sdk/lib/_internal/compiler/js_lib/js_names.dart b/sdk/lib/_internal/compiler/js_lib/js_names.dart
index 76c72be..708b873 100644
--- a/sdk/lib/_internal/compiler/js_lib/js_names.dart
+++ b/sdk/lib/_internal/compiler/js_lib/js_names.dart
@@ -130,7 +130,8 @@
return result;
}
- int get _jsMangledNamesLength => JS('int', '#.length', _jsMangledNames);
+ int get _jsMangledNamesLength => JS('int', 'Object.keys(#).length',
+ _jsMangledNames);
String operator[](String key) {
if (_cache == null || _jsMangledNamesLength != _cacheLength) {
diff --git a/sdk/lib/_internal/compiler/js_lib/regexp_helper.dart b/sdk/lib/_internal/compiler/js_lib/regexp_helper.dart
index 4bdf754..e99810a 100644
--- a/sdk/lib/_internal/compiler/js_lib/regexp_helper.dart
+++ b/sdk/lib/_internal/compiler/js_lib/regexp_helper.dart
@@ -101,7 +101,7 @@
// Dart exception.
String errorMessage = JS('String', r'String(#)', regexp);
throw new FormatException(
- "Illegal RegExp pattern: $source, $errorMessage");
+ "Illegal RegExp pattern ($errorMessage)", source);
}
Match firstMatch(String string) {
diff --git a/sdk/lib/_internal/pub/lib/src/barback/dependency_computer.dart b/sdk/lib/_internal/pub/lib/src/barback/dependency_computer.dart
index 0105cbf..dfca127 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/dependency_computer.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/dependency_computer.dart
@@ -75,7 +75,7 @@
return phase.expand((config) {
var id = config.id;
if (id.isBuiltInTransformer) return [];
- if (id.package != _graph.entrypoint.root.name &&
+ if (package.name != _graph.entrypoint.root.name &&
!config.canTransformPublicFiles) {
return [];
}
diff --git a/sdk/lib/_internal/pub/lib/src/command/run.dart b/sdk/lib/_internal/pub/lib/src/command/run.dart
index eca10b9..55cc957 100644
--- a/sdk/lib/_internal/pub/lib/src/command/run.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/run.dart
@@ -12,6 +12,7 @@
import '../command.dart';
import '../executable.dart';
import '../io.dart';
+import '../log.dart' as log;
import '../utils.dart';
/// Handles the `run` pub command.
@@ -51,6 +52,21 @@
usageException("Cannot run an executable in a subdirectory of a " +
"dependency.");
}
+ } else if (onlyIdentifierRegExp.hasMatch(executable)) {
+ // "pub run foo" means the same thing as "pub run foo:foo" as long as
+ // "foo" is a valid Dart identifier (and thus package name).
+
+ // TODO(nweiz): Remove this after Dart 1.10 ships.
+ var localPath = p.join("bin", "$executable.dart");
+ if (fileExists(localPath) && executable != entrypoint.root.name) {
+ log.warning(
+ 'In future releases, "pub run $executable" will mean the same '
+ 'thing as "pub run $executable:$executable".\n'
+ 'Run "pub run ${p.join("bin", executable)}" explicitly to run the '
+ 'local executable.');
+ } else {
+ package = executable;
+ }
}
var mode;
diff --git a/sdk/lib/_internal/pub/lib/src/executable.dart b/sdk/lib/_internal/pub/lib/src/executable.dart
index 1c22b80..1b36468 100644
--- a/sdk/lib/_internal/pub/lib/src/executable.dart
+++ b/sdk/lib/_internal/pub/lib/src/executable.dart
@@ -18,6 +18,23 @@
import 'log.dart' as log;
import 'utils.dart';
+/// All signals that can be caught by a Dart process.
+///
+/// This intentionally omits SIGINT. SIGINT usually comes from a user pressing
+/// Control+C on the terminal, and the terminal automatically passes the signal
+/// to all processes in the process tree. If we forwarded it manually, the
+/// subprocess would see two instances, which could cause problems. Instead, we
+/// just ignore it and let the terminal pass it to the subprocess.
+final _catchableSignals = Platform.isWindows
+ ? [ProcessSignal.SIGHUP]
+ : [
+ ProcessSignal.SIGHUP,
+ ProcessSignal.SIGTERM,
+ ProcessSignal.SIGUSR1,
+ ProcessSignal.SIGUSR2,
+ ProcessSignal.SIGWINCH,
+ ];
+
/// Runs [executable] from [package] reachable from [entrypoint].
///
/// The executable string is a relative Dart file path using native path
@@ -132,6 +149,9 @@
vmArgs.addAll(args);
var process = await Process.start(Platform.executable, vmArgs);
+
+ _forwardSignals(process);
+
// Note: we're not using process.std___.pipe(std___) here because
// that prevents pub from also writing to the output streams.
process.stderr.listen(stderr.add);
@@ -176,6 +196,8 @@
runProcess(input) async {
var process = await Process.start(Platform.executable, vmArgs);
+ _forwardSignals(process);
+
// Note: we're not using process.std___.pipe(std___) here because
// that prevents pub from also writing to the output streams.
process.stderr.listen(stderr.add);
@@ -194,6 +216,20 @@
return runProcess(stdin2);
}
+/// Forwards all catchable signals to [process].
+void _forwardSignals(Process process) {
+ // See [_catchableSignals].
+ ProcessSignal.SIGINT.watch().listen(
+ (_) => log.fine("Ignoring SIGINT in pub."));
+
+ for (var signal in _catchableSignals) {
+ signal.watch().listen((_) {
+ log.fine("Forwarding $signal to running process.");
+ process.kill(signal);
+ });
+ }
+}
+
/// Runs the executable snapshot at [snapshotPath].
Future<int> _runCachedExecutable(Entrypoint entrypoint, String snapshotPath,
List<String> args) {
diff --git a/sdk/lib/_internal/pub/lib/src/http.dart b/sdk/lib/_internal/pub/lib/src/http.dart
index 4fe118e..3d0453a 100644
--- a/sdk/lib/_internal/pub/lib/src/http.dart
+++ b/sdk/lib/_internal/pub/lib/src/http.dart
@@ -11,6 +11,7 @@
import 'package:http/http.dart' as http;
import 'package:http_throttle/http_throttle.dart';
+import 'package:stack_trace/stack_trace.dart';
import 'io.dart';
import 'log.dart' as log;
@@ -107,6 +108,9 @@
throw new PubHttpException(response);
});
}).catchError((error, stackTrace) {
+ // Work around issue 23008.
+ if (stackTrace == null) stackTrace = new Chain.current();
+
if (error is SocketException &&
error.osError != null) {
if (error.osError.errorCode == 8 ||
diff --git a/sdk/lib/_internal/pub/lib/src/preprocess.dart b/sdk/lib/_internal/pub/lib/src/preprocess.dart
index a77b9bd..738829f 100644
--- a/sdk/lib/_internal/pub/lib/src/preprocess.dart
+++ b/sdk/lib/_internal/pub/lib/src/preprocess.dart
@@ -7,6 +7,8 @@
import 'package:pub_semver/pub_semver.dart';
import 'package:string_scanner/string_scanner.dart';
+import 'utils.dart';
+
/// Runs a simple preprocessor over [input] to remove sections that are
/// incompatible with the available barback version.
///
@@ -102,7 +104,7 @@
/// Handle an `if` operator.
void _if() {
_scanner.expect(new RegExp(r"if[ \t]+"), name: "if statement");
- _scanner.expect(new RegExp(r"[a-zA-Z0-9_]+"), name: "package name");
+ _scanner.expect(identifierRegExp, name: "package name");
var package = _scanner.lastMatch[0];
_scanner.scan(new RegExp(r"[ \t]*"));
diff --git a/sdk/lib/_internal/pub/lib/src/utils.dart b/sdk/lib/_internal/pub/lib/src/utils.dart
index 09575d7..14d81a6 100644
--- a/sdk/lib/_internal/pub/lib/src/utils.dart
+++ b/sdk/lib/_internal/pub/lib/src/utils.dart
@@ -23,6 +23,15 @@
export '../../asset/dart/utils.dart';
+/// A regular expression matching a Dart identifier.
+///
+/// This also matches a package name, since they must be Dart identifiers.
+final identifierRegExp = new RegExp(r"[a-zA-Z_][a-zA-Z0-9_]+");
+
+/// Like [identifierRegExp], but anchored so that it only matches strings that
+/// are *just* Dart identifiers.
+final onlyIdentifierRegExp = new RegExp("^${identifierRegExp.pattern}\$");
+
/// A pair of values.
class Pair<E, F> {
E first;
diff --git a/sdk/lib/_internal/pub/lib/src/validator/size.dart b/sdk/lib/_internal/pub/lib/src/validator/size.dart
index 0b8d05f..b3da388 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/size.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/size.dart
@@ -10,8 +10,8 @@
import '../entrypoint.dart';
import '../validator.dart';
-/// The maximum size of the package to upload (10 MB).
-const _MAX_SIZE = 10 * 1024 * 1024;
+/// The maximum size of the package to upload (100 MB).
+const _MAX_SIZE = 100 * 1024 * 1024;
/// A validator that validates that a package isn't too big.
class SizeValidator extends Validator {
@@ -25,7 +25,7 @@
if (size <= _MAX_SIZE) return;
var sizeInMb = (size / math.pow(2, 20)).toStringAsPrecision(4);
errors.add("Your package is $sizeInMb MB. Hosted packages must be "
- "smaller than 10 MB.");
+ "smaller than 100 MB.");
});
}
}
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index a9f84bd..5571320 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -16,4 +16,4 @@
[ $runtime == vm && $system == windows ]
test/run/app_can_read_from_stdin_test: Fail # Issue 19448
-test/lish/many_files_test: Fail # Issue 22996
+test/run/forwards_signal_posix_test: SkipByDesign
diff --git a/sdk/lib/_internal/pub/test/dependency_computer/dev_transformers_test.dart b/sdk/lib/_internal/pub/test/dependency_computer/dev_transformers_test.dart
index db1671c..6daa90b 100644
--- a/sdk/lib/_internal/pub/test/dependency_computer/dev_transformers_test.dart
+++ b/sdk/lib/_internal/pub/test/dependency_computer/dev_transformers_test.dart
@@ -47,6 +47,28 @@
expectDependencies({"myapp": []});
});
+ integration("does return a dependency's transformer that the root package "
+ "uses", () {
+ d.dir(appPath, [
+ d.pubspec({
+ "name": "myapp",
+ "dependencies": {"foo": {"path": "../foo"}},
+ "transformers": [{"foo": {"\$include": "test/myapp_test.dart"}}]
+ }),
+ d.dir("test", [d.file("myapp_test.dart", "")])
+ ]).create();
+
+ d.dir("foo", [
+ d.pubspec({
+ "name": "foo",
+ "version": "1.0.0"
+ }),
+ d.dir("lib", [d.file("foo.dart", transformer())])
+ ]).create();
+
+ expectDependencies({"foo": []});
+ });
+
integration("doesn't return a dependency's transformer that can run on bin",
() {
d.dir(appPath, [
diff --git a/sdk/lib/_internal/pub/test/get/cache_transformed_dependency_test.dart b/sdk/lib/_internal/pub/test/get/cache_transformed_dependency_test.dart
index f197805..5d0d354 100644
--- a/sdk/lib/_internal/pub/test/get/cache_transformed_dependency_test.dart
+++ b/sdk/lib/_internal/pub/test/get/cache_transformed_dependency_test.dart
@@ -294,7 +294,7 @@
])
]).create();
- var pub = pubRun(args: ["script"]);
+ var pub = pubRun(args: ["bin/script"]);
pub.stdout.expect("Modified!");
pub.shouldExit();
});
@@ -334,7 +334,7 @@
])
]).create();
- var pub = pubRun(args: ["script"]);
+ var pub = pubRun(args: ["bin/script"]);
pub.stdout.expect("Hello!");
pub.shouldExit();
});
diff --git a/sdk/lib/_internal/pub/test/lish/many_files_test.dart b/sdk/lib/_internal/pub/test/lish/many_files_test.dart
index 1adec26..776779a 100644
--- a/sdk/lib/_internal/pub/test/lish/many_files_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/many_files_test.dart
@@ -19,10 +19,14 @@
/// The maximum number of bytes in an entire path.
///
/// This is [Windows's number][MAX_PATH], which is a much tighter constraint
-/// than OS X or Linux. We use it everywhere for consistency.
+/// than OS X or Linux. We subtract one because Windows counts it as the number
+/// of bytes in a path C string including the terminating NUL but we only count
+/// characters here.
+///
+/// We use this limit on all platforms for consistency.
///
/// [MAX_PATH]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383130(v=vs.85).aspx
-const _pathMax = 260;
+const _pathMax = 260 - 1;
main() {
initConfig();
diff --git a/sdk/lib/_internal/pub/test/run/app_can_read_from_stdin_test.dart b/sdk/lib/_internal/pub/test/run/app_can_read_from_stdin_test.dart
index 3a31604..933de2c 100644
--- a/sdk/lib/_internal/pub/test/run/app_can_read_from_stdin_test.dart
+++ b/sdk/lib/_internal/pub/test/run/app_can_read_from_stdin_test.dart
@@ -28,7 +28,7 @@
])
]).create();
- var pub = pubRun(args: ["script"]);
+ var pub = pubRun(args: ["bin/script"]);
pub.stdout.expect("started");
pub.writeLine("first");
diff --git a/sdk/lib/_internal/pub/test/run/displays_transformer_logs_test.dart b/sdk/lib/_internal/pub/test/run/displays_transformer_logs_test.dart
index 1614175..1dff2d2 100644
--- a/sdk/lib/_internal/pub/test/run/displays_transformer_logs_test.dart
+++ b/sdk/lib/_internal/pub/test/run/displays_transformer_logs_test.dart
@@ -66,7 +66,7 @@
createLockFile('myapp', pkg: ['barback']);
- var pub = pubRun(args: ["script"]);
+ var pub = pubRun(args: ["bin/script"]);
// Note that the info log is only displayed here because the test
// harness runs pub in verbose mode. By default, only the warning would
diff --git a/sdk/lib/_internal/pub/test/run/does_not_run_on_transformer_error_test.dart b/sdk/lib/_internal/pub/test/run/does_not_run_on_transformer_error_test.dart
index 3ae0a1e..51985a3 100644
--- a/sdk/lib/_internal/pub/test/run/does_not_run_on_transformer_error_test.dart
+++ b/sdk/lib/_internal/pub/test/run/does_not_run_on_transformer_error_test.dart
@@ -50,7 +50,7 @@
createLockFile('myapp', pkg: ['barback']);
- var pub = pubRun(args: ["script"]);
+ var pub = pubRun(args: ["bin/script"]);
pub.stderr.expect("[Error from Failing]:");
pub.stderr.expect("myapp|bin/script.dart.");
diff --git a/sdk/lib/_internal/pub/test/run/doesnt_load_an_unnecessary_transformer_test.dart b/sdk/lib/_internal/pub/test/run/doesnt_load_an_unnecessary_transformer_test.dart
index 098b166..1be2487 100644
--- a/sdk/lib/_internal/pub/test/run/doesnt_load_an_unnecessary_transformer_test.dart
+++ b/sdk/lib/_internal/pub/test/run/doesnt_load_an_unnecessary_transformer_test.dart
@@ -47,7 +47,7 @@
// This shouldn't load the transformer, since it doesn't transform
// anything that the entrypoint imports. If it did load the transformer,
// we'd know since it would throw an exception.
- var pub = pubRun(args: ["hi"]);
+ var pub = pubRun(args: ["bin/hi"]);
pub.stdout.expect("Hello!");
pub.shouldExit();
});
diff --git a/sdk/lib/_internal/pub/test/run/forwards_signal_posix_test.dart b/sdk/lib/_internal/pub/test/run/forwards_signal_posix_test.dart
new file mode 100644
index 0000000..6b9e222
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/run/forwards_signal_posix_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+const _catchableSignals = const [
+ ProcessSignal.SIGHUP,
+ ProcessSignal.SIGTERM,
+ ProcessSignal.SIGUSR1,
+ ProcessSignal.SIGUSR2,
+ ProcessSignal.SIGWINCH,
+];
+
+const SCRIPT = """
+import 'dart:io';
+
+main() {
+ ProcessSignal.SIGHUP.watch().first.then(print);
+ ProcessSignal.SIGTERM.watch().first.then(print);
+ ProcessSignal.SIGUSR1.watch().first.then(print);
+ ProcessSignal.SIGUSR2.watch().first.then(print);
+ ProcessSignal.SIGWINCH.watch().first.then(print);
+
+ print("ready");
+}
+""";
+
+main() {
+ initConfig();
+ integration('forwards signals to the inner script', () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir("bin", [
+ d.file("script.dart", SCRIPT)
+ ])
+ ]).create();
+
+ var pub = pubRun(args: ["bin/script"]);
+
+ pub.stdout.expect("ready");
+ for (var signal in _catchableSignals) {
+ pub.signal(signal);
+ pub.stdout.expect(signal.toString());
+ }
+
+ pub.kill();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/run/ignores_explicit_dart2js_transformer_test.dart b/sdk/lib/_internal/pub/test/run/ignores_explicit_dart2js_transformer_test.dart
index ffeb779..a5bcdb3 100644
--- a/sdk/lib/_internal/pub/test/run/ignores_explicit_dart2js_transformer_test.dart
+++ b/sdk/lib/_internal/pub/test/run/ignores_explicit_dart2js_transformer_test.dart
@@ -18,7 +18,7 @@
])
]).create();
- var pub = pubRun(args: ["script"]);
+ var pub = pubRun(args: ["bin/script"]);
pub.stdout.expect("Hello!");
pub.shouldExit(0);
});
diff --git a/sdk/lib/_internal/pub/test/run/mode_test.dart b/sdk/lib/_internal/pub/test/run/mode_test.dart
index f6c60ff..ff8fd4b 100644
--- a/sdk/lib/_internal/pub/test/run/mode_test.dart
+++ b/sdk/lib/_internal/pub/test/run/mode_test.dart
@@ -43,12 +43,12 @@
createLockFile('myapp', pkg: ['barback']);
// By default it should run in debug mode.
- var pub = pubRun(args: ["script"]);
+ var pub = pubRun(args: ["bin/script"]);
pub.stdout.expect("debug");
pub.shouldExit();
// A custom mode should be specifiable.
- pub = pubRun(args: ["--mode", "custom-mode", "script"]);
+ pub = pubRun(args: ["--mode", "custom-mode", "bin/script"]);
pub.stdout.expect("custom-mode");
pub.shouldExit();
});
diff --git a/sdk/lib/_internal/pub/test/run/nonexistent_script_test.dart b/sdk/lib/_internal/pub/test/run/nonexistent_script_test.dart
index ce385fc..7704fdf 100644
--- a/sdk/lib/_internal/pub/test/run/nonexistent_script_test.dart
+++ b/sdk/lib/_internal/pub/test/run/nonexistent_script_test.dart
@@ -15,7 +15,7 @@
d.appPubspec()
]).create();
- var pub = pubRun(args: ["script"]);
+ var pub = pubRun(args: [p.join("bin", "script")]);
pub.stderr.expect("Could not find ${p.join("bin", "script.dart")}.");
pub.shouldExit(exit_codes.NO_INPUT);
});
diff --git a/sdk/lib/_internal/pub/test/run/passes_along_arguments_test.dart b/sdk/lib/_internal/pub/test/run/passes_along_arguments_test.dart
index 711d64b..4f16a0c 100644
--- a/sdk/lib/_internal/pub/test/run/passes_along_arguments_test.dart
+++ b/sdk/lib/_internal/pub/test/run/passes_along_arguments_test.dart
@@ -23,7 +23,7 @@
// Use some args that would trip up pub's arg parser to ensure that it
// isn't trying to look at them.
- var pub = pubRun(args: ["args", "--verbose", "-m", "--", "help"]);
+ var pub = pubRun(args: ["bin/args", "--verbose", "-m", "--", "help"]);
pub.stdout.expect("--verbose -m -- help");
pub.shouldExit();
diff --git a/sdk/lib/_internal/pub/test/run/runs_a_generated_script_test.dart b/sdk/lib/_internal/pub/test/run/runs_a_generated_script_test.dart
index cd29aa7..ab136b9 100644
--- a/sdk/lib/_internal/pub/test/run/runs_a_generated_script_test.dart
+++ b/sdk/lib/_internal/pub/test/run/runs_a_generated_script_test.dart
@@ -40,7 +40,7 @@
createLockFile('myapp', pkg: ['barback']);
- var pub = pubRun(args: ["script"]);
+ var pub = pubRun(args: ["bin/script"]);
pub.stdout.expect("generated");
pub.shouldExit();
diff --git a/sdk/lib/_internal/pub/test/run/runs_app_in_entrypoint_test.dart b/sdk/lib/_internal/pub/test/run/runs_app_in_entrypoint_test.dart
index e3cb233..2aaaa29 100644
--- a/sdk/lib/_internal/pub/test/run/runs_app_in_entrypoint_test.dart
+++ b/sdk/lib/_internal/pub/test/run/runs_app_in_entrypoint_test.dart
@@ -25,7 +25,7 @@
])
]).create();
- var pub = pubRun(args: ["script"]);
+ var pub = pubRun(args: ["bin/script"]);
pub.stdout.expect("stdout output");
pub.stderr.expect("stderr output");
pub.shouldExit(123);
diff --git a/sdk/lib/_internal/pub/test/run/runs_app_in_entrypoint_with_warning_test.dart b/sdk/lib/_internal/pub/test/run/runs_app_in_entrypoint_with_warning_test.dart
new file mode 100644
index 0000000..922525b
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/run/runs_app_in_entrypoint_with_warning_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:path/path.dart' as p;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+const SCRIPT = """
+import 'dart:io';
+
+main() {
+ stdout.writeln("stdout output");
+ stderr.writeln("stderr output");
+ exitCode = 123;
+}
+""";
+
+main() {
+ initConfig();
+ integration('runs a Dart application in the entrypoint package', () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir("bin", [
+ d.file("script.dart", SCRIPT)
+ ])
+ ]).create();
+
+ var pub = pubRun(args: ["script"]);
+ pub.stdout.expect("stdout output");
+ pub.stderr.expect(
+ 'In future releases, "pub run script" will mean the same thing as "pub '
+ 'run script:script".');
+ pub.stderr.expect(
+ 'Run "pub run ${p.join('bin', 'script')}" explicitly to run the local '
+ 'executable.');
+ pub.stderr.expect("stderr output");
+ pub.shouldExit(123);
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/run/runs_shorthand_app_in_dependency_test.dart b/sdk/lib/_internal/pub/test/run/runs_shorthand_app_in_dependency_test.dart
new file mode 100644
index 0000000..6c9f64b
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/run/runs_shorthand_app_in_dependency_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+main() {
+ initConfig();
+ integration('runs a shorthand Dart application in a dependency', () {
+ d.dir("foo", [
+ d.libPubspec("foo", "1.0.0"),
+ d.dir("bin", [
+ d.file("foo.dart", "main() => print('foo');")
+ ])
+ ]).create();
+
+ d.dir(appPath, [
+ d.pubspec({
+ "name": "myapp",
+ "dependencies": {
+ "foo": {"path": "../foo"}
+ }
+ })
+ ]).create();
+
+ pubGet();
+
+ var pub = pubRun(args: ["foo"]);
+ pub.stdout.expect("foo");
+ pub.shouldExit();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/run/runs_transformer_in_entrypoint_test.dart b/sdk/lib/_internal/pub/test/run/runs_transformer_in_entrypoint_test.dart
index 07df36f..f367433 100644
--- a/sdk/lib/_internal/pub/test/run/runs_transformer_in_entrypoint_test.dart
+++ b/sdk/lib/_internal/pub/test/run/runs_transformer_in_entrypoint_test.dart
@@ -32,7 +32,7 @@
createLockFile('myapp', pkg: ['barback']);
- var pub = pubRun(args: ["hi"]);
+ var pub = pubRun(args: ["bin/hi"]);
pub.stdout.expect("(hi, transformed)");
pub.shouldExit();
diff --git a/sdk/lib/_internal/pub/test/serve/404_page_test.dart b/sdk/lib/_internal/pub/test/serve/404_page_test.dart
index d37c387..7a77c40 100644
--- a/sdk/lib/_internal/pub/test/serve/404_page_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/404_page_test.dart
@@ -39,7 +39,7 @@
expect(response.statusCode, equals(404));
// Should mention the asset that can't be found.
- expect(response.body, contains('"/packages"'));
+ expect(response.body, contains('"/packages"'));
});
endPubServe();
diff --git a/sdk/lib/_internal/pub/test/validator/size_test.dart b/sdk/lib/_internal/pub/test/validator/size_test.dart
index 9949280..37b9eab 100644
--- a/sdk/lib/_internal/pub/test/validator/size_test.dart
+++ b/sdk/lib/_internal/pub/test/validator/size_test.dart
@@ -22,12 +22,12 @@
setUp(d.validPackage.create);
- integration('should consider a package valid if it is <= 10 MB', () {
+ integration('considers a package valid if it is <= 100 MB', () {
expectNoValidationError(size(100));
- expectNoValidationError(size(10 * math.pow(2, 20)));
+ expectNoValidationError(size(100 * math.pow(2, 20)));
});
- integration('should consider a package invalid if it is more than 10 MB', () {
- expectValidationError(size(10 * math.pow(2, 20) + 1));
+ integration('considers a package invalid if it is more than 100 MB', () {
+ expectValidationError(size(100 * math.pow(2, 20) + 1));
});
}
diff --git a/sdk/lib/convert/html_escape.dart b/sdk/lib/convert/html_escape.dart
index 512d9c3..f4be4c6 100644
--- a/sdk/lib/convert/html_escape.dart
+++ b/sdk/lib/convert/html_escape.dart
@@ -7,39 +7,125 @@
// TODO(floitsch) - Document - Issue 13097
const HtmlEscape HTML_ESCAPE = const HtmlEscape();
+/**
+ * HTML escape modes.
+ *
+ * Allows specifying a mode for HTML escaping that depend on the context
+ * where the escaped result is going to be used.
+ * The relevant contexts are:
+ *
+ * * as text content of an HTML element.
+ * * as value of a (single- or double-) quoted attribute value.
+ *
+ * All modes require escaping of `&` (ampersand) characters, and may
+ * enable escaping of more characters.
+ */
class HtmlEscapeMode {
final String _name;
+ /** Whether to escape '<' and '>'. */
final bool escapeLtGt;
+ /** Whether to escape '"' (quote). */
final bool escapeQuot;
+ /** Whether to escape "'" (apostrophe). */
final bool escapeApos;
- final bool escapeSlash;
- // TODO(floitsch) - Document - Issue 13097
+ /**
+ * Default escaping mode which escape all characters.
+ *
+ * The result of such an escaping is usable both in element content and
+ * in any attribute value.
+ *
+ * The escaping only works for elements with normal HTML content,
+ * and not for, for example, script or style element content,
+ * which require escapes matching their particular content syntax.
+ */
static const HtmlEscapeMode UNKNOWN =
- const HtmlEscapeMode._('unknown', true, true, true, true);
+ const HtmlEscapeMode._('unknown', true, true, true);
- // TODO(floitsch) - Document - Issue 13097
+ /**
+ * Escaping mode for text going into double-quoted HTML attribute values.
+ *
+ * The result should not be used as the content of an unquoted
+ * or single-quoted attribute value.
+ *
+ * Escapes only double quotes (`"`) but not single quotes (`'`).
+ */
static const HtmlEscapeMode ATTRIBUTE =
- const HtmlEscapeMode._('attribute', false, true, false, false);
+ const HtmlEscapeMode._('attribute', false, true, false);
- // TODO(floitsch) - Document - Issue 13097
+ /**
+ * Escaping mode for text going into single-quoted HTML attribute values.
+ *
+ * The result should not be used as the content of an unquoted
+ * or double-quoted attribute value.
+ *
+ * Escapes only single quotes (`'`) but not double quotes (`"`).
+ */
+ static const HtmlEscapeMode SQ_ATTRIBUTE =
+ const HtmlEscapeMode._('attribute', false, false, true);
+
+ /**
+ * Escaping mode for text going into HTML element content.
+ *
+ * The escaping only works for elements with normal HTML content,
+ * and not for, for example, script or style element content,
+ * which require escapes matching their particular content syntax.
+ *
+ * Escapes `<` and `>` characters.
+ */
static const HtmlEscapeMode ELEMENT =
- const HtmlEscapeMode._('element', true, false, false, true);
+ const HtmlEscapeMode._('element', true, false, false);
- // TODO(floitsch) - Document - Issue 13097
- const HtmlEscapeMode._(this._name, this.escapeLtGt, this.escapeQuot,
- this.escapeApos, this.escapeSlash);
+ const HtmlEscapeMode._(
+ this._name, this.escapeLtGt, this.escapeQuot, this.escapeApos);
+
+ /**
+ * Create a custom escaping mode.
+ *
+ * All modes escape `&`.
+ * The mode can further be set to escape `<` and `>` ([escapeLtGt]),
+ * `"` ([escapeQuot]) and/or `'` ([escapeApos]).
+ */
+ const HtmlEscapeMode({String name: "custom",
+ this.escapeLtGt: false,
+ this.escapeQuot: false,
+ this.escapeApos: false}) : _name = name;
String toString() => _name;
}
- // TODO(floitsch) - Document - Issue 13097
+/**
+ * Converter which escapes characters with special meaning in HTML.
+ *
+ * The converter finds characters that are siginificant in HTML source and
+ * replaces them with corresponding HTML entities.
+ *
+ * The characters that need escaping in HTML are:
+ *
+ * * `&` (ampersand) always need to be escaped.
+ * * `<` (less than) and '>' (greater than) when inside an element.
+ * * `"` (quote) when inside a double-quoted attribute value.
+ * * `'` (apostrophe) when inside a single-quoted attribute value.
+ * Apostrophe is escaped as `'` instead of `'` since
+ * not all browsers understand `'`.
+ *
+ * Escaping `>` (greater than) isn't necessary, but the result is often
+ * found to be easier to read if greater-than is also escaped whenever
+ * less-than is.
+ */
class HtmlEscape extends Converter<String, String> {
- // TODO(floitsch) - Document - Issue 13097
+ /** The [HtmlEscapeMode] used by the converter. */
final HtmlEscapeMode mode;
- // TODO(floitsch) - Document - Issue 13097
+ /**
+ * Create converter that escapes HTML characters.
+ *
+ * If [mode] is provided as either [HtmlEscapeMode.ATTRIBUTE] or
+ * [HtmlEscapeMode.ELEMENT], only the corresponding subset of HTML
+ * characters are escaped.
+ * The default is to escape all HTML characters.
+ */
const HtmlEscape([this.mode = HtmlEscapeMode.UNKNOWN]);
String convert(String text) {
@@ -47,29 +133,34 @@
return val == null ? text : val;
}
+ /**
+ * Converts the substring of text from start to end.
+ *
+ * Returns `null` if no changes were necessary, otherwise returns
+ * the converted string.
+ */
String _convert(String text, int start, int end) {
StringBuffer result = null;
for (int i = start; i < end; i++) {
var ch = text[i];
- String replace = null;
+ String replacement = null;
switch (ch) {
- case '&': replace = '&'; break;
- case '\u00A0'/*NO-BREAK SPACE*/: replace = ' '; break;
- case '"': if (mode.escapeQuot) replace = '"'; break;
- case "'": if (mode.escapeApos) replace = '''; break;
- case '<': if (mode.escapeLtGt) replace = '<'; break;
- case '>': if (mode.escapeLtGt) replace = '>'; break;
- case '/': if (mode.escapeSlash) replace = '/'; break;
+ case '&': replacement = '&'; break;
+ case '"': if (mode.escapeQuot) replacement = '"'; break;
+ case "'": if (mode.escapeApos) replacement = '''; break;
+ case '<': if (mode.escapeLtGt) replacement = '<'; break;
+ case '>': if (mode.escapeLtGt) replacement = '>'; break;
}
- if (replace != null) {
- if (result == null) result = new StringBuffer(text.substring(start, i));
- result.write(replace);
- } else if (result != null) {
- result.write(ch);
+ if (replacement != null) {
+ if (result == null) result = new StringBuffer();
+ if (i > start) result.write(text.substring(start, i));
+ result.write(replacement);
+ start = i + 1;
}
}
-
- return result != null ? result.toString() : null;
+ if (result == null) return null;
+ if (end > start) result.write(text.substring(start, end));
+ return result.toString();
}
StringConversionSink startChunkedConversion(Sink<String> sink) {
diff --git a/sdk/lib/core/exceptions.dart b/sdk/lib/core/exceptions.dart
index 3ca1fb3..38af7af 100644
--- a/sdk/lib/core/exceptions.dart
+++ b/sdk/lib/core/exceptions.dart
@@ -46,7 +46,7 @@
final String message;
/**
- * The actual source input that caused the error.
+ * The actual source input which caused the error.
*
* This is usually a [String], but can be other types too.
* If it is a string, parts of it may be included in the [toString] message.
@@ -73,8 +73,8 @@
/**
* Creates a new FormatException with an optional error [message].
*
- * Optionally also supply the actual [source] that had the incorrect format,
- * and an [offset] in the format where a problem was detected.
+ * Optionally also supply the actual [source] with the incorrect format,
+ * and the [offset] in the format where a problem was detected.
*/
const FormatException([this.message = "", this.source, this.offset]);
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index 06bb3ca..14e2d80 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -146,11 +146,14 @@
/**
* Creates a new `Uri` object by parsing a URI string.
*
+ * If [start] and [end] are provided, only the substring from `start`
+ * to `end` is parsed as a URI.
+ *
* If the string is not valid as a URI or URI reference,
* invalid characters will be percent escaped where possible.
* The resulting `Uri` will represent a valid URI or URI reference.
*/
- static Uri parse(String uri) {
+ static Uri parse(String uri, [int start = 0, int end]) {
// This parsing will not validate percent-encoding, IPv6, etc. When done
// it will call `new Uri(...)` which will perform these validations.
// This is purely splitting up the URI string into components.
@@ -216,14 +219,15 @@
String path = null;
String query = null;
String fragment = null;
+ if (end == null) end = uri.length;
- int index = 0;
- int pathStart = 0;
+ int index = start;
+ int pathStart = start;
// End of input-marker.
int char = EOI;
void parseAuth() {
- if (index == uri.length) {
+ if (index == end) {
char = EOI;
return;
}
@@ -231,7 +235,7 @@
int lastColon = -1;
int lastAt = -1;
char = uri.codeUnitAt(index);
- while (index < uri.length) {
+ while (index < end) {
char = uri.codeUnitAt(index);
if (char == _SLASH || char == _QUESTION || char == _NUMBER_SIGN) {
break;
@@ -245,7 +249,7 @@
lastColon = -1;
int endBracket = uri.indexOf(']', index + 1);
if (endBracket == -1) {
- index = uri.length;
+ index = end;
char = EOI;
break;
} else {
@@ -277,7 +281,7 @@
hostEnd = lastColon;
}
host = _makeHost(uri, hostStart, hostEnd, true);
- if (index < uri.length) {
+ if (index < end) {
char = uri.codeUnitAt(index);
}
}
@@ -298,22 +302,22 @@
// All other breaks set their own state.
int state = NOT_IN_PATH;
int i = index; // Temporary alias for index to avoid bug 19550 in dart2js.
- while (i < uri.length) {
+ while (i < end) {
char = uri.codeUnitAt(i);
if (char == _QUESTION || char == _NUMBER_SIGN) {
state = NOT_IN_PATH;
break;
}
if (char == _SLASH) {
- state = (i == 0) ? ALLOW_AUTH : IN_PATH;
+ state = (i == start) ? ALLOW_AUTH : IN_PATH;
break;
}
if (char == _COLON) {
- if (i == 0) _fail(uri, 0, "Invalid empty scheme");
- scheme = _makeScheme(uri, i);
+ if (i == start) _fail(uri, start, "Invalid empty scheme");
+ scheme = _makeScheme(uri, start, i);
i++;
pathStart = i;
- if (i == uri.length) {
+ if (i == end) {
char = EOI;
state = NOT_IN_PATH;
} else {
@@ -338,7 +342,7 @@
// Have seen one slash either at start or right after scheme.
// If two slashes, it's an authority, otherwise it's just the path.
index++;
- if (index == uri.length) {
+ if (index == end) {
char = EOI;
state = NOT_IN_PATH;
} else {
@@ -360,7 +364,7 @@
if (state == IN_PATH) {
// Characters from pathStart to index (inclusive) are known
// to be part of the path.
- while (++index < uri.length) {
+ while (++index < end) {
char = uri.codeUnitAt(index);
if (char == _QUESTION || char == _NUMBER_SIGN) {
break;
@@ -376,15 +380,21 @@
path = _makePath(uri, pathStart, index, null, ensureLeadingSlash, isFile);
if (char == _QUESTION) {
- int numberSignIndex = uri.indexOf('#', index + 1);
+ int numberSignIndex = -1;
+ for (int i = index + 1; i < end; i++) {
+ if (uri.codeUnitAt(i) == _NUMBER_SIGN) {
+ numberSignIndex = i;
+ break;
+ }
+ }
if (numberSignIndex < 0) {
- query = _makeQuery(uri, index + 1, uri.length, null);
+ query = _makeQuery(uri, index + 1, end, null);
} else {
query = _makeQuery(uri, index + 1, numberSignIndex, null);
- fragment = _makeFragment(uri, numberSignIndex + 1, uri.length);
+ fragment = _makeFragment(uri, numberSignIndex + 1, end);
}
} else if (char == _NUMBER_SIGN) {
- fragment = _makeFragment(uri, index + 1, uri.length);
+ fragment = _makeFragment(uri, index + 1, end);
}
return new Uri._internal(scheme,
userinfo,
@@ -482,7 +492,7 @@
String query,
Map<String, String> queryParameters,
String fragment}) {
- scheme = _makeScheme(scheme, _stringOrNullLength(scheme));
+ scheme = _makeScheme(scheme, 0, _stringOrNullLength(scheme));
userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo));
host = _makeHost(host, 0, _stringOrNullLength(host), false);
// Special case this constructor for backwards compatibility.
@@ -872,7 +882,7 @@
// to check even the existing port.
bool schemeChanged = false;
if (scheme != null) {
- scheme = _makeScheme(scheme, scheme.length);
+ scheme = _makeScheme(scheme, 0, scheme.length);
schemeChanged = true;
} else {
scheme = this.scheme;
@@ -1100,14 +1110,14 @@
*
* Schemes are converted to lower case. They cannot contain escapes.
*/
- static String _makeScheme(String scheme, int end) {
- if (end == 0) return "";
- final int firstCodeUnit = scheme.codeUnitAt(0);
+ static String _makeScheme(String scheme, int start, int end) {
+ if (start == end) return "";
+ final int firstCodeUnit = scheme.codeUnitAt(start);
if (!_isAlphabeticCharacter(firstCodeUnit)) {
- _fail(scheme, 0, "Scheme not starting with alphabetic character");
+ _fail(scheme, start, "Scheme not starting with alphabetic character");
}
bool allLowercase = firstCodeUnit >= _LOWER_CASE_A;
- for (int i = 0; i < end; i++) {
+ for (int i = start; i < end; i++) {
final int codeUnit = scheme.codeUnitAt(i);
if (!_isSchemeCharacter(codeUnit)) {
_fail(scheme, i, "Illegal scheme character");
@@ -1116,7 +1126,7 @@
allLowercase = false;
}
}
- scheme = scheme.substring(0, end);
+ scheme = scheme.substring(start, end);
if (!allLowercase) scheme = scheme.toLowerCase();
return scheme;
}
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index c08cc44..e780d2e 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -55,12 +55,14 @@
// Not actually used, but imported since dart:html can generate these objects.
import 'dart:_js_helper' show
convertDartClosureToJS, Creates, JavaScriptIndexingBehavior,
- JSName, Native, Null, Returns,
+ JSName, Native, Null, Returns, Inline, ForceInline,
findDispatchTagForInterceptorClass, setNativeSubclassDispatchRecord,
makeLeafDispatchRecord;
import 'dart:_interceptors' show
- Interceptor, JSExtendableArray, findInterceptorConstructorForType,
- findConstructorForNativeSubclassType, getNativeInterceptor,
+ Interceptor, JSExtendableArray, JSUInt31,
+ findInterceptorConstructorForType,
+ findConstructorForNativeSubclassType,
+ getNativeInterceptor,
setDispatchProperty;
export 'dart:math' show Rectangle, Point;
@@ -3315,7 +3317,7 @@
@DomName('CSSStyleDeclaration')
@Native("CSSStyleDeclaration,MSStyleCSSProperties,CSS2Properties")
- class CssStyleDeclaration extends Interceptor with
+class CssStyleDeclaration extends Interceptor with
CssStyleDeclarationBase {
factory CssStyleDeclaration() => new CssStyleDeclaration.css('');
@@ -3357,12 +3359,27 @@
@DomName('CSSStyleDeclaration.setProperty')
void setProperty(String propertyName, String value, [String priority]) {
+ return _setPropertyHelper(_browserPropertyName(propertyName),
+ value, priority);
+ }
+
+ String _browserPropertyName(String propertyName) {
+ String name = _readCache(propertyName);
+ if (name is String) return name;
if (_supportsProperty(_camelCase(propertyName))) {
- return _setPropertyHelper(propertyName, value, priority);
+ name = propertyName;
} else {
- return _setPropertyHelper(Device.cssPrefix + propertyName, value,
- priority);
+ name = Device.cssPrefix + propertyName;
}
+ _writeCache(propertyName, name);
+ return name;
+ }
+
+ static final _propertyCache = JS('', '{}');
+ static String _readCache(String key) =>
+ JS('String|Null', '#[#]', _propertyCache, key);
+ static void _writeCache(String key, String value) {
+ JS('void', '#[#] = #', _propertyCache, key, value);
}
static String _camelCase(String hyphenated) {
@@ -3374,18 +3391,9 @@
}
void _setPropertyHelper(String propertyName, String value, [String priority]) {
- // try/catch for IE9 which throws on unsupported values.
- try {
- if (value == null) value = '';
- if (priority == null) {
- priority = '';
- }
- JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority);
- // Bug #2772, IE9 requires a poke to actually apply the value.
- if (JS('bool', '!!#.setAttribute', this)) {
- JS('void', '#.setAttribute(#, #)', this, propertyName, value);
- }
- } catch (e) {}
+ if (value == null) value = '';
+ if (priority == null) priority = '';
+ JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority);
}
/**
@@ -3435,6 +3443,997 @@
@DocsEditable()
String removeProperty(String propertyName) native;
+
+ /** Gets the value of "background" */
+ String get background => this._background;
+
+ /** Sets the value of "background" */
+ void set background(String value) {
+ _background = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('background')
+ String _background;
+
+ /** Gets the value of "background-attachment" */
+ String get backgroundAttachment => this._backgroundAttachment;
+
+ /** Sets the value of "background-attachment" */
+ void set backgroundAttachment(String value) {
+ _backgroundAttachment = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('backgroundAttachment')
+ String _backgroundAttachment;
+
+ /** Gets the value of "background-color" */
+ String get backgroundColor => this._backgroundColor;
+
+ /** Sets the value of "background-color" */
+ void set backgroundColor(String value) {
+ _backgroundColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('backgroundColor')
+ String _backgroundColor;
+
+ /** Gets the value of "background-image" */
+ String get backgroundImage => this._backgroundImage;
+
+ /** Sets the value of "background-image" */
+ void set backgroundImage(String value) {
+ _backgroundImage = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('backgroundImage')
+ String _backgroundImage;
+
+ /** Gets the value of "background-position" */
+ String get backgroundPosition => this._backgroundPosition;
+
+ /** Sets the value of "background-position" */
+ void set backgroundPosition(String value) {
+ _backgroundPosition = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('backgroundPosition')
+ String _backgroundPosition;
+
+ /** Gets the value of "background-repeat" */
+ String get backgroundRepeat => this._backgroundRepeat;
+
+ /** Sets the value of "background-repeat" */
+ void set backgroundRepeat(String value) {
+ _backgroundRepeat = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('backgroundRepeat')
+ String _backgroundRepeat;
+
+ /** Gets the value of "border" */
+ String get border => this._border;
+
+ /** Sets the value of "border" */
+ void set border(String value) {
+ _border = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('border')
+ String _border;
+
+ /** Gets the value of "border-bottom" */
+ String get borderBottom => this._borderBottom;
+
+ /** Sets the value of "border-bottom" */
+ void set borderBottom(String value) {
+ _borderBottom = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderBottom')
+ String _borderBottom;
+
+ /** Gets the value of "border-bottom-color" */
+ String get borderBottomColor => this._borderBottomColor;
+
+ /** Sets the value of "border-bottom-color" */
+ void set borderBottomColor(String value) {
+ _borderBottomColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderBottomColor')
+ String _borderBottomColor;
+
+ /** Gets the value of "border-bottom-style" */
+ String get borderBottomStyle => this._borderBottomStyle;
+
+ /** Sets the value of "border-bottom-style" */
+ void set borderBottomStyle(String value) {
+ _borderBottomStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderBottomStyle')
+ String _borderBottomStyle;
+
+ /** Gets the value of "border-bottom-width" */
+ String get borderBottomWidth => this._borderBottomWidth;
+
+ /** Sets the value of "border-bottom-width" */
+ void set borderBottomWidth(String value) {
+ _borderBottomWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderBottomWidth')
+ String _borderBottomWidth;
+
+ /** Gets the value of "border-collapse" */
+ String get borderCollapse => this._borderCollapse;
+
+ /** Sets the value of "border-collapse" */
+ void set borderCollapse(String value) {
+ _borderCollapse = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderCollapse')
+ String _borderCollapse;
+
+ /** Gets the value of "border-color" */
+ String get borderColor => this._borderColor;
+
+ /** Sets the value of "border-color" */
+ void set borderColor(String value) {
+ _borderColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderColor')
+ String _borderColor;
+
+ /** Gets the value of "border-left" */
+ String get borderLeft => this._borderLeft;
+
+ /** Sets the value of "border-left" */
+ void set borderLeft(String value) {
+ _borderLeft = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderLeft')
+ String _borderLeft;
+
+ /** Gets the value of "border-left-color" */
+ String get borderLeftColor => this._borderLeftColor;
+
+ /** Sets the value of "border-left-color" */
+ void set borderLeftColor(String value) {
+ _borderLeftColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderLeftColor')
+ String _borderLeftColor;
+
+ /** Gets the value of "border-left-style" */
+ String get borderLeftStyle => this._borderLeftStyle;
+
+ /** Sets the value of "border-left-style" */
+ void set borderLeftStyle(String value) {
+ _borderLeftStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderLeftStyle')
+ String _borderLeftStyle;
+
+ /** Gets the value of "border-left-width" */
+ String get borderLeftWidth => this._borderLeftWidth;
+
+ /** Sets the value of "border-left-width" */
+ void set borderLeftWidth(String value) {
+ _borderLeftWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderLeftWidth')
+ String _borderLeftWidth;
+
+ /** Gets the value of "border-right" */
+ String get borderRight => this._borderRight;
+
+ /** Sets the value of "border-right" */
+ void set borderRight(String value) {
+ _borderRight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderRight')
+ String _borderRight;
+
+ /** Gets the value of "border-right-color" */
+ String get borderRightColor => this._borderRightColor;
+
+ /** Sets the value of "border-right-color" */
+ void set borderRightColor(String value) {
+ _borderRightColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderRightColor')
+ String _borderRightColor;
+
+ /** Gets the value of "border-right-style" */
+ String get borderRightStyle => this._borderRightStyle;
+
+ /** Sets the value of "border-right-style" */
+ void set borderRightStyle(String value) {
+ _borderRightStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderRightStyle')
+ String _borderRightStyle;
+
+ /** Gets the value of "border-right-width" */
+ String get borderRightWidth => this._borderRightWidth;
+
+ /** Sets the value of "border-right-width" */
+ void set borderRightWidth(String value) {
+ _borderRightWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderRightWidth')
+ String _borderRightWidth;
+
+ /** Gets the value of "border-spacing" */
+ String get borderSpacing => this._borderSpacing;
+
+ /** Sets the value of "border-spacing" */
+ void set borderSpacing(String value) {
+ _borderSpacing = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderSpacing')
+ String _borderSpacing;
+
+ /** Gets the value of "border-style" */
+ String get borderStyle => this._borderStyle;
+
+ /** Sets the value of "border-style" */
+ void set borderStyle(String value) {
+ _borderStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderStyle')
+ String _borderStyle;
+
+ /** Gets the value of "border-top" */
+ String get borderTop => this._borderTop;
+
+ /** Sets the value of "border-top" */
+ void set borderTop(String value) {
+ _borderTop = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderTop')
+ String _borderTop;
+
+ /** Gets the value of "border-top-color" */
+ String get borderTopColor => this._borderTopColor;
+
+ /** Sets the value of "border-top-color" */
+ void set borderTopColor(String value) {
+ _borderTopColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderTopColor')
+ String _borderTopColor;
+
+ /** Gets the value of "border-top-style" */
+ String get borderTopStyle => this._borderTopStyle;
+
+ /** Sets the value of "border-top-style" */
+ void set borderTopStyle(String value) {
+ _borderTopStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderTopStyle')
+ String _borderTopStyle;
+
+ /** Gets the value of "border-top-width" */
+ String get borderTopWidth => this._borderTopWidth;
+
+ /** Sets the value of "border-top-width" */
+ void set borderTopWidth(String value) {
+ _borderTopWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderTopWidth')
+ String _borderTopWidth;
+
+ /** Gets the value of "border-width" */
+ String get borderWidth => this._borderWidth;
+
+ /** Sets the value of "border-width" */
+ void set borderWidth(String value) {
+ _borderWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderWidth')
+ String _borderWidth;
+
+ /** Gets the value of "bottom" */
+ String get bottom => this._bottom;
+
+ /** Sets the value of "bottom" */
+ void set bottom(String value) {
+ _bottom = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('bottom')
+ String _bottom;
+
+ /** Gets the value of "caption-side" */
+ String get captionSide => this._captionSide;
+
+ /** Sets the value of "caption-side" */
+ void set captionSide(String value) {
+ _captionSide = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('captionSide')
+ String _captionSide;
+
+ /** Gets the value of "clear" */
+ String get clear => this._clear;
+
+ /** Sets the value of "clear" */
+ void set clear(String value) {
+ _clear = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('clear')
+ String _clear;
+
+ /** Gets the value of "clip" */
+ String get clip => this._clip;
+
+ /** Sets the value of "clip" */
+ void set clip(String value) {
+ _clip = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('clip')
+ String _clip;
+
+ /** Gets the value of "color" */
+ String get color => this._color;
+
+ /** Sets the value of "color" */
+ void set color(String value) {
+ _color = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('color')
+ String _color;
+
+ /** Gets the value of "content" */
+ String get content => this._content;
+
+ /** Sets the value of "content" */
+ void set content(String value) {
+ _content = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('content')
+ String _content;
+
+ /** Gets the value of "cursor" */
+ String get cursor => this._cursor;
+
+ /** Sets the value of "cursor" */
+ void set cursor(String value) {
+ _cursor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('cursor')
+ String _cursor;
+
+ /** Gets the value of "direction" */
+ String get direction => this._direction;
+
+ /** Sets the value of "direction" */
+ void set direction(String value) {
+ _direction = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('direction')
+ String _direction;
+
+ /** Gets the value of "display" */
+ String get display => this._display;
+
+ /** Sets the value of "display" */
+ void set display(String value) {
+ _display = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('display')
+ String _display;
+
+ /** Gets the value of "empty-cells" */
+ String get emptyCells => this._emptyCells;
+
+ /** Sets the value of "empty-cells" */
+ void set emptyCells(String value) {
+ _emptyCells = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('emptyCells')
+ String _emptyCells;
+
+ /** Gets the value of "font" */
+ String get font => this._font;
+
+ /** Sets the value of "font" */
+ void set font(String value) {
+ _font = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('font')
+ String _font;
+
+ /** Gets the value of "font-family" */
+ String get fontFamily => this._fontFamily;
+
+ /** Sets the value of "font-family" */
+ void set fontFamily(String value) {
+ _fontFamily = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('fontFamily')
+ String _fontFamily;
+
+ /** Gets the value of "font-size" */
+ String get fontSize => this._fontSize;
+
+ /** Sets the value of "font-size" */
+ void set fontSize(String value) {
+ _fontSize = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('fontSize')
+ String _fontSize;
+
+ /** Gets the value of "font-style" */
+ String get fontStyle => this._fontStyle;
+
+ /** Sets the value of "font-style" */
+ void set fontStyle(String value) {
+ _fontStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('fontStyle')
+ String _fontStyle;
+
+ /** Gets the value of "font-variant" */
+ String get fontVariant => this._fontVariant;
+
+ /** Sets the value of "font-variant" */
+ void set fontVariant(String value) {
+ _fontVariant = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('fontVariant')
+ String _fontVariant;
+
+ /** Gets the value of "font-weight" */
+ String get fontWeight => this._fontWeight;
+
+ /** Sets the value of "font-weight" */
+ void set fontWeight(String value) {
+ _fontWeight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('fontWeight')
+ String _fontWeight;
+
+ /** Gets the value of "height" */
+ String get height => this._height;
+
+ /** Sets the value of "height" */
+ void set height(String value) {
+ _height = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('height')
+ String _height;
+
+ /** Gets the value of "left" */
+ String get left => this._left;
+
+ /** Sets the value of "left" */
+ void set left(String value) {
+ _left = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('left')
+ String _left;
+
+ /** Gets the value of "letter-spacing" */
+ String get letterSpacing => this._letterSpacing;
+
+ /** Sets the value of "letter-spacing" */
+ void set letterSpacing(String value) {
+ _letterSpacing = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('letterSpacing')
+ String _letterSpacing;
+
+ /** Gets the value of "line-height" */
+ String get lineHeight => this._lineHeight;
+
+ /** Sets the value of "line-height" */
+ void set lineHeight(String value) {
+ _lineHeight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('lineHeight')
+ String _lineHeight;
+
+ /** Gets the value of "list-style" */
+ String get listStyle => this._listStyle;
+
+ /** Sets the value of "list-style" */
+ void set listStyle(String value) {
+ _listStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('listStyle')
+ String _listStyle;
+
+ /** Gets the value of "list-style-image" */
+ String get listStyleImage => this._listStyleImage;
+
+ /** Sets the value of "list-style-image" */
+ void set listStyleImage(String value) {
+ _listStyleImage = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('listStyleImage')
+ String _listStyleImage;
+
+ /** Gets the value of "list-style-position" */
+ String get listStylePosition => this._listStylePosition;
+
+ /** Sets the value of "list-style-position" */
+ void set listStylePosition(String value) {
+ _listStylePosition = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('listStylePosition')
+ String _listStylePosition;
+
+ /** Gets the value of "list-style-type" */
+ String get listStyleType => this._listStyleType;
+
+ /** Sets the value of "list-style-type" */
+ void set listStyleType(String value) {
+ _listStyleType = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('listStyleType')
+ String _listStyleType;
+
+ /** Gets the value of "margin" */
+ String get margin => this._margin;
+
+ /** Sets the value of "margin" */
+ void set margin(String value) {
+ _margin = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('margin')
+ String _margin;
+
+ /** Gets the value of "margin-bottom" */
+ String get marginBottom => this._marginBottom;
+
+ /** Sets the value of "margin-bottom" */
+ void set marginBottom(String value) {
+ _marginBottom = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('marginBottom')
+ String _marginBottom;
+
+ /** Gets the value of "margin-left" */
+ String get marginLeft => this._marginLeft;
+
+ /** Sets the value of "margin-left" */
+ void set marginLeft(String value) {
+ _marginLeft = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('marginLeft')
+ String _marginLeft;
+
+ /** Gets the value of "margin-right" */
+ String get marginRight => this._marginRight;
+
+ /** Sets the value of "margin-right" */
+ void set marginRight(String value) {
+ _marginRight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('marginRight')
+ String _marginRight;
+
+ /** Gets the value of "margin-top" */
+ String get marginTop => this._marginTop;
+
+ /** Sets the value of "margin-top" */
+ void set marginTop(String value) {
+ _marginTop = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('marginTop')
+ String _marginTop;
+
+ /** Gets the value of "max-height" */
+ String get maxHeight => this._maxHeight;
+
+ /** Sets the value of "max-height" */
+ void set maxHeight(String value) {
+ _maxHeight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('maxHeight')
+ String _maxHeight;
+
+ /** Gets the value of "max-width" */
+ String get maxWidth => this._maxWidth;
+
+ /** Sets the value of "max-width" */
+ void set maxWidth(String value) {
+ _maxWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('maxWidth')
+ String _maxWidth;
+
+ /** Gets the value of "min-height" */
+ String get minHeight => this._minHeight;
+
+ /** Sets the value of "min-height" */
+ void set minHeight(String value) {
+ _minHeight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('minHeight')
+ String _minHeight;
+
+ /** Gets the value of "min-width" */
+ String get minWidth => this._minWidth;
+
+ /** Sets the value of "min-width" */
+ void set minWidth(String value) {
+ _minWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('minWidth')
+ String _minWidth;
+
+ /** Gets the value of "outline" */
+ String get outline => this._outline;
+
+ /** Sets the value of "outline" */
+ void set outline(String value) {
+ _outline = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('outline')
+ String _outline;
+
+ /** Gets the value of "outline-color" */
+ String get outlineColor => this._outlineColor;
+
+ /** Sets the value of "outline-color" */
+ void set outlineColor(String value) {
+ _outlineColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('outlineColor')
+ String _outlineColor;
+
+ /** Gets the value of "outline-style" */
+ String get outlineStyle => this._outlineStyle;
+
+ /** Sets the value of "outline-style" */
+ void set outlineStyle(String value) {
+ _outlineStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('outlineStyle')
+ String _outlineStyle;
+
+ /** Gets the value of "outline-width" */
+ String get outlineWidth => this._outlineWidth;
+
+ /** Sets the value of "outline-width" */
+ void set outlineWidth(String value) {
+ _outlineWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('outlineWidth')
+ String _outlineWidth;
+
+ /** Gets the value of "overflow" */
+ String get overflow => this._overflow;
+
+ /** Sets the value of "overflow" */
+ void set overflow(String value) {
+ _overflow = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('overflow')
+ String _overflow;
+
+ /** Gets the value of "padding" */
+ String get padding => this._padding;
+
+ /** Sets the value of "padding" */
+ void set padding(String value) {
+ _padding = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('padding')
+ String _padding;
+
+ /** Gets the value of "padding-bottom" */
+ String get paddingBottom => this._paddingBottom;
+
+ /** Sets the value of "padding-bottom" */
+ void set paddingBottom(String value) {
+ _paddingBottom = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('paddingBottom')
+ String _paddingBottom;
+
+ /** Gets the value of "padding-left" */
+ String get paddingLeft => this._paddingLeft;
+
+ /** Sets the value of "padding-left" */
+ void set paddingLeft(String value) {
+ _paddingLeft = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('paddingLeft')
+ String _paddingLeft;
+
+ /** Gets the value of "padding-right" */
+ String get paddingRight => this._paddingRight;
+
+ /** Sets the value of "padding-right" */
+ void set paddingRight(String value) {
+ _paddingRight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('paddingRight')
+ String _paddingRight;
+
+ /** Gets the value of "padding-top" */
+ String get paddingTop => this._paddingTop;
+
+ /** Sets the value of "padding-top" */
+ void set paddingTop(String value) {
+ _paddingTop = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('paddingTop')
+ String _paddingTop;
+
+ /** Gets the value of "page-break-after" */
+ String get pageBreakAfter => this._pageBreakAfter;
+
+ /** Sets the value of "page-break-after" */
+ void set pageBreakAfter(String value) {
+ _pageBreakAfter = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('pageBreakAfter')
+ String _pageBreakAfter;
+
+ /** Gets the value of "page-break-before" */
+ String get pageBreakBefore => this._pageBreakBefore;
+
+ /** Sets the value of "page-break-before" */
+ void set pageBreakBefore(String value) {
+ _pageBreakBefore = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('pageBreakBefore')
+ String _pageBreakBefore;
+
+ /** Gets the value of "page-break-inside" */
+ String get pageBreakInside => this._pageBreakInside;
+
+ /** Sets the value of "page-break-inside" */
+ void set pageBreakInside(String value) {
+ _pageBreakInside = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('pageBreakInside')
+ String _pageBreakInside;
+
+ /** Gets the value of "position" */
+ String get position => this._position;
+
+ /** Sets the value of "position" */
+ void set position(String value) {
+ _position = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('position')
+ String _position;
+
+ /** Gets the value of "quotes" */
+ String get quotes => this._quotes;
+
+ /** Sets the value of "quotes" */
+ void set quotes(String value) {
+ _quotes = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('quotes')
+ String _quotes;
+
+ /** Gets the value of "right" */
+ String get right => this._right;
+
+ /** Sets the value of "right" */
+ void set right(String value) {
+ _right = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('right')
+ String _right;
+
+ /** Gets the value of "table-layout" */
+ String get tableLayout => this._tableLayout;
+
+ /** Sets the value of "table-layout" */
+ void set tableLayout(String value) {
+ _tableLayout = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('tableLayout')
+ String _tableLayout;
+
+ /** Gets the value of "text-align" */
+ String get textAlign => this._textAlign;
+
+ /** Sets the value of "text-align" */
+ void set textAlign(String value) {
+ _textAlign = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('textAlign')
+ String _textAlign;
+
+ /** Gets the value of "text-decoration" */
+ String get textDecoration => this._textDecoration;
+
+ /** Sets the value of "text-decoration" */
+ void set textDecoration(String value) {
+ _textDecoration = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('textDecoration')
+ String _textDecoration;
+
+ /** Gets the value of "text-indent" */
+ String get textIndent => this._textIndent;
+
+ /** Sets the value of "text-indent" */
+ void set textIndent(String value) {
+ _textIndent = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('textIndent')
+ String _textIndent;
+
+ /** Gets the value of "text-transform" */
+ String get textTransform => this._textTransform;
+
+ /** Sets the value of "text-transform" */
+ void set textTransform(String value) {
+ _textTransform = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('textTransform')
+ String _textTransform;
+
+ /** Gets the value of "top" */
+ String get top => this._top;
+
+ /** Sets the value of "top" */
+ void set top(String value) {
+ _top = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('top')
+ String _top;
+
+ /** Gets the value of "unicode-bidi" */
+ String get unicodeBidi => this._unicodeBidi;
+
+ /** Sets the value of "unicode-bidi" */
+ void set unicodeBidi(String value) {
+ _unicodeBidi = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('unicodeBidi')
+ String _unicodeBidi;
+
+ /** Gets the value of "vertical-align" */
+ String get verticalAlign => this._verticalAlign;
+
+ /** Sets the value of "vertical-align" */
+ void set verticalAlign(String value) {
+ _verticalAlign = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('verticalAlign')
+ String _verticalAlign;
+
+ /** Gets the value of "visibility" */
+ String get visibility => this._visibility;
+
+ /** Sets the value of "visibility" */
+ void set visibility(String value) {
+ _visibility = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('visibility')
+ String _visibility;
+
+ /** Gets the value of "white-space" */
+ String get whiteSpace => this._whiteSpace;
+
+ /** Sets the value of "white-space" */
+ void set whiteSpace(String value) {
+ _whiteSpace = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('whiteSpace')
+ String _whiteSpace;
+
+ /** Gets the value of "width" */
+ String get width => this._width;
+
+ /** Sets the value of "width" */
+ void set width(String value) {
+ _width = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('width')
+ String _width;
+
+ /** Gets the value of "word-spacing" */
+ String get wordSpacing => this._wordSpacing;
+
+ /** Sets the value of "word-spacing" */
+ void set wordSpacing(String value) {
+ _wordSpacing = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('wordSpacing')
+ String _wordSpacing;
+
+ /** Gets the value of "z-index" */
+ String get zIndex => this._zIndex;
+
+ /** Sets the value of "z-index" */
+ void set zIndex(String value) {
+ _zIndex = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('zIndex')
+ String _zIndex;
+
}
class _CssStyleDeclarationSet extends Object with CssStyleDeclarationBase {
@@ -3454,6 +4453,466 @@
_elementCssStyleDeclarationSetIterable.forEach((e) =>
e.setProperty(propertyName, value, priority));
}
+
+
+ void _setAll(String propertyName, String value) {
+ value = value == null ? '' : value;
+ for (Element element in _elementIterable) {
+ JS('void', '#.style[#] = #', element, propertyName, value);
+ }
+ }
+
+ /** Sets the value of "background" */
+ void set background(String value) {
+ _setAll('background', value);
+ }
+
+ /** Sets the value of "background-attachment" */
+ void set backgroundAttachment(String value) {
+ _setAll('backgroundAttachment', value);
+ }
+
+ /** Sets the value of "background-color" */
+ void set backgroundColor(String value) {
+ _setAll('backgroundColor', value);
+ }
+
+ /** Sets the value of "background-image" */
+ void set backgroundImage(String value) {
+ _setAll('backgroundImage', value);
+ }
+
+ /** Sets the value of "background-position" */
+ void set backgroundPosition(String value) {
+ _setAll('backgroundPosition', value);
+ }
+
+ /** Sets the value of "background-repeat" */
+ void set backgroundRepeat(String value) {
+ _setAll('backgroundRepeat', value);
+ }
+
+ /** Sets the value of "border" */
+ void set border(String value) {
+ _setAll('border', value);
+ }
+
+ /** Sets the value of "border-bottom" */
+ void set borderBottom(String value) {
+ _setAll('borderBottom', value);
+ }
+
+ /** Sets the value of "border-bottom-color" */
+ void set borderBottomColor(String value) {
+ _setAll('borderBottomColor', value);
+ }
+
+ /** Sets the value of "border-bottom-style" */
+ void set borderBottomStyle(String value) {
+ _setAll('borderBottomStyle', value);
+ }
+
+ /** Sets the value of "border-bottom-width" */
+ void set borderBottomWidth(String value) {
+ _setAll('borderBottomWidth', value);
+ }
+
+ /** Sets the value of "border-collapse" */
+ void set borderCollapse(String value) {
+ _setAll('borderCollapse', value);
+ }
+
+ /** Sets the value of "border-color" */
+ void set borderColor(String value) {
+ _setAll('borderColor', value);
+ }
+
+ /** Sets the value of "border-left" */
+ void set borderLeft(String value) {
+ _setAll('borderLeft', value);
+ }
+
+ /** Sets the value of "border-left-color" */
+ void set borderLeftColor(String value) {
+ _setAll('borderLeftColor', value);
+ }
+
+ /** Sets the value of "border-left-style" */
+ void set borderLeftStyle(String value) {
+ _setAll('borderLeftStyle', value);
+ }
+
+ /** Sets the value of "border-left-width" */
+ void set borderLeftWidth(String value) {
+ _setAll('borderLeftWidth', value);
+ }
+
+ /** Sets the value of "border-right" */
+ void set borderRight(String value) {
+ _setAll('borderRight', value);
+ }
+
+ /** Sets the value of "border-right-color" */
+ void set borderRightColor(String value) {
+ _setAll('borderRightColor', value);
+ }
+
+ /** Sets the value of "border-right-style" */
+ void set borderRightStyle(String value) {
+ _setAll('borderRightStyle', value);
+ }
+
+ /** Sets the value of "border-right-width" */
+ void set borderRightWidth(String value) {
+ _setAll('borderRightWidth', value);
+ }
+
+ /** Sets the value of "border-spacing" */
+ void set borderSpacing(String value) {
+ _setAll('borderSpacing', value);
+ }
+
+ /** Sets the value of "border-style" */
+ void set borderStyle(String value) {
+ _setAll('borderStyle', value);
+ }
+
+ /** Sets the value of "border-top" */
+ void set borderTop(String value) {
+ _setAll('borderTop', value);
+ }
+
+ /** Sets the value of "border-top-color" */
+ void set borderTopColor(String value) {
+ _setAll('borderTopColor', value);
+ }
+
+ /** Sets the value of "border-top-style" */
+ void set borderTopStyle(String value) {
+ _setAll('borderTopStyle', value);
+ }
+
+ /** Sets the value of "border-top-width" */
+ void set borderTopWidth(String value) {
+ _setAll('borderTopWidth', value);
+ }
+
+ /** Sets the value of "border-width" */
+ void set borderWidth(String value) {
+ _setAll('borderWidth', value);
+ }
+
+ /** Sets the value of "bottom" */
+ void set bottom(String value) {
+ _setAll('bottom', value);
+ }
+
+ /** Sets the value of "caption-side" */
+ void set captionSide(String value) {
+ _setAll('captionSide', value);
+ }
+
+ /** Sets the value of "clear" */
+ void set clear(String value) {
+ _setAll('clear', value);
+ }
+
+ /** Sets the value of "clip" */
+ void set clip(String value) {
+ _setAll('clip', value);
+ }
+
+ /** Sets the value of "color" */
+ void set color(String value) {
+ _setAll('color', value);
+ }
+
+ /** Sets the value of "content" */
+ void set content(String value) {
+ _setAll('content', value);
+ }
+
+ /** Sets the value of "cursor" */
+ void set cursor(String value) {
+ _setAll('cursor', value);
+ }
+
+ /** Sets the value of "direction" */
+ void set direction(String value) {
+ _setAll('direction', value);
+ }
+
+ /** Sets the value of "display" */
+ void set display(String value) {
+ _setAll('display', value);
+ }
+
+ /** Sets the value of "empty-cells" */
+ void set emptyCells(String value) {
+ _setAll('emptyCells', value);
+ }
+
+ /** Sets the value of "font" */
+ void set font(String value) {
+ _setAll('font', value);
+ }
+
+ /** Sets the value of "font-family" */
+ void set fontFamily(String value) {
+ _setAll('fontFamily', value);
+ }
+
+ /** Sets the value of "font-size" */
+ void set fontSize(String value) {
+ _setAll('fontSize', value);
+ }
+
+ /** Sets the value of "font-style" */
+ void set fontStyle(String value) {
+ _setAll('fontStyle', value);
+ }
+
+ /** Sets the value of "font-variant" */
+ void set fontVariant(String value) {
+ _setAll('fontVariant', value);
+ }
+
+ /** Sets the value of "font-weight" */
+ void set fontWeight(String value) {
+ _setAll('fontWeight', value);
+ }
+
+ /** Sets the value of "height" */
+ void set height(String value) {
+ _setAll('height', value);
+ }
+
+ /** Sets the value of "left" */
+ void set left(String value) {
+ _setAll('left', value);
+ }
+
+ /** Sets the value of "letter-spacing" */
+ void set letterSpacing(String value) {
+ _setAll('letterSpacing', value);
+ }
+
+ /** Sets the value of "line-height" */
+ void set lineHeight(String value) {
+ _setAll('lineHeight', value);
+ }
+
+ /** Sets the value of "list-style" */
+ void set listStyle(String value) {
+ _setAll('listStyle', value);
+ }
+
+ /** Sets the value of "list-style-image" */
+ void set listStyleImage(String value) {
+ _setAll('listStyleImage', value);
+ }
+
+ /** Sets the value of "list-style-position" */
+ void set listStylePosition(String value) {
+ _setAll('listStylePosition', value);
+ }
+
+ /** Sets the value of "list-style-type" */
+ void set listStyleType(String value) {
+ _setAll('listStyleType', value);
+ }
+
+ /** Sets the value of "margin" */
+ void set margin(String value) {
+ _setAll('margin', value);
+ }
+
+ /** Sets the value of "margin-bottom" */
+ void set marginBottom(String value) {
+ _setAll('marginBottom', value);
+ }
+
+ /** Sets the value of "margin-left" */
+ void set marginLeft(String value) {
+ _setAll('marginLeft', value);
+ }
+
+ /** Sets the value of "margin-right" */
+ void set marginRight(String value) {
+ _setAll('marginRight', value);
+ }
+
+ /** Sets the value of "margin-top" */
+ void set marginTop(String value) {
+ _setAll('marginTop', value);
+ }
+
+ /** Sets the value of "max-height" */
+ void set maxHeight(String value) {
+ _setAll('maxHeight', value);
+ }
+
+ /** Sets the value of "max-width" */
+ void set maxWidth(String value) {
+ _setAll('maxWidth', value);
+ }
+
+ /** Sets the value of "min-height" */
+ void set minHeight(String value) {
+ _setAll('minHeight', value);
+ }
+
+ /** Sets the value of "min-width" */
+ void set minWidth(String value) {
+ _setAll('minWidth', value);
+ }
+
+ /** Sets the value of "outline" */
+ void set outline(String value) {
+ _setAll('outline', value);
+ }
+
+ /** Sets the value of "outline-color" */
+ void set outlineColor(String value) {
+ _setAll('outlineColor', value);
+ }
+
+ /** Sets the value of "outline-style" */
+ void set outlineStyle(String value) {
+ _setAll('outlineStyle', value);
+ }
+
+ /** Sets the value of "outline-width" */
+ void set outlineWidth(String value) {
+ _setAll('outlineWidth', value);
+ }
+
+ /** Sets the value of "overflow" */
+ void set overflow(String value) {
+ _setAll('overflow', value);
+ }
+
+ /** Sets the value of "padding" */
+ void set padding(String value) {
+ _setAll('padding', value);
+ }
+
+ /** Sets the value of "padding-bottom" */
+ void set paddingBottom(String value) {
+ _setAll('paddingBottom', value);
+ }
+
+ /** Sets the value of "padding-left" */
+ void set paddingLeft(String value) {
+ _setAll('paddingLeft', value);
+ }
+
+ /** Sets the value of "padding-right" */
+ void set paddingRight(String value) {
+ _setAll('paddingRight', value);
+ }
+
+ /** Sets the value of "padding-top" */
+ void set paddingTop(String value) {
+ _setAll('paddingTop', value);
+ }
+
+ /** Sets the value of "page-break-after" */
+ void set pageBreakAfter(String value) {
+ _setAll('pageBreakAfter', value);
+ }
+
+ /** Sets the value of "page-break-before" */
+ void set pageBreakBefore(String value) {
+ _setAll('pageBreakBefore', value);
+ }
+
+ /** Sets the value of "page-break-inside" */
+ void set pageBreakInside(String value) {
+ _setAll('pageBreakInside', value);
+ }
+
+ /** Sets the value of "position" */
+ void set position(String value) {
+ _setAll('position', value);
+ }
+
+ /** Sets the value of "quotes" */
+ void set quotes(String value) {
+ _setAll('quotes', value);
+ }
+
+ /** Sets the value of "right" */
+ void set right(String value) {
+ _setAll('right', value);
+ }
+
+ /** Sets the value of "table-layout" */
+ void set tableLayout(String value) {
+ _setAll('tableLayout', value);
+ }
+
+ /** Sets the value of "text-align" */
+ void set textAlign(String value) {
+ _setAll('textAlign', value);
+ }
+
+ /** Sets the value of "text-decoration" */
+ void set textDecoration(String value) {
+ _setAll('textDecoration', value);
+ }
+
+ /** Sets the value of "text-indent" */
+ void set textIndent(String value) {
+ _setAll('textIndent', value);
+ }
+
+ /** Sets the value of "text-transform" */
+ void set textTransform(String value) {
+ _setAll('textTransform', value);
+ }
+
+ /** Sets the value of "top" */
+ void set top(String value) {
+ _setAll('top', value);
+ }
+
+ /** Sets the value of "unicode-bidi" */
+ void set unicodeBidi(String value) {
+ _setAll('unicodeBidi', value);
+ }
+
+ /** Sets the value of "vertical-align" */
+ void set verticalAlign(String value) {
+ _setAll('verticalAlign', value);
+ }
+
+ /** Sets the value of "visibility" */
+ void set visibility(String value) {
+ _setAll('visibility', value);
+ }
+
+ /** Sets the value of "white-space" */
+ void set whiteSpace(String value) {
+ _setAll('whiteSpace', value);
+ }
+
+ /** Sets the value of "width" */
+ void set width(String value) {
+ _setAll('width', value);
+ }
+
+ /** Sets the value of "word-spacing" */
+ void set wordSpacing(String value) {
+ _setAll('wordSpacing', value);
+ }
+
+ /** Sets the value of "z-index" */
+ void set zIndex(String value) {
+ _setAll('zIndex', value);
+ }
+
+
// Important note: CssStyleDeclarationSet does NOT implement every method
// available in CssStyleDeclaration. Some of the methods don't make so much
// sense in terms of having a resonable value to return when you're
@@ -11796,6 +13255,33 @@
* used when an explicit accessor is not available.
*/
ElementEvents get on => new ElementEvents(this);
+
+ /**
+ * Verify if any of the attributes that we use in the sanitizer look unexpected,
+ * possibly indicating DOM clobbering attacks.
+ *
+ * Those attributes are: attributes, lastChild, children, previousNode and tagName.
+ */
+ bool get _hasCorruptedAttributes {
+ return JS('bool', r'''
+ (function(element) {
+ if (!(element.attributes instanceof NamedNodeMap)) {
+ return true;
+ }
+ var childNodes = element.childNodes;
+ if (element.lastChild &&
+ element.lastChild !== childNodes[childNodes.length -1]) {
+ return true;
+ }
+ if (element.children) { // On Safari, children can apparently be null.
+ if (!((element.children instanceof HTMLCollection) ||
+ (element.children instanceof NodeList))) {
+ return true;
+ }
+ }
+ return false;
+ })(#)''', this);
+ }
@DomName('Element.offsetHeight')
@DocsEditable()
@@ -24843,7 +26329,7 @@
@DomName('RTCIceCandidateEvent')
// http://dev.w3.org/2011/webrtc/editor/webrtc.html#rtcicecandidate-type
@Experimental()
-@Native("RTCIceCandidateEvent")
+@Native("RTCIceCandidateEvent,RTCPeerConnectionIceEvent")
class RtcIceCandidateEvent extends Event {
// To suppress missing implicit constructor warnings.
factory RtcIceCandidateEvent._() { throw new UnsupportedError("Not supported"); }
@@ -34891,6 +36377,12 @@
*
* If [shouldAdd] is true, then we always add that [value] to the element. If
* [shouldAdd] is false then we always remove [value] from the element.
+ *
+ * If this corresponds to one element, returns `true` if [value] is present
+ * after the operation, and returns `false` if [value] is absent after the
+ * operation.
+ *
+ * If this corresponds to many elements, `null` is always returned.
*/
bool toggle(String value, [bool shouldAdd]);
@@ -34917,7 +36409,7 @@
* If this corresponds to one element. Returns true if [value] was added to
* the set, otherwise false.
*
- * If this corresponds to many elements, null is always returned.
+ * If this corresponds to many elements, `null` is always returned.
*/
bool add(String value);
@@ -34958,90 +36450,6 @@
*/
void toggleAll(Iterable<String> iterable, [bool shouldAdd]);
}
-
-/**
- * A set (union) of the CSS classes that are present in a set of elements.
- * Implemented separately from _ElementCssClassSet for performance.
- */
-class _MultiElementCssClassSet extends CssClassSetImpl {
- final Iterable<Element> _elementIterable;
- Iterable<_ElementCssClassSet> _elementCssClassSetIterable;
-
- _MultiElementCssClassSet(this._elementIterable) {
- _elementCssClassSetIterable = new List.from(_elementIterable).map(
- (e) => new _ElementCssClassSet(e));
- }
-
- Set<String> readClasses() {
- var s = new LinkedHashSet<String>();
- _elementCssClassSetIterable.forEach(
- (_ElementCssClassSet e) => s.addAll(e.readClasses()));
- return s;
- }
-
- void writeClasses(Set<String> s) {
- var classes = s.join(' ');
- for (Element e in _elementIterable) {
- e.className = classes;
- }
- }
-
- /**
- * Helper method used to modify the set of css classes on this element.
- *
- * f - callback with:
- * s - a Set of all the css class name currently on this element.
- *
- * After f returns, the modified set is written to the
- * className property of this element.
- */
- modify( f(Set<String> s)) {
- _elementCssClassSetIterable.forEach((_ElementCssClassSet e) => e.modify(f));
- }
-
- /**
- * Adds the class [value] to the element if it is not on it, removes it if it
- * is.
- */
- bool toggle(String value, [bool shouldAdd]) =>
- _elementCssClassSetIterable.fold(false,
- (bool changed, _ElementCssClassSet e) =>
- e.toggle(value, shouldAdd) || changed);
-
- /**
- * Remove the class [value] from element, and return true on successful
- * removal.
- *
- * This is the Dart equivalent of jQuery's
- * [removeClass](http://api.jquery.com/removeClass/).
- */
- bool remove(Object value) => _elementCssClassSetIterable.fold(false,
- (bool changed, _ElementCssClassSet e) => e.remove(value) || changed);
-}
-
-class _ElementCssClassSet extends CssClassSetImpl {
-
- final Element _element;
-
- _ElementCssClassSet(this._element);
-
- Set<String> readClasses() {
- var s = new LinkedHashSet<String>();
- var classname = _element.className;
-
- for (String name in classname.split(' ')) {
- String trimmed = name.trim();
- if (!trimmed.isEmpty) {
- s.add(trimmed);
- }
- }
- return s;
- }
-
- void writeClasses(Set<String> s) {
- _element.className = s.join(' ');
- }
-}
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
@@ -35303,6 +36711,254 @@
final _CONTENT = 'content';
final _PADDING = 'padding';
final _MARGIN = 'margin';
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+/**
+ * A set (union) of the CSS classes that are present in a set of elements.
+ * Implemented separately from _ElementCssClassSet for performance.
+ */
+class _MultiElementCssClassSet extends CssClassSetImpl {
+ final Iterable<Element> _elementIterable;
+
+ // TODO(sra): Perhaps we should store the DomTokenList instead.
+ final List<CssClassSetImpl> _sets;
+
+ factory _MultiElementCssClassSet(Iterable<Element> elements) {
+ return new _MultiElementCssClassSet._(elements,
+ elements.map((Element e) => e.classes).toList());
+ }
+
+ _MultiElementCssClassSet._(this._elementIterable, this._sets);
+
+ Set<String> readClasses() {
+ var s = new LinkedHashSet<String>();
+ _sets.forEach((CssClassSetImpl e) => s.addAll(e.readClasses()));
+ return s;
+ }
+
+ void writeClasses(Set<String> s) {
+ var classes = s.join(' ');
+ for (Element e in _elementIterable) {
+ e.className = classes;
+ }
+ }
+
+ /**
+ * Helper method used to modify the set of css classes on this element.
+ *
+ * f - callback with:
+ * s - a Set of all the css class name currently on this element.
+ *
+ * After f returns, the modified set is written to the
+ * className property of this element.
+ */
+ modify( f(Set<String> s)) {
+ _sets.forEach((CssClassSetImpl e) => e.modify(f));
+ }
+
+ /**
+ * Adds the class [value] to the element if it is not on it, removes it if it
+ * is.
+ *
+ * TODO(sra): It seems wrong to collect a 'changed' flag like this when the
+ * underlying toggle returns an 'is set' flag.
+ */
+ bool toggle(String value, [bool shouldAdd]) =>
+ _sets.fold(false,
+ (bool changed, CssClassSetImpl e) =>
+ e.toggle(value, shouldAdd) || changed);
+
+ /**
+ * Remove the class [value] from element, and return true on successful
+ * removal.
+ *
+ * This is the Dart equivalent of jQuery's
+ * [removeClass](http://api.jquery.com/removeClass/).
+ */
+ bool remove(Object value) => _sets.fold(false,
+ (bool changed, CssClassSetImpl e) => e.remove(value) || changed);
+}
+
+class _ElementCssClassSet extends CssClassSetImpl {
+ final Element _element;
+
+ _ElementCssClassSet(this._element);
+
+ Set<String> readClasses() {
+ var s = new LinkedHashSet<String>();
+ var classname = _element.className;
+
+ for (String name in classname.split(' ')) {
+ String trimmed = name.trim();
+ if (!trimmed.isEmpty) {
+ s.add(trimmed);
+ }
+ }
+ return s;
+ }
+
+ void writeClasses(Set<String> s) {
+ _element.className = s.join(' ');
+ }
+
+ int get length => _classListLength(_classListOf(_element));
+ bool get isEmpty => length == 0;
+ bool get isNotEmpty => length != 0;
+
+ void clear() {
+ _element.className = '';
+ }
+
+ bool contains(String value) {
+ return _contains(_element, value);
+ }
+
+ bool add(String value) {
+ return _add(_element, value);
+ }
+
+ bool remove(Object value) {
+ return value is String && _remove(_element, value);
+ }
+
+ bool toggle(String value, [bool shouldAdd]) {
+ return _toggle(_element, value, shouldAdd);
+ }
+
+ void addAll(Iterable<String> iterable) {
+ _addAll(_element, iterable);
+ }
+
+ void removeAll(Iterable<String> iterable) {
+ _removeAll(_element, iterable);
+ }
+
+ void retainAll(Iterable<String> iterable) {
+ _removeWhere(_element, iterable.toSet().contains, false);
+ }
+
+ void removeWhere(bool test(String name)) {
+ _removeWhere(_element, test, true);
+ }
+
+ void retainWhere(bool test(String name)) {
+ _removeWhere(_element, test, false);
+ }
+
+ static bool _contains(Element _element, String value) {
+ return _classListContains(_classListOf(_element), value);
+ }
+
+ static bool _add(Element _element, String value) {
+ DomTokenList list = _classListOf(_element);
+ // Compute returned result independently of action upon the set. One day we
+ // will be able to optimize it way if unused.
+ bool added = !_classListContains(list, value);
+ _classListAdd(list, value);
+ return added;
+ }
+
+ static bool _remove(Element _element, String value) {
+ DomTokenList list = _classListOf(_element);
+ bool removed = _classListContains(list, value);
+ _classListRemove(list, value);
+ return removed;
+ }
+
+ static bool _toggle(Element _element, String value, bool shouldAdd) {
+ // There is no value that can be passed as the second argument of
+ // DomTokenList.toggle that behaves the same as passing one argument.
+ // `null` is seen as false, meaning 'remove'.
+ return shouldAdd == null
+ ? _toggleDefault(_element, value)
+ : _toggleOnOff(_element, value, shouldAdd);
+ }
+
+ static bool _toggleDefault(Element _element, String value) {
+ DomTokenList list = _classListOf(_element);
+ return _classListToggle1(list, value);
+ }
+
+ static bool _toggleOnOff(Element _element, String value, bool shouldAdd) {
+ DomTokenList list = _classListOf(_element);
+ // IE's toggle does not take a second parameter. We would prefer:
+ //
+ // return _classListToggle2(list, value, shouldAdd);
+ //
+ if (shouldAdd) {
+ _classListAdd(list, value);
+ return true;
+ } else {
+ _classListRemove(list, value);
+ return false;
+ }
+ }
+
+ static void _addAll(Element _element, Iterable<String> iterable) {
+ DomTokenList list = _classListOf(_element);
+ for (String value in iterable) {
+ _classListAdd(list, value);
+ }
+ }
+
+ static void _removeAll(Element _element, Iterable<String> iterable) {
+ DomTokenList list = _classListOf(_element);
+ for (var value in iterable) {
+ _classListRemove(list, value);
+ }
+ }
+
+ static void _removeWhere(
+ Element _element, bool test(String name), bool doRemove) {
+ DomTokenList list = _classListOf(_element);
+ int i = 0;
+ while (i < _classListLength(list)) {
+ String item = list.item(i);
+ if (doRemove == test(item)) {
+ _classListRemove(list, item);
+ } else {
+ ++i;
+ }
+ }
+ }
+
+ // A collection of static methods for DomTokenList. These methods are a
+ // work-around for the lack of annotations to express the full behaviour of
+ // the DomTokenList methods.
+
+ static DomTokenList _classListOf(Element e) =>
+ JS('returns:DomTokenList;creates:DomTokenList;effects:none;depends:all;',
+ '#.classList', e);
+
+ static int _classListLength(DomTokenList list) =>
+ JS('returns:JSUInt31;effects:none;depends:all;', '#.length', list);
+
+ static bool _classListContains(DomTokenList list, String value) =>
+ JS('returns:bool;effects:none;depends:all;',
+ '#.contains(#)', list, value);
+
+ static void _classListAdd(DomTokenList list, String value) {
+ // list.add(value);
+ JS('', '#.add(#)', list, value);
+ }
+
+ static void _classListRemove(DomTokenList list, String value) {
+ // list.remove(value);
+ JS('', '#.remove(#)', list, value);
+ }
+
+ static bool _classListToggle1(DomTokenList list, String value) {
+ return JS('bool', '#.toggle(#)', list, value);
+ }
+
+ static bool _classListToggle2(
+ DomTokenList list, String value, bool shouldAdd) {
+ return JS('bool', '#.toggle(#, #)', list, value, shouldAdd);
+ }
+}
/**
* Class representing a
@@ -38009,6 +39665,13 @@
if (element is svg.ScriptElement) {
return false;
}
+ // Firefox 37 has issues with creating foreign elements inside a
+ // foreignobject tag as SvgElement. We don't want foreignobject contents
+ // anyway, so just remove the whole tree outright. And we can't rely
+ // on IE recognizing the SvgForeignObject type, so go by tagName. Bug 23144
+ if (element is svg.SvgElement && element.tagName == 'foreignObject') {
+ return false;
+ }
if (element is svg.SvgElement) {
return true;
}
@@ -39103,7 +40766,7 @@
_hiddenAnchor.protocol == _loc.protocol) ||
(_hiddenAnchor.hostname == '' &&
_hiddenAnchor.port == '' &&
- _hiddenAnchor.protocol == ':');
+ (_hiddenAnchor.protocol == ':' || _hiddenAnchor.protocol == ''));
}
}
@@ -39137,29 +40800,46 @@
_ValidatingTreeSanitizer(this.validator) {}
void sanitizeTree(Node node) {
- void walk(Node node) {
- sanitizeNode(node);
+ void walk(Node node, Node parent) {
+ sanitizeNode(node, parent);
var child = node.lastChild;
while (child != null) {
// Child may be removed during the walk.
var nextChild = child.previousNode;
- walk(child);
+ walk(child, node);
child = nextChild;
}
}
- walk(node);
+ walk(node, null);
}
- void sanitizeNode(Node node) {
+ /// Aggressively try to remove node.
+ void _removeNode(Node node, Node parent) {
+ // If we have the parent, it's presumably already passed more sanitization or
+ // is the fragment, so ask it to remove the child. And if that fails try to
+ // set the outer html.
+ if (parent == null) {
+ node.remove();
+ } else {
+ parent._removeChild(node);
+ }
+ }
+
+ void sanitizeNode(Node node, Node parent) {
switch (node.nodeType) {
case Node.ELEMENT_NODE:
Element element = node;
+ if (element._hasCorruptedAttributes) {
+ window.console.warn('Removing element due to corrupted attributes on <${element}>');
+ _removeNode(node, parent);
+ break;
+ }
var attrs = element.attributes;
if (!validator.allowsElement(element)) {
window.console.warn(
'Removing disallowed element <${element.tagName}>');
- element.remove();
+ _removeNode(node, parent);
break;
}
@@ -39168,7 +40848,7 @@
if (!validator.allowsAttribute(element, 'is', isAttr)) {
window.console.warn('Removing disallowed type extension '
'<${element.tagName} is="$isAttr">');
- element.remove();
+ _removeNode(node, parent);
break;
}
}
@@ -39197,7 +40877,7 @@
case Node.CDATA_SECTION_NODE:
break;
default:
- node.remove();
+ _removeNode(node, parent);
}
}
}
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 4b331b7..63e26ae 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -4234,7 +4234,7 @@
@DomName('CSSStyleDeclaration')
- class CssStyleDeclaration extends NativeFieldWrapperClass2 with
+class CssStyleDeclaration extends NativeFieldWrapperClass2 with
CssStyleDeclarationBase {
factory CssStyleDeclaration() => new CssStyleDeclaration.css('');
@@ -4284,14 +4284,25 @@
@DomName('CSSStyleDeclaration.setProperty')
void setProperty(String propertyName, String value, [String priority]) {
- if (_supportsProperty(_camelCase(propertyName))) {
- return _setPropertyHelper(propertyName, value, priority);
- } else {
- return _setPropertyHelper(Device.cssPrefix + propertyName, value,
- priority);
- }
+ return _setPropertyHelper(_browserPropertyName(propertyName),
+ value, priority);
}
+ String _browserPropertyName(String propertyName) {
+ String name = _readCache(propertyName);
+ if (name is String) return name;
+ if (_supportsProperty(_camelCase(propertyName))) {
+ name = propertyName;
+ } else {
+ name = Device.cssPrefix + propertyName;
+ }
+ _writeCache(propertyName, name);
+ return name;
+ }
+
+ static String _readCache(String key) => null;
+ static void _writeCache(String key, value) {}
+
static String _camelCase(String hyphenated) {
// The "ms" prefix is always lowercased.
return hyphenated.replaceFirst(new RegExp('^-ms-'), 'ms-').replaceAllMapped(
@@ -4382,6 +4393,9 @@
_elementCssStyleDeclarationSetIterable.forEach((e) =>
e.setProperty(propertyName, value, priority));
}
+
+
+
// Important note: CssStyleDeclarationSet does NOT implement every method
// available in CssStyleDeclaration. Some of the methods don't make so much
// sense in terms of having a resonable value to return when you're
@@ -12634,6 +12648,15 @@
* used when an explicit accessor is not available.
*/
ElementEvents get on => new ElementEvents(this);
+
+ /**
+ * Verify if any of the attributes that we use in the sanitizer look unexpected,
+ * possibly indicating DOM clobbering attacks.
+ *
+ * Those attributes are: attributes, lastChild, children, previousNode and tagName.
+ */
+ // Dartium isn't affected by these attacks, because it goes directly to the C++ API.
+ bool get _hasCorruptedAttributes => false;
@DomName('Element.offsetHeight')
@DocsEditable()
@@ -37276,6 +37299,12 @@
*
* If [shouldAdd] is true, then we always add that [value] to the element. If
* [shouldAdd] is false then we always remove [value] from the element.
+ *
+ * If this corresponds to one element, returns `true` if [value] is present
+ * after the operation, and returns `false` if [value] is absent after the
+ * operation.
+ *
+ * If this corresponds to many elements, `null` is always returned.
*/
bool toggle(String value, [bool shouldAdd]);
@@ -37302,7 +37331,7 @@
* If this corresponds to one element. Returns true if [value] was added to
* the set, otherwise false.
*
- * If this corresponds to many elements, null is always returned.
+ * If this corresponds to many elements, `null` is always returned.
*/
bool add(String value);
@@ -37343,6 +37372,10 @@
*/
void toggleAll(Iterable<String> iterable, [bool shouldAdd]);
}
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
/**
* A set (union) of the CSS classes that are present in a set of elements.
@@ -40394,6 +40427,13 @@
if (element is svg.ScriptElement) {
return false;
}
+ // Firefox 37 has issues with creating foreign elements inside a
+ // foreignobject tag as SvgElement. We don't want foreignobject contents
+ // anyway, so just remove the whole tree outright. And we can't rely
+ // on IE recognizing the SvgForeignObject type, so go by tagName. Bug 23144
+ if (element is svg.SvgElement && element.tagName == 'foreignObject') {
+ return false;
+ }
if (element is svg.SvgElement) {
return true;
}
@@ -40544,7 +40584,7 @@
_hiddenAnchor.protocol == _loc.protocol) ||
(_hiddenAnchor.hostname == '' &&
_hiddenAnchor.port == '' &&
- _hiddenAnchor.protocol == ':');
+ (_hiddenAnchor.protocol == ':' || _hiddenAnchor.protocol == ''));
}
}
@@ -40578,29 +40618,46 @@
_ValidatingTreeSanitizer(this.validator) {}
void sanitizeTree(Node node) {
- void walk(Node node) {
- sanitizeNode(node);
+ void walk(Node node, Node parent) {
+ sanitizeNode(node, parent);
var child = node.lastChild;
while (child != null) {
// Child may be removed during the walk.
var nextChild = child.previousNode;
- walk(child);
+ walk(child, node);
child = nextChild;
}
}
- walk(node);
+ walk(node, null);
}
- void sanitizeNode(Node node) {
+ /// Aggressively try to remove node.
+ void _removeNode(Node node, Node parent) {
+ // If we have the parent, it's presumably already passed more sanitization or
+ // is the fragment, so ask it to remove the child. And if that fails try to
+ // set the outer html.
+ if (parent == null) {
+ node.remove();
+ } else {
+ parent._removeChild(node);
+ }
+ }
+
+ void sanitizeNode(Node node, Node parent) {
switch (node.nodeType) {
case Node.ELEMENT_NODE:
Element element = node;
+ if (element._hasCorruptedAttributes) {
+ window.console.warn('Removing element due to corrupted attributes on <${element}>');
+ _removeNode(node, parent);
+ break;
+ }
var attrs = element.attributes;
if (!validator.allowsElement(element)) {
window.console.warn(
'Removing disallowed element <${element.tagName}>');
- element.remove();
+ _removeNode(node, parent);
break;
}
@@ -40609,7 +40666,7 @@
if (!validator.allowsAttribute(element, 'is', isAttr)) {
window.console.warn('Removing disallowed type extension '
'<${element.tagName} is="$isAttr">');
- element.remove();
+ _removeNode(node, parent);
break;
}
}
@@ -40638,7 +40695,7 @@
case Node.CDATA_SECTION_NODE:
break;
default:
- node.remove();
+ _removeNode(node, parent);
}
}
}
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
index 09f06ea..97d4fd7 100644
--- a/sdk/lib/io/http_parser.dart
+++ b/sdk/lib/io/http_parser.dart
@@ -334,6 +334,74 @@
}
}
+ // Process end of headers. Returns true if the parser should stop
+ // parsing and return. This will be in case of either an upgrade
+ // request or a request or response with an empty body.
+ bool _headersEnd() {
+ _headers._mutable = false;
+
+ _transferLength = _headers.contentLength;
+ // Ignore the Content-Length header if Transfer-Encoding
+ // is chunked (RFC 2616 section 4.4)
+ if (_chunked) _transferLength = -1;
+
+ // If a request message has neither Content-Length nor
+ // Transfer-Encoding the message must not have a body (RFC
+ // 2616 section 4.3).
+ if (_messageType == _MessageType.REQUEST &&
+ _transferLength < 0 &&
+ _chunked == false) {
+ _transferLength = 0;
+ }
+ if (_connectionUpgrade) {
+ _state = _State.UPGRADED;
+ _transferLength = 0;
+ }
+ _createIncoming(_transferLength);
+ if (_requestParser) {
+ _incoming.method =
+ new String.fromCharCodes(_method);
+ _incoming.uri =
+ Uri.parse(
+ new String.fromCharCodes(_uri_or_reason_phrase));
+ } else {
+ _incoming.statusCode = _statusCode;
+ _incoming.reasonPhrase =
+ new String.fromCharCodes(_uri_or_reason_phrase);
+ }
+ _method.clear();
+ _uri_or_reason_phrase.clear();
+ if (_connectionUpgrade) {
+ _incoming.upgraded = true;
+ _parserCalled = false;
+ var tmp = _incoming;
+ _closeIncoming();
+ _controller.add(tmp);
+ return true;
+ }
+ if (_transferLength == 0 ||
+ (_messageType == _MessageType.RESPONSE && _noMessageBody)) {
+ _reset();
+ var tmp = _incoming;
+ _closeIncoming();
+ _controller.add(tmp);
+ return false;
+ } else if (_chunked) {
+ _state = _State.CHUNK_SIZE;
+ _remainingContent = 0;
+ } else if (_transferLength > 0) {
+ _remainingContent = _transferLength;
+ _state = _State.BODY;
+ } else {
+ // Neither chunked nor content length. End of body
+ // indicated by close.
+ _state = _State.BODY;
+ }
+ _parserCalled = false;
+ _controller.add(_incoming);
+ return true;
+ }
+
// From RFC 2616.
// generic-message = start-line
// *(message-header CRLF)
@@ -487,8 +555,13 @@
throw new HttpException("Invalid response line");
}
} else {
- _expect(byte, _CharCode.CR);
- _state = _State.REQUEST_LINE_ENDING;
+ if (byte == _CharCode.CR) {
+ _state = _State.REQUEST_LINE_ENDING;
+ } else {
+ _expect(byte, _CharCode.LF);
+ _messageType = _MessageType.REQUEST;
+ _state = _State.HEADER_START;
+ }
}
break;
@@ -545,6 +618,9 @@
_headers = new _HttpHeaders(version);
if (byte == _CharCode.CR) {
_state = _State.HEADER_ENDING;
+ } else if (byte == _CharCode.LF) {
+ _state = _State.HEADER_ENDING;
+ _index--; // Make the new state see the LF again.
} else {
// Start of new header field.
_headerField.add(_toLowerCaseByte(byte));
@@ -566,6 +642,8 @@
case _State.HEADER_VALUE_START:
if (byte == _CharCode.CR) {
_state = _State.HEADER_VALUE_FOLDING_OR_ENDING;
+ } else if (byte == _CharCode.LF) {
+ _state = _State.HEADER_VALUE_FOLD_OR_END;
} else if (byte != _CharCode.SP && byte != _CharCode.HT) {
// Start of new header value.
_headerValue.add(byte);
@@ -576,6 +654,8 @@
case _State.HEADER_VALUE:
if (byte == _CharCode.CR) {
_state = _State.HEADER_VALUE_FOLDING_OR_ENDING;
+ } else if (byte == _CharCode.LF) {
+ _state = _State.HEADER_VALUE_FOLD_OR_END;
} else {
_headerValue.add(byte);
}
@@ -613,6 +693,9 @@
if (byte == _CharCode.CR) {
_state = _State.HEADER_ENDING;
+ } else if (byte == _CharCode.LF) {
+ _state = _State.HEADER_ENDING;
+ _index--; // Make the new state see the LF again.
} else {
// Start of new header field.
_headerField.add(_toLowerCaseByte(byte));
@@ -623,67 +706,11 @@
case _State.HEADER_ENDING:
_expect(byte, _CharCode.LF);
- _headers._mutable = false;
-
- _transferLength = _headers.contentLength;
- // Ignore the Content-Length header if Transfer-Encoding
- // is chunked (RFC 2616 section 4.4)
- if (_chunked) _transferLength = -1;
-
- // If a request message has neither Content-Length nor
- // Transfer-Encoding the message must not have a body (RFC
- // 2616 section 4.3).
- if (_messageType == _MessageType.REQUEST &&
- _transferLength < 0 &&
- _chunked == false) {
- _transferLength = 0;
- }
- if (_connectionUpgrade) {
- _state = _State.UPGRADED;
- _transferLength = 0;
- }
- _createIncoming(_transferLength);
- if (_requestParser) {
- _incoming.method =
- new String.fromCharCodes(_method);
- _incoming.uri =
- Uri.parse(
- new String.fromCharCodes(_uri_or_reason_phrase));
- } else {
- _incoming.statusCode = _statusCode;
- _incoming.reasonPhrase =
- new String.fromCharCodes(_uri_or_reason_phrase);
- }
- _method.clear();
- _uri_or_reason_phrase.clear();
- if (_connectionUpgrade) {
- _incoming.upgraded = true;
- _parserCalled = false;
- var tmp = _incoming;
- _closeIncoming();
- _controller.add(tmp);
+ if (_headersEnd()) {
return;
- }
- if (_transferLength == 0 ||
- (_messageType == _MessageType.RESPONSE && _noMessageBody)) {
- _reset();
- var tmp = _incoming;
- _closeIncoming();
- _controller.add(tmp);
- break;
- } else if (_chunked) {
- _state = _State.CHUNK_SIZE;
- _remainingContent = 0;
- } else if (_transferLength > 0) {
- _remainingContent = _transferLength;
- _state = _State.BODY;
} else {
- // Neither chunked nor content length. End of body
- // indicated by close.
- _state = _State.BODY;
+ break;
}
- _parserCalled = false;
- _controller.add(_incoming);
return;
case _State.CHUNK_SIZE_STARTING_CR:
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index 2d8ecab..ea1bd76 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -431,16 +431,16 @@
/**
* [ProcessResult] represents the result of running a non-interactive
- * process started with [:Process.run:].
+ * process started with [Process.run] or [Process.runSync].
*/
-abstract class ProcessResult {
+class ProcessResult {
/**
* Exit code for the process.
*
* See [Process.exitCode] for more information in the exit code
* value.
*/
- int get exitCode;
+ final int exitCode;
/**
* Standard output from the process. The value used for the
@@ -448,7 +448,7 @@
* `null` was used this value is of type `List<int> otherwise it is
* of type `String`.
*/
- get stdout;
+ final stdout;
/**
* Standard error from the process. The value used for the
@@ -456,12 +456,14 @@
* `null` was used this value is of type `List<int>
* otherwise it is of type `String`.
*/
- get stderr;
+ final stderr;
/**
- * Process id from the process.
+ * Process id of the process.
*/
- int get pid;
+ final int pid;
+
+ ProcessResult(this.pid, this.exitCode, this.stdout, this.stderr);
}
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index bcd5d07..ba0ac01 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -4797,13 +4797,7 @@
return fragment.nodes.where((e) => e is SvgElement).single;
}
- _AttributeClassSet _cssClassSet;
- CssClassSet get classes {
- if (_cssClassSet == null) {
- _cssClassSet = new _AttributeClassSet(this);
- }
- return _cssClassSet;
- }
+ CssClassSet get classes => new _AttributeClassSet(this);
List<Element> get children => new FilteredElementList<Element>(this);
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index deacd52..d480db3 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -5437,13 +5437,7 @@
return fragment.nodes.where((e) => e is SvgElement).single;
}
- _AttributeClassSet _cssClassSet;
- CssClassSet get classes {
- if (_cssClassSet == null) {
- _cssClassSet = new _AttributeClassSet(this);
- }
- return _cssClassSet;
- }
+ CssClassSet get classes => new _AttributeClassSet(this);
List<Element> get children => new FilteredElementList<Element>(this);
diff --git a/tests/co19/co19-analyzer2.status b/tests/co19/co19-analyzer2.status
index 8807107..b0072cf 100644
--- a/tests/co19/co19-analyzer2.status
+++ b/tests/co19/co19-analyzer2.status
@@ -6,6 +6,7 @@
WebPlatformTest/html/semantics/forms/the-textarea-element/textarea-type_t01: fail
LayoutTests/fast/forms/checkValidity-001_t01: fail
+Language/12_Expressions/29_Assignable_Expressions_A01_t08: StaticWarning
# TBF: infinite look: class A {const A();final m = const A();}
Language/12_Expressions/01_Constants_A17_t03: fail
@@ -67,7 +68,6 @@
Language/12_Expressions/15_Method_Invocation/2_Cascaded_Invocation_A01_t19: MissingStaticWarning
-Language/12_Expressions/29_Assignable_Expressions_A01_t09: MissingStaticWarning
Language/13_Statements/06_For/1_For_Loop_A01_t07: MissingStaticWarning
Language/13_Statements/06_For/1_For_Loop_A01_t08: MissingStaticWarning
Language/13_Statements/09_Switch_A10_t03: MissingStaticWarning
@@ -287,3 +287,6 @@
WebPlatformTest/html/semantics/forms/the-input-element/email_t02: StaticWarning # co19 issue 701
Language/12_Expressions/12_Instance_Creation/2_Const_A11_t01: MissingCompileTimeError # Issue 22010
Language/12_Expressions/12_Instance_Creation/2_Const_A11_t03: MissingCompileTimeError # Issue 22010
+Language/15_Types/4_Interface_Types_A10_t03: StaticWarning # co19 issue 745
+Language/15_Types/4_Interface_Types_A10_t07: StaticWarning # co19 issue 745
+Language/15_Types/4_Interface_Types_A10_t09: StaticWarning # co19 issue 745
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index 8a25345..0e54aec 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -3,6 +3,7 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dart2dart && $builder_tag == new_backend ]
+Language/12_Expressions/18_Assignment_A04_t09: RuntimeError # Issue 23015
LibTest/collection/ListBase/ListBase_class_A01_t02: Crash # issue 19953
LibTest/collection/ListMixin/ListMixin_class_A01_t02: Crash # issue 19953
LibTest/core/List/List_class_A01_t02: Crash # issue 19953
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index a88dee0..e68755a 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -2,6 +2,8 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
+LayoutTests/fast/innerHTML/innerHTML-svg-write_t01: Skip # Temporary suppression, WIP alanknight
+
[ $compiler == dart2js ]
Language/03_Overview/1_Scoping_A02_t05: CompileTimeError # Issue 21072
Language/03_Overview/1_Scoping_A02_t06: CompileTimeError # Issue 21072
@@ -503,6 +505,7 @@
LayoutTests/fast/canvas/webgl/uniform-location_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/uninitialized-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/webgl-depth-texture_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/webgl-layer-update_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/css-generated-content/hit-test-generated-content_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/css-generated-content/malformed-url_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css-generated-content/pseudo-animation-before-onload_t01: Pass, RuntimeError # Please triage this failure
@@ -700,7 +703,6 @@
LayoutTests/fast/dom/blur-contenteditable_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/dom/characterdata-api-arguments_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/computed-style-set-property_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/custom/document-register-svg-extends_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/custom/element-names_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/dom/dataset-xhtml_t01: RuntimeError # Please triage this failure
@@ -1990,7 +1992,6 @@
LayoutTests/fast/dom/characterdata-api-arguments_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/click-method-on-html-element_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/computed-style-set-property_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/containerNode_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/dom/css-delete-doc_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/css-innerHTML_t01: RuntimeError # Please triage this failure
@@ -2925,6 +2926,28 @@
[ $compiler == dart2js && $runtime == ff && $system == windows ]
LayoutTests/fast/dom/Window/window-scroll-arguments_t01: RuntimeError # Issue 22564
WebPlatformTest/html/syntax/parsing/math-parse_t03: RuntimeError # Issue 22564
+LayoutTests/fast/dom/Attr/access-after-element-destruction_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/HTMLOutputElement/htmloutputelement-value_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/Range/surroundContents-check-boundary-points_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/Range/surroundContents-for-detached-node_t01: RuntimeError # Please triage this failure
+LibTest/html/Element/insertAdjacentElement_A01_t01: RuntimeError # Please triage this failure
+LibTest/html/Element/insertAllBefore_A01_t01: RuntimeError # Please triage this failure
+LibTest/html/Element/insertAllBefore_A02_t01: RuntimeError # Please triage this failure
+LibTest/html/Element/insertBefore_A01_t01: RuntimeError # Please triage this failure
+LibTest/html/Element/insertBefore_A02_t01: RuntimeError # Please triage this failure
+LibTest/html/Element/nodes_A01_t02: RuntimeError # Please triage this failure
+LibTest/html/Element/replaceWith_A01_t01: RuntimeError # Please triage this failure
+LibTest/html/IFrameElement/children_A01_t02: RuntimeError # Please triage this failure
+LibTest/html/IFrameElement/insertAdjacentElement_A01_t01: RuntimeError # Please triage this failure
+LibTest/html/IFrameElement/insertAllBefore_A01_t01: RuntimeError # Please triage this failure
+LibTest/html/IFrameElement/insertAllBefore_A02_t01: RuntimeError # Please triage this failure
+LibTest/html/IFrameElement/insertBefore_A01_t01: RuntimeError # Please triage this failure
+LibTest/html/IFrameElement/insertBefore_A02_t01: RuntimeError # Please triage this failure
+LibTest/html/IFrameElement/nodes_A01_t02: RuntimeError # Please triage this failure
+LibTest/html/IFrameElement/nodes_setter_A01_t01: RuntimeError # Please triage this failure
+LibTest/html/IFrameElement/replaceWith_A01_t01: RuntimeError # Please triage this failure
+WebPlatformTest/dom/nodes/attributes/setAttributeNS_A03_t01: RuntimeError # Please triage this failure
+WebPlatformTest/html-templates/serializing-html-templates/outerhtml_t01: RuntimeError # Please triage this failure
[ $compiler == dart2js && $runtime == ff && $system != windows ]
LayoutTests/fast/canvas/canvas-resetTransform_t01: RuntimeError # Please triage this failure
@@ -3369,7 +3392,6 @@
LayoutTests/fast/dom/attribute-namespaces-get-set_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/characterdata-api-arguments_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/computed-style-set-property_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/custom/attribute-changed-callback_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/custom/constructor-calls-created-synchronously_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/custom/created-callback_t01: RuntimeError # Please triage this failure
@@ -4657,7 +4679,6 @@
LayoutTests/fast/dom/characterdata-api-arguments_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/comment-not-documentElement_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/computed-style-set-property_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/createDocumentType-ownerDocument_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/createElementNS-namespace-errors_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/custom/attribute-changed-callback_t01: RuntimeError # Please triage this failure
@@ -5893,7 +5914,6 @@
LayoutTests/fast/css/inherited-properties-rare-text_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/insertRule-font-face_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/insertRule-media_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css/invalid-hex-color_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/invalid-import-rule-insertion_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/invalid-predefined-color_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/invalid-rule-value_t01: RuntimeError # Please triage this failure
@@ -5971,7 +5991,6 @@
LayoutTests/fast/css/shadow-current-color_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/css/sheet-collection-link_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/shorthand-priority_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css/shorthand-setProperty-important_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/sibling-selectors_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/space-before-charset-external_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/sticky/parsing-position-sticky_t01: RuntimeError # Please triage this failure
@@ -6258,7 +6277,7 @@
LayoutTests/fast/dom/click-method-on-html-element_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/clone-node-form-elements_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/computed-style-set-property_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/clone-node-z-index_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/containerNode_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/createDocumentType-ownerDocument_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/createElementNS-namespace-errors_t01: RuntimeError # Please triage this failure
@@ -7913,7 +7932,6 @@
LayoutTests/fast/css/inherited-properties-rare-text_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/insertRule-font-face_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/insertRule-media_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css/invalid-hex-color_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/invalid-import-rule-insertion_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/invalid-predefined-color_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/invalid-rule-value_t01: RuntimeError # Please triage this failure
@@ -7991,7 +8009,6 @@
LayoutTests/fast/css/shadow-current-color_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/css/sheet-collection-link_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/shorthand-priority_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css/shorthand-setProperty-important_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/sibling-selectors_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/space-before-charset-external_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/sticky/parsing-position-sticky_t01: RuntimeError # Please triage this failure
@@ -8258,7 +8275,7 @@
LayoutTests/fast/dom/characterdata-api-arguments_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/click-method-on-html-element_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/computed-style-set-property_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/clone-node-z-index_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/containerNode_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/createDocumentType-ownerDocument_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/createElementNS-namespace-errors_t01: RuntimeError # Please triage this failure
diff --git a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
index a7bb1ba..b0bdf8d 100644
--- a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
+++ b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
@@ -28,8 +28,11 @@
"lib/src/resolution/semantic_visitor.dart": const [
"The method 'error"],
"lib/src/resolution/semantic_visitor_mixins.dart": const [
- "The method 'error",
- "Mixin' is never used."]
+ "The method 'error"],
+
+ // Uncalled type predicate. Keep while related predicates are used.
+ "lib/src/ssa/nodes.dart": const [
+ "The method 'isArray' is never called"],
};
void main() {
diff --git a/tests/compiler/dart2js/backend_dart/sexpr2_test.dart b/tests/compiler/dart2js/backend_dart/sexpr2_test.dart
index 3cff4de..fb55ec0 100644
--- a/tests/compiler/dart2js/backend_dart/sexpr2_test.dart
+++ b/tests/compiler/dart2js/backend_dart/sexpr2_test.dart
@@ -25,7 +25,7 @@
void checkOutput(String elementName,
Element element,
String expectedOutput) {
- ExecutableDefinition ir = compiler.irBuilder.getIr(element);
+ RootNode ir = compiler.irBuilder.getIr(element);
if (expectedOutput == null) {
Expect.isNull(ir, "\nInput:\n${result.input}\n"
"No CPS IR expected for $element");
diff --git a/tests/compiler/dart2js/backend_dart/sexpr_unstringifier.dart b/tests/compiler/dart2js/backend_dart/sexpr_unstringifier.dart
index 1f06307..aa2c1ac 100644
--- a/tests/compiler/dart2js/backend_dart/sexpr_unstringifier.dart
+++ b/tests/compiler/dart2js/backend_dart/sexpr_unstringifier.dart
@@ -16,12 +16,12 @@
show DartType;
import 'package:compiler/src/elements/elements.dart'
show Entity, Element, Elements, Local, TypeVariableElement, ErroneousElement,
- TypeDeclarationElement, ExecutableElement;
+ TypeDeclarationElement, ExecutableElement, PublicName;
import 'package:compiler/src/elements/modelx.dart'
show ErroneousElementX, TypeVariableElementX;
import 'package:compiler/src/tree/tree.dart' show LiteralDartString;
import 'package:compiler/src/universe/universe.dart'
- show Selector, SelectorKind;
+ show Selector, SelectorKind, CallStructure;
import 'package:compiler/src/cps_ir/cps_ir_nodes.dart';
/// Used whenever a node constructed by [SExpressionUnstringifier] needs a
@@ -190,7 +190,8 @@
} else {
kind = SelectorKind.CALL;
}
- return new Selector(kind, name, null, argumentCount);
+ return new Selector(kind, new PublicName(name),
+ new CallStructure.unnamed(argumentCount));
}
/// Returns the tokens in s. Note that string literals are not necessarily
@@ -317,7 +318,7 @@
tokens.consumeEnd();
return new FunctionDefinition(element, thisParameter, parameters,
- new RunnableBody(body, cont), null, null);
+ new Body(body, cont), null, null);
}
/// (IsTrue arg)
@@ -411,7 +412,7 @@
List<Primitive> args = parsePrimitiveList();
tokens.consumeEnd();
- return new InvokeContinuation(cont, args, recursive: isRecursive);
+ return new InvokeContinuation(cont, args, isRecursive: isRecursive);
}
/// (InvokeMethod receiver method (args) cont)
diff --git a/tests/compiler/dart2js/interceptor_almost_constant_test.dart b/tests/compiler/dart2js/interceptor_almost_constant_test.dart
new file mode 100644
index 0000000..f32c3f4
--- /dev/null
+++ b/tests/compiler/dart2js/interceptor_almost_constant_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
+import 'compiler_helper.dart';
+
+const String TEST_ONE = r"""
+ foo(b) {
+ var a = b ? [1,2,3] : null;
+ print(a.first);
+ }
+""";
+
+main() {
+ asyncTest(() => Future.wait([
+ // Check that almost-constant interceptor is used.
+ compile(TEST_ONE, entry: 'foo', check: (String generated) {
+ String re = r'a && [\w\.]*_methods';
+ Expect.isTrue(generated.contains(new RegExp(re)), 'contains /$re/');
+ })
+ ]));
+}
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_basic_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_basic_test.dart
index 902ea6b..5b0b557 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_basic_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_basic_test.dart
@@ -111,8 +111,8 @@
print(new Set.from([1, 2, 3]));
}""", r"""
function() {
- P.print(P.Set_Set());
- P.print(P.Set_Set$from([1, 2, 3]));
+ P.print(P.Set_Set(null));
+ P.print(P.Set_Set$from([1, 2, 3], null));
return null;
}"""),
// Call synthetic constructor.
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_constructor_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_constructor_test.dart
index 13547488..e77d5cd 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_constructor_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_constructor_test.dart
@@ -164,6 +164,56 @@
v0.Bar$5$q$w$y$z("x", null, "w", "y", "z");
return v0;
}"""),
+ const TestEntry(r"""
+class C<T> {
+ foo() => T;
+}
+main() {
+ print(new C<int>().foo());
+}""", r"""
+function() {
+ P.print(V.C$(P.$int).foo$0());
+ return null;
+}"""),
+ const TestEntry(r"""
+class C<T> {
+ foo() => C;
+}
+main() {
+ print(new C<int>().foo());
+}""", r"""
+function() {
+ P.print(V.C$().foo$0());
+ return null;
+}"""),
+ const TestEntry.forMethod('generative_constructor(C#)', r"""
+class C<T> {
+ C() { print(T); }
+ foo() => print(T);
+}
+main() {
+ new C<int>();
+}""", r"""
+function($T) {
+ var v0;
+ v0 = H.setRuntimeTypeInfo(new V.C(), [$T]);
+ v0.C$0();
+ return v0;
+}"""),
+ const TestEntry.forMethod('generative_constructor(C#)', r"""
+class C<T> {
+ var x;
+ C() : x = new D<T>();
+}
+class D<T> {
+ foo() => T;
+}
+main() {
+ print(new C<int>().x.foo());
+}""", r"""
+function($T) {
+ return H.setRuntimeTypeInfo(new V.C(V.D$($T)), [$T]);
+}"""),
];
void main() {
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_interceptors_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_interceptors_test.dart
index e15bf3e..64515ce 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_interceptors_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_interceptors_test.dart
@@ -37,7 +37,7 @@
}""",
r"""
function() {
- var l, i, v0, x, j, v1;
+ var l, i, v0, x, j;
l = ["hest", ["h", "e", "s", "t"]];
P.print(J.getInterceptor$as(l).get$length(l));
i = 0;
@@ -48,8 +48,8 @@
x = J.getInterceptor$as(l).$index(l, i);
j = 0;
while (true) {
- v1 = J.getInterceptor$as(x).get$length(x);
- if (P.identical(J.getInterceptor$n(j).$lt(j, v1), true)) {
+ v0 = J.getInterceptor$as(x).get$length(x);
+ if (P.identical(J.getInterceptor$n(j).$lt(j, v0), true)) {
P.print(J.getInterceptor$as(x).$index(x, j));
j = J.getInterceptor$ns(j).$add(j, 1);
} else {
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_runtime_types_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_runtime_types_test.dart
index 86f8260..debe5b0 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_runtime_types_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_runtime_types_test.dart
@@ -43,6 +43,29 @@
function() {
return P.print($createType($typeToString($getSubstitutedTypeArgument(this, "\$asC", 1))));
}"""),
+ const TestEntry.forMethod('function(C#foo)', r"""
+class C<T> {
+ foo() => new D<C<T>>();
+}
+class D<T> {
+ bar() => T;
+}
+main() {
+ print(new C<int>().foo().bar());
+}""", """
+function() {
+ return V.D\$([V.C, $getTypeArgument(this, 0)]);
+}"""),
+ const TestEntry.forMethod('generative_constructor(C#)', r"""
+class C<X, Y, Z> {
+ foo() => 'C<$X $Y, $Z>';
+}
+main() {
+ new C<C, int, String>().foo();
+}""", r"""
+function($X, $Y, $Z) {
+ return H.setRuntimeTypeInfo(new V.C(), [$X, $Y, $Z]);
+}"""),
];
void main() {
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart
index 29a42ad..9ea9201 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart
@@ -40,18 +40,15 @@
return compiler.enqueuer.codegen.generatedCode[mainFunction];
}
-js.Node getJsNodeForElement(Compiler compiler,
- Element element) {
+js.Node getJsNodeForElement(Compiler compiler, Element element) {
return compiler.enqueuer.codegen.generatedCode[element];
}
-ir.ExecutableDefinition getIrNodeForElement(Compiler compiler,
- Element element) {
+ir.RootNode getIrNodeForElement(Compiler compiler, Element element) {
return compiler.irBuilder.getIr(element);
}
-String getCodeForMethod(Compiler compiler,
- String name) {
+String getCodeForMethod(Compiler compiler, String name) {
Element foundElement;
for (Element element in compiler.enqueuer.codegen.generatedCode.keys) {
if (element.toString() == name) {
diff --git a/tests/compiler/dart2js/js_spec_string_test.dart b/tests/compiler/dart2js/js_spec_string_test.dart
index 8ebbfd7..876c87c 100644
--- a/tests/compiler/dart2js/js_spec_string_test.dart
+++ b/tests/compiler/dart2js/js_spec_string_test.dart
@@ -20,6 +20,10 @@
errorMessage = message;
throw "error";
}
+ reportError(spannable, kind, arguments) {
+ errorMessage = '$arguments'; // E.g. "{text: Duplicate tag 'new'.}"
+ throw "error";
+ }
noSuchMethod(_) => null;
}
@@ -28,10 +32,16 @@
{List returns,
List creates,
SideEffects expectedSideEffects,
+ NativeThrowBehavior expectedThrows,
+ bool expectedNew,
+ bool expectedGvn,
bool expectError: false}) {
List actualReturns = [];
List actualCreates = [];
SideEffects actualSideEffects;
+ NativeThrowBehavior actualThrows;
+ bool actualNew;
+ bool actualGvn;
Listener listener = new Listener();
try {
NativeBehavior.processSpecString(
@@ -39,18 +49,28 @@
null,
specString,
setSideEffects: (effects) { actualSideEffects = effects; },
+ setThrows: (b) { actualThrows = b; },
+ setIsAllocation: (b) { actualNew = b; },
+ setUseGvn: (b) { actualGvn = b; },
resolveType: (t) => t,
typesReturned: actualReturns, typesInstantiated: actualCreates,
objectType: OBJECT, nullType: NULL);
} catch (e) {
Expect.isTrue(expectError);
- Expect.isNotNull(listener.errorMessage, 'Internal error expected.');
+ Expect.isNotNull(listener.errorMessage, 'Error expected.');
return;
}
- Expect.isNull(listener.errorMessage, 'Unexpected internal error.');
- Expect.listEquals(returns, actualReturns, 'Unexpected returns.');
- Expect.listEquals(creates, actualCreates, 'Unexpected creates.');
+ Expect.isNull(listener.errorMessage, 'Unexpected error.');
+ if (returns != null) {
+ Expect.listEquals(returns, actualReturns, 'Unexpected returns.');
+ }
+ if (creates != null) {
+ Expect.listEquals(creates, actualCreates, 'Unexpected creates.');
+ }
Expect.equals(expectedSideEffects, actualSideEffects);
+ Expect.equals(expectedThrows, actualThrows);
+ Expect.equals(expectedNew, actualNew);
+ Expect.equals(expectedGvn, actualGvn);
}
void testWithSideEffects(String specString,
@@ -217,6 +237,8 @@
testWithSideEffects('returns:A;', returns: ['A'], creates: []);
testWithSideEffects('returns:A|B;', returns: ['A', 'B'], creates: []);
testWithSideEffects('returns:A|B|C;', returns: ['A', 'B', 'C'], creates: []);
+ testWithSideEffects('returns: A| B |C ;',
+ returns: ['A', 'B', 'C'], creates: []);
testWithSideEffects('creates:void;', expectError: true);
testWithSideEffects('creates:;', expectError: true);
@@ -236,4 +258,28 @@
returns: ['A', 'B'], creates: ['A', 'C']);
testWithSideEffects(' returns:A|B|C; creates:A; ',
returns: ['A', 'B', 'C'], creates: ['A']);
+
+ test('throws:must', expectedThrows: NativeThrowBehavior.MUST);
+ test('throws:may', expectedThrows: NativeThrowBehavior.MAY);
+ test('throws:never', expectedThrows: NativeThrowBehavior.NEVER);
+ test('throws:null(1)',
+ expectedThrows:
+ NativeThrowBehavior.MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS);
+
+ test('new:true', expectedNew: true);
+ test('new:false', expectedNew: false);
+ test('returns:A;new:true', returns: ['A'], expectedNew: true);
+ test(' new : true ; returns:A;', returns: ['A'], expectedNew: true);
+ test('new:true;returns:A;new:true', expectError: true);
+
+ test('gvn:true', expectedGvn: true);
+ test('gvn:false', expectedGvn: false);
+ test('returns:A;gvn:true', returns: ['A'], expectedGvn: true);
+ test(' gvn : true ; returns:A;', returns: ['A'], expectedGvn: true);
+ test('gvn:true;returns:A;gvn:true', expectError: true);
+
+ test('gvn: true; new: true', expectError: true);
+ test('gvn: true; new: false', expectedGvn: true, expectedNew: false);
+ test('gvn: false; new: true', expectedGvn: false, expectedNew: true);
+ test('gvn: false; new: false', expectedGvn: false, expectedNew: false);
}
diff --git a/tests/compiler/dart2js/minify_many_locals_test.dart b/tests/compiler/dart2js/minify_many_locals_test.dart
index b1379ae..75345a4 100644
--- a/tests/compiler/dart2js/minify_many_locals_test.dart
+++ b/tests/compiler/dart2js/minify_many_locals_test.dart
@@ -7,17 +7,23 @@
import 'package:expect/expect.dart';
import 'compiler_helper.dart';
+// TODO(johnniwinther): This value is some what arbitrary. With the old
+// [ResolvedVisitor] we could handle 2000, with the new [ResolvedVisitor] build
+// upon the [SemanticVisitor] we can handle <1300. Update (increase) the value
+// when the [SssBuilder] is no longer build upon the [ResolvedVisitor] .
+const int NUMBER_OF_PARAMETERS = 1250;
+
main() {
var buffer = new StringBuffer();
buffer.write("foo(");
- for (int i = 0; i < 2000; i++) {
+ for (int i = 0; i < NUMBER_OF_PARAMETERS; i++) {
buffer.write("x$i, ");
}
buffer.write("x) { int i = ");
- for (int i = 0; i < 2000; i++) {
+ for (int i = 0; i < NUMBER_OF_PARAMETERS; i++) {
buffer.write("x$i+");
}
- buffer.write("2000; return i; }");
+ buffer.write("$NUMBER_OF_PARAMETERS; return i; }");
String code = buffer.toString();
asyncTest(() => compile(code, entry: 'foo', minify: true)
diff --git a/tests/compiler/dart2js/no_such_method_enabled_test.dart b/tests/compiler/dart2js/no_such_method_enabled_test.dart
index c9da1a0..cb994a9 100644
--- a/tests/compiler/dart2js/no_such_method_enabled_test.dart
+++ b/tests/compiler/dart2js/no_such_method_enabled_test.dart
@@ -231,6 +231,57 @@
}));
}
+dummyImplTest11() {
+ String source = """
+class A {
+ noSuchMethod(Invocation x) {
+ print('foo');
+ throw 'foo';
+ }
+}
+main() {
+ print(new A().foo());
+}
+""";
+ Uri uri = new Uri(scheme: 'source');
+ var compiler = compilerFor(source, uri);
+ asyncTest(() => compiler.runCompiler(uri).then((_) {
+ Expect.isTrue(compiler.backend.enabledNoSuchMethod);
+ ClassElement clsA = findElement(compiler, 'A');
+ Expect.isTrue(
+ compiler.backend.noSuchMethodRegistry.otherImpls.contains(
+ clsA.lookupMember('noSuchMethod')));
+ Expect.isTrue(
+ compiler.backend.noSuchMethodRegistry.complexNoReturnImpls.contains(
+ clsA.lookupMember('noSuchMethod')));
+ }));
+}
+
+dummyImplTest12() {
+ String source = """
+class A {
+ noSuchMethod(Invocation x) {
+ return toString();
+ }
+}
+main() {
+ print(new A().foo());
+}
+""";
+ Uri uri = new Uri(scheme: 'source');
+ var compiler = compilerFor(source, uri);
+ asyncTest(() => compiler.runCompiler(uri).then((_) {
+ Expect.isTrue(compiler.backend.enabledNoSuchMethod);
+ ClassElement clsA = findElement(compiler, 'A');
+ Expect.isTrue(
+ compiler.backend.noSuchMethodRegistry.otherImpls.contains(
+ clsA.lookupMember('noSuchMethod')));
+ Expect.isTrue(
+ compiler.backend.noSuchMethodRegistry.complexReturningImpls.contains(
+ clsA.lookupMember('noSuchMethod')));
+ }));
+}
+
main() {
dummyImplTest();
dummyImplTest2();
@@ -242,4 +293,6 @@
dummyImplTest8();
dummyImplTest9();
dummyImplTest10();
+ dummyImplTest11();
+ dummyImplTest12();
}
diff --git a/tests/compiler/dart2js/private_test.dart b/tests/compiler/dart2js/private_test.dart
index df4c40a..5121422 100644
--- a/tests/compiler/dart2js/private_test.dart
+++ b/tests/compiler/dart2js/private_test.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:async';
import "package:expect/expect.dart";
import "package:async_helper/async_helper.dart";
import 'mock_compiler.dart';
@@ -41,127 +42,132 @@
''';
-void analyze(String text, [expectedWarnings]) {
- if (expectedWarnings == null) expectedWarnings = [];
- if (expectedWarnings is !List) expectedWarnings = [expectedWarnings];
+analyze(String text, [expectedWarnings]) {
+ return () {
+ if (expectedWarnings == null) expectedWarnings = [];
+ if (expectedWarnings is !List) expectedWarnings = [expectedWarnings];
- MockCompiler compiler = new MockCompiler.internal(analyzeOnly: true);
- compiler.registerSource(Uri.parse(PRIVATE_SOURCE_URI), PRIVATE_SOURCE);
- compiler.diagnosticHandler = (uri, int begin, int end, String message, kind) {
- SourceFile sourceFile = compiler.sourceFiles[uri.toString()];
- if (sourceFile != null) {
- print(sourceFile.getLocationMessage(message, begin, end));
- } else {
- print(message);
- }
+ MockCompiler compiler = new MockCompiler.internal(analyzeOnly: true);
+ compiler.registerSource(Uri.parse(PRIVATE_SOURCE_URI), PRIVATE_SOURCE);
+ compiler.diagnosticHandler =
+ (uri, int begin, int end, String message, kind) {
+ SourceFile sourceFile = compiler.sourceFiles[uri.toString()];
+ if (sourceFile != null) {
+ print(sourceFile.getLocationMessage(message, begin, end));
+ } else {
+ print(message);
+ }
+ };
+
+ String source = '''
+ library public;
+
+ import '$PRIVATE_SOURCE_URI';
+
+ void main() {
+ PublicClass publicClass;
+ $text
+ }
+ ''';
+ Uri uri = Uri.parse('src:public');
+ compiler.registerSource(uri, source);
+ return compiler.runCompiler(uri).then((_) {
+ compareWarningKinds(text, expectedWarnings, compiler.warnings);
+ });
};
-
- String source = '''
- library public;
-
- import '$PRIVATE_SOURCE_URI';
-
- void main() {
- PublicClass publicClass;
- $text
- }
- ''';
- Uri uri = Uri.parse('src:public');
- compiler.registerSource(uri, source);
- asyncTest(() => compiler.runCompiler(uri).then((_) {
- compareWarningKinds(text, expectedWarnings, compiler.warnings);
- }));
}
void main() {
- // Read from private variable.
- analyze('var value = _privateVariable;', MessageKind.CANNOT_RESOLVE);
- // Write to private variable.
- analyze('_privateVariable = 0;', MessageKind.CANNOT_RESOLVE);
- // Access private function.
- analyze('var value = _privateFunction;', MessageKind.CANNOT_RESOLVE);
- // Call private function.
- analyze('_privateFunction();', MessageKind.CANNOT_RESOLVE);
+ asyncTest(() => Future.forEach([
+ // Read from private variable.
+ analyze('var value = _privateVariable;', MessageKind.CANNOT_RESOLVE),
+ // Write to private variable.
+ analyze('_privateVariable = 0;', MessageKind.CANNOT_RESOLVE),
+ // Access private function.
+ analyze('var value = _privateFunction;', MessageKind.CANNOT_RESOLVE),
+ // Call private function.
+ analyze('_privateFunction();', MessageKind.CANNOT_RESOLVE),
- // Call unnamed (public) constructor on private class.
- analyze('new _PrivateClass();', MessageKind.CANNOT_RESOLVE);
- // Call public constructor on private class.
- analyze('new _PrivateClass.publicConstructor();',
- MessageKind.CANNOT_RESOLVE);
- // Call private constructor on private class.
- analyze('new _PrivateClass._privateConstructor();',
- MessageKind.CANNOT_RESOLVE);
- // Call public getter of private type.
- analyze('var value = publicClass.private;');
- // Read from private field on private class.
- analyze('var value = publicClass.private._privateField;',
- MessageKind.PRIVATE_ACCESS);
- // Write to private field on private class.
- analyze('publicClass.private._privateField = 0;',
- MessageKind.PRIVATE_ACCESS);
- // Call private getter on private class.
- analyze('var value = publicClass.private._privateGetter;',
- MessageKind.PRIVATE_ACCESS);
- // Call private setter on private class.
- analyze('publicClass.private._privateSetter = 0;',
- MessageKind.PRIVATE_ACCESS);
- // Access private method on private class.
- analyze('var value = publicClass.private._privateMethod;',
- MessageKind.PRIVATE_ACCESS);
- // Call private method on private class.
- analyze('publicClass.private._privateMethod();',
- MessageKind.PRIVATE_ACCESS);
+ // Call unnamed (public) constructor on private class.
+ analyze('new _PrivateClass();', MessageKind.CANNOT_RESOLVE),
+ // Call public constructor on private class.
+ analyze('new _PrivateClass.publicConstructor();',
+ MessageKind.CANNOT_RESOLVE),
+ // Call private constructor on private class.
+ analyze('new _PrivateClass._privateConstructor();',
+ MessageKind.CANNOT_RESOLVE),
+ // Call public getter of private type.
+ analyze('var value = publicClass.private;'),
+ // Read from private field on private class.
+ analyze('var value = publicClass.private._privateField;',
+ MessageKind.PRIVATE_ACCESS),
+ // Write to private field on private class.
+ analyze('publicClass.private._privateField = 0;',
+ MessageKind.PRIVATE_ACCESS),
+ // Call private getter on private class.
+ analyze('var value = publicClass.private._privateGetter;',
+ MessageKind.PRIVATE_ACCESS),
+ // Call private setter on private class.
+ analyze('publicClass.private._privateSetter = 0;',
+ MessageKind.PRIVATE_ACCESS),
+ // Access private method on private class.
+ analyze('var value = publicClass.private._privateMethod;',
+ MessageKind.PRIVATE_ACCESS),
+ // Call private method on private class.
+ analyze('publicClass.private._privateMethod();',
+ MessageKind.PRIVATE_ACCESS),
- // Read from public field on private class.
- analyze('var value = publicClass.private.publicField;');
- // Write to public field on private class.
- analyze('publicClass.private.publicField = 0;');
- // Call public getter on private class.
- analyze('var value = publicClass.private.publicGetter;');
- // Call public setter on private class.
- analyze('publicClass.private.publicSetter = 0;');
- // Access public method on private class.
- analyze('var value = publicClass.private.publicMethod;');
- // Call public method on private class.
- analyze('publicClass.private.publicMethod();');
+ // Read from public field on private class.
+ analyze('var value = publicClass.private.publicField;'),
+ // Write to public field on private class.
+ analyze('publicClass.private.publicField = 0;'),
+ // Call public getter on private class.
+ analyze('var value = publicClass.private.publicGetter;'),
+ // Call public setter on private class.
+ analyze('publicClass.private.publicSetter = 0;'),
+ // Access public method on private class.
+ analyze('var value = publicClass.private.publicMethod;'),
+ // Call public method on private class.
+ analyze('publicClass.private.publicMethod();'),
- // Call unnamed (public) constructor on public class.
- analyze('publicClass = new PublicClass();');
- // Call public constructor on public class.
- analyze('publicClass = new PublicClass.publicConstructor();');
- // Call private constructor on public class.
- analyze('publicClass = new PublicClass._privateConstructor();',
- MessageKind.PRIVATE_ACCESS);
- // Read from private field on public class.
- analyze('var value = publicClass._privateField;',
- MessageKind.PRIVATE_ACCESS);
- // Write to private field on public class.
- analyze('publicClass._privateField = 0;',
- MessageKind.PRIVATE_ACCESS);
- // Call private getter on public class.
- analyze('var value = publicClass._privateGetter;',
- MessageKind.PRIVATE_ACCESS);
- // Call private setter on public class.
- analyze('publicClass._privateSetter = 0;',
- MessageKind.PRIVATE_ACCESS);
- // Access private method on public class.
- analyze('var value = publicClass._privateMethod;',
- MessageKind.PRIVATE_ACCESS);
- // Call private method on public class.
- analyze('publicClass._privateMethod();',
- MessageKind.PRIVATE_ACCESS);
+ // Call unnamed (public) constructor on public class.
+ analyze('publicClass = new PublicClass();'),
+ // Call public constructor on public class.
+ analyze('publicClass = new PublicClass.publicConstructor();'),
+ // Call private constructor on public class.
+ analyze('publicClass = new PublicClass._privateConstructor();',
+ MessageKind.CANNOT_FIND_CONSTRUCTOR),
+ // Read from private field on public class.
+ analyze('var value = publicClass._privateField;',
+ MessageKind.PRIVATE_ACCESS),
+ // Write to private field on public class.
+ analyze('publicClass._privateField = 0;',
+ MessageKind.PRIVATE_ACCESS),
+ // Call private getter on public class.
+ analyze('var value = publicClass._privateGetter;',
+ MessageKind.PRIVATE_ACCESS),
+ // Call private setter on public class.
+ analyze('publicClass._privateSetter = 0;',
+ MessageKind.PRIVATE_ACCESS),
+ // Access private method on public class.
+ analyze('var value = publicClass._privateMethod;',
+ MessageKind.PRIVATE_ACCESS),
+ // Call private method on public class.
+ analyze('publicClass._privateMethod();',
+ MessageKind.PRIVATE_ACCESS),
- // Read from public field on public class.
- analyze('var value = publicClass.publicField;');
- // Write to public field on public class.
- analyze('publicClass.publicField = 0;');
- // Call public getter on public class.
- analyze('var value = publicClass.publicGetter;');
- // Call public setter on public class.
- analyze('publicClass.publicSetter = 0;');
- // Access public method on public class.
- analyze('var value = publicClass.publicMethod;');
- // Call public method on public class.
- analyze('publicClass.publicMethod();');
+ // Read from public field on public class.
+ analyze('var value = publicClass.publicField;'),
+ // Write to public field on public class.
+ analyze('publicClass.publicField = 0;'),
+ // Call public getter on public class.
+ analyze('var value = publicClass.publicGetter;'),
+ // Call public setter on public class.
+ analyze('publicClass.publicSetter = 0;'),
+ // Access public method on public class.
+ analyze('var value = publicClass.publicMethod;'),
+ // Call public method on public class.
+ analyze('publicClass.publicMethod();'),
+ ], (f) => f()));
}
diff --git a/tests/compiler/dart2js/semantic_visitor_test.dart b/tests/compiler/dart2js/semantic_visitor_test.dart
index fea44dc..cdacd2c 100644
--- a/tests/compiler/dart2js/semantic_visitor_test.dart
+++ b/tests/compiler/dart2js/semantic_visitor_test.dart
@@ -4,6 +4,7 @@
library dart2js.semantics_visitor_test;
+import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
import 'package:compiler/src/constants/expressions.dart';
@@ -34,6 +35,11 @@
final setter;
final constant;
final selector;
+ final parameters;
+ final body;
+ final target;
+ final targetType;
+ final initializers;
const Visit(this.method,
{this.element,
@@ -50,7 +56,12 @@
this.getter,
this.setter,
this.constant,
- this.selector});
+ this.selector,
+ this.parameters,
+ this.body,
+ this.target,
+ this.targetType,
+ this.initializers});
int get hashCode => toString().hashCode;
@@ -104,6 +115,21 @@
if (selector != null) {
sb.write(',selector=$selector');
}
+ if (parameters != null) {
+ sb.write(',parameters=$parameters');
+ }
+ if (body != null) {
+ sb.write(',body=$body');
+ }
+ if (target != null) {
+ sb.write(',target=$target');
+ }
+ if (targetType != null) {
+ sb.write(',targetType=$targetType');
+ }
+ if (initializers != null) {
+ sb.write(',initializers=$initializers');
+ }
return sb.toString();
}
}
@@ -113,15 +139,15 @@
final String code;
final /*Visit | List<Visit>*/ expectedVisits;
final String cls;
+ final String method;
const Test(this.code, this.expectedVisits)
- : cls = null, codeByPrefix = null;
- const Test.clazz(this.code, this.expectedVisits)
- : cls = 'C', codeByPrefix = null;
+ : cls = null, method = 'm', codeByPrefix = null;
+ const Test.clazz(this.code, this.expectedVisits,
+ {this.cls: 'C', this.method: 'm'})
+ : codeByPrefix = null;
const Test.prefix(this.codeByPrefix, this.code, this.expectedVisits)
- : cls = null;
-
- String get method => 'm';
+ : cls = null, method = 'm';
String toString() {
StringBuffer sb = new StringBuffer();
@@ -135,7 +161,8 @@
}
}
-const List<Test> TESTS = const [
+const Map<String, List<Test>> SEND_TESTS = const {
+ 'Parameters': const [
// Parameters
const Test('m(o) => o;',
const Visit(VisitKind.VISIT_PARAMETER_GET,
@@ -149,7 +176,8 @@
element: 'parameter(m#o)',
arguments: '(null,42)',
selector: 'Selector(call, call, arity=2)')),
-
+ ],
+ 'Local variables': const [
// Local variables
const Test('m() { var o; return o; }',
const Visit(VisitKind.VISIT_LOCAL_VARIABLE_GET,
@@ -163,7 +191,8 @@
element: 'variable(m#o)',
arguments: '(null,42)',
selector: 'Selector(call, call, arity=2)')),
-
+ ],
+ 'Local functions': const [
// Local functions
const Test('m() { o(a, b) {}; return o; }',
const Visit(VisitKind.VISIT_LOCAL_FUNCTION_GET,
@@ -173,7 +202,8 @@
element: 'function(m#o)',
arguments: '(null,42)',
selector: 'Selector(call, call, arity=2)')),
-
+ ],
+ 'Static fields': const [
// Static fields
const Test(
'''
@@ -285,7 +315,8 @@
const Visit(VisitKind.VISIT_STATIC_FIELD_INVOKE,
element: 'field(C#o)',
arguments: '(null,42)')),
-
+ ],
+ 'Static properties': const [
// Static properties
const Test(
'''
@@ -399,7 +430,8 @@
const Visit(VisitKind.VISIT_STATIC_GETTER_INVOKE,
element: 'getter(C#o)',
arguments: '(null,42)')),
-
+ ],
+ 'Static functions': const [
// Static functions
const Test(
'''
@@ -473,7 +505,8 @@
const Visit(VisitKind.VISIT_STATIC_FUNCTION_INVOKE,
element: 'function(C#o)',
arguments: '(null,42)')),
-
+ ],
+ 'Top level fields': const [
// Top level fields
const Test(
'''
@@ -521,7 +554,8 @@
const Visit(VisitKind.VISIT_TOP_LEVEL_FIELD_INVOKE,
element: 'field(o)',
arguments: '(null,42)')),
-
+ ],
+ 'Top level properties': const [
// Top level properties
const Test(
'''
@@ -571,7 +605,8 @@
const Visit(VisitKind.VISIT_TOP_LEVEL_GETTER_INVOKE,
element: 'getter(o)',
arguments: '(null,42)')),
-
+ ],
+ 'Top level functions': const [
// Top level functions
const Test(
'''
@@ -596,23 +631,37 @@
const Visit(VisitKind.VISIT_TOP_LEVEL_FUNCTION_INVOKE,
element: 'function(o)',
arguments: '(null,42)')),
-
+ ],
+ 'Dynamic properties': const [
// Dynamic properties
const Test('m(o) => o.foo;',
- const Visit(VisitKind.VISIT_DYNAMIC_PROPERTY_GET,
- receiver: 'o',
- name: 'foo')),
+ const [
+ const Visit(VisitKind.VISIT_DYNAMIC_PROPERTY_GET,
+ receiver: 'o',
+ name: 'foo'),
+ const Visit(VisitKind.VISIT_PARAMETER_GET,
+ element: 'parameter(m#o)'),
+ ]),
const Test('m(o) { o.foo = 42; }',
- const Visit(VisitKind.VISIT_DYNAMIC_PROPERTY_SET,
- receiver: 'o',
- name: 'foo',
- rhs: '42')),
+ const [
+ const Visit(VisitKind.VISIT_DYNAMIC_PROPERTY_SET,
+ receiver: 'o',
+ name: 'foo',
+ rhs: '42'),
+ const Visit(VisitKind.VISIT_PARAMETER_GET,
+ element: 'parameter(m#o)'),
+ ]),
const Test('m(o) { o.foo(null, 42); }',
- const Visit(VisitKind.VISIT_DYNAMIC_PROPERTY_INVOKE,
- receiver: 'o',
- name: 'foo',
- arguments: '(null,42)')),
-
+ const [
+ const Visit(VisitKind.VISIT_DYNAMIC_PROPERTY_INVOKE,
+ receiver: 'o',
+ name: 'foo',
+ arguments: '(null,42)'),
+ const Visit(VisitKind.VISIT_PARAMETER_GET,
+ element: 'parameter(m#o)'),
+ ]),
+ ],
+ 'This access': const [
// This access
const Test.clazz(
'''
@@ -630,7 +679,8 @@
''',
const Visit(VisitKind.VISIT_THIS_INVOKE,
arguments: '(null,42)')),
-
+ ],
+ 'This properties': const [
// This properties
const Test.clazz(
'''
@@ -728,7 +778,8 @@
const Visit(VisitKind.VISIT_THIS_PROPERTY_INVOKE,
name: 'foo',
arguments: '(null,42)')),
-
+ ],
+ 'Super fields': const [
// Super fields
const Test.clazz(
'''
@@ -765,7 +816,8 @@
const Visit(VisitKind.VISIT_SUPER_FIELD_INVOKE,
element: 'field(B#o)',
arguments: '(null,42)')),
-
+ ],
+ 'Super properties': const [
// Super properties
const Test.clazz(
'''
@@ -802,7 +854,8 @@
const Visit(VisitKind.VISIT_SUPER_GETTER_INVOKE,
element: 'getter(B#o)',
arguments: '(null,42)')),
-
+ ],
+ 'Super methods': const [
// Super methods
const Test.clazz(
'''
@@ -827,13 +880,15 @@
const Visit(VisitKind.VISIT_SUPER_METHOD_INVOKE,
element: 'function(B#o)',
arguments: '(null,42)')),
-
+ ],
+ 'Expression invoke': const [
// Expression invoke
const Test('m() => (a, b){}(null, 42);',
const Visit(VisitKind.VISIT_EXPRESSION_INVOKE,
receiver: '(a,b){}',
arguments: '(null,42)')),
-
+ ],
+ 'Class type literals': const [
// Class type literals
const Test(
'''
@@ -850,7 +905,8 @@
const Visit(VisitKind.VISIT_CLASS_TYPE_LITERAL_INVOKE,
constant: 'C',
arguments: '(null,42)')),
-
+ ],
+ 'Typedef type literals': const [
// Typedef type literals
const Test(
'''
@@ -867,7 +923,8 @@
const Visit(VisitKind.VISIT_TYPEDEF_TYPE_LITERAL_INVOKE,
constant: 'F',
arguments: '(null,42)')),
-
+ ],
+ 'Type variable type literals': const [
// Type variable type literals
const Test.clazz(
'''
@@ -887,6 +944,8 @@
element: 'type_variable(C#T)',
arguments: '(null,42)')),
+ ],
+ 'Dynamic type literals': const [
// Dynamic type literals
const Test(
'''
@@ -903,28 +962,32 @@
const Visit(VisitKind.VISIT_DYNAMIC_TYPE_LITERAL_INVOKE,
constant: 'dynamic',
arguments: '(null,42)')),*/
-
+ ],
+ 'Assert': const [
// Assert
const Test(
'''
m() { assert(false); }
''',
const Visit(VisitKind.VISIT_ASSERT, expression: 'false')),
-
+ ],
+ 'Logical and': const [
// Logical and
const Test(
'''
m() => true && false;
''',
const Visit(VisitKind.VISIT_LOGICAL_AND, left: 'true', right: 'false')),
-
+ ],
+ 'Logical or': const [
// Logical or
const Test(
'''
m() => true || false;
''',
const Visit(VisitKind.VISIT_LOGICAL_OR, left: 'true', right: 'false')),
-
+ ],
+ 'Is test': const [
// Is test
const Test(
'''
@@ -932,7 +995,8 @@
m() => 0 is C;
''',
const Visit(VisitKind.VISIT_IS, expression: '0', type: 'C')),
-
+ ],
+ 'Is not test': const [
// Is not test
const Test(
'''
@@ -940,15 +1004,17 @@
m() => 0 is! C;
''',
const Visit(VisitKind.VISIT_IS_NOT, expression: '0', type: 'C')),
-
- // Is test
+ ],
+ 'As test': const [
+ // As test
const Test(
'''
class C {}
m() => 0 as C;
''',
const Visit(VisitKind.VISIT_AS, expression: '0', type: 'C')),
-
+ ],
+ 'Binary operators': const [
// Binary operators
const Test(
'''
@@ -1053,6 +1119,8 @@
element: 'function(B#+)',
operator: '+',
right: '42')),
+ ],
+ 'Index': const [
// Index
const Test(
'''
@@ -1114,7 +1182,8 @@
setter: 'function(B#[]=)',
index: '42',
operator: '--')),
-
+ ],
+ 'Equals': const [
// Equals
const Test(
'''
@@ -1134,7 +1203,8 @@
const Visit(VisitKind.VISIT_SUPER_EQUALS,
element: 'function(B#==)',
right: '42')),
-
+ ],
+ 'Not equals': const [
// Not equals
const Test(
'''
@@ -1155,7 +1225,8 @@
const Visit(VisitKind.VISIT_SUPER_NOT_EQUALS,
element: 'function(B#==)',
right: '42')),*/
-
+ ],
+ 'Unary expression': const [
// Unary expression
const Test(
'''
@@ -1196,7 +1267,8 @@
m() => !0;
''',
const Visit(VisitKind.VISIT_NOT, expression: '0')),
-
+ ],
+ 'Index set': const [
// Index set
const Test(
'''
@@ -1215,7 +1287,8 @@
''',
const Visit(VisitKind.VISIT_SUPER_INDEX_SET,
element: 'function(B#[]=)', index: '1', rhs: '2')),
-
+ ],
+ 'Compound assignment': const [
// Compound assignment
const Test(
'''
@@ -1533,7 +1606,8 @@
const Visit(VisitKind.VISIT_SUPER_FIELD_FIELD_COMPOUND,
getter: 'field(B#a)', setter: 'field(A#a)',
operator: '+=', rhs: '42')),*/
-
+ ],
+ 'Compound index assignment': const [
// Compound index assignment
const Test(
'''
@@ -1555,7 +1629,8 @@
const Visit(VisitKind.VISIT_SUPER_COMPOUND_INDEX_SET,
getter: 'function(B#[])', setter: 'function(B#[]=)',
index: '1', operator: '+=', rhs: '42')),*/
-
+ ],
+ 'Prefix expression': const [
// Prefix expression
const Test(
'''
@@ -1777,8 +1852,9 @@
const Visit(VisitKind.VISIT_SUPER_FIELD_SETTER_PREFIX,
getter: 'field(A#a)', setter: 'setter(B#a)',
operator: '++')),
-
- // Prefix expression
+ ],
+ 'Postfix expression': const [
+ // Postfix expression
const Test(
'''
m(a) => a.b--;
@@ -1999,79 +2075,266 @@
const Visit(VisitKind.VISIT_SUPER_FIELD_SETTER_POSTFIX,
getter: 'field(A#a)', setter: 'setter(B#a)',
operator: '++')),
+ ],
+ 'Constructor invocations': const [
+ const Test(
+ '''
+ class Class {
+ const Class(a, b);
+ }
+ m() => const Class(true, 42);
+ ''',
+ const Visit(VisitKind.VISIT_CONST_CONSTRUCTOR_INVOKE,
+ constant: 'const Class(true, 42)')),
+ const Test(
+ '''
+ class Class {}
+ m() => new Class();
+ ''',
+ const Visit(VisitKind.VISIT_GENERATIVE_CONSTRUCTOR_INVOKE,
+ element: 'generative_constructor(Class#)',
+ arguments: '()',
+ type: 'Class',
+ selector: 'Selector(call, , arity=0)')),
+ const Test(
+ '''
+ class Class {
+ Class(a, b);
+ }
+ m() => new Class(true, 42);
+ ''',
+ const Visit(VisitKind.VISIT_GENERATIVE_CONSTRUCTOR_INVOKE,
+ element: 'generative_constructor(Class#)',
+ arguments: '(true,42)',
+ type: 'Class',
+ selector: 'Selector(call, , arity=2)')),
+ const Test(
+ '''
+ class Class {
+ Class.named(a, b);
+ }
+ m() => new Class.named(true, 42);
+ ''',
+ const Visit(VisitKind.VISIT_GENERATIVE_CONSTRUCTOR_INVOKE,
+ element: 'generative_constructor(Class#named)',
+ arguments: '(true,42)',
+ type: 'Class',
+ selector: 'Selector(call, named, arity=2)')),
+ const Test(
+ '''
+ class Class {
+ Class(a, b) : this._(a, b);
+ Class._(a, b);
+ }
+ m() => new Class(true, 42);
+ ''',
+ const Visit(VisitKind.VISIT_REDIRECTING_GENERATIVE_CONSTRUCTOR_INVOKE,
+ element: 'generative_constructor(Class#)',
+ arguments: '(true,42)',
+ type: 'Class',
+ selector: 'Selector(call, , arity=2)')),
+ const Test(
+ '''
+ class Class {
+ factory Class(a, b) => new Class._(a, b);
+ Class._(a, b);
+ }
+ m() => new Class(true, 42);
+ ''',
+ const Visit(VisitKind.VISIT_FACTORY_CONSTRUCTOR_INVOKE,
+ element: 'function(Class#)',
+ arguments: '(true,42)',
+ type: 'Class',
+ selector: 'Selector(call, , arity=2)')),
+ const Test(
+ '''
+ class Class<T> {
+ factory Class(a, b) = Class<int>.a;
+ factory Class.a(a, b) = Class<Class<T>>.b;
+ Class.b(a, b);
+ }
+ m() => new Class<double>(true, 42);
+ ''',
+ const Visit(VisitKind.VISIT_REDIRECTING_FACTORY_CONSTRUCTOR_INVOKE,
+ element: 'function(Class#)',
+ arguments: '(true,42)',
+ type: 'Class<double>',
+ target: 'generative_constructor(Class#b)',
+ targetType: 'Class<Class<int>>',
+ selector: 'Selector(call, , arity=2)')),
+ const Test(
+ '''
+ class Class {
+ Class(a, b);
+ }
+ m() => new Class.unresolved(true, 42);
+ ''',
+ const Visit(
+ VisitKind.ERROR_UNRESOLVED_CONSTRUCTOR_INVOKE,
+ arguments: '(true,42)')),
+ const Test(
+ '''
+ m() => new Unresolved(true, 42);
+ ''',
+ const Visit(
+ // TODO(johnniwinther): Update this to
+ // `VisitKind.ERROR_UNRESOLVED_CLASS_CONSTRUCTOR_INVOKE`.
+ VisitKind.ERROR_UNRESOLVED_CONSTRUCTOR_INVOKE,
+ arguments: '(true,42)')),
+ const Test(
+ '''
+ abstract class AbstractClass {}
+ m() => new AbstractClass();
+ ''',
+ const Visit(
+ VisitKind.ERROR_ABSTRACT_CLASS_CONSTRUCTOR_INVOKE,
+ element: 'generative_constructor(AbstractClass#)',
+ type: 'AbstractClass',
+ arguments: '()',
+ selector: 'Selector(call, , arity=0)')),
+ const Test(
+ '''
+ class Class {
+ factory Class(a, b) = Unresolved;
+ }
+ m() => new Class(true, 42);
+ ''',
+ const Visit(
+ VisitKind.ERROR_UNRESOLVED_REDIRECTING_FACTORY_CONSTRUCTOR_INVOKE,
+ element: 'function(Class#)',
+ arguments: '(true,42)',
+ type: 'Class',
+ selector: 'Selector(call, , arity=2)')),
+ const Test(
+ '''
+ class Class {
+ factory Class(a, b) = Class.named;
+ }
+ m() => new Class(true, 42);
+ ''',
+ const Visit(
+ VisitKind.ERROR_UNRESOLVED_REDIRECTING_FACTORY_CONSTRUCTOR_INVOKE,
+ element: 'function(Class#)',
+ arguments: '(true,42)',
+ type: 'Class',
+ selector: 'Selector(call, , arity=2)')),
+ const Test(
+ '''
+ class Class {
+ factory Class(a, b) = Class.named;
+ factory Class.named(a, b) = Class.unresolved;
+ }
+ m() => new Class(true, 42);
+ ''',
+ const Visit(
+ VisitKind.ERROR_UNRESOLVED_REDIRECTING_FACTORY_CONSTRUCTOR_INVOKE,
+ element: 'function(Class#)',
+ arguments: '(true,42)',
+ type: 'Class',
+ selector: 'Selector(call, , arity=2)')),
+ const Test(
+ '''
+ abstract class AbstractClass {
+ AbstractClass(a, b);
+ }
+ class Class {
+ factory Class(a, b) = AbstractClass;
+ }
+ m() => new Class(true, 42);
+ ''',
+ const Visit(
+ VisitKind.ERROR_UNRESOLVED_REDIRECTING_FACTORY_CONSTRUCTOR_INVOKE,
+ element: 'function(Class#)',
+ arguments: '(true,42)',
+ type: 'Class',
+ selector: 'Selector(call, , arity=2)')),
+ ],
+};
-];
+main(List<String> arguments) {
+ asyncTest(() => Future.forEach([
+ () {
+ return test(
+ arguments,
+ SEND_TESTS,
+ (elements) => new SemanticSendTestVisitor(elements));
+ },
+ ], (f) => f()));
+}
-main() {
+Future test(List<String> arguments,
+ Map<String, List<Test>> TESTS,
+ SemanticTestVisitor createVisitor(TreeElements elements)) {
Map<String, String> sourceFiles = {};
Map<String, Test> testMap = {};
StringBuffer mainSource = new StringBuffer();
int index = 0;
- TESTS.forEach((Test test) {
- StringBuffer testSource = new StringBuffer();
- if (test.codeByPrefix != null) {
- String prefixFilename = 'pre$index.dart';
- sourceFiles[prefixFilename] = test.codeByPrefix;
- testSource.writeln("import '$prefixFilename' as p;");
- }
+ TESTS.forEach((String group, List<Test> tests) {
+ if (arguments.isNotEmpty && !arguments.contains(group)) return;
- String filename = 'lib$index.dart';
- testSource.writeln(test.code);
- sourceFiles[filename] = testSource.toString();
- mainSource.writeln("import '$filename';");
- testMap[filename] = test;
- index++;
+ tests.forEach((Test test) {
+ StringBuffer testSource = new StringBuffer();
+ if (test.codeByPrefix != null) {
+ String prefixFilename = 'pre$index.dart';
+ sourceFiles[prefixFilename] = test.codeByPrefix;
+ testSource.writeln("import '$prefixFilename' as p;");
+ }
+
+ String filename = 'lib$index.dart';
+ testSource.writeln(test.code);
+ sourceFiles[filename] = testSource.toString();
+ mainSource.writeln("import '$filename';");
+ testMap[filename] = test;
+ index++;
+ });
});
mainSource.writeln("main() {}");
sourceFiles['main.dart'] = mainSource.toString();
- asyncTest(() {
- Compiler compiler = compilerFor(sourceFiles,
- options: ['--analyze-all', '--analyze-only']);
- return compiler.run(Uri.parse('memory:main.dart')).then((_) {
- testMap.forEach((String filename, Test test) {
- LibraryElement library = compiler.libraryLoader.lookupLibrary(
- Uri.parse('memory:$filename'));
- var expectedVisits = test.expectedVisits;
- if (expectedVisits is! List) {
- expectedVisits = [expectedVisits];
- }
- AstElement element;
- String cls = test.cls;
- String method = test.method;
- if (cls == null) {
- element = library.find(method);
- } else {
- ClassElement classElement = library.find(cls);
- Expect.isNotNull(classElement,
- "Class '$cls' not found in:\n"
- "${library.compilationUnit.script.text}");
- element = classElement.localLookup(method);
- }
- Expect.isNotNull(element, "Element '$method' not found in:\n"
- "${library.compilationUnit.script.text}");
- ResolvedAst resolvedAst = element.resolvedAst;
- SemanticTestVisitor visitor =
- new SemanticTestVisitor(resolvedAst.elements);
- try {
- compiler.withCurrentElement(resolvedAst.element, () {
- //print(resolvedAst.node.toDebugString());
- resolvedAst.node.accept(visitor);
- });
- } catch (e, s) {
- Expect.fail("$e:\n$s\nIn test:\n"
- "${library.compilationUnit.script.text}");
- }
- Expect.listEquals(expectedVisits, visitor.visits,
- "In test:\n"
- "${library.compilationUnit.script.text}");
- });
+ Compiler compiler = compilerFor(sourceFiles,
+ options: ['--analyze-all', '--analyze-only']);
+ return compiler.run(Uri.parse('memory:main.dart')).then((_) {
+ testMap.forEach((String filename, Test test) {
+ LibraryElement library = compiler.libraryLoader.lookupLibrary(
+ Uri.parse('memory:$filename'));
+ var expectedVisits = test.expectedVisits;
+ if (expectedVisits is! List) {
+ expectedVisits = [expectedVisits];
+ }
+ AstElement element;
+ String cls = test.cls;
+ String method = test.method;
+ if (cls == null) {
+ element = library.find(method);
+ } else {
+ ClassElement classElement = library.find(cls);
+ Expect.isNotNull(classElement,
+ "Class '$cls' not found in:\n"
+ "${library.compilationUnit.script.text}");
+ element = classElement.localLookup(method);
+ }
+ Expect.isNotNull(element, "Element '$method' not found in:\n"
+ "${library.compilationUnit.script.text}");
+ ResolvedAst resolvedAst = element.resolvedAst;
+ SemanticTestVisitor visitor = createVisitor(resolvedAst.elements);
+ try {
+ compiler.withCurrentElement(resolvedAst.element, () {
+ //print(resolvedAst.node.toDebugString());
+ resolvedAst.node.accept(visitor);
+ });
+ } catch (e, s) {
+ Expect.fail("$e:\n$s\nIn test:\n"
+ "${library.compilationUnit.script.text}");
+ }
+ Expect.listEquals(expectedVisits, visitor.visits,
+ "In test:\n"
+ "${library.compilationUnit.script.text}");
});
});
}
-class SemanticTestVisitor extends SemanticVisitor with SemanticSendVisitor {
+abstract class SemanticTestVisitor extends TraversalVisitor {
List<Visit> visits = <Visit>[];
SemanticTestVisitor(TreeElements elements) : super(elements);
@@ -2081,13 +2344,11 @@
internalError(Spannable spannable, String message) {
throw new SpannableAssertionFailure(spannable, message);
}
+}
- SemanticSendVisitor get sendVisitor => this;
+class SemanticSendTestVisitor extends SemanticTestVisitor {
- @override
- visitNode(Node node) {
- node.visitChildren(this);
- }
+ SemanticSendTestVisitor(TreeElements elements) : super(elements);
@override
visitAs(
@@ -2145,7 +2406,7 @@
@override
visitClassTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
arg) {
visits.add(new Visit(VisitKind.VISIT_CLASS_TYPE_LITERAL_GET,
constant: constant.getText()));
@@ -2154,7 +2415,7 @@
@override
visitClassTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
arg) {
@@ -2166,7 +2427,7 @@
@override
errorClassTypeLiteralSet(
SendSet node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
Node rhs,
arg) {
visits.add(new Visit(VisitKind.VISIT_CLASS_TYPE_LITERAL_INVOKE,
@@ -2222,6 +2483,7 @@
arg) {
visits.add(new Visit(VisitKind.VISIT_DYNAMIC_PROPERTY_GET,
receiver: receiver, name: selector.name));
+ apply(receiver, arg);
}
@override
@@ -2233,6 +2495,7 @@
arg) {
visits.add(new Visit(VisitKind.VISIT_DYNAMIC_PROPERTY_INVOKE,
receiver: receiver, name: selector.name, arguments: arguments));
+ apply(receiver, arg);
apply(arguments, arg);
}
@@ -2245,12 +2508,13 @@
arg) {
visits.add(new Visit(VisitKind.VISIT_DYNAMIC_PROPERTY_SET,
receiver: receiver, name: selector.name, rhs: rhs));
+ apply(receiver, arg);
}
@override
visitDynamicTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
arg) {
visits.add(new Visit(VisitKind.VISIT_DYNAMIC_TYPE_LITERAL_GET,
constant: constant.getText()));
@@ -2259,7 +2523,7 @@
@override
visitDynamicTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
arg) {
@@ -2270,7 +2534,7 @@
@override
errorDynamicTypeLiteralSet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
Node rhs,
arg) {
visits.add(new Visit(VisitKind.VISIT_DYNAMIC_TYPE_LITERAL_SET,
@@ -2702,7 +2966,7 @@
@override
visitTypedefTypeLiteralGet(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
arg) {
visits.add(new Visit(VisitKind.VISIT_TYPEDEF_TYPE_LITERAL_GET,
constant: constant.getText()));
@@ -2711,7 +2975,7 @@
@override
visitTypedefTypeLiteralInvoke(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
NodeList arguments,
Selector selector,
arg) {
@@ -2723,7 +2987,7 @@
@override
errorTypedefTypeLiteralSet(
SendSet node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
Node rhs,
arg) {
visits.add(new Visit(VisitKind.VISIT_TYPEDEF_TYPE_LITERAL_SET,
@@ -3344,7 +3608,7 @@
@override
errorClassTypeLiteralCompound(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
AssignmentOperator operator,
Node rhs,
arg) {
@@ -3356,7 +3620,7 @@
@override
errorDynamicTypeLiteralCompound(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
AssignmentOperator operator,
Node rhs,
arg) {
@@ -3380,7 +3644,7 @@
@override
errorTypedefTypeLiteralCompound(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
AssignmentOperator operator,
Node rhs,
arg) {
@@ -3401,7 +3665,7 @@
@override
errorClassTypeLiteralPrefix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
arg) {
visits.add(new Visit(VisitKind.ERROR_CLASS_TYPE_LITERAL_PREFIX,
@@ -3411,7 +3675,7 @@
@override
errorDynamicTypeLiteralPrefix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
arg) {
visits.add(new Visit(VisitKind.ERROR_DYNAMIC_TYPE_LITERAL_PREFIX,
@@ -3588,7 +3852,7 @@
@override
errorTypedefTypeLiteralPrefix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
arg) {
visits.add(new Visit(VisitKind.ERROR_TYPEDEF_TYPE_LITERAL_PREFIX,
@@ -3607,7 +3871,7 @@
@override
errorClassTypeLiteralPostfix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
arg) {
visits.add(new Visit(VisitKind.ERROR_CLASS_TYPE_LITERAL_POSTFIX,
@@ -3617,7 +3881,7 @@
@override
errorDynamicTypeLiteralPostfix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
arg) {
visits.add(new Visit(VisitKind.ERROR_DYNAMIC_TYPE_LITERAL_POSTFIX,
@@ -3794,7 +4058,7 @@
@override
errorTypedefTypeLiteralPostfix(
Send node,
- TypeConstantExpression constant,
+ ConstantExpression constant,
IncDecOperator operator,
arg) {
visits.add(new Visit(VisitKind.ERROR_TYPEDEF_TYPE_LITERAL_POSTFIX,
@@ -4015,6 +4279,151 @@
index: index, operator: operator));
apply(index, arg);
}
+
+ @override
+ errorUnresolvedClassConstructorInvoke(
+ NewExpression node,
+ Element constructor,
+ MalformedType type,
+ NodeList arguments,
+ Selector selector,
+ arg) {
+ // TODO(johnniwinther): Test [type] and [selector].
+ visits.add(new Visit(
+ VisitKind.ERROR_UNRESOLVED_CLASS_CONSTRUCTOR_INVOKE,
+ arguments: arguments));
+ apply(arguments, arg);
+ }
+
+ @override
+ errorUnresolvedConstructorInvoke(
+ NewExpression node,
+ Element constructor,
+ DartType type,
+ NodeList arguments,
+ Selector selector,
+ arg) {
+ // TODO(johnniwinther): Test [type] and [selector].
+ visits.add(new Visit(
+ VisitKind.ERROR_UNRESOLVED_CONSTRUCTOR_INVOKE,
+ arguments: arguments));
+ apply(arguments, arg);
+ }
+
+ @override
+ visitConstConstructorInvoke(
+ NewExpression node,
+ ConstructedConstantExpression constant,
+ arg) {
+ visits.add(new Visit(VisitKind.VISIT_CONST_CONSTRUCTOR_INVOKE,
+ constant: constant.getText()));
+ }
+
+ @override
+ visitFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ arg) {
+ visits.add(new Visit(
+ VisitKind.VISIT_FACTORY_CONSTRUCTOR_INVOKE,
+ element: constructor,
+ type: type,
+ arguments: arguments,
+ selector: selector));
+ apply(arguments, arg);
+ }
+
+ @override
+ visitGenerativeConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ arg) {
+ visits.add(new Visit(
+ VisitKind.VISIT_GENERATIVE_CONSTRUCTOR_INVOKE,
+ element: constructor,
+ type: type,
+ arguments: arguments,
+ selector: selector));
+ apply(arguments, arg);
+ }
+
+ @override
+ visitRedirectingFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ ConstructorElement effectiveTarget,
+ InterfaceType effectiveTargetType,
+ NodeList arguments,
+ Selector selector,
+ arg) {
+ visits.add(new Visit(
+ VisitKind.VISIT_REDIRECTING_FACTORY_CONSTRUCTOR_INVOKE,
+ element: constructor,
+ type: type,
+ target: effectiveTarget,
+ targetType: effectiveTargetType,
+ arguments: arguments,
+ selector: selector));
+ apply(arguments, arg);
+ }
+
+ @override
+ visitRedirectingGenerativeConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ arg) {
+ visits.add(new Visit(
+ VisitKind.VISIT_REDIRECTING_GENERATIVE_CONSTRUCTOR_INVOKE,
+ element: constructor,
+ type: type,
+ arguments: arguments,
+ selector: selector));
+ apply(arguments, arg);
+ }
+
+ @override
+ errorAbstractClassConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ arg) {
+ visits.add(new Visit(
+ VisitKind.ERROR_ABSTRACT_CLASS_CONSTRUCTOR_INVOKE,
+ element: constructor,
+ type: type,
+ arguments: arguments,
+ selector: selector));
+ apply(arguments, arg);
+ }
+
+ @override
+ errorUnresolvedRedirectingFactoryConstructorInvoke(
+ NewExpression node,
+ ConstructorElement constructor,
+ InterfaceType type,
+ NodeList arguments,
+ Selector selector,
+ arg) {
+ visits.add(new Visit(
+ VisitKind.ERROR_UNRESOLVED_REDIRECTING_FACTORY_CONSTRUCTOR_INVOKE,
+ element: constructor,
+ type: type,
+ arguments: arguments,
+ selector: selector));
+ apply(arguments, arg);
+ }
}
enum VisitKind {
@@ -4174,5 +4583,16 @@
VISIT_IS_NOT,
VISIT_AS,
+ VISIT_CONST_CONSTRUCTOR_INVOKE,
+ VISIT_GENERATIVE_CONSTRUCTOR_INVOKE,
+ VISIT_REDIRECTING_GENERATIVE_CONSTRUCTOR_INVOKE,
+ VISIT_FACTORY_CONSTRUCTOR_INVOKE,
+ VISIT_REDIRECTING_FACTORY_CONSTRUCTOR_INVOKE,
+
+ ERROR_UNRESOLVED_CLASS_CONSTRUCTOR_INVOKE,
+ ERROR_UNRESOLVED_CONSTRUCTOR_INVOKE,
+ ERROR_ABSTRACT_CLASS_CONSTRUCTOR_INVOKE,
+ ERROR_UNRESOLVED_REDIRECTING_FACTORY_CONSTRUCTOR_INVOKE,
+
// TODO(johnniwinther): Add tests for error cases.
}
diff --git a/tests/compiler/dart2js_extra/23056_test.dart b/tests/compiler/dart2js_extra/23056_test.dart
new file mode 100644
index 0000000..c8953f2
--- /dev/null
+++ b/tests/compiler/dart2js_extra/23056_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for http://dartbug.com/23056/
+// Ensure that Mixin prototypes are initialized before first use.
+
+// Mirrors is the only way to have a getter be equipped with metadata.
+@MirrorsUsed(targets: 'M', override: '*')
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+class M {
+ @NoInline()
+ bool get foo => true;
+}
+
+class A extends Object with M {
+ @NoInline()
+ bool get foo => super.foo;
+}
+
+@AssumeDynamic() @NoInline()
+bool hide(bool x) => x;
+
+main() {
+ Expect.isTrue((hide(true) ? new A() : new M()).foo);
+}
diff --git a/tests/compiler/dart2js_native/native_field_optimization_test.dart b/tests/compiler/dart2js_native/native_field_optimization_test.dart
new file mode 100644
index 0000000..405dccc
--- /dev/null
+++ b/tests/compiler/dart2js_native/native_field_optimization_test.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:_js_helper";
+import "package:expect/expect.dart";
+
+// Test that compiler is cautious with optimizations on native fields. The
+// motivation is that DOM properties are getters and setters with arbitrary
+// effects. Setting CSSStyleDeclaration.borderLeft can canonicalize the value
+// and changes the value of CSSStyleDeclaration.border.
+
+@Native("Foo")
+class Foo {
+ var a;
+ var b;
+ var ab;
+}
+
+Foo makeFoo() native;
+
+void setup() native """
+function Foo() { this.i = 0; }
+
+Object.defineProperty(Foo.prototype, 'a', {
+ get: function () { return (this._a || '') + ++this.i; },
+ set: function (v) { this._a = v.toLowerCase(); }
+});
+
+Object.defineProperty(Foo.prototype, 'b', {
+ get: function () { return this._b || ''; },
+ set: function (v) { this._b = v.toLowerCase(); }
+});
+
+Object.defineProperty(Foo.prototype, 'ab', {
+ get: function () { return this.a + ' ' + this.b; },
+ set: function (v) {
+ var s = v.split(' ');
+ this.a = s[0];
+ this.b = s[1];
+ }
+});
+
+makeFoo = function() { return new Foo() }
+""";
+
+
+test1() {
+ var f = makeFoo();
+ f.a = 'Hi';
+ f.b = 'There';
+ Expect.equals('hi1 there', f.ab);
+}
+
+test2() {
+ // Test for CSE. dart2js currently does CSE loads. Is this the right choice?
+ var f = makeFoo();
+ var a1 = f.a;
+ var b1 = f.b;
+ var a2 = f.a;
+ Expect.equals('1', a1);
+ if (a2 == a1) {
+ // We did CSE.
+ } else {
+ Expect.equals('2', a2);
+ }
+}
+
+test3() {
+ // Must not CSE over a native field store.
+ var f = makeFoo();
+ var a1 = f.a;
+ f.ab = 'X Y';
+ var a2 = f.a;
+ Expect.equals('1', a1);
+ Expect.equals('x2', a2);
+}
+
+test4() {
+ // Must not store-forward.
+ var f = makeFoo();
+ f.a = 'A';
+ var a2 = f.a;
+ Expect.equals('a1', a2);
+}
+
+main() {
+ setup();
+ (test1)();
+ (test2)();
+ (test3)();
+ (test4)();
+}
diff --git a/tests/corelib/uri_parse_test.dart b/tests/corelib/uri_parse_test.dart
index 2a0c980..1e9ceb7 100644
--- a/tests/corelib/uri_parse_test.dart
+++ b/tests/corelib/uri_parse_test.dart
@@ -9,37 +9,48 @@
var schemes = ["", "file", "ws", "ftp"];
var fragments = ["", "#", "#f", "#fragment", "#l:?/"];
var queries = ["", "?", "?q", "?query", "?q:/"];
- var paths = ["/", "/x", "/x/y", "/x/y/", "/x:y"];
+ var paths = ["/", "/x", "/x/y", "/x/y/", "/x:y", "x", "x/y", "x/y/"];
var userInfos = ["", "x", "xxx", "x:4", "xxx:444", "x:4:x"];
var hosts = ["", "h", "hhh", "h:4", "hhh:444", "[::1.2.3.4]"];
void check(uriString, scheme, fragment, query, path, user, host) {
- var uri = Uri.parse(uriString);
- Expect.equals(scheme, uri.scheme);
- var uriFragment = uri.fragment;
- if (fragment.startsWith('#')) uriFragment = "#$uriFragment";
- Expect.equals(fragment, uriFragment);
- var uriQuery = uri.query;
- if (query.startsWith('?')) uriQuery = "?$uriQuery";
- Expect.equals(query, uriQuery);
- Expect.equals(path, uri.path);
- Expect.equals(user, uri.userInfo);
- var uriHost = uri.host;
- if (host.startsWith("[")) uriHost = "[$uriHost]";
- if (uri.port != 0) uriHost += ":${uri.port}";
- Expect.equals(host, uriHost);
+ for (var uri in [Uri.parse(uriString),
+ Uri.parse(">\u{10000}>$uriString<\u{10000}<",
+ 4, uriString.length + 4),
+ Uri.parse("http://example.com/$uriString#?:/[]\"",
+ 19, uriString.length + 19),
+ Uri.parse(uriString * 3,
+ uriString.length, uriString.length * 2)]) {
+ String name = "$uriString -> $uri";
+ Expect.equals(scheme, uri.scheme, name);
+ var uriFragment = uri.fragment;
+ if (fragment.startsWith('#')) uriFragment = "#$uriFragment";
+ Expect.equals(fragment, uriFragment, name);
+ var uriQuery = uri.query;
+ if (query.startsWith('?')) uriQuery = "?$uriQuery";
+ Expect.equals(query, uriQuery, name);
+ Expect.equals(path, uri.path, name);
+ Expect.equals(user, uri.userInfo, name);
+ var uriHost = uri.host;
+ if (host.startsWith("[")) uriHost = "[$uriHost]";
+ if (uri.port != 0) uriHost += ":${uri.port}";
+ Expect.equals(host, uriHost, name);
+ }
}
for (var scheme in schemes) {
for (var fragment in fragments) {
for (var query in queries) {
for (var path in paths) {
+ // File scheme URIs always get a leading slash.
+ if (scheme == "file" && !path.startsWith('/')) continue;
for (var user in userInfos) {
for (var host in hosts) {
var auth = host;
var s = scheme;
if (user.isNotEmpty) auth = "$user@$auth";
if (auth.isNotEmpty) auth = "//$auth";
+ if (auth.isNotEmpty && !path.startsWith('/')) continue;
check("$scheme${scheme.isEmpty ? "" : ":"}"
"$auth$path$query$fragment",
scheme,
diff --git a/tests/html/custom/attribute_changed_callback_test.dart b/tests/html/custom/attribute_changed_callback_test.dart
index 3eaa446..d0c0e32 100644
--- a/tests/html/custom/attribute_changed_callback_test.dart
+++ b/tests/html/custom/attribute_changed_callback_test.dart
@@ -4,6 +4,7 @@
library attribute_changed_callback_test;
+import 'dart:async';
import 'dart:html';
import 'dart:js' as js;
import 'package:unittest/html_individual_config.dart';
@@ -31,8 +32,14 @@
static var invocations = [];
+ Completer completer;
+
void attributeChanged(name, oldValue, newValue) {
invocations.add('$name: $oldValue => $newValue');
+ if (completer != null) {
+ completer.complete('value changed to $newValue');
+ completer = null;
+ }
}
}
@@ -84,20 +91,31 @@
b.attributes.remove('data-v');
expect(B.invocations, ['data-v: x => null']);
});
- });
- group('unsupported_on_polyfill', () {
test('add, change ID', () {
B.invocations = [];
var b = new B();
+ var completer = new Completer();
+ b.completer = completer;
b.id = 'x';
- expect(B.invocations, ['created', 'id: null => x']);
-
- B.invocations = [];
- b.attributes.remove('id');
- expect(B.invocations, ['id: x => null']);
+ return completer.future
+ .then((_) => expect(B.invocations, ['created', 'id: null => x']))
+ .then((_) {
+ B.invocations = [];
+ var secondCompleter = new Completer();
+ b.completer = secondCompleter;
+ b.attributes.remove('id');
+ return secondCompleter.future;
+ })
+ .then((_) => expect(B.invocations, ['id: x => null']));
});
+ });
+
+ group('unsupported_on_polyfill', () {
+
+ // If these tests start passing, don't remove the status suppression. Move
+ // the tests to the fullYy_supported group.
test('add, change classes', () {
var b = new B();
diff --git a/tests/html/custom_elements_23127_test.dart b/tests/html/custom_elements_23127_test.dart
new file mode 100644
index 0000000..6386690
--- /dev/null
+++ b/tests/html/custom_elements_23127_test.dart
@@ -0,0 +1,126 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+// Regression test for http://dartbug.com/23127
+// Tests super calls to a custom element upgrade constructor with various
+// combinations of parameters and type arguments.
+
+library custom_elements_23127_test;
+import 'dart:async';
+import 'dart:html';
+import 'package:unittest/html_individual_config.dart';
+import 'package:unittest/unittest.dart';
+import 'utils.dart';
+
+abstract class B1 extends HtmlElement {
+ void action();
+
+ B1.created() : super.created() {
+ action();
+ }
+}
+
+abstract class B1T<T> extends HtmlElement {
+ void action();
+ var qq = false;
+ B1T.created() : super.created() {
+ action();
+ qq = this is T;
+ }
+}
+
+abstract class B2 extends HtmlElement {
+ void action();
+ var qq;
+ B2.created([a = 1, b = 2, c = 3])
+ : qq = callTwice(() => ++a * ++b), // [a] and [b] are boxed.
+ super.created() {
+ action();
+ qq = [qq, a, b, c];
+ }
+}
+
+abstract class B2T<T> extends HtmlElement {
+ void action();
+ var qq;
+ B2T.created([a = 1, b = 2, c = 3])
+ : qq = callTwice(() => ++a * ++b),
+ super.created() {
+ action();
+ qq = [this is T, qq, a, b, c];
+ }
+}
+
+class C1 extends B1 {
+ int z;
+ C1.created() : super.created();
+ action() => z = 3;
+}
+
+class C1T extends B1T {
+ int z;
+ C1T.created() : super.created();
+ action() => z = 3;
+}
+
+class C2 extends B2 {
+ int z;
+ C2.created() : super.created(20);
+ action() => z = 3;
+}
+
+class C2T extends B2T {
+ int z;
+ C2T.created() : super.created(20);
+ action() => z = 3;
+}
+
+
+
+var callTwice;
+
+main() {
+ useHtmlIndividualConfiguration();
+
+ setUp(() => customElementsReady);
+
+ callTwice = (f) { f(); return f(); };
+
+ group('baseline', () {
+ test('C1', () {
+ document.register('x-c1', C1);
+ C1 e = document.createElement('x-c1');
+ expect(e.z, 3);
+ });
+ });
+
+ group('c1t', () {
+ test('C1T', () {
+ document.register('x-c1t', C1T);
+ C1T e = document.createElement('x-c1t');
+ expect(e.z, 3);
+ expect(e.qq, true);
+ });
+ });
+
+ group('c2', () {
+ test('C2', () {
+ document.register('x-c2', C2);
+ C2 e = document.createElement('x-c2');
+ expect(e.z, 3);
+ expect(e.qq, [88, 22, 4, 3]);
+ });
+ });
+
+ group('c2t', () {
+ test('C2T', () {
+ document.register('x-c2t', C2T);
+ C2T e = document.createElement('x-c2t');
+ expect(e.z, 3);
+ expect(e.qq, [true, 88, 22, 4, 3]);
+ });
+ });
+
+}
diff --git a/tests/html/custom_elements_23127_test.html b/tests/html/custom_elements_23127_test.html
new file mode 100644
index 0000000..b0b68b5
--- /dev/null
+++ b/tests/html/custom_elements_23127_test.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <title> custom_elements_23127_test </title>
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <h1> Running custom_elements_23127_test </h1>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/tests/html/element_classes_svg_test.dart b/tests/html/element_classes_svg_test.dart
new file mode 100644
index 0000000..0acd2a7
--- /dev/null
+++ b/tests/html/element_classes_svg_test.dart
@@ -0,0 +1,200 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library ElementTest;
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:svg' as svg;
+
+// Test for `querySelectorAll(xxx).classes.op()` where the query returns mixed
+// Html and Svg elements.
+
+Element makeElementsContainer() {
+ var e = new Element.html(
+ '<ul class="yes foo">'
+ '<li class="yes quux qux">'
+ '</ul>');
+ final svgContent = r"""
+<svg version="1.1">
+ <circle class="yes qux"></circle>
+ <path class="yes classy"></path>
+</svg>""";
+ final svgElement = new svg.SvgElement.svg(svgContent);
+ e.append(svgElement);
+ return e;
+}
+
+Element elementsContainer;
+
+ElementList<Element> elementsSetup() {
+ elementsContainer = makeElementsContainer();
+ document.documentElement.children.add(elementsContainer);
+ var elements = document.querySelectorAll('.yes');
+ expect(elements.length, 4);
+ return elements;
+}
+
+void elementsTearDown() {
+ if (elementsContainer != null) {
+ document.documentElement.children.remove(elementsContainer);
+ elementsContainer = null;
+ }
+}
+
+/// Returns a canonical string for Set<String> and lists of Element's classes.
+String view(var e) {
+ if (e is Set) return '${e.toList()..sort()}';
+ if (e is Element) return view(e.classes);
+ if (e is Iterable) return '${e.map(view).toList()}';
+ throw new ArgumentError('Cannot make canonical view string for: $e}');
+}
+
+main() {
+ useHtmlConfiguration();
+
+ Set<String> extractClasses(Element el) {
+ final match = new RegExp('class="([^"]+)"').firstMatch(el.outerHtml);
+ return new LinkedHashSet.from(match[1].split(' '));
+ }
+
+ tearDown(elementsTearDown);
+
+ test('list_view', () {
+ // Test that the 'view' helper function is behaving.
+ var elements = elementsSetup();
+ expect(view(elements.classes), '[classy, foo, quux, qux, yes]');
+ expect(view(elements),
+ '[[foo, yes], [quux, qux, yes], [qux, yes], [classy, yes]]');
+ });
+
+ test('listClasses=', () {
+ var elements = elementsSetup();
+
+ elements.classes = ['foo', 'qux'];
+ expect(view(elements.classes), '[foo, qux]');
+ expect(view(elements), '[[foo, qux], [foo, qux], [foo, qux], [foo, qux]]');
+
+ var elements2 = document.querySelectorAll('.qux');
+ expect(view(elements2.classes), '[foo, qux]');
+ expect(view(elements2), '[[foo, qux], [foo, qux], [foo, qux], [foo, qux]]');
+
+ for (Element e in elements2) {
+ expect(e.classes, orderedEquals(['foo', 'qux']));
+ expect(extractClasses(e), orderedEquals(['foo', 'qux']));
+ }
+
+ elements.classes = [];
+ expect(view(elements2.classes), '[]');
+ expect(view(elements2), '[[], [], [], []]');
+ });
+
+ test('listMap', () {
+ var elements = elementsSetup();
+ expect(elements.classes.map((c) => c.toUpperCase()).toList(),
+ unorderedEquals(['YES', 'FOO', 'QUX', 'QUUX', 'CLASSY']));
+ });
+
+ test('listContains', () {
+ var elements = elementsSetup();
+ expect(elements.classes.contains('classy'), isTrue);
+ expect(elements.classes.contains('troll'), isFalse);
+ });
+
+
+ test('listAdd', () {
+ var elements = elementsSetup();
+ var added = elements.classes.add('lassie');
+ expect(added, isNull);
+
+ expect(view(elements.classes), '[classy, foo, lassie, quux, qux, yes]');
+ expect(view(elements),
+ '[[foo, lassie, yes], [lassie, quux, qux, yes], '
+ '[lassie, qux, yes], [classy, lassie, yes]]');
+ });
+
+ test('listRemove', () {
+ var elements = elementsSetup();
+ expect(elements.classes.remove('lassi'), isFalse);
+ expect(view(elements.classes), '[classy, foo, quux, qux, yes]');
+ expect(view(elements),
+ '[[foo, yes], [quux, qux, yes], [qux, yes], [classy, yes]]');
+
+ expect(elements.classes.remove('qux'), isTrue);
+ expect(view(elements.classes), '[classy, foo, quux, yes]');
+ expect(view(elements),
+ '[[foo, yes], [quux, yes], [yes], [classy, yes]]');
+ });
+
+ test('listToggle', () {
+ var elements = elementsSetup();
+ elements.classes.toggle('qux');
+ expect(view(elements.classes), '[classy, foo, quux, qux, yes]');
+ expect(view(elements),
+ '[[foo, qux, yes], [quux, yes], [yes], [classy, qux, yes]]');
+ });
+
+ test('listAddAll', () {
+ var elements = elementsSetup();
+ elements.classes.addAll(['qux', 'lassi', 'sassy']);
+ expect(view(elements.classes),
+ '[classy, foo, lassi, quux, qux, sassy, yes]');
+ expect(view(elements),
+ '[[foo, lassi, qux, sassy, yes], [lassi, quux, qux, sassy, yes], '
+ '[lassi, qux, sassy, yes], [classy, lassi, qux, sassy, yes]]');
+ });
+
+ test('listRemoveAll', () {
+ var elements = elementsSetup();
+ elements.classes.removeAll(['qux', 'classy', 'mumble']);
+ expect(view(elements.classes), '[foo, quux, yes]');
+ expect(view(elements),
+ '[[foo, yes], [quux, yes], [yes], [yes]]');
+
+ elements.classes.removeAll(['foo', 'yes']);
+ expect(view(elements.classes), '[quux]');
+ expect(view(elements),
+ '[[], [quux], [], []]');
+ });
+
+ test('listToggleAll', () {
+ var elements = elementsSetup();
+ elements.classes.toggleAll(['qux', 'mornin']);
+ expect(view(elements.classes), '[classy, foo, mornin, quux, qux, yes]');
+ expect(view(elements),
+ '[[foo, mornin, qux, yes], [mornin, quux, yes], '
+ '[mornin, yes], [classy, mornin, qux, yes]]');
+
+ });
+
+ test('listRetainAll', () {
+ var elements = elementsSetup();
+ elements.classes.retainAll(['bar', 'baz', 'classy', 'qux']);
+ expect(view(elements.classes), '[classy, qux]');
+ expect(view(elements), '[[], [qux], [qux], [classy]]');
+ });
+
+ test('listRemoveWhere', () {
+ var elements = elementsSetup();
+ elements.classes.removeWhere((s) => s.startsWith('q'));
+ expect(view(elements.classes), '[classy, foo, yes]');
+ expect(view(elements),
+ '[[foo, yes], [yes], [yes], [classy, yes]]');
+ });
+
+ test('listRetainWhere', () {
+ var elements = elementsSetup();
+ elements.classes.retainWhere((s) => s.startsWith('q'));
+ expect(view(elements.classes), '[quux, qux]');
+ expect(view(elements),
+ '[[], [quux, qux], [qux], []]');
+ });
+
+ test('listContainsAll', () {
+ var elements = elementsSetup();
+ expect(elements.classes.containsAll(['qux', 'mornin']), isFalse);
+ expect(elements.classes.containsAll(['qux', 'classy']), isTrue);
+ });
+}
diff --git a/tests/html/element_classes_test.dart b/tests/html/element_classes_test.dart
index d1d23ee..14af4bd 100644
--- a/tests/html/element_classes_test.dart
+++ b/tests/html/element_classes_test.dart
@@ -8,29 +8,53 @@
import 'dart:collection';
import 'dart:html';
-main() {
- useHtmlConfiguration();
+Element makeElement() => new Element.tag('div');
- Element makeElement() => new Element.tag('div');
-
- Element makeElementWithChildren() =>
- new Element.html("<div><br/><img/><input/></div>");
-
- Element makeElementWithClasses() =>
+Element makeElementWithClasses() =>
new Element.html('<div class="foo bar baz"></div>');
- Element makeListElement() =>
- new Element.html('<ul class="foo bar baz">'
- '<li class="quux qux"><li class="meta">'
- '<li class="classy lassy"><li class="qux lassy"></ul>');
+Set<String> makeClassSet() => makeElementWithClasses().classes;
- Set<String> makeClassSet() => makeElementWithClasses().classes;
+Element makeListElement() =>
+ new Element.html('<ul class="foo bar baz">'
+ '<li class="quux qux">'
+ '<li class="meta">'
+ '<li class="classy lassy">'
+ '<li class="qux lassy">'
+ '</ul>');
+
+Element listElement;
+
+ElementList<Element> listElementSetup() {
+ listElement = makeListElement();
+ document.documentElement.children.add(listElement);
+ return document.querySelectorAll('li');
+}
+
+void listElementTearDown() {
+ if (listElement != null) {
+ document.documentElement.children.remove(listElement);
+ listElement = null;
+ }
+}
+
+/// Returns a canonical string for Set<String> and lists of Element's classes.
+String view(var e) {
+ if (e is Set) return '${e.toList()..sort()}';
+ if (e is Element) return view(e.classes);
+ if (e is Iterable) return '${e.map(view).toList()}';
+ throw new ArgumentError('Cannot make canonical view string for: $e}');
+}
+
+main() {
+ useHtmlConfiguration();
Set<String> extractClasses(Element el) {
final match = new RegExp('class="([^"]+)"').firstMatch(el.outerHtml);
return new LinkedHashSet.from(match[1].split(' '));
}
+
test('affects the "class" attribute', () {
final el = makeElementWithClasses();
el.classes.add('qux');
@@ -168,8 +192,28 @@
expect(classes, orderedEquals(['qux','bar', 'foo']));
});
+ test('retainAll', () {
+ final classes = makeClassSet();
+ classes.retainAll(['bar', 'baz', 'qux']);
+ expect(classes, orderedEquals(['bar', 'baz']));
+ });
+
+ test('removeWhere', () {
+ final classes = makeClassSet();
+ classes.removeWhere((s) => s.startsWith('b'));
+ expect(classes, orderedEquals(['foo']));
+ });
+
+ test('retainWhere', () {
+ final classes = makeClassSet();
+ classes.retainWhere((s) => s.startsWith('b'));
+ expect(classes, orderedEquals(['bar', 'baz']));
+ });
+
test('containsAll', () {
final classes = makeClassSet();
+ expect(classes.containsAll(['foo', 'baz']), isTrue);
+ expect(classes.containsAll(['foo', 'qux']), isFalse);
expect(classes.containsAll(['foo', 'baz'].toSet()), isTrue);
expect(classes.containsAll(['foo', 'qux'].toSet()), isFalse);
});
@@ -196,13 +240,15 @@
expect(classes, orderedEquals(['foo', 'bar', 'aardvark', 'baz']));
});
- Element listElement;
+ tearDown(listElementTearDown);
- ElementList<Element> listElementSetup() {
- listElement = makeListElement();
- document.documentElement.children.add(listElement);
- return document.queryAll('li');
- }
+ test('list_view', () {
+ // Test that the 'view' helper function is behaving.
+ var elements = listElementSetup();
+ expect(view(elements.classes), '[classy, lassy, meta, quux, qux]');
+ expect(view(elements),
+ '[[quux, qux], [meta], [classy, lassy], [lassy, qux]]');
+ });
test('listClasses=', () {
var elements = listElementSetup();
@@ -214,24 +260,20 @@
}
elements.classes = [];
- for (Element e in elements) {
- expect(e.classes, []);
- }
- document.documentElement.children.remove(listElement);
+ expect(view(elements.classes), '[]');
+ expect(view(elements), '[[], [], [], []]');
});
test('listMap', () {
var elements = listElementSetup();
expect(elements.classes.map((c) => c.toUpperCase()).toList(),
unorderedEquals(['QUX', 'QUUX', 'META', 'CLASSY', 'LASSY']));
- document.documentElement.children.remove(listElement);
});
test('listContains', () {
var elements = listElementSetup();
expect(elements.classes.contains('lassy'), isTrue);
expect(elements.classes.contains('foo'), isFalse);
- document.documentElement.children.remove(listElement);
});
@@ -240,98 +282,85 @@
var added = elements.classes.add('lassie');
expect(added, isNull);
- expect(elements.classes,
- unorderedEquals(['lassie', 'qux', 'quux', 'meta', 'classy', 'lassy']));
- for (Element e in elements) {
- expect(e.classes, anyOf(unorderedEquals(['quux', 'qux', 'lassie']),
- unorderedEquals(['meta', 'lassie']),
- unorderedEquals(['classy', 'lassy', 'lassie']),
- unorderedEquals(['qux', 'lassy', 'lassie'])));
- }
- document.documentElement.children.remove(listElement);
+ expect(view(elements.classes), '[classy, lassie, lassy, meta, quux, qux]');
+ expect(view(elements),
+ '[[lassie, quux, qux], [lassie, meta], [classy, lassie, lassy], '
+ '[lassie, lassy, qux]]');
});
test('listRemove', () {
var elements = listElementSetup();
expect(elements.classes.remove('lassi'), isFalse);
- expect(elements.classes,
- unorderedEquals(['qux', 'quux', 'meta', 'classy', 'lassy']));
- for (Element e in elements) {
- expect(e.classes, anyOf(unorderedEquals(['quux', 'qux']),
- unorderedEquals(['meta']), unorderedEquals(['classy', 'lassy']),
- unorderedEquals(['qux', 'lassy'])));
- }
+ expect(view(elements.classes), '[classy, lassy, meta, quux, qux]');
+ expect(view(elements),
+ '[[quux, qux], [meta], [classy, lassy], [lassy, qux]]');
expect(elements.classes.remove('qux'), isTrue);
- expect(elements.classes,
- unorderedEquals(['quux', 'meta', 'classy', 'lassy']));
- for (Element e in elements) {
- expect(e.classes, anyOf(unorderedEquals(['quux']),
- unorderedEquals(['meta']), unorderedEquals(['classy', 'lassy']),
- unorderedEquals(['lassy'])));
- }
- document.documentElement.children.remove(listElement);
+ expect(view(elements.classes), '[classy, lassy, meta, quux]');
+ expect(view(elements), '[[quux], [meta], [classy, lassy], [lassy]]');
});
test('listToggle', () {
var elements = listElementSetup();
elements.classes.toggle('qux');
- expect(elements.classes,
- unorderedEquals(['qux', 'quux', 'meta', 'classy', 'lassy']));
- for (Element e in elements) {
- expect(e.classes, anyOf(unorderedEquals(['quux']),
- unorderedEquals(['meta', 'qux']), unorderedEquals(['classy', 'lassy',
- 'qux']), unorderedEquals(['lassy'])));
- }
- document.documentElement.children.remove(listElement);
+ expect(view(elements.classes), '[classy, lassy, meta, quux, qux]');
+ expect(view(elements),
+ '[[quux], [meta, qux], [classy, lassy, qux], [lassy]]');
});
test('listAddAll', () {
var elements = listElementSetup();
elements.classes.addAll(['qux', 'lassi', 'sassy']);
- expect(elements.classes,
- unorderedEquals(['qux', 'quux', 'meta', 'classy', 'lassy', 'sassy',
- 'lassi']));
- for (Element e in elements) {
- expect(e.classes, anyOf(
- unorderedEquals(['quux', 'qux', 'lassi', 'sassy']),
- unorderedEquals(['meta', 'qux', 'lassi', 'sassy']),
- unorderedEquals(['classy', 'lassy', 'qux', 'lassi','sassy']),
- unorderedEquals(['lassy', 'qux', 'lassi', 'sassy'])));
- }
- document.documentElement.children.remove(listElement);
+ expect(view(elements.classes),
+ '[classy, lassi, lassy, meta, quux, qux, sassy]');
+ expect(view(elements),
+ '[[lassi, quux, qux, sassy], [lassi, meta, qux, sassy], '
+ '[classy, lassi, lassy, qux, sassy], [lassi, lassy, qux, sassy]]');
});
test('listRemoveAll', () {
var elements = listElementSetup();
elements.classes.removeAll(['qux', 'lassy', 'meta']);
- expect(elements.classes,
- unorderedEquals(['quux','classy']));
- for (Element e in elements) {
- expect(e.classes, anyOf(unorderedEquals(['quux']),
- unorderedEquals([]), unorderedEquals(['classy'])));
- }
- document.documentElement.children.remove(listElement);
+ expect(view(elements.classes), '[classy, quux]');
+ expect(view(elements), '[[quux], [], [classy], []]');
+
});
test('listToggleAll', () {
var elements = listElementSetup();
elements.classes.toggleAll(['qux', 'meta', 'mornin']);
- expect(elements.classes,
- unorderedEquals(['qux', 'quux', 'meta', 'classy', 'lassy', 'mornin']));
- for (Element e in elements) {
- expect(e.classes, anyOf(unorderedEquals(['quux', 'meta', 'mornin']),
- unorderedEquals(['qux', 'mornin']),
- unorderedEquals(['classy', 'lassy', 'qux', 'mornin', 'meta']),
- unorderedEquals(['lassy', 'mornin', 'meta'])));
- }
- document.documentElement.children.remove(listElement);
+ expect(view(elements.classes), '[classy, lassy, meta, mornin, quux, qux]');
+ expect(view(elements),
+ '[[meta, mornin, quux], [mornin, qux], '
+ '[classy, lassy, meta, mornin, qux], [lassy, meta, mornin]]');
+
+ });
+
+ test('listRetainAll', () {
+ var elements = listElementSetup();
+ elements.classes.retainAll(['bar', 'baz', 'qux']);
+ expect(view(elements.classes), '[qux]');
+ expect(view(elements), '[[qux], [], [], [qux]]');
+ });
+
+ test('listRemoveWhere', () {
+ var elements = listElementSetup();
+ elements.classes.removeWhere((s) => s.startsWith('q'));
+ expect(view(elements.classes), '[classy, lassy, meta]');
+ expect(view(elements),
+ '[[], [meta], [classy, lassy], [lassy]]');
+ });
+
+ test('listRetainWhere', () {
+ var elements = listElementSetup();
+ elements.classes.retainWhere((s) => s.startsWith('q'));
+ expect(view(elements.classes), '[quux, qux]');
+ expect(view(elements), '[[quux, qux], [], [], [qux]]');
});
test('listContainsAll', () {
var elements = listElementSetup();
expect(elements.classes.containsAll(['qux', 'meta', 'mornin']), isFalse);
expect(elements.classes.containsAll(['qux', 'lassy', 'classy']), isTrue);
- document.documentElement.children.remove(listElement);
});
}
diff --git a/tests/html/html.status b/tests/html/html.status
index c367d6f..c9d468d 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -6,6 +6,7 @@
interactive_test: Skip # Must be run manually.
dromaeo_smoke_test: Skip # Issue 14521, 8257
cross_frame_test: Skip # Test reloads itself. Issue 18558
+svgelement_test/constructors: Skip # Temporary suppression, WIP alanknight
[ $compiler == none && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
custom/attribute_changed_callback_test/unsupported_on_polyfill: Fail # Issue 18931 (Disabled for Chrome 35 roll)
@@ -37,6 +38,7 @@
[ $compiler == dart2js && ($runtime == safari || $runtime == safarimobilesim || $runtime == ff || $ie) ]
custom/entered_left_view_test/viewless_document: Fail # Polyfill does not handle this
fontface_test: Fail # Fontface not supported on these.
+custom/attribute_changed_callback_test/unsupported_on_polyfill: Fail # Polyfill does not support
element_animate_test: Fail # Element.animate not supported on these browsers.
[ $compiler == none && $runtime == dartium && $system == macos]
@@ -52,6 +54,7 @@
isolates_test: Fail # Issue 13921
indexeddb_3_test: Skip # Issue 19578. Timeouts and RuntimeError
fileapi_test/getFile: Pass, Fail # Issue 20488
+node_validator_test/dom_clobbering: Skip # Dartium is immune to DOM clobbering, so the HTML passes through the sanitizer.
[ $compiler == none && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) && $mode == debug ]
websocket_test/websocket: Skip # Issue 17666
@@ -189,7 +192,6 @@
[ $runtime == ie11 ]
custom/document_register_type_extensions_test/single-parameter: Fail # Issue 13193.
canvasrenderingcontext2d_test/arc: Pass, Fail # Pixel unexpected value. Please triage this failure.
-node_validator_test: Pass, RuntimeError # Issues 20657, 20659.
worker_test/functional: Pass, Fail # Issues 20659.
transferables_test: Pass, Fail # Issues 20659.
@@ -378,9 +380,6 @@
[ $compiler == dart2js && ($runtime == drt || $runtime ==chrome) ]
wheelevent_test: Fail # Issue 12958
-[ $compiler == dart2js && $runtime == ff && $system == windows ]
-node_validator_test: Fail # Issue 22564
-
[ $compiler == dart2js && $runtime == chrome]
svgelement_test/supported_altGlyph: RuntimeError # Issue 22154
diff --git a/tests/html/node_validator_test.dart b/tests/html/node_validator_test.dart
index 3189ec3..46b2beb 100644
--- a/tests/html/node_validator_test.dart
+++ b/tests/html/node_validator_test.dart
@@ -4,11 +4,10 @@
library validator_test;
-import 'dart:async';
import 'dart:html';
import 'dart:svg' as svg;
import 'package:unittest/unittest.dart';
-import 'package:unittest/html_config.dart';
+import 'package:unittest/html_individual_config.dart';
import 'utils.dart';
@@ -19,6 +18,11 @@
var b = document.body.createFragment(reference,
treeSanitizer: nullSanitizer);
+ // Prevent a false pass when both the html and the reference both get entirely
+ // deleted, which is technically a match, but unlikely to be what we meant.
+ if (reference != '') {
+ expect(b.childNodes.length > 0, isTrue);
+ }
validateNodeTree(a, b);
}
@@ -47,9 +51,9 @@
}
main() {
- useHtmlConfiguration();
+ useHtmlIndividualConfiguration();
- group('DOM sanitization', () {
+ group('DOM_sanitization', () {
var validator = new NodeValidatorBuilder.common();
testHtml('allows simple constructs',
@@ -131,7 +135,7 @@
});
});
- group('URI sanitization', () {
+ group('URI_sanitization', () {
var recorder = new RecordingUriValidator();
var validator = new NodeValidatorBuilder()..allowHtml5(uriPolicy: recorder);
@@ -186,228 +190,237 @@
['s']);
});
- group('NodeValidationPolicy', () {
+ group('allowNavigation', () {
+ var validator = new NodeValidatorBuilder()..allowNavigation();
- group('allowNavigation', () {
- var validator = new NodeValidatorBuilder()..allowNavigation();
+ testHtml('allows anchor tags',
+ validator,
+ '<a href="#foo">foo</a>');
- testHtml('allows anchor tags',
+ testHtml('allows form elements',
+ validator,
+ '<form method="post" action="/foo"></form>');
+
+ testHtml('disallows script navigation',
+ validator,
+ '<a href="javascript:foo = 1">foo</a>',
+ '<a>foo</a>');
+
+ testHtml('disallows cross-site navigation',
+ validator,
+ '<a href="http://example.com">example.com</a>',
+ '<a>example.com</a>');
+
+ testHtml('blocks other elements',
+ validator,
+ '<a href="#foo"><b>foo</b></a>',
+ '<a href="#foo"></a>');
+
+ testHtml('blocks tag extension',
+ validator,
+ '<a is="x-foo"></a>',
+ '');
+ });
+
+ group('allowImages', () {
+ var validator = new NodeValidatorBuilder()..allowImages();
+
+ testHtml('allows images',
+ validator,
+ '<img src="/foo.jpg" alt="something" width="100" height="100"/>');
+
+ testHtml('blocks onerror',
+ validator,
+ '<img src="/foo.jpg" onerror="something"/>',
+ '<img src="/foo.jpg"/>');
+
+ testHtml('enforces same-origin',
+ validator,
+ '<img src="http://example.com/foo.jpg"/>',
+ '<img/>');
+ });
+
+ group('allowCustomElement', () {
+ var validator = new NodeValidatorBuilder()
+ ..allowCustomElement(
+ 'x-foo',
+ attributes: ['bar'],
+ uriAttributes: ['baz'])
+ ..allowHtml5();
+
+ testHtml('allows custom elements',
+ validator,
+ '<x-foo bar="something" baz="/foo.jpg"></x-foo>');
+
+
+ testHtml('validates custom tag URIs',
+ validator,
+ '<x-foo baz="http://example.com/foo.jpg"></x-foo>',
+ '<x-foo></x-foo>');
+
+ testHtml('blocks type extensions',
+ validator,
+ '<div is="x-foo"></div>',
+ '');
+
+ testHtml('blocks tags on non-matching elements',
+ validator,
+ '<div bar="foo"></div>',
+ '<div></div>');
+ });
+
+ group('allowTagExtension', () {
+ var validator = new NodeValidatorBuilder()
+ ..allowTagExtension(
+ 'x-foo',
+ 'div',
+ attributes: ['bar'],
+ uriAttributes: ['baz'])
+ ..allowHtml5();
+
+ testHtml('allows tag extensions',
+ validator,
+ '<div is="x-foo" bar="something" baz="/foo.jpg"></div>');
+
+ testHtml('blocks custom elements',
validator,
- '<a href="#foo">foo</a>');
-
- testHtml('allows form elements',
- validator,
- '<form method="post" action="/foo"></form>');
-
- testHtml('disallows script navigation',
- validator,
- '<a href="javascript:foo = 1">foo</a>',
- '<a>foo</a>');
-
- testHtml('disallows cross-site navigation',
- validator,
- '<a href="http://example.com">example.com</a>',
- '<a>example.com</a>');
-
- testHtml('blocks other elements',
- validator,
- '<a href="#foo"><b>foo</b></a>',
- '<a href="#foo"></a>');
-
- testHtml('blocks tag extension',
- validator,
- '<a is="x-foo"></a>',
- '');
- });
-
- group('allowImages', () {
- var validator = new NodeValidatorBuilder()..allowImages();
-
- testHtml('allows images',
- validator,
- '<img src="/foo.jpg" alt="something" width="100" height="100"/>');
-
- testHtml('blocks onerror',
- validator,
- '<img src="/foo.jpg" onerror="something"/>',
- '<img src="/foo.jpg"/>');
-
- testHtml('enforces same-origin',
- validator,
- '<img src="http://example.com/foo.jpg"/>',
- '<img/>');
- });
-
- group('allowCustomElement', () {
- var validator = new NodeValidatorBuilder()
- ..allowCustomElement(
- 'x-foo',
- attributes: ['bar'],
- uriAttributes: ['baz'])
- ..allowHtml5();
-
- testHtml('allows custom elements',
- validator,
- '<x-foo bar="something" baz="/foo.jpg"></x-foo>');
-
-
- testHtml('validates custom tag URIs',
- validator,
- '<x-foo baz="http://example.com/foo.jpg"></x-foo>',
- '<x-foo></x-foo>');
-
- testHtml('blocks type extensions',
- validator,
- '<div is="x-foo"></div>',
+ '<x-foo></x-foo>',
'');
- testHtml('blocks tags on non-matching elements',
- validator,
- '<div bar="foo"></div>',
- '<div></div>');
- });
-
- group('allowTagExtension', () {
- var validator = new NodeValidatorBuilder()
- ..allowTagExtension(
- 'x-foo',
- 'div',
- attributes: ['bar'],
- uriAttributes: ['baz'])
- ..allowHtml5();
-
- testHtml('allows tag extensions',
- validator,
- '<div is="x-foo" bar="something" baz="/foo.jpg"></div>');
-
- testHtml('blocks custom elements',
- validator,
- '<x-foo></x-foo>',
- '');
-
- testHtml('validates tag extension URIs',
- validator,
- '<div is="x-foo" baz="http://example.com/foo.jpg"></div>',
- '<div is="x-foo"></div>');
-
- testHtml('blocks tags on non-matching elements',
- validator,
- '<div bar="foo"></div>',
- '<div></div>');
-
- testHtml('blocks non-matching tags',
- validator,
- '<span is="x-foo">something</span>',
- '');
-
- validator = new NodeValidatorBuilder()
- ..allowTagExtension(
- 'x-foo',
- 'div',
- attributes: ['bar'],
- uriAttributes: ['baz'])
- ..allowTagExtension(
- 'x-else',
- 'div');
-
- testHtml('blocks tags on non-matching custom elements',
- validator,
- '<div bar="foo" is="x-else"></div>',
- '<div is="x-else"></div>');
- });
-
- group('allowTemplating', () {
- var validator = new NodeValidatorBuilder()
- ..allowTemplating()
- ..allowHtml5();
-
- testHtml('allows templates',
- validator,
- '<template bind="{{a}}"></template>');
-
- testHtml('allows template attributes',
- validator,
- '<template bind="{{a}}" ref="foo" repeat="{{}}" if="{{}}" syntax="foo"></template>');
-
- testHtml('allows template attribute',
- validator,
- '<div template repeat="{{}}"></div>');
-
- testHtml('blocks illegal template attribute',
- validator,
- '<div template="foo" repeat="{{}}"></div>',
- '<div></div>');
- });
-
- group('allowSvg', () {
- var validator = new NodeValidatorBuilder()..allowSvg();
-
- testHtml('allows basic SVG',
+ testHtml('validates tag extension URIs',
validator,
- '<svg xmlns="http://www.w3.org/2000/svg'
- 'xmlns:xlink="http://www.w3.org/1999/xlink">'
- '<image xlink:href="foo" data-foo="bar"/>'
- '</svg>');
+ '<div is="x-foo" baz="http://example.com/foo.jpg"></div>',
+ '<div is="x-foo"></div>');
- testHtml('blocks script elements',
+ testHtml('blocks tags on non-matching elements',
validator,
- '<svg xmlns="http://www.w3.org/2000/svg>'
- '<script></script>'
- '</svg>',
- '<svg xmlns="http://www.w3.org/2000/svg></svg>');
+ '<div bar="foo"></div>',
+ '<div></div>');
- testHtml('blocks script handlers',
+ testHtml('blocks non-matching tags',
validator,
- '<svg xmlns="http://www.w3.org/2000/svg'
- 'xmlns:xlink="http://www.w3.org/1999/xlink">'
- '<image xlink:href="foo" onerror="something"/>'
- '</svg>',
- '<svg xmlns="http://www.w3.org/2000/svg'
- 'xmlns:xlink="http://www.w3.org/1999/xlink">'
- '<image xlink:href="foo"/>'
- '</svg>');
+ '<span is="x-foo">something</span>',
+ '');
- testHtml('blocks foreignObject content',
+ validator = new NodeValidatorBuilder()
+ ..allowTagExtension(
+ 'x-foo',
+ 'div',
+ attributes: ['bar'],
+ uriAttributes: ['baz'])
+ ..allowTagExtension(
+ 'x-else',
+ 'div');
+
+ testHtml('blocks tags on non-matching custom elements',
validator,
- '<svg xmlns="http://www.w3.org/2000/svg>'
- '<foreignobject width="100" height="150">'
- '<body xmlns="http://www.w3.org/1999/xhtml">'
- '<div>Some content</div>'
- '</body>'
- '</foreignobject>'
- '</svg>',
- '<svg xmlns="http://www.w3.org/2000/svg>'
- '<foreignobject width="100" height="150"></foreignobject>'
- '</svg>');
- });
+ '<div bar="foo" is="x-else"></div>',
+ '<div is="x-else"></div>');
+ });
- group('allowInlineStyles', () {
- var validator = new NodeValidatorBuilder()
- ..allowTextElements()
- ..allowInlineStyles();
+ group('allowTemplating', () {
+ var validator = new NodeValidatorBuilder()
+ ..allowTemplating()
+ ..allowHtml5();
- testHtml('allows inline styles',
- validator,
- '<span style="background-color:red">text</span>');
+ testHtml('allows templates',
+ validator,
+ '<template bind="{{a}}"></template>');
- testHtml('blocks other attributes',
- validator,
- '<span class="red-span"></span>',
- '<span></span>');
+ testHtml('allows template attributes',
+ validator,
+ '<template bind="{{a}}" ref="foo" repeat="{{}}" if="{{}}" syntax="foo"></template>');
- validator = new NodeValidatorBuilder()
- ..allowTextElements()
- ..allowInlineStyles(tagName: 'span');
+ testHtml('allows template attribute',
+ validator,
+ '<div template repeat="{{}}"></div>');
- testHtml('scoped allows inline styles on spans',
- validator,
- '<span style="background-color:red">text</span>');
+ testHtml('blocks illegal template attribute',
+ validator,
+ '<div template="foo" repeat="{{}}"></div>',
+ '<div></div>');
+ });
- testHtml('scoped blocks inline styles on LIs',
- validator,
- '<li style="background-color:red">text</li>',
- '<li>text</li>');
- });
+ group('allowSvg', () {
+ var validator = new NodeValidatorBuilder()
+ ..allowSvg()
+ ..allowTextElements();
+
+ testHtml('allows basic SVG',
+ validator,
+ '<svg xmlns="http://www.w3.org/2000/svg'
+ 'xmlns:xlink="http://www.w3.org/1999/xlink">'
+ '<image xlink:href="foo" data-foo="bar"/>'
+ '</svg>');
+
+ testHtml('blocks script elements',
+ validator,
+ '<svg xmlns="http://www.w3.org/2000/svg>'
+ '<script></script>'
+ '</svg>',
+ '');
+
+ testHtml('blocks script elements but allows other',
+ validator,
+ '<svg xmlns="http://www.w3.org/2000/svg>'
+ '<script></script><ellipse cx="200" cy="80" rx="100" ry="50"></ellipse>'
+ '</svg>',
+ '<svg xmlns="http://www.w3.org/2000/svg>'
+ '<ellipse cx="200" cy="80" rx="100" ry="50"></ellipse>'
+ '</svg>');
+
+ testHtml('blocks script handlers',
+ validator,
+ '<svg xmlns="http://www.w3.org/2000/svg'
+ 'xmlns:xlink="http://www.w3.org/1999/xlink">'
+ '<image xlink:href="foo" onerror="something"/>'
+ '</svg>',
+ '<svg xmlns="http://www.w3.org/2000/svg'
+ 'xmlns:xlink="http://www.w3.org/1999/xlink">'
+ '<image xlink:href="foo"/>'
+ '</svg>');
+
+ testHtml('blocks foreignObject content',
+ validator,
+ '<svg xmlns="http://www.w3.org/2000/svg">'
+ '<foreignobject width="100" height="150">'
+ '<body xmlns="http://www.w3.org/1999/xhtml">'
+ '<div>Some content</div>'
+ '</body>'
+ '</foreignobject>'
+ '<b>42</b>'
+ '</svg>',
+ '<svg xmlns="http://www.w3.org/2000/svg">'
+ '<b>42</b>'
+ '</svg>');
+ });
+
+ group('allowInlineStyles', () {
+ var validator = new NodeValidatorBuilder()
+ ..allowTextElements()
+ ..allowInlineStyles();
+
+ testHtml('allows inline styles',
+ validator,
+ '<span style="background-color:red">text</span>');
+
+ testHtml('blocks other attributes',
+ validator,
+ '<span class="red-span"></span>',
+ '<span></span>');
+
+ validator = new NodeValidatorBuilder()
+ ..allowTextElements()
+ ..allowInlineStyles(tagName: 'span');
+
+ testHtml('scoped allows inline styles on spans',
+ validator,
+ '<span style="background-color:red">text</span>');
+
+ testHtml('scoped blocks inline styles on LIs',
+ validator,
+ '<li style="background-color:red">text</li>',
+ '<li>text</li>');
});
group('throws', () {
@@ -456,4 +469,47 @@
expect(element.children[0] is svg.ImageElement, isTrue);
});
});
+
+ group('dom_clobbering', () {
+ var validator = new NodeValidatorBuilder.common();
+
+ testHtml('DOM clobbering of attributes with single node',
+ validator,
+ "<form onmouseover='alert(1)'><input name='attributes'>",
+ "");
+
+ testHtml('DOM clobbering of attributes with multiple nodes',
+ validator,
+ "<form onmouseover='alert(1)'><input name='attributes'>"
+ "<input name='attributes'>",
+ "");
+
+ testHtml('DOM clobbering of lastChild',
+ validator,
+ "<form><input name='lastChild'><input onmouseover='alert(1)'>",
+ "");
+
+ testHtml('DOM clobbering of both children and lastChild',
+ validator,
+ "<form><input name='lastChild'><input name='children'>"
+ "<input id='children'><input onmouseover='alert(1)'>",
+ "");
+
+ testHtml('DOM clobbering of both children and lastChild, different order',
+ validator,
+ "<form><input name='children'><input name='children'>"
+ "<input id='children' name='lastChild'>"
+ "<input id='bad' onmouseover='alert(1)'>",
+ "");
+
+ testHtml('tagName makes containing form invalid',
+ validator,
+ "<form onmouseover='alert(2)'><input name='tagName'>",
+ "");
+
+ testHtml('tagName without mouseover',
+ validator,
+ "<form><input name='tagName'>",
+ "");
+ });
}
diff --git a/tests/language/assign_to_type_test.dart b/tests/language/assign_to_type_test.dart
new file mode 100644
index 0000000..97da693
--- /dev/null
+++ b/tests/language/assign_to_type_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that an attempt to assign to a class, enum, typedef, or type
+// parameter produces a static warning and runtime error.
+
+import "package:expect/expect.dart";
+
+noMethod(e) => e is NoSuchMethodError;
+
+class C<T> {
+ f() {
+ Expect.throws(() => T = null, noMethod); /// 01: static type warning
+ }
+}
+
+class D {}
+
+enum E { e0 }
+
+typedef void F();
+
+main() {
+ new C<D>().f();
+ Expect.throws(() => D = null, noMethod); /// 02: static type warning
+ Expect.throws(() => E = null, noMethod); /// 03: static type warning
+ Expect.throws(() => F = null, noMethod); /// 04: static type warning
+}
diff --git a/tests/language/async_regression_23058_test.dart b/tests/language/async_regression_23058_test.dart
new file mode 100644
index 0000000..ebec58e
--- /dev/null
+++ b/tests/language/async_regression_23058_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for issue 23058.
+
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+class A {
+ var x = new B();
+
+ foo() async {
+ return x.foo == 2 ? 42 : x.foo;
+ }
+}
+
+class B {
+ var x = 0;
+
+ get foo {
+ if (x == -1) {
+ return 0;
+ } else {
+ return x++;
+ }
+ }
+}
+
+main() {
+ asyncStart();
+ new A().foo().then((result) {
+ Expect.equals(1, result);
+ asyncEnd();
+ });
+}
\ No newline at end of file
diff --git a/tests/language/catch_liveness_test.dart b/tests/language/catch_liveness_test.dart
new file mode 100644
index 0000000..27b9488
--- /dev/null
+++ b/tests/language/catch_liveness_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+@AssumeDynamic() @NoInline()
+foo() => 1;
+
+@AssumeDynamic() @NoInline()
+throwException() => throw 'x';
+
+main() {
+ var x = 10;
+ var e2 = null;
+ try {
+ var t = foo();
+ throwException();
+ print(t);
+ x = 3;
+ } catch(e) {
+ Expect.equals(10, x);
+ e2 = e;
+ }
+ Expect.equals(10, x);
+ Expect.equals('x', e2);
+}
diff --git a/tests/language/conditional_access_helper.dart b/tests/language/conditional_access_helper.dart
new file mode 100644
index 0000000..3b31e28
--- /dev/null
+++ b/tests/language/conditional_access_helper.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Library used by conditional_property_assignment_test.dart,
+// conditional_property_access_test.dart, and
+// conditional_method_invocation_test.dart, all of which import it using the
+// prefix "h.".
+
+library lib;
+
+var topLevelVar;
+
+class C {
+ static var staticField;
+}
diff --git a/tests/language/conditional_method_invocation_test.dart b/tests/language/conditional_method_invocation_test.dart
new file mode 100644
index 0000000..e194ab9
--- /dev/null
+++ b/tests/language/conditional_method_invocation_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify semantics of the ?. operator when it is used to invoke a method.
+
+// SharedOptions=--enable-null-aware-operators
+
+import "package:expect/expect.dart";
+import "conditional_access_helper.dart" as h;
+
+bad() {
+ Expect.fail('Should not be executed');
+}
+
+noMethod(e) => e is NoSuchMethodError;
+
+class B {}
+
+class C extends B {
+ f(callback()) => callback();
+ int g(int callback()) => callback();
+}
+
+C nullC() => null;
+
+main() {
+ // Make sure the "none" test fails if method invocation using "?." is not
+ // implemented. This makes status files easier to maintain.
+ nullC()?.f(null);
+
+ // o?.m(...) is equivalent to ((x) => x == null ? null : x.m(...))(o).
+ Expect.equals(null, nullC()?.f(bad())); /// 01: ok
+ Expect.equals(1, new C()?.f(() => 1)); /// 02: ok
+
+ // The static type of o?.m(...) is the same as the static type of
+ // o.m(...).
+ { int i = nullC()?.g(bad()); Expect.equals(null, i); } /// 03: ok
+ { int i = new C()?.g(() => 1); Expect.equals(1, i); } /// 04: ok
+ { String s = nullC()?.g(bad()); Expect.equals(null, s); } /// 05: static type warning
+ { String s = new C()?.g(() => null); Expect.equals(null, s); } /// 06: static type warning
+
+ // Let T be the static type of o and let y be a fresh variable of type T.
+ // Exactly the same static warnings that would be caused by y.m(...) are also
+ // generated in the case of o?.m(...).
+ { B b = new C(); Expect.equals(1, b?.f(() => 1)); } /// 07: static type warning
+ { int i = 1; Expect.equals(null, nullC()?.f(i)); } /// 08: static type warning
+
+ // Consequently, '?.' cannot be used to invoke static methods of classes.
+ Expect.throws(() => C?.staticMethod(), noMethod); /// 09: static type warning
+ Expect.throws(() => h.C?.staticMethod(), noMethod); /// 10: static type warning
+
+ // Nor can it be used to access toplevel functions in libraries imported via
+ // prefix.
+ Expect.throws(() => h?.topLevelFunction(), noMethod); /// 11: static type warning
+
+ // However, '?.' can be used to access the toString method on the class Type.
+ Expect.equals(C?.toString(), (C).toString()); /// 12: ok
+ Expect.equals(h.C?.toString(), (h.C).toString()); /// 13: ok
+}
diff --git a/tests/language/conditional_property_access_test.dart b/tests/language/conditional_property_access_test.dart
new file mode 100644
index 0000000..e821865
--- /dev/null
+++ b/tests/language/conditional_property_access_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify semantics of the ?. operator when it does not appear on the LHS of an
+// assignment.
+
+// SharedOptions=--enable-null-aware-operators
+
+import "package:expect/expect.dart";
+import "conditional_access_helper.dart" as h;
+
+noMethod(e) => e is NoSuchMethodError;
+
+class B {}
+
+class C extends B {
+ int v;
+ C(this.v);
+ static var staticField;
+}
+
+C nullC() => null;
+
+main() {
+ // Make sure the "none" test fails if property access using "?." is not
+ // implemented. This makes status files easier to maintain.
+ nullC()?.v;
+
+ // e1?.id is equivalent to ((x) => x == null ? null : x.id)(e1).
+ Expect.equals(null, nullC()?.v); /// 01: ok
+ Expect.equals(1, new C(1)?.v); /// 02: ok
+
+ // The static type of e1?.d is the static type of e1.id.
+ { int i = new C(1)?.v; Expect.equals(1, i); } /// 03: ok
+ { String s = new C(null)?.v; Expect.equals(null, s); } /// 04: static type warning
+
+ // Let T be the static type of e1 and let y be a fresh variable of type T.
+ // Exactly the same static warnings that would be caused by y.id are also
+ // generated in the case of e1?.id.
+ Expect.equals(null, nullC()?.bad); /// 05: static type warning
+ { B b = new C(1); Expect.equals(1, b?.v); } /// 06: static type warning
+
+ // Consequently, '?.' cannot be used to access static properties of classes.
+ Expect.throws(() => C?.staticField, noMethod); /// 07: static type warning
+ Expect.throws(() => h.C?.staticField, noMethod); /// 08: static type warning
+
+ // Nor can it be used to access toplevel properties in libraries imported via
+ // prefix.
+ Expect.throws(() => h?.topLevelVar, noMethod); /// 09: static type warning
+
+ // However, '?.' can be used to access the hashCode getter on the class Type.
+ Expect.equals(C?.hashCode, (C).hashCode); /// 10: ok
+ Expect.equals(h.C?.hashCode, (h.C).hashCode); /// 11: ok
+}
diff --git a/tests/language/conditional_property_assignment_test.dart b/tests/language/conditional_property_assignment_test.dart
new file mode 100644
index 0000000..bf77842
--- /dev/null
+++ b/tests/language/conditional_property_assignment_test.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify semantics of the ?. operator when it appears on the LHS of an
+// assignment.
+
+// SharedOptions=--enable-null-aware-operators
+
+import "package:expect/expect.dart";
+import "conditional_access_helper.dart" as h;
+
+bad() {
+ Expect.fail('Should not be executed');
+}
+
+noMethod(e) => e is NoSuchMethodError;
+
+class B {}
+
+class C extends B {
+ int v;
+ C(this.v);
+ static var staticField;
+}
+
+class D {
+ E v;
+ D(this.v);
+}
+
+class E {
+ G operator+(int i) => new I();
+}
+
+class F {}
+
+class G extends E implements F {}
+
+class H {}
+
+class I extends G implements H {}
+
+C nullC() => null;
+
+main() {
+ // Make sure the "none" test fails if assignment to "?." is not implemented.
+ // This makes status files easier to maintain.
+ nullC()?.v = 1;
+
+ // e1?.v = e2 is equivalent to ((x) => x == null ? null : x.v = e2)(e1).
+ Expect.equals(null, nullC()?.v = bad()); /// 01: ok
+ { C c = new C(1); Expect.equals(2, c?.v = 2); Expect.equals(2, c.v); } /// 02: ok
+
+ // The static type of e1?.v = e2 is the static type of e2.
+ { D d = new D(new E()); G g = new G(); F f = (d?.v = g); Expect.identical(f, g); } /// 03: ok
+ { D d = new D(new E()); E e = new G(); F f = (d?.v = e); Expect.identical(f, e); } /// 04: static type warning
+
+ // Exactly the same static warnings that would be caused by e1.v = e2 are
+ // also generated in the case of e1?.v = e2.
+ Expect.equals(null, nullC()?.bad = bad()); /// 05: static type warning
+ { B b = new C(1); Expect.equals(2, b?.v = 2); Expect.equals(2, (b as C).v); } /// 06: static type warning
+
+ // e1?.v op= e2 is equivalent to ((x) => x?.v = x.v op e2)(e1).
+ Expect.equals(null, nullC()?.v += bad()); /// 07: ok
+ { C c = new C(1); Expect.equals(3, c?.v += 2); Expect.equals(3, c.v); } /// 08: ok
+
+ // The static type of e1?.v op= e2 is the static type of e1.v op e2.
+ { D d = new D(new E()); F f = (d?.v += 1); Expect.identical(d.v, f); } /// 09: ok
+
+ // Let T be the static type of e1 and let y be a fresh variable of type T.
+ // Exactly the same static warnings that would be caused by y.v op e2 are
+ // also generated in the case of e1?.v op= e2.
+ Expect.equals(null, nullC()?.bad = bad()); /// 10: static type warning
+ { B b = new C(1); Expect.equals(3, b?.v += 2); Expect.equals(3, (b as C).v); } /// 11: static type warning
+ { D d = new D(new E()); F f = (d?.v += nullC()); Expect.identical(d.v, f); } /// 12: static type warning
+ { D d = new D(new E()); H h = (d?.v += 1); Expect.identical(d.v, h); } /// 13: static type warning
+
+ // Consequently, '?.' cannot be used to assign to static properties of
+ // classes.
+ Expect.throws(() => C?.staticField = null, noMethod); /// 14: static type warning
+ Expect.throws(() => C?.staticField += null, noMethod); /// 15: static type warning
+ Expect.throws(() => C?.staticField ??= null, noMethod); /// 16: static type warning
+ Expect.throws(() => h.C?.staticField = null, noMethod); /// 17: static type warning
+ Expect.throws(() => h.C?.staticField += null, noMethod); /// 18: static type warning
+ Expect.throws(() => h.C?.staticField ??= null, noMethod); /// 19: static type warning
+
+ // Nor can it be used to assign to toplevel properties in libraries imported
+ // via prefix.
+ Expect.throws(() => h?.topLevelVar = null, noMethod); /// 20: static type warning
+ Expect.throws(() => h?.topLevelVar += null, noMethod); /// 21: static type warning
+ Expect.throws(() => h?.topLevelVar ??= null, noMethod); /// 22: static type warning
+}
diff --git a/tests/language/const_dynamic_type_literal_test.dart b/tests/language/const_dynamic_type_literal_test.dart
new file mode 100644
index 0000000..a1be0f3
--- /dev/null
+++ b/tests/language/const_dynamic_type_literal_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that 'dynamic' can be used in const expressions and has the expected
+// behavior.
+
+import "package:expect/expect.dart";
+
+const d = dynamic;
+const i = int;
+
+void main() {
+ Expect.isTrue(identical(d, dynamic)); /// 01: ok
+ Expect.equals(1, const { d: 1, d: 2 }.length); /// 02: static type warning
+ Expect.equals(2, const { d: 1, i: 2 }.length); /// 03: ok
+}
diff --git a/tests/language/if_null_assignment_behavior_test.dart b/tests/language/if_null_assignment_behavior_test.dart
new file mode 100644
index 0000000..548d94a
--- /dev/null
+++ b/tests/language/if_null_assignment_behavior_test.dart
@@ -0,0 +1,204 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify semantics of the ??= operator, including order of operations, by
+// keeping track of the operations performed.
+
+// SharedOptions=--enable-null-aware-operators
+
+import "package:expect/expect.dart";
+import "if_null_assignment_helper.dart" as h;
+
+bad() {
+ Expect.fail('Should not be executed');
+}
+
+var xGetValue = null;
+
+get x {
+ h.operations.add('x');
+ var tmp = xGetValue;
+ xGetValue = null;
+ return tmp;
+}
+
+void set x(value) {
+ h.operations.add('x=$value');
+}
+
+var yGetValue = null;
+
+get y {
+ h.operations.add('y');
+ var tmp = yGetValue;
+ yGetValue = null;
+ return tmp;
+}
+
+void set y(value) {
+ h.operations.add('y=$value');
+}
+
+var zGetValue = null;
+
+get z {
+ h.operations.add('z');
+ var tmp = zGetValue;
+ zGetValue = null;
+ return tmp;
+}
+
+void set z(value) {
+ h.operations.add('z=$value');
+}
+
+var fValue = null;
+
+f() {
+ h.operations.add('f()');
+ var tmp = fValue;
+ fValue = null;
+ return tmp;
+}
+
+void check(expectedValue, f(), expectedOperations) {
+ Expect.equals(expectedValue, f());
+ Expect.listEquals(expectedOperations, h.operations);
+ h.operations = [];
+}
+
+void checkThrows(expectedException, f(), expectedOperations) {
+ Expect.throws(f, expectedException);
+ Expect.listEquals(expectedOperations, h.operations);
+ h.operations = [];
+}
+
+noMethod(e) => e is NoSuchMethodError;
+
+class C {
+ final String s;
+
+ C(this.s);
+
+ @override
+ String toString() => s;
+
+ static var xGetValue = null;
+
+ static get x {
+ h.operations.add('C.x');
+ var tmp = xGetValue;
+ xGetValue = null;
+ return tmp;
+ }
+
+ static void set x(value) {
+ h.operations.add('C.x=$value');
+ }
+
+ var vGetValue = null;
+
+ get v {
+ h.operations.add('$s.v');
+ var tmp = vGetValue;
+ vGetValue = null;
+ return tmp;
+ }
+
+ void set v(value) {
+ h.operations.add('$s.v=$value');
+ }
+
+ var indexGetValue = null;
+
+ operator[](index) {
+ h.operations.add('$s[$index]');
+ var tmp = indexGetValue;
+ indexGetValue = null;
+ return tmp;
+ }
+
+ void operator[]=(index, value) {
+ h.operations.add('$s[$index]=$value');
+ }
+
+ final finalOne = 1;
+ final finalNull = null;
+
+ void instanceTest() {
+ // v ??= e is equivalent to ((x) => x == null ? v = e : x)(v)
+ vGetValue = 1; check(1, () => v ??= bad(), ['$s.v']); /// 01: ok
+ yGetValue = 1; check(1, () => v ??= y, ['$s.v', 'y', '$s.v=1']); /// 02: ok
+ check(1, () => finalOne ??= bad(), []); /// 03: static type warning
+ yGetValue = 1; checkThrows(noMethod, () => finalNull ??= y, ['y']); /// 04: static type warning
+ }
+}
+
+class D extends C {
+ D(String s) : super(s);
+
+ get v => bad();
+
+ void set v(value) {
+ bad();
+ }
+
+ void derivedInstanceTest() {
+ // super.v ??= e is equivalent to
+ // ((x) => x == null ? super.v = e : x)(super.v)
+ vGetValue = 1; check(1, () => super.v ??= bad(), ['$s.v']); /// 05: ok
+ yGetValue = 1; check(1, () => super.v ??= y, ['$s.v', 'y', '$s.v=1']); /// 06: ok
+ }
+}
+
+main() {
+ // Make sure the "none" test fails if "??=" is not implemented. This makes
+ // status files easier to maintain.
+ var _; _ ??= null;
+
+ new C('c').instanceTest();
+ new D('d').derivedInstanceTest();
+
+ // v ??= e is equivalent to ((x) => x == null ? v = e : x)(v)
+ xGetValue = 1; check(1, () => x ??= bad(), ['x']); /// 07: ok
+ yGetValue = 1; check(1, () => x ??= y, ['x', 'y', 'x=1']); /// 08: ok
+ h.xGetValue = 1; check(1, () => h.x ??= bad(), ['h.x']); /// 09: ok
+ yGetValue = 1; check(1, () => h.x ??= y, ['h.x', 'y', 'h.x=1']); /// 10: ok
+ { var l = 1; check(1, () => l ??= bad(), []); } /// 11: ok
+ { var l; yGetValue = 1; check(1, () => l ??= y, ['y']); Expect.equals(1, l); } /// 12: ok
+ { final l = 1; check(1, () => l ??= bad(), []); } /// 13: static type warning
+ { final l = null; yGetValue = 1; checkThrows(noMethod, () => l ??= y, ['y']); } /// 14: static type warning
+ check(C, () => C ??= bad(), []); /// 15: static type warning
+
+ // C.v ??= e is equivalent to ((x) => x == null ? C.v = e : x)(C.v)
+ C.xGetValue = 1; check(1, () => C.x ??= bad(), ['C.x']); /// 16: ok
+ yGetValue = 1; check(1, () => C.x ??= y, ['C.x', 'y', 'C.x=1']); /// 17: ok
+ h.C.xGetValue = 1; check(1, () => h.C.x ??= bad(), ['h.C.x']); /// 18: ok
+ yGetValue = 1; check(1, () => h.C.x ??= y, ['h.C.x', 'y', 'h.C.x=1']); /// 19: ok
+
+ // e1.v ??= e2 is equivalent to
+ // ((x) => ((y) => y == null ? x.v = e2 : y)(x.v))(e1)
+ xGetValue = new C('x'); xGetValue.vGetValue = 1; /// 20: ok
+ check(1, () => x.v ??= bad(), ['x', 'x.v']); /// 20: continued
+ xGetValue = new C('x'); yGetValue = 1; /// 21: ok
+ check(1, () => x.v ??= y, ['x', 'x.v', 'y', 'x.v=1']); /// 21: continued
+ fValue = new C('f()'); fValue.vGetValue = 1; /// 22: ok
+ check(1, () => f().v ??= bad(), ['f()', 'f().v']); /// 22: continued
+ fValue = new C('f()'); yGetValue = 1; /// 23: ok
+ check(1, () => f().v ??= y, ['f()', 'f().v', 'y', 'f().v=1']); /// 23: continued
+
+ // e1[e2] ??= e3 is equivalent to
+ // ((a, i) => ((x) => x == null ? a[i] = e3 : x)(a[i]))(e1, e2)
+ xGetValue = new C('x'); yGetValue = 1; xGetValue.indexGetValue = 2; /// 24: ok
+ check(2, () => x[y] ??= bad(), ['x', 'y', 'x[1]']); /// 24: continued
+ xGetValue = new C('x'); yGetValue = 1; zGetValue = 2; /// 25: ok
+ check(2, () => x[y] ??= z, ['x', 'y', 'x[1]', 'z', 'x[1]=2']); /// 25: continued
+
+ // e1?.v ??= e2 is equivalent to ((x) => x == null ? null : x.v ??= e2)(e1).
+ check(null, () => x?.v ??= bad(), ['x']); /// 26: ok
+ xGetValue = new C('x'); xGetValue.vGetValue = 1; /// 27: ok
+ check(1, () => x?.v ??= bad(), ['x', 'x.v']); /// 27: continued
+ xGetValue = new C('x'); yGetValue = 1; /// 28: ok
+ check(1, () => x?.v ??= y, ['x', 'x.v', 'y', 'x.v=1']); /// 28: continued
+}
diff --git a/tests/language/if_null_assignment_helper.dart b/tests/language/if_null_assignment_helper.dart
new file mode 100644
index 0000000..9d6819b
--- /dev/null
+++ b/tests/language/if_null_assignment_helper.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Library used by if_null_assignment_behavior_test.dart, which
+// imports it using the prefix "h.".
+
+library lib;
+
+import "package:expect/expect.dart";
+
+List<String> operations = [];
+
+var xGetValue = null;
+
+get x {
+ operations.add('h.x');
+ var tmp = xGetValue;
+ xGetValue = null;
+ return tmp;
+}
+
+void set x(value) {
+ operations.add('h.x=$value');
+}
+
+class C {
+ static var xGetValue = null;
+
+ static get x {
+ operations.add('h.C.x');
+ var tmp = xGetValue;
+ xGetValue = null;
+ return tmp;
+ }
+
+ static void set x(value) {
+ operations.add('h.C.x=$value');
+ }
+}
diff --git a/tests/language/if_null_assignment_static_test.dart b/tests/language/if_null_assignment_static_test.dart
new file mode 100644
index 0000000..03739c4
--- /dev/null
+++ b/tests/language/if_null_assignment_static_test.dart
@@ -0,0 +1,176 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that the static type of a ??= b is the least upper bound of the
+// static types of a and b.
+
+// SharedOptions=--enable-null-aware-operators
+
+import "package:expect/expect.dart";
+
+// Determine whether the VM is running in checked mode.
+bool get checkedMode {
+ try {
+ var x = 'foo';
+ int y = x;
+ return false;
+ } catch (_) {
+ return true;
+ }
+}
+
+noMethod(e) => e is NoSuchMethodError;
+
+bad() {
+ Expect.fail('Should not be executed');
+}
+
+class A {
+ String a;
+}
+
+class B extends A {
+ String b;
+}
+
+class C extends A {
+ String c;
+}
+
+A get a => null;
+
+void set a(A value) {}
+
+B get b => null;
+
+void set b(B value) {}
+
+class ClassWithStaticGetters {
+ static A get a => null;
+
+ static void set a(A value) {}
+
+ static B get b => null;
+
+ static void set b(B value) {}
+}
+
+class ClassWithInstanceGetters {
+ A get a => null;
+
+ void set a(A value) {}
+
+ B get b => null;
+
+ void set b(B value) {}
+}
+
+class DerivedClass extends ClassWithInstanceGetters {
+ dynamic get a => bad();
+
+ void set a(dynamic value) { bad(); }
+
+ dynamic get b => bad();
+
+ void set b(dynamic value) { bad(); }
+
+ void derivedTest() {
+ // The static type of super.v ??= e is the LUB of the static types of
+ // super.v and e.
+ (super.a ??= new A()).a; /// 01: ok
+ Expect.throws(() => (super.a ??= new A()).b, noMethod); /// 02: static type warning
+ (super.a ??= new B()).a; /// 03: ok
+ (super.a ??= new B()).b; /// 04: static type warning
+ if (!checkedMode) {
+ (super.b ??= new A()).a; /// 05: ok
+ Expect.throws(() => (super.b ??= new A()).b, noMethod); /// 06: static type warning
+
+ // Exactly the same static warnings that would be caused by super.v = e
+ // are also generated in the case of super.v ??= e.
+ super.b ??= new C(); /// 07: static type warning
+ }
+ }
+}
+
+main() {
+ // Make sure the "none" test fails if "??=" is not implemented. This makes
+ // status files easier to maintain.
+ var _; _ ??= null;
+
+ new DerivedClass().derivedTest();
+
+ // The static type of v ??= e is the LUB of the static types of v and e.
+ (a ??= new A()).a; /// 08: ok
+ Expect.throws(() => (a ??= new A()).b, noMethod); /// 09: static type warning
+ (a ??= new B()).a; /// 10: ok
+ (a ??= new B()).b; /// 11: static type warning
+ if (!checkedMode) {
+ (b ??= new A()).a; /// 12: ok
+ Expect.throws(() => (b ??= new A()).b, noMethod); /// 13: static type warning
+
+ // Exactly the same static warnings that would be caused by v = e are also
+ // generated in the case of v ??= e.
+ b ??= new C(); /// 14: static type warning
+ }
+
+ // The static type of C.v ??= e is the LUB of the static types of C.v and e.
+ (ClassWithStaticGetters.a ??= new A()).a; /// 15: ok
+ Expect.throws(() => (ClassWithStaticGetters.a ??= new A()).b, noMethod); /// 16: static type warning
+ (ClassWithStaticGetters.a ??= new B()).a; /// 17: ok
+ (ClassWithStaticGetters.a ??= new B()).b; /// 18: static type warning
+ if (!checkedMode) {
+ (ClassWithStaticGetters.b ??= new A()).a; /// 19: ok
+ Expect.throws(() => (ClassWithStaticGetters.b ??= new A()).b, noMethod); /// 20: static type warning
+
+ // Exactly the same static warnings that would be caused by C.v = e are
+ // also generated in the case of C.v ??= e.
+ ClassWithStaticGetters.b ??= new C(); /// 21: static type warning
+ }
+
+ // The static type of e1.v ??= e2 is the LUB of the static types of e1.v and
+ // e2.
+ (new ClassWithInstanceGetters().a ??= new A()).a; /// 22: ok
+ Expect.throws(() => (new ClassWithInstanceGetters().a ??= new A()).b, noMethod); /// 23: static type warning
+ (new ClassWithInstanceGetters().a ??= new B()).a; /// 24: ok
+ (new ClassWithInstanceGetters().a ??= new B()).b; /// 25: static type warning
+ if (!checkedMode) {
+ (new ClassWithInstanceGetters().b ??= new A()).a; /// 26: ok
+ Expect.throws(() => (new ClassWithInstanceGetters().b ??= new A()).b, noMethod); /// 27: static type warning
+
+ // Exactly the same static warnings that would be caused by e1.v = e2 are
+ // also generated in the case of e1.v ??= e2.
+ new ClassWithInstanceGetters().b ??= new C(); /// 28: static type warning
+ }
+
+ // The static type of e1[e2] ??= e3 is the LUB of the static types of e1[e2]
+ // and e3.
+ ((<A>[null])[0] ??= new A()).a; /// 29: ok
+ Expect.throws(() => ((<A>[null])[0] ??= new A()).b, noMethod); /// 30: static type warning
+ ((<A>[null])[0] ??= new B()).a; /// 31: ok
+ ((<A>[null])[0] ??= new B()).b; /// 32: static type warning
+ if (!checkedMode) {
+ ((<B>[null])[0] ??= new A()).a; /// 33: ok
+ Expect.throws(() => ((<B>[null])[0] ??= new A()).b, noMethod); /// 34: static type warning
+
+ // Exactly the same static warnings that would be caused by e1[e2] = e3 are
+ // also generated in the case of e1[e2] ??= e3.
+ (<B>[null])[0] ??= new C(); /// 35: static type warning
+ }
+
+ // The static type of e1?.v op= e2 is the static type of e1.v op e2,
+ // therefore the static type of e1?.v ??= e2 is the static type of
+ // e1.v ?? e2, which is the LUB of the static types of e1?.v and e2.
+ (new ClassWithInstanceGetters()?.a ??= new A()).a; /// 36: ok
+ Expect.throws(() => (new ClassWithInstanceGetters()?.a ??= new A()).b, noMethod); /// 37: static type warning
+ (new ClassWithInstanceGetters()?.a ??= new B()).a; /// 38: ok
+ (new ClassWithInstanceGetters()?.a ??= new B()).b; /// 39: static type warning
+ if (!checkedMode) {
+ (new ClassWithInstanceGetters()?.b ??= new A()).a; /// 40: ok
+ Expect.throws(() => (new ClassWithInstanceGetters()?.b ??= new A()).b, noMethod); /// 41: static type warning
+
+ // Exactly the same static warnings that would be caused by e1.v ??= e2 are
+ // also generated in the case of e1?.v ??= e2.
+ new ClassWithInstanceGetters()?.b ??= new C(); /// 42: static type warning
+ }
+}
diff --git a/tests/language/if_null_behavior_test.dart b/tests/language/if_null_behavior_test.dart
new file mode 100644
index 0000000..4fcbfa7
--- /dev/null
+++ b/tests/language/if_null_behavior_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Evaluation of an if-null expresion e of the form e1 ?? e2 is equivalent to
+// the evaluation of the expression ((x) => x == null ? e2 : x)(e1). The
+// static type of e is the least upper bound of the static type of e1 and the
+// static type of e2.
+
+// SharedOptions=--enable-null-aware-operators
+
+import "package:expect/expect.dart";
+
+class A {
+ final String a;
+ A(this.a);
+}
+
+class B extends A {
+ B(String v) : b = v, super(v);
+ final String b;
+}
+
+class C extends A {
+ C(String v) : c = v, super(v);
+ final String c;
+}
+
+B nullB() => null;
+C nullC() => null;
+
+noMethod(e) => e is NoSuchMethodError;
+
+main() {
+ // Make sure the "none" test fails if "??" is not implemented. This makes
+ // status files easier to maintain.
+ var _ = null ?? null;
+
+ Expect.equals(1, 1 ?? 2); /// 01: ok
+ Expect.equals(1, 1 ?? null); /// 02: ok
+ Expect.equals(2, null ?? 2); /// 03: ok
+ Expect.equals(null, null ?? null); /// 04: ok
+ Expect.equals('B', (new B('B') ?? new C('C')).a); /// 05: ok
+ Expect.equals('B', (new B('B') ?? new C('C')).b); /// 06: static type warning
+ Expect.throws(() => (new B('B') ?? new C('C')).c, noMethod); /// 07: static type warning
+ Expect.equals('B', (new B('B') ?? nullC()).a); /// 08: ok
+ Expect.equals('B', (new B('B') ?? nullC()).b); /// 09: static type warning
+ Expect.throws(() => (new B('B') ?? nullC()).c, noMethod); /// 10: static type warning
+ Expect.equals('C', (nullB() ?? new C('C')).a); /// 11: ok
+ Expect.throws(() => (nullB() ?? new C('C')).b, noMethod); /// 12: static type warning
+ Expect.equals('C', (nullB() ?? new C('C')).c); /// 13: static type warning
+ Expect.throws(() => (nullB() ?? nullC()).a, noMethod); /// 14: ok
+ Expect.throws(() => (nullB() ?? nullC()).b, noMethod); /// 15: static type warning
+ Expect.throws(() => (nullB() ?? nullC()).c, noMethod); /// 16: static type warning
+}
diff --git a/tests/language/if_null_evaluation_order_test.dart b/tests/language/if_null_evaluation_order_test.dart
new file mode 100644
index 0000000..bc067e1
--- /dev/null
+++ b/tests/language/if_null_evaluation_order_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Evaluation of an if-null expresion e of the form e1 ?? e2 is equivalent to
+// the evaluation of the expression ((x) => x == null ? e2 : x)(e1).
+//
+// Therefore, e1 should be evaluated first; if it is non-null, e2 should not
+// be evaluated.
+
+// SharedOptions=--enable-null-aware-operators
+
+import "package:expect/expect.dart";
+
+void bad() {
+ throw new Exception();
+}
+
+bool firstExecuted = false;
+
+first() {
+ firstExecuted = true;
+ return null;
+}
+
+second() {
+ Expect.isTrue(firstExecuted);
+ return 2;
+}
+
+main() {
+ // Make sure the "none" test fails if "??" is not implemented. This makes
+ // status files easier to maintain.
+ var _ = null ?? null;
+
+ Expect.equals(1, 1 ?? bad()); /// 01: ok
+ Expect.equals(2, first() ?? second()); /// 02: ok
+}
diff --git a/tests/language/if_null_precedence_test.dart b/tests/language/if_null_precedence_test.dart
new file mode 100644
index 0000000..32d49ce
--- /dev/null
+++ b/tests/language/if_null_precedence_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that '??' binds tighter than '?:' and less tightly than '||'.
+
+// SharedOptions=--enable-null-aware-operators
+
+import "package:expect/expect.dart";
+
+assertionError(e) => e is AssertionError;
+
+// Determine whether the VM is running in checked mode.
+bool get checkedMode {
+ try {
+ var x = 'foo';
+ int y = x;
+ return false;
+ } catch (_) {
+ return true;
+ }
+}
+
+main() {
+ // Make sure the "none" test fails if "??" is not implemented. This makes
+ // status files easier to maintain.
+ var _ = null ?? null;
+
+ // "a ?? b ?? c" should be legal, and should evaluate to the first non-null
+ // value (or null if there are no non-null values).
+ Expect.equals(1, 1 ?? 2 ?? 3); /// 01: ok
+ Expect.equals(2, null ?? 2 ?? 3); /// 02: ok
+ Expect.equals(3, null ?? null ?? 3); /// 03: ok
+ Expect.equals(null, null ?? null ?? null); /// 04: ok
+
+ // "a ?? b ? c : d" should parse as "(a ?? b) ? c : d", therefore provided
+ // that a is true, b need not be a bool. An incorrect parse of
+ // "a ?? (b ? c : d)" would require b to be a bool to avoid a static type
+ // warning.
+ Expect.equals(2, true ?? 1 ? 2 : 3); /// 05: ok
+
+ // "a ?? b || c" should parse as "a ?? (b || c)", therefore it's a static
+ // type warning if b doesn't have type bool. An incorrect parse of
+ // "(a ?? b) || c" would allow b to have any type provided that a is bool.
+ Expect.equals(false, false ?? 1 || true); /// 06: static type warning
+
+ // "a || b ?? c" should parse as "(a || b) ?? c", therefore it is a static
+ // type warning if b doesn't have type bool. An incorrect parse of
+ // "a || (b ?? c)" would allow b to have any type provided that c is bool.
+ if (checkedMode) {
+ Expect.throws(() => false || 1 ?? true, assertionError); /// 07: static type warning
+ } else {
+ Expect.equals(false, false || 1 ?? true); /// 07: continued
+ }
+
+ if (checkedMode) {
+ // An incorrect parse of "a || (b ?? c)" would result in no checked-mode
+ // error.
+ Expect.throws(() => false || null ?? true, assertionError); /// 08: ok
+ } else {
+ // An incorrect parse of "a || (b ?? c)" would result in c being evaluated.
+ int i = 0; /// 08: continued
+ Expect.equals(false, false || null ?? i++ == 0); /// 08: continued
+ Expect.equals(0, i); /// 08: continued
+ }
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index 0d182a6..f49e43c9 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -17,6 +17,17 @@
# Regular bugs which should be fixed.
duplicate_export_negative_test: Fail # Issue 6134
+[ $compiler == none ]
+# Null-aware operators aren't implemented in the VM yet.
+if_null_evaluation_order_test: Fail
+if_null_precedence_test: Fail
+if_null_behavior_test: Fail
+if_null_assignment_behavior_test: Fail
+if_null_assignment_static_test: Fail
+conditional_property_assignment_test: Fail
+conditional_property_access_test: Fail
+conditional_method_invocation_test: Fail
+
[ $compiler == dart2dart ]
deferred_load_library_wrong_args_test/none: Fail # Issue 17523
deferred_load_inval_code_test: Fail # Issue 17523
@@ -27,6 +38,8 @@
deferred_closurize_load_library_test: Fail # Issue 17523
deferred_inlined_test: Fail # Issue 17523
deferred_optimized_test: Fail # Issue 17523
+multiline_strings_test: Fail # Issue (pending)
+regress_22443_test: Fail # Issue 17523
enum_mirror_test: Skip # Issue 11511.
override_inheritance_mixed_test/08: Fail # Issue 18124
@@ -43,8 +56,6 @@
async_star_test/02: RuntimeError
async_star_test/05: Timeout, RuntimeError
-[ $compiler == none && ($runtime == drt || $runtime == dartium|| $runtime == ContentShellOnAndroid) ]
-
[ $compiler == none && $runtime == vm ]
class_keyword_test/02: MissingCompileTimeError # Issue 13627
unicode_bom_test: Fail # Issue 16067
@@ -54,6 +65,7 @@
[ $compiler == none ]
dynamic_prefix_core_test/01: RuntimeError # Issue 12478
+multiline_strings_test: Fail # Issue 23020
[ $compiler == none && ($runtime == vm || $runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
dynamic_prefix_core_test/none: Fail # Issue 12478
@@ -104,6 +116,6 @@
[ $compiler == none && $runtime == ContentShellOnAndroid ]
gc_test: SkipSlow # Times out flakily. Issue 20956
-[ $compiler == none && $runtime == vm && ( $arch == simarm || $arch == arm || $arch == simarm64 || $arch == arm64 || $arch == simmips || $arch == mips) ]
+[ $compiler == none && $runtime == vm && ( $arch == simarm || $arch == arm || $arch == armv5te || $arch == simarm64 || $arch == arm64 || $arch == simmips || $arch == mips) ]
vm/load_to_load_unaligned_forwarding_vm_test: Pass, Crash # Unaligned offset. Issue 22151
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index b381c07..6b777de 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -11,6 +11,8 @@
await_backwards_compatibility_test/none: CompileTimeError # Issue 22052
await_test: CompileTimeError # Issue 22052
async_await_test/02: CompileTimeError # Issue 22052
+regress_17382_test: Skip # don't care about the static warning.
+regress_23038_test/01: Skip # Issue 23038
issue13179_test: CompileTimeError # Issue 13179
@@ -35,6 +37,11 @@
async_await_syntax_test/c10a: MissingStaticWarning
async_await_syntax_test/d10a: MissingStaticWarning
+assign_to_type_test/01: MissingStaticWarning
+assign_to_type_test/02: MissingStaticWarning
+assign_to_type_test/03: MissingStaticWarning
+assign_to_type_test/04: MissingStaticWarning
+
# Runtime negative test. No static errors or warnings.
closure_call_wrong_argument_count_negative_test: skip
@@ -509,6 +516,21 @@
compile_time_constant10_test/none: CompileTimeError # Issue 21177
+const_dynamic_type_literal_test: CompileTimeError # Issue 22989
+
+regress_21912_test/02: StaticWarning # Issue 21912
+regress_22976_test/02: StaticWarning # Issue 22976
+
+# Null-aware operators aren't implemented in the Java-based analyzer.
+if_null_evaluation_order_test: CompileTimeError
+if_null_precedence_test: CompileTimeError
+if_null_behavior_test: CompileTimeError
+if_null_assignment_behavior_test: CompileTimeError
+if_null_assignment_static_test: CompileTimeError
+conditional_property_assignment_test: CompileTimeError
+conditional_property_access_test: CompileTimeError
+conditional_method_invocation_test: CompileTimeError
+
# Issue 16391. These tests are supposed to produce a compile time
# error in checked mode, but they don't:
[ $compiler == dartanalyzer && $checked ]
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index eb9d175..8baf949 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -13,6 +13,8 @@
enum_syntax_test/05: Fail # 21649
enum_syntax_test/06: Fail # 21649
+regress_17382_test: Skip # don't care about the static warning.
+
# Test issue 12694 (was analyzer issue), (1) when "abstract" is import prefix using it as type is warning; (2) currently analyzer resolves prefix as field (don't ask)
built_in_identifier_prefix_test: CompileTimeError # Issue 12694
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 272ba36..1be445a 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -59,6 +59,20 @@
ref_before_declaration_test/05: MissingCompileTimeError
ref_before_declaration_test/06: MissingCompileTimeError
+regress_22976_test/01: CompileTimeError # Issue 23132
+regress_22976_test/02: CompileTimeError # Issue 23132
+
+# Null-aware operators aren't implemented in dart2js yet.
+if_null_evaluation_order_test: CompileTimeError
+if_null_precedence_test: CompileTimeError
+if_null_behavior_test: CompileTimeError
+if_null_assignment_behavior_test: CompileTimeError
+if_null_assignment_static_test: CompileTimeError
+conditional_property_assignment_test: CompileTimeError
+conditional_property_access_test: CompileTimeError
+conditional_method_invocation_test: CompileTimeError
+super_conditional_operator_test/none: CompileTimeError
+
# VM specific tests that should not be run by dart2js.
vm/*: Skip # Issue 12699
@@ -148,6 +162,9 @@
enum_const_test/02: RuntimeError # Issue 21817
+const_dynamic_type_literal_test/02: CompileTimeError # Issue 23009
+const_dynamic_type_literal_test/03: CompileTimeError # Issue 23009
+
# Compilation errors.
method_override5_test: RuntimeError # Issue 12809
external_test/10: CompileTimeError # Issue 12887
@@ -187,6 +204,9 @@
[ $compiler == dart2dart && $builder_tag == new_backend ]
regress_13494_test: Pass # Issue 22370, passes for the wrong reason
+await_for_cancel_test: RuntimeError # Issue 23015
+regress_22936_test/01: RuntimeError # Issue 23015
+async_star_cancel_and_throw_in_finally_test: RuntimeError # Issue 23015
[ $compiler == dart2dart && $builder_tag == new_backend && $host_checked ]
large_implicit_getter_test: Crash # Stack overflow
@@ -212,6 +232,8 @@
# Calling unresolved class constructor:
call_nonexistent_constructor_test/01: Fail # Issue 13082
call_nonexistent_constructor_test/02: Fail # Issue 13082
+private_access_test/05: Fail # Issue 13082
+private_access_test/06: Fail # Issue 13082
bad_override_test/01: Fail # Issue 11496
bad_override_test/02: Fail # Issue 11496
@@ -267,5 +289,9 @@
regress_21795_test: RuntimeError # Issue 12605
[ $compiler == dart2js && $runtime == d8 && $system == windows ]
-*deferred*: Skip # Issue 17458
-cha_deopt*: Skip # Issue 17458
+# Detection of d8 runtime does not work on Windows so the runtime result is
+# unreliable; at the time of writing, 32 passed, 31 failed with runtime error.
+# Marked with Pass,RuntimeError to avoid undetected compile-time failures.
+*deferred*: Pass,RuntimeError # Issue 17458
+cha_deopt*: Pass,RuntimeError # Issue 17458
+regress_22443_test: Pass,RuntimeError # Issue 17458
diff --git a/tests/language/metadata_test.dart b/tests/language/metadata_test.dart
index dc901c2..29f11dc 100644
--- a/tests/language/metadata_test.dart
+++ b/tests/language/metadata_test.dart
@@ -29,7 +29,8 @@
static String staticField;
@Meta.Alien("ET") int foo(@meta1 bool fool, {@meta1 @Tag("opt") x: 100}) {
- return x;
+ @meta2 @meta1 g() => 10;
+ return x * g();
}
@Tag(r"timewarp")
diff --git a/tests/language/mul_recipr_test.dart b/tests/language/mul_recipr_test.dart
new file mode 100644
index 0000000..da4d7a1
--- /dev/null
+++ b/tests/language/mul_recipr_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test program checking that optimizations are not too aggresive and
+// incorrect:
+// - (a * (1.0 / b))
+//
+// VMOptions=--optimization-counter-threshold=8 --no-use-osr
+
+import "package:expect/expect.dart";
+
+var xx = 23.0;
+
+main() {
+ xx = 1e-6;
+ scaleIt(1e-310);
+ Expect.isTrue(xx.isInfinite);
+ for (int i = 0; i < 10; i++) {
+ xx = 24.0;
+ scaleIt(6.0);
+ Expect.equals(4.0, xx);
+ }
+ xx = 1e-6;
+ scaleIt(1e-310);
+ Expect.isTrue(xx.isInfinite);
+}
+
+scaleIt(double b) {
+ scale(1.0 / b);
+}
+
+scale(a) {
+ xx *= a;
+}
\ No newline at end of file
diff --git a/tests/language/multiline_strings_test.dart b/tests/language/multiline_strings_test.dart
new file mode 100644
index 0000000..d7f8f3e
--- /dev/null
+++ b/tests/language/multiline_strings_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+main() {
+ Expect.equals('foo', '''
+foo''');
+
+ Expect.equals('\\\nfoo', '''\\
+foo''');
+
+ Expect.equals('\t\nfoo', '''\t
+foo''');
+
+ Expect.equals('foo', '''\
+foo''');
+
+ Expect.equals('foo', '''\ \
+foo''');
+
+ Expect.equals(' \nfoo', '''\x20
+foo''');
+
+ String x = ' ';
+ Expect.equals(' \nfoo', '''$x
+foo''');
+
+ Expect.equals('foo', r'''
+foo''');
+
+ Expect.equals('\\\\\nfoo', r'''\\
+foo''');
+
+ Expect.equals('\\t\nfoo', r'''\t
+foo''');
+
+ Expect.equals('foo', r'''\
+foo''');
+
+ Expect.equals('foo', r'''\ \
+foo''');
+}
diff --git a/tests/language/private_access_lib.dart b/tests/language/private_access_lib.dart
new file mode 100644
index 0000000..e9af620
--- /dev/null
+++ b/tests/language/private_access_lib.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library private;
+
+_function() {}
+
+class _Class {}
+
+class Class {
+ Class._constructor();
+}
\ No newline at end of file
diff --git a/tests/language/private_access_test.dart b/tests/language/private_access_test.dart
new file mode 100644
index 0000000..f9c4ad4
--- /dev/null
+++ b/tests/language/private_access_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+import 'private_access_lib.dart';
+import 'private_access_lib.dart' as private;
+
+main() {
+ Expect.throws(() => _function(), /// 01: static type warning
+ (e) => e is NoSuchMethodError); /// 01: continued
+ Expect.throws(() => private._function(), /// 02: static type warning
+ (e) => e is NoSuchMethodError); /// 02: continued
+ Expect.throws(() => new _Class()); /// 03: static type warning
+ Expect.throws(() => new private._Class()); /// 04: static type warning
+ Expect.throws(() => new Class._constructor(), /// 05: static type warning
+ (e) => e is NoSuchMethodError); /// 05: continued
+ Expect.throws(() => new private.Class._constructor(), /// 06: static type warning
+ (e) => e is NoSuchMethodError); /// 06: continued
+}
\ No newline at end of file
diff --git a/tests/language/regress_17382_test.dart b/tests/language/regress_17382_test.dart
new file mode 100644
index 0000000..749bcf0
--- /dev/null
+++ b/tests/language/regress_17382_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for issue 17382.
+
+import 'package:expect/expect.dart';
+
+var mCalled = false;
+
+m(x) { mCalled = true; return x; }
+
+main() {
+ try {
+ tl(m(0));
+ } catch (e) {
+ }
+ Expect.isTrue(mCalled);
+}
+
diff --git a/tests/language/regress_21912_test.dart b/tests/language/regress_21912_test.dart
new file mode 100644
index 0000000..a978882
--- /dev/null
+++ b/tests/language/regress_21912_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for issue 21912.
+
+class A {}
+class B extends A {}
+
+typedef T Function2<S, T>(S z);
+typedef B AToB(A x);
+typedef A BToA(B x);
+
+void main() {
+ {
+ Function2<Function2<A, B>, Function2<B, A>> t1;
+ Function2<AToB, BToA> t2;
+ Function2<Function2<int, double>, Function2<int, double>> left;
+ left = t1; /// 01: ok
+ left = t2; /// 02: ok
+ }
+}
diff --git a/tests/language/regress_22443_lib.dart b/tests/language/regress_22443_lib.dart
new file mode 100644
index 0000000..4499cf9
--- /dev/null
+++ b/tests/language/regress_22443_lib.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library regress_22443;
+
+class LazyClass {
+}
diff --git a/tests/language/regress_22443_test.dart b/tests/language/regress_22443_test.dart
new file mode 100644
index 0000000..d0a6908
--- /dev/null
+++ b/tests/language/regress_22443_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'regress_22443_lib.dart' deferred as D;
+import 'package:expect/expect.dart';
+
+int fooCount = 0;
+
+foo() {
+ fooCount++;
+ return new D.LazyClass();
+}
+
+main() {
+ var caughtIt = false;
+ try { foo(); } catch (e) { caughtIt = true; };
+ D.loadLibrary().then((_) {
+ foo();
+ Expect.isTrue(caughtIt);
+ Expect.equals(2, fooCount);
+ });
+}
diff --git a/tests/language/regress_22976_test.dart b/tests/language/regress_22976_test.dart
new file mode 100644
index 0000000..67d6957
--- /dev/null
+++ b/tests/language/regress_22976_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for issue 22976.
+
+class A<T> {}
+class B<T> implements A<T> {}
+class C<S, T> implements B<S>, A<T> {}
+
+main() {
+ A<int> a0 = new C<int, String>(); /// 01: ok
+ A<int> a1 = new C<String, int>(); /// 02: ok
+}
diff --git a/tests/language/regress_23038_test.dart b/tests/language/regress_23038_test.dart
new file mode 100644
index 0000000..643ca78
--- /dev/null
+++ b/tests/language/regress_23038_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class C<T> {
+ const
+ factory /// 01: compile-time error
+ C()
+ = C<C<T>> /// 01: continued
+ ;
+}
+
+main() {
+ const C<int>();
+}
diff --git a/tests/language/regress_23046_test.dart b/tests/language/regress_23046_test.dart
new file mode 100644
index 0000000..cb7b84a
--- /dev/null
+++ b/tests/language/regress_23046_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Make sure the logic for skipping the initial quotes in a string isn't
+// re-triggered after an interpolation expression.
+
+const String x = '$y"';
+const String y = 'foo';
+const Map m = const { x: 0, y: 1 };
+
+main() {
+ Expect.equals(x, 'foo"');
+ Expect.equals(m.length, 2);
+}
diff --git a/tests/language/regress_23051_test.dart b/tests/language/regress_23051_test.dart
new file mode 100644
index 0000000..6d466d3
--- /dev/null
+++ b/tests/language/regress_23051_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for issue 23051.
+
+main() {
+ new A(); /// 01: compile-time error
+}
+
+class A { /// 01: continued
+ // Note the trailing ' in the next line. /// 01: continued
+ get foo => bar();' /// 01: continued
+ /// 01: continued
+ String bar( /// 01: continued
\ No newline at end of file
diff --git a/tests/language/regress_23089_test.dart b/tests/language/regress_23089_test.dart
new file mode 100644
index 0000000..138749f
--- /dev/null
+++ b/tests/language/regress_23089_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+abstract class IPeer<C extends IP2PClient> {
+}
+
+abstract class IPeerRoom<P extends IPeer, C extends IP2PClient> {
+}
+
+abstract class IP2PClient<R extends IPeerRoom> {
+
+}
+
+class _Peer<C extends _P2PClient> implements IPeer<C> {
+
+}
+
+class _PeerRoom<P extends _Peer, C extends _P2PClient>
+ implements IPeerRoom<P, C> {
+
+}
+
+abstract class _P2PClient<R extends _PeerRoom, P extends _Peer>
+ implements IP2PClient<R> {
+
+}
+
+void main() {
+}
diff --git a/tests/language/super_conditional_operator_test.dart b/tests/language/super_conditional_operator_test.dart
new file mode 100644
index 0000000..83914ee
--- /dev/null
+++ b/tests/language/super_conditional_operator_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that the ?. operator cannot be used with "super".
+
+// SharedOptions=--enable-null-aware-operators
+
+class B {
+ B();
+ B.namedConstructor();
+ var field = 1;
+ method() => 1;
+}
+
+class C extends B {
+ C()
+ : super?.namedConstructor() /// 01: compile-time error
+ ;
+
+ test() {
+ super?.field = 1; /// 02: compile-time error
+ super?.field += 1; /// 03: compile-time error
+ super?.field ??= 1; /// 04: compile-time error
+ super?.field; /// 05: compile-time error
+ 1 * super?.field; /// 06: compile-time error
+ -super?.field; /// 07: compile-time error
+ ~super?.field; /// 08: compile-time error
+ !super?.field; /// 09: compile-time error
+ --super?.field; /// 10: compile-time error
+ ++super?.field; /// 11: compile-time error
+ super?.method(); /// 12: compile-time error
+ 1 * super?.method(); /// 13: compile-time error
+ -super?.method(); /// 14: compile-time error
+ ~super?.method(); /// 15: compile-time error
+ !super?.method(); /// 16: compile-time error
+ --super?.method(); /// 17: compile-time error
+ ++super?.method(); /// 18: compile-time error
+ }
+}
+
+main() {
+ new C().test();
+}
diff --git a/tests/language/vm/regress_23117_vm_test.dart b/tests/language/vm/regress_23117_vm_test.dart
new file mode 100644
index 0000000..550d550
--- /dev/null
+++ b/tests/language/vm/regress_23117_vm_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Test location summary for Uint32 multiplication.
+// VMOptions=--optimization-counter-threshold=5
+
+import 'package:expect/expect.dart';
+
+mintLeftShift(x, y) => x << y;
+mintRightShift(x, y) => x >> y;
+
+main() {
+ for (var i = 0; i < 20; i++) {
+ var x = 1 + (1 << (i + 32));
+ Expect.equals(x, mintLeftShift(x, 0));
+ Expect.equals(x, mintRightShift(x, 0));
+ Expect.equals(2*x, mintLeftShift(x, 1));
+ Expect.equals(x~/2, mintRightShift(x, 1));
+ Expect.equals(x, mintRightShift(mintLeftShift(x, i), i));
+ }
+}
diff --git a/tests/lib/convert/html_escape_test.dart b/tests/lib/convert/html_escape_test.dart
index 674c781..787ae34 100644
--- a/tests/lib/convert/html_escape_test.dart
+++ b/tests/lib/convert/html_escape_test.dart
@@ -8,16 +8,19 @@
const _NOOP = 'Nothing_to_escape';
-const _TEST_INPUT = '<A </test> of \u00A0 "double" & \'single\' values>';
+const _TEST_INPUT = """<A </test> of \xA0 "double" & 'single' values>""";
-const _OUTPUT_UNKNOWN = '<A </test> of "double" & '
- ''single' values>';
+const _OUTPUT_UNKNOWN = '<A </test> of \xA0 "double" & '
+ ''single' values>';
-const _OUTPUT_ATTRIBUTE = "<A </test> of "double" & "
- "\'single\' values>";
+const _OUTPUT_ATTRIBUTE =
+ "<A </test> of \xA0 "double" & 'single' values>";
-const _OUTPUT_ELEMENT = '<A </test> of "double" & '
- '\'single\' values>';
+const _OUTPUT_SQ_ATTRIBUTE =
+ '<A </test> of \xA0 "double" & 'single' values>';
+
+const _OUTPUT_ELEMENT =
+ """<A </test> of \xA0 "double" & 'single' values>""";
void _testMode(HtmlEscape escape, String input, String expected) {
_testConvert(escape, input, expected);
@@ -80,6 +83,7 @@
_testMode(const HtmlEscape(), _TEST_INPUT, _OUTPUT_UNKNOWN);
_testMode(const HtmlEscape(HtmlEscapeMode.UNKNOWN), _TEST_INPUT, _OUTPUT_UNKNOWN);
_testMode(const HtmlEscape(HtmlEscapeMode.ATTRIBUTE), _TEST_INPUT, _OUTPUT_ATTRIBUTE);
+ _testMode(const HtmlEscape(HtmlEscapeMode.SQ_ATTRIBUTE), _TEST_INPUT, _OUTPUT_SQ_ATTRIBUTE);
_testMode(const HtmlEscape(HtmlEscapeMode.ELEMENT), _TEST_INPUT, _OUTPUT_ELEMENT);
_testMode(HTML_ESCAPE, _NOOP, _NOOP);
}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 6e59d60..a965810 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -247,7 +247,6 @@
[ $compiler == none ]
async/timer_not_available_test: SkipByDesign # only meant to test when there is no way to implement timer (currently only in d8)
-mirrors/generic_local_function_test: RuntimeError # Issue 14913
mirrors/symbol_validation_test: RuntimeError # Issue 13596
mirrors/mirrors_used*: SkipByDesign # Invalid tests. MirrorsUsed does not have a specification, and dart:mirrors is not required to hide declarations that are not covered by any MirrorsUsed annotation.
@@ -288,6 +287,9 @@
# Deferred loading is not supported by dart2dart.
async/deferred/deferred_in_isolate_test: Skip # Issue 17523
+[ $compiler == dart2dart && $builder_tag == new_backend ]
+async/future_test: RuntimeError # Issue 23015
+
[ $compiler == none && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
# Dart vm does not support spawn from a dom-enabled isolate.
async/deferred/deferred_in_isolate_test: RuntimeError # Issue 16209
diff --git a/tests/lib/mirrors/method_mirror_source_other.dart b/tests/lib/mirrors/method_mirror_source_other.dart
new file mode 100644
index 0000000..29adf5b
--- /dev/null
+++ b/tests/lib/mirrors/method_mirror_source_other.dart
@@ -0,0 +1,6 @@
+main() {
+ print("Blah");
+}
+// This function must be on the first line.
+
+class SomethingInOther {}
\ No newline at end of file
diff --git a/tests/lib/mirrors/method_mirror_source_test.dart b/tests/lib/mirrors/method_mirror_source_test.dart
index d0aad92..9b09452 100644
--- a/tests/lib/mirrors/method_mirror_source_test.dart
+++ b/tests/lib/mirrors/method_mirror_source_test.dart
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
import "dart:mirrors";
-
import "package:expect/expect.dart";
+import "method_mirror_source_other.dart";
expectSource(Mirror mirror, String source) {
MethodMirror methodMirror;
@@ -14,7 +14,7 @@
methodMirror = mirror as MethodMirror;
}
Expect.isTrue(methodMirror is MethodMirror);
- Expect.equals(methodMirror.source, source);
+ Expect.equals(source, methodMirror.source);
}
foo1() {}
@@ -98,4 +98,11 @@
var a = () {};
expectSource(reflect(namedClosure), "namedClosure(x,y,z) => 1;");
expectSource(reflect(a), "() {}");
+
+ // Function at first line.
+ LibraryMirror otherLib = reflectClass(SomethingInOther).owner;
+ expectSource(otherLib.declarations[#main],
+"""main() {
+ print("Blah");
+}""");
}
diff --git a/tests/lib/mirrors/optional_parameters_test.dart b/tests/lib/mirrors/optional_parameters_test.dart
new file mode 100644
index 0000000..edb3f56
--- /dev/null
+++ b/tests/lib/mirrors/optional_parameters_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for http://dartbug.com/22987.
+// Ensure that functions whose signature only differs in optionality of
+// parameters are reflected correctly.
+
+library optional_parameter_test;
+
+@MirrorsUsed(targets: 'optional_parameter_test')
+import "dart:mirrors";
+import 'package:expect/expect.dart';
+
+class A {
+ foo(int x) => x;
+}
+
+class B {
+ foo([int x]) => x+1;
+}
+
+main () {
+ var x = {};
+ x["A"] = reflect(new A());
+ x["B"] = reflect(new B());
+
+ Expect.equals(1, x["A"].invoke(#foo, [1]).reflectee);
+ Expect.equals(2, x["B"].invoke(#foo, [1]).reflectee);
+}
diff --git a/tests/lib/mirrors/reflect_two_classes_test.dart b/tests/lib/mirrors/reflect_two_classes_test.dart
new file mode 100644
index 0000000..83c71de
--- /dev/null
+++ b/tests/lib/mirrors/reflect_two_classes_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This is a regression test for http://dartbug.com/23054
+
+library index;
+
+@MirrorsUsed(targets: const [Bar, Foo], symbols: const ['bar', 'getBar', 'foo', 'getFoo'], override: '*')
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+main() {
+ var bar = new Bar();
+ var barMirror = reflect(bar);
+ Expect.equals(42, barMirror.getField(#bar).reflectee, "bar field");
+ Expect.equals(42, barMirror.invoke(#getBar, []).reflectee, "getBar Method");
+
+ var foo = new Foo();
+ var fooMirror = reflect(foo);
+ Expect.equals(9, fooMirror.getField(#foo).reflectee, "foo field");
+ Expect.equals(9, fooMirror.invoke(#getFoo, []).reflectee, "getFoo Method");
+}
+
+class Bar {
+ int bar = 42;
+
+ int getBar() => bar;
+}
+
+class Foo {
+ int foo = 9;
+
+ int getFoo() => foo;
+}
+
diff --git a/tests/standalone/io/http_parser_test.dart b/tests/standalone/io/http_parser_test.dart
index c5da991..6302dc6 100644
--- a/tests/standalone/io/http_parser_test.dart
+++ b/tests/standalone/io/http_parser_test.dart
@@ -150,6 +150,42 @@
testWrite(requestData, 1);
}
+ static void _testParseRequestLean(String request,
+ String expectedMethod,
+ String expectedUri,
+ {int expectedTransferLength: 0,
+ int expectedBytesReceived: 0,
+ Map expectedHeaders: null,
+ bool chunked: false,
+ bool upgrade: false,
+ int unparsedLength: 0,
+ bool connectionClose: false,
+ String expectedVersion: "1.1"}) {
+ _testParseRequest(request,
+ expectedMethod,
+ expectedUri,
+ expectedTransferLength: expectedTransferLength,
+ expectedBytesReceived: expectedBytesReceived,
+ expectedHeaders: expectedHeaders,
+ chunked: chunked,
+ upgrade: upgrade,
+ unparsedLength: unparsedLength,
+ connectionClose: connectionClose,
+ expectedVersion: expectedVersion);
+ // Same test but with only \n instead of \r\n terminating each header line.
+ _testParseRequest(request.replaceAll('\r', ''),
+ expectedMethod,
+ expectedUri,
+ expectedTransferLength: expectedTransferLength,
+ expectedBytesReceived: expectedBytesReceived,
+ expectedHeaders: expectedHeaders,
+ chunked: chunked,
+ upgrade: upgrade,
+ unparsedLength: unparsedLength,
+ connectionClose: connectionClose,
+ expectedVersion: expectedVersion);
+ }
+
static void _testParseInvalidRequest(String request) {
_HttpParser httpParser;
bool errorCalled;
@@ -356,33 +392,33 @@
"SEARCH",
// Methods with HTTP prefix.
"H", "HT", "HTT", "HTTP", "HX", "HTX", "HTTX", "HTTPX"];
+ methods = ['GET'];
methods.forEach((method) {
request = "$method / HTTP/1.1\r\n\r\n";
- _testParseRequest(request, method, "/");
+ _testParseRequestLean(request, method, "/");
request = "$method /index.html HTTP/1.1\r\n\r\n";
- _testParseRequest(request, method, "/index.html");
+ _testParseRequestLean(request, method, "/index.html");
});
-
request = "GET / HTTP/1.0\r\n\r\n";
- _testParseRequest(request, "GET", "/",
- expectedVersion: "1.0",
- connectionClose: true);
+ _testParseRequestLean(request, "GET", "/",
+ expectedVersion: "1.0",
+ connectionClose: true);
request = "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n";
- _testParseRequest(request, "GET", "/", expectedVersion: "1.0");
+ _testParseRequestLean(request, "GET", "/", expectedVersion: "1.0");
request = """
POST /test HTTP/1.1\r
AAA: AAA\r
\r
""";
- _testParseRequest(request, "POST", "/test");
+ _testParseRequestLean(request, "POST", "/test");
request = """
POST /test HTTP/1.1\r
\r
""";
- _testParseRequest(request, "POST", "/test");
+ _testParseRequestLean(request, "POST", "/test");
request = """
POST /test HTTP/1.1\r
@@ -393,7 +429,7 @@
headers = new Map();
headers["header-a"] = "AAA";
headers["x-header-b"] = "bbb";
- _testParseRequest(request, "POST", "/test", expectedHeaders: headers);
+ _testParseRequestLean(request, "POST", "/test", expectedHeaders: headers);
request = """
POST /test HTTP/1.1\r
@@ -405,7 +441,7 @@
headers = new Map();
headers["empty-header-1"] = "";
headers["empty-header-2"] = "";
- _testParseRequest(request, "POST", "/test", expectedHeaders: headers);
+ _testParseRequestLean(request, "POST", "/test", expectedHeaders: headers);
request = """
POST /test HTTP/1.1\r
@@ -416,7 +452,7 @@
headers = new Map();
headers["header-a"] = "AAA";
headers["x-header-b"] = "bbb";
- _testParseRequest(request, "POST", "/test", expectedHeaders: headers);
+ _testParseRequestLean(request, "POST", "/test", expectedHeaders: headers);
request = """
POST /test HTTP/1.1\r
@@ -431,18 +467,18 @@
headers = new Map();
headers["header-a"] = "AAA";
headers["x-header-b"] = "bbb";
- _testParseRequest(request, "POST", "/test", expectedHeaders: headers);
+ _testParseRequestLean(request, "POST", "/test", expectedHeaders: headers);
request = """
POST /test HTTP/1.1\r
Content-Length: 10\r
\r
0123456789""";
- _testParseRequest(request,
- "POST",
- "/test",
- expectedTransferLength: 10,
- expectedBytesReceived: 10);
+ _testParseRequestLean(request,
+ "POST",
+ "/test",
+ expectedTransferLength: 10,
+ expectedBytesReceived: 10);
// Test connection close header.
request = "GET /test HTTP/1.1\r\nConnection: close\r\n\r\n";
diff --git a/tools/VERSION b/tools/VERSION
index 80747fa..0476332 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 10
PATCH 0
-PRERELEASE 0
-PRERELEASE_PATCH 2
+PRERELEASE 1
+PRERELEASE_PATCH 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index f166bc1..9e47f59 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -80,6 +80,8 @@
test_set = web_pattern.group(4)
if web_pattern.group(6) == 'csp':
csp = True
+ # Always run csp mode minified
+ minified = True
shard_index = web_pattern.group(8)
total_shards = web_pattern.group(9)
elif dart2js_full_pattern:
diff --git a/tools/build.py b/tools/build.py
index ec0646b..4282589 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -55,7 +55,7 @@
default=False, action="store_true")
result.add_option("-a", "--arch",
help='Target architectures (comma-separated).',
- metavar='[all,ia32,x64,simarm,arm,simmips,mips,simarm64,arm64,]',
+ metavar='[all,ia32,x64,simarm,arm,armv5te,simmips,mips,simarm64,arm64,]',
default=utils.GuessArchitecture())
result.add_option("--os",
help='Target OSs (comma-separated).',
@@ -105,7 +105,7 @@
print "Unknown mode %s" % mode
return False
for arch in options.arch:
- archs = ['ia32', 'x64', 'simarm', 'arm', 'simmips', 'mips',
+ archs = ['ia32', 'x64', 'simarm', 'arm', 'armv5te', 'simmips', 'mips',
'simarm64', 'arm64',]
if not arch in archs:
print "Unknown arch %s" % arch
@@ -123,7 +123,7 @@
print ("Cross-compilation to %s is not supported on host os %s."
% (os_name, HOST_OS))
return False
- if not arch in ['ia32', 'arm', 'arm64', 'mips']:
+ if not arch in ['ia32', 'arm', 'armv5te', 'arm64', 'mips']:
print ("Cross-compilation to %s is not supported for architecture %s."
% (os_name, arch))
return False
@@ -162,6 +162,7 @@
return None
+
def SetTools(arch, target_os, options):
toolsOverride = None
diff --git a/tools/dom/scripts/cssProperties.CSS21.txt b/tools/dom/scripts/cssProperties.CSS21.txt
new file mode 100644
index 0000000..8c715c5
--- /dev/null
+++ b/tools/dom/scripts/cssProperties.CSS21.txt
@@ -0,0 +1,102 @@
+// Universally supported properties.
+//
+// This list was constructed by filtering CSS2.1 properties against
+// CSSPropertyNames.in
+//
+// TODO(sra): Remove this file once we have samples from all supported browsers.
+
+backgroundAttachment
+backgroundColor
+backgroundImage
+backgroundPosition
+backgroundRepeat
+background
+borderCollapse
+borderColor
+borderSpacing
+borderStyle
+borderTop
+borderRight
+borderBottom
+borderLeft
+borderTopColor
+borderRightColor
+borderBottomColor
+borderLeftColor
+borderTopStyle
+borderRightStyle
+borderBottomStyle
+borderLeftStyle
+borderTopWidth
+borderRightWidth
+borderBottomWidth
+borderLeftWidth
+borderWidth
+border
+bottom
+captionSide
+clear
+clip
+color
+content
+counterIncrement
+counterReset
+cursor
+direction
+display
+emptyCells
+float
+fontFamily
+fontSize
+fontStyle
+fontVariant
+fontWeight
+font
+height
+left
+letterSpacing
+lineHeight
+listStyleImage
+listStylePosition
+listStyleType
+listStyle
+marginRight
+marginLeft
+marginTop
+marginBottom
+margin
+maxHeight
+maxWidth
+minHeight
+minWidth
+orphans
+outlineColor
+outlineStyle
+outlineWidth
+outline
+overflow
+paddingTop
+paddingRight
+paddingBottom
+paddingLeft
+padding
+pageBreakAfter
+pageBreakBefore
+pageBreakInside
+position
+quotes
+right
+tableLayout
+textAlign
+textDecoration
+textIndent
+textTransform
+top
+unicodeBidi
+verticalAlign
+visibility
+whiteSpace
+widows
+width
+wordSpacing
+zIndex
diff --git a/tools/dom/scripts/cssProperties.chrome40.txt b/tools/dom/scripts/cssProperties.chrome40.txt
new file mode 100644
index 0000000..5bb010d
--- /dev/null
+++ b/tools/dom/scripts/cssProperties.chrome40.txt
@@ -0,0 +1,358 @@
+# Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36
+cssText
+alignContent
+alignItems
+alignSelf
+alignmentBaseline
+all
+backfaceVisibility
+background
+backgroundAttachment
+backgroundBlendMode
+backgroundClip
+backgroundColor
+backgroundImage
+backgroundOrigin
+backgroundPosition
+backgroundPositionX
+backgroundPositionY
+backgroundRepeat
+backgroundRepeatX
+backgroundRepeatY
+backgroundSize
+baselineShift
+border
+borderBottom
+borderBottomColor
+borderBottomLeftRadius
+borderBottomRightRadius
+borderBottomStyle
+borderBottomWidth
+borderCollapse
+borderColor
+borderImage
+borderImageOutset
+borderImageRepeat
+borderImageSlice
+borderImageSource
+borderImageWidth
+borderLeft
+borderLeftColor
+borderLeftStyle
+borderLeftWidth
+borderRadius
+borderRight
+borderRightColor
+borderRightStyle
+borderRightWidth
+borderSpacing
+borderStyle
+borderTop
+borderTopColor
+borderTopLeftRadius
+borderTopRightRadius
+borderTopStyle
+borderTopWidth
+borderWidth
+bottom
+boxShadow
+boxSizing
+bufferedRendering
+captionSide
+clear
+clip
+clipPath
+clipRule
+color
+colorInterpolation
+colorInterpolationFilters
+colorRendering
+content
+counterIncrement
+counterReset
+cursor
+direction
+display
+dominantBaseline
+emptyCells
+enableBackground
+fill
+fillOpacity
+fillRule
+filter
+flex
+flexBasis
+flexDirection
+flexFlow
+flexGrow
+flexShrink
+flexWrap
+float
+floodColor
+floodOpacity
+font
+fontFamily
+fontKerning
+fontSize
+fontStretch
+fontStyle
+fontVariant
+fontVariantLigatures
+fontWeight
+glyphOrientationHorizontal
+glyphOrientationVertical
+height
+imageRendering
+justifyContent
+left
+letterSpacing
+lightingColor
+lineHeight
+listStyle
+listStyleImage
+listStylePosition
+listStyleType
+margin
+marginBottom
+marginLeft
+marginRight
+marginTop
+marker
+markerEnd
+markerMid
+markerStart
+mask
+maskType
+maxHeight
+maxWidth
+maxZoom
+minHeight
+minWidth
+minZoom
+objectFit
+objectPosition
+opacity
+order
+orientation
+orphans
+outline
+outlineColor
+outlineOffset
+outlineStyle
+outlineWidth
+overflow
+overflowWrap
+overflowX
+overflowY
+padding
+paddingBottom
+paddingLeft
+paddingRight
+paddingTop
+page
+pageBreakAfter
+pageBreakBefore
+pageBreakInside
+paintOrder
+perspective
+perspectiveOrigin
+pointerEvents
+position
+quotes
+resize
+right
+shapeImageThreshold
+shapeMargin
+shapeOutside
+shapeRendering
+size
+speak
+src
+stopColor
+stopOpacity
+stroke
+strokeDasharray
+strokeDashoffset
+strokeLinecap
+strokeLinejoin
+strokeMiterlimit
+strokeOpacity
+strokeWidth
+tabSize
+tableLayout
+textAlign
+textAnchor
+textDecoration
+textIndent
+textOverflow
+textRendering
+textShadow
+textTransform
+top
+touchAction
+transform
+transformOrigin
+transformStyle
+transition
+transitionDelay
+transitionDuration
+transitionProperty
+transitionTimingFunction
+unicodeBidi
+unicodeRange
+userZoom
+vectorEffect
+verticalAlign
+visibility
+webkitAnimation
+webkitAnimationDelay
+webkitAnimationDirection
+webkitAnimationDuration
+webkitAnimationFillMode
+webkitAnimationIterationCount
+webkitAnimationName
+webkitAnimationPlayState
+webkitAnimationTimingFunction
+webkitAppRegion
+webkitAppearance
+webkitBackfaceVisibility
+webkitBackgroundClip
+webkitBackgroundComposite
+webkitBackgroundOrigin
+webkitBackgroundSize
+webkitBorderAfter
+webkitBorderAfterColor
+webkitBorderAfterStyle
+webkitBorderAfterWidth
+webkitBorderBefore
+webkitBorderBeforeColor
+webkitBorderBeforeStyle
+webkitBorderBeforeWidth
+webkitBorderEnd
+webkitBorderEndColor
+webkitBorderEndStyle
+webkitBorderEndWidth
+webkitBorderHorizontalSpacing
+webkitBorderImage
+webkitBorderRadius
+webkitBorderStart
+webkitBorderStartColor
+webkitBorderStartStyle
+webkitBorderStartWidth
+webkitBorderVerticalSpacing
+webkitBoxAlign
+webkitBoxDecorationBreak
+webkitBoxDirection
+webkitBoxFlex
+webkitBoxFlexGroup
+webkitBoxLines
+webkitBoxOrdinalGroup
+webkitBoxOrient
+webkitBoxPack
+webkitBoxReflect
+webkitBoxShadow
+webkitClipPath
+webkitColumnBreakAfter
+webkitColumnBreakBefore
+webkitColumnBreakInside
+webkitColumnCount
+webkitColumnGap
+webkitColumnRule
+webkitColumnRuleColor
+webkitColumnRuleStyle
+webkitColumnRuleWidth
+webkitColumnSpan
+webkitColumnWidth
+webkitColumns
+webkitFilter
+webkitFontFeatureSettings
+webkitFontSizeDelta
+webkitFontSmoothing
+webkitHighlight
+webkitHyphenateCharacter
+webkitLineBoxContain
+webkitLineBreak
+webkitLineClamp
+webkitLocale
+webkitLogicalHeight
+webkitLogicalWidth
+webkitMarginAfter
+webkitMarginAfterCollapse
+webkitMarginBefore
+webkitMarginBeforeCollapse
+webkitMarginBottomCollapse
+webkitMarginCollapse
+webkitMarginEnd
+webkitMarginStart
+webkitMarginTopCollapse
+webkitMask
+webkitMaskBoxImage
+webkitMaskBoxImageOutset
+webkitMaskBoxImageRepeat
+webkitMaskBoxImageSlice
+webkitMaskBoxImageSource
+webkitMaskBoxImageWidth
+webkitMaskClip
+webkitMaskComposite
+webkitMaskImage
+webkitMaskOrigin
+webkitMaskPosition
+webkitMaskPositionX
+webkitMaskPositionY
+webkitMaskRepeat
+webkitMaskRepeatX
+webkitMaskRepeatY
+webkitMaskSize
+webkitMaxLogicalHeight
+webkitMaxLogicalWidth
+webkitMinLogicalHeight
+webkitMinLogicalWidth
+webkitPaddingAfter
+webkitPaddingBefore
+webkitPaddingEnd
+webkitPaddingStart
+webkitPerspective
+webkitPerspectiveOrigin
+webkitPerspectiveOriginX
+webkitPerspectiveOriginY
+webkitPrintColorAdjust
+webkitRtlOrdering
+webkitRubyPosition
+webkitTapHighlightColor
+webkitTextCombine
+webkitTextDecorationsInEffect
+webkitTextEmphasis
+webkitTextEmphasisColor
+webkitTextEmphasisPosition
+webkitTextEmphasisStyle
+webkitTextFillColor
+webkitTextOrientation
+webkitTextSecurity
+webkitTextStroke
+webkitTextStrokeColor
+webkitTextStrokeWidth
+webkitTransform
+webkitTransformOrigin
+webkitTransformOriginX
+webkitTransformOriginY
+webkitTransformOriginZ
+webkitTransformStyle
+webkitTransition
+webkitTransitionDelay
+webkitTransitionDuration
+webkitTransitionProperty
+webkitTransitionTimingFunction
+webkitUserDrag
+webkitUserModify
+webkitUserSelect
+webkitWritingMode
+whiteSpace
+widows
+width
+willChange
+wordBreak
+wordSpacing
+wordWrap
+writingMode
+zIndex
+zoom
diff --git a/tools/dom/scripts/cssProperties.ff36.txt b/tools/dom/scripts/cssProperties.ff36.txt
new file mode 100644
index 0000000..5b649d6
--- /dev/null
+++ b/tools/dom/scripts/cssProperties.ff36.txt
@@ -0,0 +1,474 @@
+# Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:36.0) Gecko/20100101 Firefox/36.0
+# 472 properties
+MozAnimation
+MozAnimationDelay
+MozAnimationDirection
+MozAnimationDuration
+MozAnimationFillMode
+MozAnimationIterationCount
+MozAnimationName
+MozAnimationPlayState
+MozAnimationTimingFunction
+MozAppearance
+MozBackfaceVisibility
+MozBinding
+MozBorderBottomColors
+MozBorderEnd
+MozBorderEndColor
+MozBorderEndStyle
+MozBorderEndWidth
+MozBorderImage
+MozBorderLeftColors
+MozBorderRightColors
+MozBorderStart
+MozBorderStartColor
+MozBorderStartStyle
+MozBorderStartWidth
+MozBorderTopColors
+MozBoxAlign
+MozBoxDirection
+MozBoxFlex
+MozBoxOrdinalGroup
+MozBoxOrient
+MozBoxPack
+MozBoxSizing
+MozColumnCount
+MozColumnFill
+MozColumnGap
+MozColumnRule
+MozColumnRuleColor
+MozColumnRuleStyle
+MozColumnRuleWidth
+MozColumnWidth
+MozColumns
+MozFloatEdge
+MozFontFeatureSettings
+MozFontLanguageOverride
+MozForceBrokenImageIcon
+MozHyphens
+MozImageRegion
+MozMarginEnd
+MozMarginStart
+MozOrient
+MozOutlineRadius
+MozOutlineRadiusBottomleft
+MozOutlineRadiusBottomright
+MozOutlineRadiusTopleft
+MozOutlineRadiusTopright
+MozPaddingEnd
+MozPaddingStart
+MozPerspective
+MozPerspectiveOrigin
+MozStackSizing
+MozTabSize
+MozTextAlignLast
+MozTextDecorationColor
+MozTextDecorationLine
+MozTextDecorationStyle
+MozTextSizeAdjust
+MozTransform
+MozTransformOrigin
+MozTransformStyle
+MozTransition
+MozTransitionDelay
+MozTransitionDuration
+MozTransitionProperty
+MozTransitionTimingFunction
+MozUserFocus
+MozUserInput
+MozUserModify
+MozUserSelect
+MozWindowDragging
+MozWindowShadow
+align-content
+align-items
+align-self
+alignContent
+alignItems
+alignSelf
+all
+animation
+animation-delay
+animation-direction
+animation-duration
+animation-fill-mode
+animation-iteration-count
+animation-name
+animation-play-state
+animation-timing-function
+animationDelay
+animationDirection
+animationDuration
+animationFillMode
+animationIterationCount
+animationName
+animationPlayState
+animationTimingFunction
+backface-visibility
+backfaceVisibility
+background
+background-attachment
+background-blend-mode
+background-clip
+background-color
+background-image
+background-origin
+background-position
+background-repeat
+background-size
+backgroundAttachment
+backgroundBlendMode
+backgroundClip
+backgroundColor
+backgroundImage
+backgroundOrigin
+backgroundPosition
+backgroundRepeat
+backgroundSize
+border
+border-bottom
+border-bottom-color
+border-bottom-left-radius
+border-bottom-right-radius
+border-bottom-style
+border-bottom-width
+border-collapse
+border-color
+border-image
+border-image-outset
+border-image-repeat
+border-image-slice
+border-image-source
+border-image-width
+border-left
+border-left-color
+border-left-style
+border-left-width
+border-radius
+border-right
+border-right-color
+border-right-style
+border-right-width
+border-spacing
+border-style
+border-top
+border-top-color
+border-top-left-radius
+border-top-right-radius
+border-top-style
+border-top-width
+border-width
+borderBottom
+borderBottomColor
+borderBottomLeftRadius
+borderBottomRightRadius
+borderBottomStyle
+borderBottomWidth
+borderCollapse
+borderColor
+borderImage
+borderImageOutset
+borderImageRepeat
+borderImageSlice
+borderImageSource
+borderImageWidth
+borderLeft
+borderLeftColor
+borderLeftStyle
+borderLeftWidth
+borderRadius
+borderRight
+borderRightColor
+borderRightStyle
+borderRightWidth
+borderSpacing
+borderStyle
+borderTop
+borderTopColor
+borderTopLeftRadius
+borderTopRightRadius
+borderTopStyle
+borderTopWidth
+borderWidth
+bottom
+box-decoration-break
+box-shadow
+box-sizing
+boxDecorationBreak
+boxShadow
+boxSizing
+caption-side
+captionSide
+clear
+clip
+clip-path
+clip-rule
+clipPath
+clipRule
+color
+color-interpolation
+color-interpolation-filters
+colorInterpolation
+colorInterpolationFilters
+content
+counter-increment
+counter-reset
+counterIncrement
+counterReset
+cssFloat
+cssText
+cursor
+direction
+display
+dominant-baseline
+dominantBaseline
+empty-cells
+emptyCells
+fill
+fill-opacity
+fill-rule
+fillOpacity
+fillRule
+filter
+flex
+flex-basis
+flex-direction
+flex-flow
+flex-grow
+flex-shrink
+flex-wrap
+flexBasis
+flexDirection
+flexFlow
+flexGrow
+flexShrink
+flexWrap
+float
+flood-color
+flood-opacity
+floodColor
+floodOpacity
+font
+font-family
+font-feature-settings
+font-kerning
+font-language-override
+font-size
+font-size-adjust
+font-stretch
+font-style
+font-synthesis
+font-variant
+font-variant-alternates
+font-variant-caps
+font-variant-east-asian
+font-variant-ligatures
+font-variant-numeric
+font-variant-position
+font-weight
+fontFamily
+fontFeatureSettings
+fontKerning
+fontLanguageOverride
+fontSize
+fontSizeAdjust
+fontStretch
+fontStyle
+fontSynthesis
+fontVariant
+fontVariantAlternates
+fontVariantCaps
+fontVariantEastAsian
+fontVariantLigatures
+fontVariantNumeric
+fontVariantPosition
+fontWeight
+height
+image-orientation
+image-rendering
+imageOrientation
+imageRendering
+ime-mode
+imeMode
+isolation
+justify-content
+justifyContent
+left
+letter-spacing
+letterSpacing
+lighting-color
+lightingColor
+line-height
+lineHeight
+list-style
+list-style-image
+list-style-position
+list-style-type
+listStyle
+listStyleImage
+listStylePosition
+listStyleType
+margin
+margin-bottom
+margin-left
+margin-right
+margin-top
+marginBottom
+marginLeft
+marginRight
+marginTop
+marker
+marker-end
+marker-mid
+marker-offset
+marker-start
+markerEnd
+markerMid
+markerOffset
+markerStart
+marks
+mask
+mask-type
+maskType
+max-height
+max-width
+maxHeight
+maxWidth
+min-height
+min-width
+minHeight
+minWidth
+mix-blend-mode
+mixBlendMode
+object-fit
+object-position
+objectFit
+objectPosition
+opacity
+order
+orphans
+outline
+outline-color
+outline-offset
+outline-style
+outline-width
+outlineColor
+outlineOffset
+outlineStyle
+outlineWidth
+overflow
+overflow-x
+overflow-y
+overflowX
+overflowY
+padding
+padding-bottom
+padding-left
+padding-right
+padding-top
+paddingBottom
+paddingLeft
+paddingRight
+paddingTop
+page
+page-break-after
+page-break-before
+page-break-inside
+pageBreakAfter
+pageBreakBefore
+pageBreakInside
+paint-order
+paintOrder
+perspective
+perspective-origin
+perspectiveOrigin
+pointer-events
+pointerEvents
+position
+quotes
+resize
+right
+scroll-behavior
+scrollBehavior
+shape-rendering
+shapeRendering
+size
+stop-color
+stop-opacity
+stopColor
+stopOpacity
+stroke
+stroke-dasharray
+stroke-dashoffset
+stroke-linecap
+stroke-linejoin
+stroke-miterlimit
+stroke-opacity
+stroke-width
+strokeDasharray
+strokeDashoffset
+strokeLinecap
+strokeLinejoin
+strokeMiterlimit
+strokeOpacity
+strokeWidth
+table-layout
+tableLayout
+text-align
+text-anchor
+text-decoration
+text-decoration-color
+text-decoration-line
+text-decoration-style
+text-indent
+text-overflow
+text-rendering
+text-shadow
+text-transform
+textAlign
+textAnchor
+textDecoration
+textDecorationColor
+textDecorationLine
+textDecorationStyle
+textIndent
+textOverflow
+textRendering
+textShadow
+textTransform
+top
+transform
+transform-origin
+transform-style
+transformOrigin
+transformStyle
+transition
+transition-delay
+transition-duration
+transition-property
+transition-timing-function
+transitionDelay
+transitionDuration
+transitionProperty
+transitionTimingFunction
+unicode-bidi
+unicodeBidi
+vector-effect
+vectorEffect
+vertical-align
+verticalAlign
+visibility
+white-space
+whiteSpace
+widows
+width
+will-change
+willChange
+word-break
+word-spacing
+word-wrap
+wordBreak
+wordSpacing
+wordWrap
+z-index
+zIndex
diff --git a/tools/dom/scripts/cssProperties.html b/tools/dom/scripts/cssProperties.html
new file mode 100644
index 0000000..a2d8bc4
--- /dev/null
+++ b/tools/dom/scripts/cssProperties.html
@@ -0,0 +1,25 @@
+<!--
+Run this file in a browser to get the CSSStyleDeclaration properties
+available in that browser
+-->
+<body>
+<script>
+function emit(text) {
+ var e = document.createElement('div');
+ e.innerHTML = text;
+ document.body.appendChild(e);
+}
+emit('# ' + navigator.userAgent);
+var s = document.body.style;
+var a = [];
+for (var p in s) {
+ if (typeof s[p] != 'string') continue;
+ a.push(p);
+}
+a.sort();
+emit('# ' + a.length + ' properties')
+for (var i = 0; i < a.length; i++) {
+ emit(a[i]);
+}
+</script>
+</body>
diff --git a/tools/dom/scripts/cssProperties.iPad4Air.onGoogleSites.txt b/tools/dom/scripts/cssProperties.iPad4Air.onGoogleSites.txt
new file mode 100644
index 0000000..5186ff4
--- /dev/null
+++ b/tools/dom/scripts/cssProperties.iPad4Air.onGoogleSites.txt
@@ -0,0 +1,159 @@
+# Mozilla/5.0 (iPad; CPU OS 8_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12D508 Safari/600.1.4
+# 157 properties
+animation
+animationDelay
+animationDirection
+animationDuration
+animationFillMode
+animationIterationCount
+animationName
+animationPlayState
+animationTimingFunction
+appearance
+azimuth
+backfaceVisibility
+background
+backgroundAttachment
+backgroundColor
+backgroundImage
+backgroundPosition
+backgroundRepeat
+backgroundSize
+border
+borderBottom
+borderBottomColor
+borderBottomLeftRadius
+borderBottomRightRadius
+borderBottomStyle
+borderBottomWidth
+borderCollapse
+borderColor
+borderLeft
+borderLeftColor
+borderLeftStyle
+borderLeftWidth
+borderRadius
+borderRight
+borderRightColor
+borderRightStyle
+borderRightWidth
+borderSpacing
+borderStyle
+borderTop
+borderTopColor
+borderTopLeftRadius
+borderTopRightRadius
+borderTopStyle
+borderTopWidth
+borderWidth
+bottom
+box
+boxShadow
+boxSizing
+captionSide
+clear
+clip
+color
+content
+cssFloat
+cue
+cueAfter
+cueBefore
+cursor
+direction
+display
+displayExtras
+displayInside
+displayOutside
+elevation
+emptyCells
+filter
+font
+fontFamily
+fontSize
+fontStretch
+fontStyle
+fontVariant
+fontWeight
+height
+left
+letterSpacing
+lineHeight
+listStyle
+listStyleImage
+listStylePosition
+listStyleType
+margin
+marginBottom
+marginLeft
+marginRight
+marginTop
+maxHeight
+maxWidth
+minHeight
+minWidth
+opacity
+outline
+outlineColor
+outlineStyle
+outlineWidth
+overflow
+overflowWrap
+overflowX
+overflowY
+padding
+paddingBottom
+paddingLeft
+paddingRight
+paddingTop
+pageBreakAfter
+pageBreakBefore
+pageBreakInside
+pause
+pauseAfter
+pauseBefore
+perspective
+perspectiveOrigin
+pitch
+pitchRange
+playDuring
+position
+quotes
+resize
+richness
+right
+speak
+speakHeader
+speakNumeral
+speakPunctuation
+speechRate
+stress
+tableLayout
+textAlign
+textDecoration
+textIndent
+textOverflow
+textShadow
+textTransform
+textWrap
+top
+transform
+transformOrigin
+transformStyle
+transition
+transitionDelay
+transitionDuration
+transitionProperty
+transitionTimingFunction
+unicodeBidi
+verticalAlign
+visibility
+voiceFamily
+volume
+whiteSpace
+width
+wordBreak
+wordSpacing
+wordWrap
+zIndex
+zoom
diff --git a/tools/dom/scripts/cssProperties.ie10.txt b/tools/dom/scripts/cssProperties.ie10.txt
new file mode 100644
index 0000000..57ed3ec
--- /dev/null
+++ b/tools/dom/scripts/cssProperties.ie10.txt
@@ -0,0 +1,296 @@
+# Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Win64; x64; Trident/7.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
+# 294 properties
+accelerator
+alignmentBaseline
+animation
+animationDelay
+animationDirection
+animationDuration
+animationFillMode
+animationIterationCount
+animationName
+animationPlayState
+animationTimingFunction
+backfaceVisibility
+background
+backgroundAttachment
+backgroundClip
+backgroundColor
+backgroundImage
+backgroundOrigin
+backgroundPosition
+backgroundPositionX
+backgroundPositionY
+backgroundRepeat
+backgroundSize
+baselineShift
+behavior
+border
+borderBottom
+borderBottomColor
+borderBottomLeftRadius
+borderBottomRightRadius
+borderBottomStyle
+borderBottomWidth
+borderCollapse
+borderColor
+borderLeft
+borderLeftColor
+borderLeftStyle
+borderLeftWidth
+borderRadius
+borderRight
+borderRightColor
+borderRightStyle
+borderRightWidth
+borderSpacing
+borderStyle
+borderTop
+borderTopColor
+borderTopLeftRadius
+borderTopRightRadius
+borderTopStyle
+borderTopWidth
+borderWidth
+bottom
+boxShadow
+boxSizing
+breakAfter
+breakBefore
+breakInside
+captionSide
+clear
+clip
+clipPath
+clipRule
+color
+colorInterpolationFilters
+columnCount
+columnFill
+columnGap
+columnRule
+columnRuleColor
+columnRuleStyle
+columnRuleWidth
+columnSpan
+columnWidth
+columns
+content
+counterIncrement
+counterReset
+cssFloat
+cssText
+cursor
+direction
+display
+dominantBaseline
+emptyCells
+enableBackground
+fill
+fillOpacity
+fillRule
+filter
+floodColor
+floodOpacity
+font
+fontFamily
+fontFeatureSettings
+fontSize
+fontSizeAdjust
+fontStretch
+fontStyle
+fontVariant
+fontWeight
+glyphOrientationHorizontal
+glyphOrientationVertical
+height
+imeMode
+kerning
+layoutFlow
+layoutGrid
+layoutGridChar
+layoutGridLine
+layoutGridMode
+layoutGridType
+left
+letterSpacing
+lightingColor
+lineBreak
+lineHeight
+listStyle
+listStyleImage
+listStylePosition
+listStyleType
+margin
+marginBottom
+marginLeft
+marginRight
+marginTop
+marker
+markerEnd
+markerMid
+markerStart
+mask
+maxHeight
+maxWidth
+minHeight
+minWidth
+msAnimation
+msAnimationDelay
+msAnimationDirection
+msAnimationDuration
+msAnimationFillMode
+msAnimationIterationCount
+msAnimationName
+msAnimationPlayState
+msAnimationTimingFunction
+msBackfaceVisibility
+msBlockProgression
+msContentZoomChaining
+msContentZoomLimit
+msContentZoomLimitMax
+msContentZoomLimitMin
+msContentZoomSnap
+msContentZoomSnapPoints
+msContentZoomSnapType
+msContentZooming
+msFlex
+msFlexAlign
+msFlexDirection
+msFlexFlow
+msFlexItemAlign
+msFlexLinePack
+msFlexNegative
+msFlexOrder
+msFlexPack
+msFlexPositive
+msFlexPreferredSize
+msFlexWrap
+msFlowFrom
+msFlowInto
+msFontFeatureSettings
+msGridColumn
+msGridColumnAlign
+msGridColumnSpan
+msGridColumns
+msGridRow
+msGridRowAlign
+msGridRowSpan
+msGridRows
+msHighContrastAdjust
+msHyphenateLimitChars
+msHyphenateLimitLines
+msHyphenateLimitZone
+msHyphens
+msInterpolationMode
+msOverflowStyle
+msPerspective
+msPerspectiveOrigin
+msScrollChaining
+msScrollLimit
+msScrollLimitXMax
+msScrollLimitXMin
+msScrollLimitYMax
+msScrollLimitYMin
+msScrollRails
+msScrollSnapPointsX
+msScrollSnapPointsY
+msScrollSnapType
+msScrollSnapX
+msScrollSnapY
+msScrollTranslation
+msTouchAction
+msTouchSelect
+msTransform
+msTransformOrigin
+msTransformStyle
+msTransition
+msTransitionDelay
+msTransitionDuration
+msTransitionProperty
+msTransitionTimingFunction
+msUserSelect
+msWrapFlow
+msWrapMargin
+msWrapThrough
+opacity
+orphans
+outline
+outlineColor
+outlineStyle
+outlineWidth
+overflow
+overflowX
+overflowY
+padding
+paddingBottom
+paddingLeft
+paddingRight
+paddingTop
+pageBreakAfter
+pageBreakBefore
+pageBreakInside
+perspective
+perspectiveOrigin
+pointerEvents
+position
+quotes
+right
+rubyAlign
+rubyOverhang
+rubyPosition
+scrollbar3dLightColor
+scrollbarArrowColor
+scrollbarBaseColor
+scrollbarDarkShadowColor
+scrollbarFaceColor
+scrollbarHighlightColor
+scrollbarShadowColor
+scrollbarTrackColor
+stopColor
+stopOpacity
+stroke
+strokeDasharray
+strokeDashoffset
+strokeLinecap
+strokeLinejoin
+strokeMiterlimit
+strokeOpacity
+strokeWidth
+styleFloat
+tableLayout
+textAlign
+textAlignLast
+textAnchor
+textAutospace
+textDecoration
+textIndent
+textJustify
+textJustifyTrim
+textKashida
+textKashidaSpace
+textOverflow
+textShadow
+textTransform
+textUnderlinePosition
+top
+transform
+transformOrigin
+transformStyle
+transition
+transitionDelay
+transitionDuration
+transitionProperty
+transitionTimingFunction
+unicodeBidi
+verticalAlign
+visibility
+whiteSpace
+widows
+width
+wordBreak
+wordSpacing
+wordWrap
+writingMode
+zIndex
+zoom
diff --git a/tools/dom/scripts/cssProperties.ie11.txt b/tools/dom/scripts/cssProperties.ie11.txt
new file mode 100644
index 0000000..2240ab3
--- /dev/null
+++ b/tools/dom/scripts/cssProperties.ie11.txt
@@ -0,0 +1,316 @@
+# Mozilla/5.0 (Windows NT 6.3; Trident/7.0; .NET4.0E; .NET4.0C; Tablet PC 2.0; rv:11.0) like Gecko
+# 314 properties
+accelerator
+alignContent
+alignItems
+alignSelf
+alignmentBaseline
+animation
+animationDelay
+animationDirection
+animationDuration
+animationFillMode
+animationIterationCount
+animationName
+animationPlayState
+animationTimingFunction
+backfaceVisibility
+background
+backgroundAttachment
+backgroundClip
+backgroundColor
+backgroundImage
+backgroundOrigin
+backgroundPosition
+backgroundPositionX
+backgroundPositionY
+backgroundRepeat
+backgroundSize
+baselineShift
+border
+borderBottom
+borderBottomColor
+borderBottomLeftRadius
+borderBottomRightRadius
+borderBottomStyle
+borderBottomWidth
+borderCollapse
+borderColor
+borderImage
+borderImageOutset
+borderImageRepeat
+borderImageSlice
+borderImageSource
+borderImageWidth
+borderLeft
+borderLeftColor
+borderLeftStyle
+borderLeftWidth
+borderRadius
+borderRight
+borderRightColor
+borderRightStyle
+borderRightWidth
+borderSpacing
+borderStyle
+borderTop
+borderTopColor
+borderTopLeftRadius
+borderTopRightRadius
+borderTopStyle
+borderTopWidth
+borderWidth
+bottom
+boxShadow
+boxSizing
+breakAfter
+breakBefore
+breakInside
+captionSide
+clear
+clip
+clipPath
+clipRule
+color
+colorInterpolationFilters
+columnCount
+columnFill
+columnGap
+columnRule
+columnRuleColor
+columnRuleStyle
+columnRuleWidth
+columnSpan
+columnWidth
+columns
+content
+counterIncrement
+counterReset
+cssFloat
+cssText
+cursor
+direction
+display
+dominantBaseline
+emptyCells
+enableBackground
+fill
+fillOpacity
+fillRule
+filter
+flex
+flexBasis
+flexDirection
+flexFlow
+flexGrow
+flexShrink
+flexWrap
+floodColor
+floodOpacity
+font
+fontFamily
+fontFeatureSettings
+fontSize
+fontSizeAdjust
+fontStretch
+fontStyle
+fontVariant
+fontWeight
+glyphOrientationHorizontal
+glyphOrientationVertical
+height
+imeMode
+justifyContent
+kerning
+layoutFlow
+layoutGrid
+layoutGridChar
+layoutGridLine
+layoutGridMode
+layoutGridType
+left
+letterSpacing
+lightingColor
+lineBreak
+lineHeight
+listStyle
+listStyleImage
+listStylePosition
+listStyleType
+margin
+marginBottom
+marginLeft
+marginRight
+marginTop
+marker
+markerEnd
+markerMid
+markerStart
+mask
+maxHeight
+maxWidth
+minHeight
+minWidth
+msAnimation
+msAnimationDelay
+msAnimationDirection
+msAnimationDuration
+msAnimationFillMode
+msAnimationIterationCount
+msAnimationName
+msAnimationPlayState
+msAnimationTimingFunction
+msBackfaceVisibility
+msBlockProgression
+msContentZoomChaining
+msContentZoomLimit
+msContentZoomLimitMax
+msContentZoomLimitMin
+msContentZoomSnap
+msContentZoomSnapPoints
+msContentZoomSnapType
+msContentZooming
+msFlex
+msFlexAlign
+msFlexDirection
+msFlexFlow
+msFlexItemAlign
+msFlexLinePack
+msFlexNegative
+msFlexOrder
+msFlexPack
+msFlexPositive
+msFlexPreferredSize
+msFlexWrap
+msFlowFrom
+msFlowInto
+msFontFeatureSettings
+msGridColumn
+msGridColumnAlign
+msGridColumnSpan
+msGridColumns
+msGridRow
+msGridRowAlign
+msGridRowSpan
+msGridRows
+msHighContrastAdjust
+msHyphenateLimitChars
+msHyphenateLimitLines
+msHyphenateLimitZone
+msHyphens
+msImeAlign
+msInterpolationMode
+msOverflowStyle
+msPerspective
+msPerspectiveOrigin
+msScrollChaining
+msScrollLimit
+msScrollLimitXMax
+msScrollLimitXMin
+msScrollLimitYMax
+msScrollLimitYMin
+msScrollRails
+msScrollSnapPointsX
+msScrollSnapPointsY
+msScrollSnapType
+msScrollSnapX
+msScrollSnapY
+msScrollTranslation
+msTextCombineHorizontal
+msTouchAction
+msTouchSelect
+msTransform
+msTransformOrigin
+msTransformStyle
+msTransition
+msTransitionDelay
+msTransitionDuration
+msTransitionProperty
+msTransitionTimingFunction
+msUserSelect
+msWrapFlow
+msWrapMargin
+msWrapThrough
+opacity
+order
+orphans
+outline
+outlineColor
+outlineStyle
+outlineWidth
+overflow
+overflowX
+overflowY
+padding
+paddingBottom
+paddingLeft
+paddingRight
+paddingTop
+pageBreakAfter
+pageBreakBefore
+pageBreakInside
+perspective
+perspectiveOrigin
+pointerEvents
+position
+quotes
+right
+rubyAlign
+rubyOverhang
+rubyPosition
+scrollbar3dLightColor
+scrollbarArrowColor
+scrollbarBaseColor
+scrollbarDarkShadowColor
+scrollbarFaceColor
+scrollbarHighlightColor
+scrollbarShadowColor
+scrollbarTrackColor
+stopColor
+stopOpacity
+stroke
+strokeDasharray
+strokeDashoffset
+strokeLinecap
+strokeLinejoin
+strokeMiterlimit
+strokeOpacity
+strokeWidth
+styleFloat
+tableLayout
+textAlign
+textAlignLast
+textAnchor
+textAutospace
+textDecoration
+textIndent
+textJustify
+textJustifyTrim
+textKashida
+textKashidaSpace
+textOverflow
+textShadow
+textTransform
+textUnderlinePosition
+top
+touchAction
+transform
+transformOrigin
+transformStyle
+transition
+transitionDelay
+transitionDuration
+transitionProperty
+transitionTimingFunction
+unicodeBidi
+verticalAlign
+visibility
+whiteSpace
+widows
+width
+wordBreak
+wordSpacing
+wordWrap
+writingMode
+zIndex
+zoom
diff --git a/tools/dom/scripts/cssProperties.ie9.txt b/tools/dom/scripts/cssProperties.ie9.txt
new file mode 100644
index 0000000..035ba26
--- /dev/null
+++ b/tools/dom/scripts/cssProperties.ie9.txt
@@ -0,0 +1,182 @@
+# Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/7.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
+# 180 properties
+accelerator
+alignmentBaseline
+background
+backgroundAttachment
+backgroundClip
+backgroundColor
+backgroundImage
+backgroundOrigin
+backgroundPosition
+backgroundPositionX
+backgroundPositionY
+backgroundRepeat
+backgroundSize
+baselineShift
+behavior
+border
+borderBottom
+borderBottomColor
+borderBottomLeftRadius
+borderBottomRightRadius
+borderBottomStyle
+borderBottomWidth
+borderCollapse
+borderColor
+borderLeft
+borderLeftColor
+borderLeftStyle
+borderLeftWidth
+borderRadius
+borderRight
+borderRightColor
+borderRightStyle
+borderRightWidth
+borderSpacing
+borderStyle
+borderTop
+borderTopColor
+borderTopLeftRadius
+borderTopRightRadius
+borderTopStyle
+borderTopWidth
+borderWidth
+bottom
+boxShadow
+boxSizing
+captionSide
+clear
+clip
+clipPath
+clipRule
+color
+content
+counterIncrement
+counterReset
+cssFloat
+cssText
+cursor
+direction
+display
+dominantBaseline
+emptyCells
+fill
+fillOpacity
+fillRule
+filter
+font
+fontFamily
+fontSize
+fontSizeAdjust
+fontStretch
+fontStyle
+fontVariant
+fontWeight
+glyphOrientationHorizontal
+glyphOrientationVertical
+height
+imeMode
+kerning
+layoutFlow
+layoutGrid
+layoutGridChar
+layoutGridLine
+layoutGridMode
+layoutGridType
+left
+letterSpacing
+lineBreak
+lineHeight
+listStyle
+listStyleImage
+listStylePosition
+listStyleType
+margin
+marginBottom
+marginLeft
+marginRight
+marginTop
+marker
+markerEnd
+markerMid
+markerStart
+mask
+maxHeight
+maxWidth
+minHeight
+minWidth
+msBlockProgression
+msInterpolationMode
+msTransform
+msTransformOrigin
+opacity
+orphans
+outline
+outlineColor
+outlineStyle
+outlineWidth
+overflow
+overflowX
+overflowY
+padding
+paddingBottom
+paddingLeft
+paddingRight
+paddingTop
+pageBreakAfter
+pageBreakBefore
+pageBreakInside
+pointerEvents
+position
+quotes
+right
+rubyAlign
+rubyOverhang
+rubyPosition
+scrollbar3dLightColor
+scrollbarArrowColor
+scrollbarBaseColor
+scrollbarDarkShadowColor
+scrollbarFaceColor
+scrollbarHighlightColor
+scrollbarShadowColor
+scrollbarTrackColor
+stopColor
+stopOpacity
+stroke
+strokeDasharray
+strokeDashoffset
+strokeLinecap
+strokeLinejoin
+strokeMiterlimit
+strokeOpacity
+strokeWidth
+styleFloat
+tableLayout
+textAlign
+textAlignLast
+textAnchor
+textAutospace
+textDecoration
+textIndent
+textJustify
+textJustifyTrim
+textKashida
+textKashidaSpace
+textOverflow
+textTransform
+textUnderlinePosition
+top
+unicodeBidi
+verticalAlign
+visibility
+whiteSpace
+widows
+width
+wordBreak
+wordSpacing
+wordWrap
+writingMode
+zIndex
+zoom
diff --git a/tools/dom/scripts/cssProperties.mobileSafari-8.2.txt b/tools/dom/scripts/cssProperties.mobileSafari-8.2.txt
new file mode 100644
index 0000000..5186ff4
--- /dev/null
+++ b/tools/dom/scripts/cssProperties.mobileSafari-8.2.txt
@@ -0,0 +1,159 @@
+# Mozilla/5.0 (iPad; CPU OS 8_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12D508 Safari/600.1.4
+# 157 properties
+animation
+animationDelay
+animationDirection
+animationDuration
+animationFillMode
+animationIterationCount
+animationName
+animationPlayState
+animationTimingFunction
+appearance
+azimuth
+backfaceVisibility
+background
+backgroundAttachment
+backgroundColor
+backgroundImage
+backgroundPosition
+backgroundRepeat
+backgroundSize
+border
+borderBottom
+borderBottomColor
+borderBottomLeftRadius
+borderBottomRightRadius
+borderBottomStyle
+borderBottomWidth
+borderCollapse
+borderColor
+borderLeft
+borderLeftColor
+borderLeftStyle
+borderLeftWidth
+borderRadius
+borderRight
+borderRightColor
+borderRightStyle
+borderRightWidth
+borderSpacing
+borderStyle
+borderTop
+borderTopColor
+borderTopLeftRadius
+borderTopRightRadius
+borderTopStyle
+borderTopWidth
+borderWidth
+bottom
+box
+boxShadow
+boxSizing
+captionSide
+clear
+clip
+color
+content
+cssFloat
+cue
+cueAfter
+cueBefore
+cursor
+direction
+display
+displayExtras
+displayInside
+displayOutside
+elevation
+emptyCells
+filter
+font
+fontFamily
+fontSize
+fontStretch
+fontStyle
+fontVariant
+fontWeight
+height
+left
+letterSpacing
+lineHeight
+listStyle
+listStyleImage
+listStylePosition
+listStyleType
+margin
+marginBottom
+marginLeft
+marginRight
+marginTop
+maxHeight
+maxWidth
+minHeight
+minWidth
+opacity
+outline
+outlineColor
+outlineStyle
+outlineWidth
+overflow
+overflowWrap
+overflowX
+overflowY
+padding
+paddingBottom
+paddingLeft
+paddingRight
+paddingTop
+pageBreakAfter
+pageBreakBefore
+pageBreakInside
+pause
+pauseAfter
+pauseBefore
+perspective
+perspectiveOrigin
+pitch
+pitchRange
+playDuring
+position
+quotes
+resize
+richness
+right
+speak
+speakHeader
+speakNumeral
+speakPunctuation
+speechRate
+stress
+tableLayout
+textAlign
+textDecoration
+textIndent
+textOverflow
+textShadow
+textTransform
+textWrap
+top
+transform
+transformOrigin
+transformStyle
+transition
+transitionDelay
+transitionDuration
+transitionProperty
+transitionTimingFunction
+unicodeBidi
+verticalAlign
+visibility
+voiceFamily
+volume
+whiteSpace
+width
+wordBreak
+wordSpacing
+wordWrap
+zIndex
+zoom
diff --git a/tools/dom/scripts/cssProperties.safari-7.1.3.txt b/tools/dom/scripts/cssProperties.safari-7.1.3.txt
new file mode 100644
index 0000000..15e1a61
--- /dev/null
+++ b/tools/dom/scripts/cssProperties.safari-7.1.3.txt
@@ -0,0 +1,399 @@
+# Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/600.3.18 (KHTML, like Gecko) Version/7.1.3 Safari/537.85.12
+# 397 properties
+alignmentBaseline
+background
+backgroundAttachment
+backgroundBlendMode
+backgroundClip
+backgroundColor
+backgroundImage
+backgroundOrigin
+backgroundPosition
+backgroundPositionX
+backgroundPositionY
+backgroundRepeat
+backgroundRepeatX
+backgroundRepeatY
+backgroundSize
+baselineShift
+border
+borderBottom
+borderBottomColor
+borderBottomLeftRadius
+borderBottomRightRadius
+borderBottomStyle
+borderBottomWidth
+borderCollapse
+borderColor
+borderImage
+borderImageOutset
+borderImageRepeat
+borderImageSlice
+borderImageSource
+borderImageWidth
+borderLeft
+borderLeftColor
+borderLeftStyle
+borderLeftWidth
+borderRadius
+borderRight
+borderRightColor
+borderRightStyle
+borderRightWidth
+borderSpacing
+borderStyle
+borderTop
+borderTopColor
+borderTopLeftRadius
+borderTopRightRadius
+borderTopStyle
+borderTopWidth
+borderWidth
+bottom
+boxShadow
+boxSizing
+bufferedRendering
+captionSide
+clear
+clip
+clipPath
+clipRule
+color
+colorInterpolation
+colorInterpolationFilters
+colorProfile
+colorRendering
+content
+counterIncrement
+counterReset
+cssText
+cursor
+direction
+display
+dominantBaseline
+emptyCells
+enableBackground
+fill
+fillOpacity
+fillRule
+filter
+float
+floodColor
+floodOpacity
+font
+fontFamily
+fontSize
+fontStretch
+fontStyle
+fontVariant
+fontWeight
+glyphOrientationHorizontal
+glyphOrientationVertical
+height
+imageRendering
+isolation
+kerning
+left
+letterSpacing
+lightingColor
+lineHeight
+listStyle
+listStyleImage
+listStylePosition
+listStyleType
+margin
+marginBottom
+marginLeft
+marginRight
+marginTop
+marker
+markerEnd
+markerMid
+markerStart
+mask
+maskType
+maxHeight
+maxWidth
+minHeight
+minWidth
+mixBlendMode
+objectFit
+opacity
+orphans
+outline
+outlineColor
+outlineOffset
+outlineStyle
+outlineWidth
+overflow
+overflowWrap
+overflowX
+overflowY
+padding
+paddingBottom
+paddingLeft
+paddingRight
+paddingTop
+page
+pageBreakAfter
+pageBreakBefore
+pageBreakInside
+paintOrder
+pointerEvents
+position
+quotes
+resize
+right
+shapeRendering
+size
+speak
+src
+stopColor
+stopOpacity
+stroke
+strokeDasharray
+strokeDashoffset
+strokeLinecap
+strokeLinejoin
+strokeMiterlimit
+strokeOpacity
+strokeWidth
+tabSize
+tableLayout
+textAlign
+textAnchor
+textDecoration
+textIndent
+textLineThrough
+textLineThroughColor
+textLineThroughMode
+textLineThroughStyle
+textLineThroughWidth
+textOverflow
+textOverline
+textOverlineColor
+textOverlineMode
+textOverlineStyle
+textOverlineWidth
+textRendering
+textShadow
+textTransform
+textUnderline
+textUnderlineColor
+textUnderlineMode
+textUnderlineStyle
+textUnderlineWidth
+top
+transition
+transitionDelay
+transitionDuration
+transitionProperty
+transitionTimingFunction
+unicodeBidi
+unicodeRange
+vectorEffect
+verticalAlign
+visibility
+webkitAlignContent
+webkitAlignItems
+webkitAlignSelf
+webkitAlt
+webkitAnimation
+webkitAnimationDelay
+webkitAnimationDirection
+webkitAnimationDuration
+webkitAnimationFillMode
+webkitAnimationIterationCount
+webkitAnimationName
+webkitAnimationPlayState
+webkitAnimationTimingFunction
+webkitAppearance
+webkitAspectRatio
+webkitBackfaceVisibility
+webkitBackgroundClip
+webkitBackgroundComposite
+webkitBackgroundOrigin
+webkitBackgroundSize
+webkitBorderAfter
+webkitBorderAfterColor
+webkitBorderAfterStyle
+webkitBorderAfterWidth
+webkitBorderBefore
+webkitBorderBeforeColor
+webkitBorderBeforeStyle
+webkitBorderBeforeWidth
+webkitBorderEnd
+webkitBorderEndColor
+webkitBorderEndStyle
+webkitBorderEndWidth
+webkitBorderFit
+webkitBorderHorizontalSpacing
+webkitBorderImage
+webkitBorderRadius
+webkitBorderStart
+webkitBorderStartColor
+webkitBorderStartStyle
+webkitBorderStartWidth
+webkitBorderVerticalSpacing
+webkitBoxAlign
+webkitBoxDecorationBreak
+webkitBoxDirection
+webkitBoxFlex
+webkitBoxFlexGroup
+webkitBoxLines
+webkitBoxOrdinalGroup
+webkitBoxOrient
+webkitBoxPack
+webkitBoxReflect
+webkitBoxShadow
+webkitClipPath
+webkitColorCorrection
+webkitColumnAxis
+webkitColumnBreakAfter
+webkitColumnBreakBefore
+webkitColumnBreakInside
+webkitColumnCount
+webkitColumnFill
+webkitColumnGap
+webkitColumnProgression
+webkitColumnRule
+webkitColumnRuleColor
+webkitColumnRuleStyle
+webkitColumnRuleWidth
+webkitColumnSpan
+webkitColumnWidth
+webkitColumns
+webkitCursorVisibility
+webkitDashboardRegion
+webkitFilter
+webkitFlex
+webkitFlexBasis
+webkitFlexDirection
+webkitFlexFlow
+webkitFlexGrow
+webkitFlexShrink
+webkitFlexWrap
+webkitFlowFrom
+webkitFlowInto
+webkitFontFeatureSettings
+webkitFontKerning
+webkitFontSizeDelta
+webkitFontSmoothing
+webkitFontVariantLigatures
+webkitHyphenateCharacter
+webkitHyphenateLimitAfter
+webkitHyphenateLimitBefore
+webkitHyphenateLimitLines
+webkitHyphens
+webkitJustifyContent
+webkitJustifySelf
+webkitLineAlign
+webkitLineBoxContain
+webkitLineBreak
+webkitLineClamp
+webkitLineGrid
+webkitLineSnap
+webkitLocale
+webkitLogicalHeight
+webkitLogicalWidth
+webkitMarginAfter
+webkitMarginAfterCollapse
+webkitMarginBefore
+webkitMarginBeforeCollapse
+webkitMarginBottomCollapse
+webkitMarginCollapse
+webkitMarginEnd
+webkitMarginStart
+webkitMarginTopCollapse
+webkitMarquee
+webkitMarqueeDirection
+webkitMarqueeIncrement
+webkitMarqueeRepetition
+webkitMarqueeSpeed
+webkitMarqueeStyle
+webkitMask
+webkitMaskBoxImage
+webkitMaskBoxImageOutset
+webkitMaskBoxImageRepeat
+webkitMaskBoxImageSlice
+webkitMaskBoxImageSource
+webkitMaskBoxImageWidth
+webkitMaskClip
+webkitMaskComposite
+webkitMaskImage
+webkitMaskOrigin
+webkitMaskPosition
+webkitMaskPositionX
+webkitMaskPositionY
+webkitMaskRepeat
+webkitMaskRepeatX
+webkitMaskRepeatY
+webkitMaskSize
+webkitMaskSourceType
+webkitMaxLogicalHeight
+webkitMaxLogicalWidth
+webkitMinLogicalHeight
+webkitMinLogicalWidth
+webkitNbspMode
+webkitOrder
+webkitPaddingAfter
+webkitPaddingBefore
+webkitPaddingEnd
+webkitPaddingStart
+webkitPerspective
+webkitPerspectiveOrigin
+webkitPerspectiveOriginX
+webkitPerspectiveOriginY
+webkitPrintColorAdjust
+webkitRegionBreakAfter
+webkitRegionBreakBefore
+webkitRegionBreakInside
+webkitRegionFragment
+webkitRtlOrdering
+webkitRubyPosition
+webkitShapeImageThreshold
+webkitShapeMargin
+webkitShapeOutside
+webkitSvgShadow
+webkitTextCombine
+webkitTextDecoration
+webkitTextDecorationColor
+webkitTextDecorationLine
+webkitTextDecorationSkip
+webkitTextDecorationStyle
+webkitTextDecorationsInEffect
+webkitTextEmphasis
+webkitTextEmphasisColor
+webkitTextEmphasisPosition
+webkitTextEmphasisStyle
+webkitTextFillColor
+webkitTextOrientation
+webkitTextSecurity
+webkitTextStroke
+webkitTextStrokeColor
+webkitTextStrokeWidth
+webkitTextUnderlinePosition
+webkitTransform
+webkitTransformOrigin
+webkitTransformOriginX
+webkitTransformOriginY
+webkitTransformOriginZ
+webkitTransformStyle
+webkitTransition
+webkitTransitionDelay
+webkitTransitionDuration
+webkitTransitionProperty
+webkitTransitionTimingFunction
+webkitUserDrag
+webkitUserModify
+webkitUserSelect
+webkitWritingMode
+whiteSpace
+widows
+width
+wordBreak
+wordSpacing
+wordWrap
+writingMode
+zIndex
+zoom
diff --git a/tools/dom/scripts/css_code_generator.py b/tools/dom/scripts/css_code_generator.py
index a290c5f..fc437dd 100644
--- a/tools/dom/scripts/css_code_generator.py
+++ b/tools/dom/scripts/css_code_generator.py
@@ -7,7 +7,7 @@
"""Generates CSSStyleDeclaration template file from css property definitions
defined in WebKit."""
-import tempfile, os
+import tempfile, os, re
COMMENT_LINE_PREFIX = ' * '
# TODO(efortuna): Pull from DEPS so that we have latest css *in sync* with our
@@ -16,6 +16,20 @@
#SOURCE_PATH = 'Source/WebCore/css/CSSPropertyNames.in'
TEMPLATE_FILE = '../templates/html/impl/impl_CSSStyleDeclaration.darttemplate'
+# These are the properties that are supported on all Dart project supported
+# browsers as camelCased names on the CssStyleDeclaration.
+BROWSER_PATHS = [
+ 'cssProperties.CSS21.txt', # Remove when we have samples from all browsers.
+ 'cssProperties.ie9.txt',
+ 'cssProperties.ie10.txt',
+ 'cssProperties.ie11.txt',
+ 'cssProperties.ff36.txt',
+ 'cssProperties.chrome40.txt',
+ 'cssProperties.safari-7.1.3.txt',
+ 'cssProperties.mobileSafari-8.2.txt',
+ 'cssProperties.iPad4Air.onGoogleSites.txt',
+ ]
+
# Supported annotations for any specific CSS properties.
annotated = {
'transition': '''@SupportedBrowser(SupportedBrowser.CHROME)
@@ -24,6 +38,12 @@
@SupportedBrowser(SupportedBrowser.SAFARI)'''
}
+class Error:
+ def __init__(self, message):
+ self.message = message
+ def __repr__(self):
+ return self.message
+
def camelCaseName(name):
"""Convert a CSS property name to a lowerCamelCase name."""
name = name.replace('-webkit-', '')
@@ -35,17 +55,35 @@
words.append(word)
return ''.join(words)
+def dashifyName(camelName):
+ def fix(match):
+ return '-' + match.group(0).lower()
+ return re.sub(r'[A-Z]', fix, camelName)
+
+def isCommentLine(line):
+ return line.strip() == '' or line.startswith('#') or line.startswith('//')
+
+def readCssProperties(filename):
+ data = open(filename).readlines()
+ data = sorted([d.strip() for d in set(data) if not isCommentLine(d)])
+ return data
+
def GenerateCssTemplateFile():
data = open(SOURCE_PATH).readlines()
# filter CSSPropertyNames.in to only the properties
# TODO(efortuna): do we also want CSSPropertyNames.in?
- data = [d[:-1] for d in data
- if len(d) > 1
- and not d.startswith('#')
- and not d.startswith('//')
+ data = [d.strip() for d in data
+ if not isCommentLine(d)
and not '=' in d]
+ browser_props = [readCssProperties(file) for file in BROWSER_PATHS]
+ universal_properties = reduce(
+ lambda a, b: set(a).intersection(b), browser_props)
+ universal_properties = universal_properties.difference(['cssText'])
+ universal_properties = universal_properties.intersection(
+ map(camelCaseName, data))
+
class_file = open(TEMPLATE_FILE, 'w')
class_file.write("""
@@ -60,8 +98,11 @@
// %s
part of $LIBRARYNAME;
+""" % SOURCE_PATH)
-$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS) class $CLASSNAME $EXTENDS with
+
+ class_file.write("""
+$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME $EXTENDS with
$(CLASSNAME)Base $IMPLEMENTS {
factory $CLASSNAME() => new CssStyleDeclaration.css('');
@@ -117,14 +158,34 @@
@DomName('CSSStyleDeclaration.setProperty')
void setProperty(String propertyName, String value, [String priority]) {
- if (_supportsProperty(_camelCase(propertyName))) {
- return _setPropertyHelper(propertyName, value, priority);
- } else {
- return _setPropertyHelper(Device.cssPrefix + propertyName, value,
- priority);
- }
+ return _setPropertyHelper(_browserPropertyName(propertyName),
+ value, priority);
}
+ String _browserPropertyName(String propertyName) {
+ String name = _readCache(propertyName);
+ if (name is String) return name;
+ if (_supportsProperty(_camelCase(propertyName))) {
+ name = propertyName;
+ } else {
+ name = Device.cssPrefix + propertyName;
+ }
+ _writeCache(propertyName, name);
+ return name;
+ }
+
+$if DART2JS
+ static final _propertyCache = JS('', '{}');
+ static String _readCache(String key) =>
+ JS('String|Null', '#[#]', _propertyCache, key);
+ static void _writeCache(String key, String value) {
+ JS('void', '#[#] = #', _propertyCache, key, value);
+ }
+$else
+ static String _readCache(String key) => null;
+ static void _writeCache(String key, value) {}
+$endif
+
static String _camelCase(String hyphenated) {
$if DART2JS
var replacedMs = JS('String', r'#.replace(/^-ms-/, "ms-")', hyphenated);
@@ -142,18 +203,9 @@
$if DART2JS
void _setPropertyHelper(String propertyName, String value, [String priority]) {
- // try/catch for IE9 which throws on unsupported values.
- try {
- if (value == null) value = '';
- if (priority == null) {
- priority = '';
- }
- JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority);
- // Bug #2772, IE9 requires a poke to actually apply the value.
- if (JS('bool', '!!#.setAttribute', this)) {
- JS('void', '#.setAttribute(#, #)', this, propertyName, value);
- }
- } catch (e) {}
+ if (value == null) value = '';
+ if (priority == null) priority = '';
+ JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority);
}
/**
@@ -176,6 +228,28 @@
static bool get supportsTransitions => true;
$endif
$!MEMBERS
+$if DART2JS
+""")
+
+ for camelName in sorted(universal_properties):
+ property = dashifyName(camelName)
+ class_file.write("""
+ /** Gets the value of "%s" */
+ String get %s => this._%s;
+
+ /** Sets the value of "%s" */
+ void set %s(String value) {
+ _%s = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('%s')
+ String _%s;
+ """ % (property, camelName, camelName,
+ property, camelName, camelName,
+ camelName, camelName))
+
+ class_file.write("""
+$endif
}
class _CssStyleDeclarationSet extends Object with CssStyleDeclarationBase {
@@ -195,6 +269,32 @@
_elementCssStyleDeclarationSetIterable.forEach((e) =>
e.setProperty(propertyName, value, priority));
}
+
+""")
+
+ class_file.write("""
+$if DART2JS
+ void _setAll(String propertyName, String value) {
+ value = value == null ? '' : value;
+ for (Element element in _elementIterable) {
+ JS('void', '#.style[#] = #', element, propertyName, value);
+ }
+ }
+""")
+
+
+ for camelName in sorted(universal_properties):
+ property = dashifyName(camelName)
+ class_file.write("""
+ /** Sets the value of "%s" */
+ void set %s(String value) {
+ _setAll('%s', value);
+ }
+ """ % (property, camelName, camelName))
+
+ class_file.write("""
+$endif
+
// Important note: CssStyleDeclarationSet does NOT implement every method
// available in CssStyleDeclaration. Some of the methods don't make so much
// sense in terms of having a resonable value to return when you're
@@ -205,12 +305,12 @@
abstract class CssStyleDeclarationBase {
String getPropertyValue(String propertyName);
void setProperty(String propertyName, String value, [String priority]);
-""" % SOURCE_PATH)
+""")
class_lines = [];
seen = set()
- for prop in sorted(data, key=lambda p: camelCaseName(p)):
+ for prop in sorted(data, key=camelCaseName):
camel_case_name = camelCaseName(prop)
upper_camel_case_name = camel_case_name[0].upper() + camel_case_name[1:];
css_name = prop.replace('-webkit-', '')
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index 6b66511..cb3e737 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -167,6 +167,8 @@
'RTCIceCandidate': 'RTCIceCandidate,mozRTCIceCandidate',
+ 'RTCIceCandidateEvent': 'RTCIceCandidateEvent,RTCPeerConnectionIceEvent',
+
'RTCSessionDescription': 'RTCSessionDescription,mozRTCSessionDescription',
'RTCDataChannel': 'RTCDataChannel,DataChannel',
diff --git a/tools/dom/src/CssClassSet.dart b/tools/dom/src/CssClassSet.dart
index 0b22ef7..0c405e4 100644
--- a/tools/dom/src/CssClassSet.dart
+++ b/tools/dom/src/CssClassSet.dart
@@ -13,6 +13,12 @@
*
* If [shouldAdd] is true, then we always add that [value] to the element. If
* [shouldAdd] is false then we always remove [value] from the element.
+ *
+ * If this corresponds to one element, returns `true` if [value] is present
+ * after the operation, and returns `false` if [value] is absent after the
+ * operation.
+ *
+ * If this corresponds to many elements, `null` is always returned.
*/
bool toggle(String value, [bool shouldAdd]);
@@ -39,7 +45,7 @@
* If this corresponds to one element. Returns true if [value] was added to
* the set, otherwise false.
*
- * If this corresponds to many elements, null is always returned.
+ * If this corresponds to many elements, `null` is always returned.
*/
bool add(String value);
@@ -80,87 +86,3 @@
*/
void toggleAll(Iterable<String> iterable, [bool shouldAdd]);
}
-
-/**
- * A set (union) of the CSS classes that are present in a set of elements.
- * Implemented separately from _ElementCssClassSet for performance.
- */
-class _MultiElementCssClassSet extends CssClassSetImpl {
- final Iterable<Element> _elementIterable;
- Iterable<_ElementCssClassSet> _elementCssClassSetIterable;
-
- _MultiElementCssClassSet(this._elementIterable) {
- _elementCssClassSetIterable = new List.from(_elementIterable).map(
- (e) => new _ElementCssClassSet(e));
- }
-
- Set<String> readClasses() {
- var s = new LinkedHashSet<String>();
- _elementCssClassSetIterable.forEach(
- (_ElementCssClassSet e) => s.addAll(e.readClasses()));
- return s;
- }
-
- void writeClasses(Set<String> s) {
- var classes = s.join(' ');
- for (Element e in _elementIterable) {
- e.className = classes;
- }
- }
-
- /**
- * Helper method used to modify the set of css classes on this element.
- *
- * f - callback with:
- * s - a Set of all the css class name currently on this element.
- *
- * After f returns, the modified set is written to the
- * className property of this element.
- */
- modify( f(Set<String> s)) {
- _elementCssClassSetIterable.forEach((_ElementCssClassSet e) => e.modify(f));
- }
-
- /**
- * Adds the class [value] to the element if it is not on it, removes it if it
- * is.
- */
- bool toggle(String value, [bool shouldAdd]) =>
- _elementCssClassSetIterable.fold(false,
- (bool changed, _ElementCssClassSet e) =>
- e.toggle(value, shouldAdd) || changed);
-
- /**
- * Remove the class [value] from element, and return true on successful
- * removal.
- *
- * This is the Dart equivalent of jQuery's
- * [removeClass](http://api.jquery.com/removeClass/).
- */
- bool remove(Object value) => _elementCssClassSetIterable.fold(false,
- (bool changed, _ElementCssClassSet e) => e.remove(value) || changed);
-}
-
-class _ElementCssClassSet extends CssClassSetImpl {
-
- final Element _element;
-
- _ElementCssClassSet(this._element);
-
- Set<String> readClasses() {
- var s = new LinkedHashSet<String>();
- var classname = _element.className;
-
- for (String name in classname.split(' ')) {
- String trimmed = name.trim();
- if (!trimmed.isEmpty) {
- s.add(trimmed);
- }
- }
- return s;
- }
-
- void writeClasses(Set<String> s) {
- _element.className = s.join(' ');
- }
-}
diff --git a/tools/dom/src/NodeValidatorBuilder.dart b/tools/dom/src/NodeValidatorBuilder.dart
index 41cab67..7ebeb36 100644
--- a/tools/dom/src/NodeValidatorBuilder.dart
+++ b/tools/dom/src/NodeValidatorBuilder.dart
@@ -453,6 +453,13 @@
if (element is svg.ScriptElement) {
return false;
}
+ // Firefox 37 has issues with creating foreign elements inside a
+ // foreignobject tag as SvgElement. We don't want foreignobject contents
+ // anyway, so just remove the whole tree outright. And we can't rely
+ // on IE recognizing the SvgForeignObject type, so go by tagName. Bug 23144
+ if (element is svg.SvgElement && element.tagName == 'foreignObject') {
+ return false;
+ }
if (element is svg.SvgElement) {
return true;
}
diff --git a/tools/dom/src/Validators.dart b/tools/dom/src/Validators.dart
index 5154a9d..ac51da1 100644
--- a/tools/dom/src/Validators.dart
+++ b/tools/dom/src/Validators.dart
@@ -111,7 +111,7 @@
_hiddenAnchor.protocol == _loc.protocol) ||
(_hiddenAnchor.hostname == '' &&
_hiddenAnchor.port == '' &&
- _hiddenAnchor.protocol == ':');
+ (_hiddenAnchor.protocol == ':' || _hiddenAnchor.protocol == ''));
}
}
@@ -145,29 +145,46 @@
_ValidatingTreeSanitizer(this.validator) {}
void sanitizeTree(Node node) {
- void walk(Node node) {
- sanitizeNode(node);
+ void walk(Node node, Node parent) {
+ sanitizeNode(node, parent);
var child = node.lastChild;
while (child != null) {
// Child may be removed during the walk.
var nextChild = child.previousNode;
- walk(child);
+ walk(child, node);
child = nextChild;
}
}
- walk(node);
+ walk(node, null);
}
- void sanitizeNode(Node node) {
+ /// Aggressively try to remove node.
+ void _removeNode(Node node, Node parent) {
+ // If we have the parent, it's presumably already passed more sanitization or
+ // is the fragment, so ask it to remove the child. And if that fails try to
+ // set the outer html.
+ if (parent == null) {
+ node.remove();
+ } else {
+ parent._removeChild(node);
+ }
+ }
+
+ void sanitizeNode(Node node, Node parent) {
switch (node.nodeType) {
case Node.ELEMENT_NODE:
Element element = node;
+ if (element._hasCorruptedAttributes) {
+ window.console.warn('Removing element due to corrupted attributes on <${element}>');
+ _removeNode(node, parent);
+ break;
+ }
var attrs = element.attributes;
if (!validator.allowsElement(element)) {
window.console.warn(
'Removing disallowed element <${element.tagName}>');
- element.remove();
+ _removeNode(node, parent);
break;
}
@@ -176,7 +193,7 @@
if (!validator.allowsAttribute(element, 'is', isAttr)) {
window.console.warn('Removing disallowed type extension '
'<${element.tagName} is="$isAttr">');
- element.remove();
+ _removeNode(node, parent);
break;
}
}
@@ -205,7 +222,7 @@
case Node.CDATA_SECTION_NODE:
break;
default:
- node.remove();
+ _removeNode(node, parent);
}
}
}
diff --git a/tools/dom/src/dart2js_CssClassSet.dart b/tools/dom/src/dart2js_CssClassSet.dart
new file mode 100644
index 0000000..783828b
--- /dev/null
+++ b/tools/dom/src/dart2js_CssClassSet.dart
@@ -0,0 +1,249 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of html;
+
+/**
+ * A set (union) of the CSS classes that are present in a set of elements.
+ * Implemented separately from _ElementCssClassSet for performance.
+ */
+class _MultiElementCssClassSet extends CssClassSetImpl {
+ final Iterable<Element> _elementIterable;
+
+ // TODO(sra): Perhaps we should store the DomTokenList instead.
+ final List<CssClassSetImpl> _sets;
+
+ factory _MultiElementCssClassSet(Iterable<Element> elements) {
+ return new _MultiElementCssClassSet._(elements,
+ elements.map((Element e) => e.classes).toList());
+ }
+
+ _MultiElementCssClassSet._(this._elementIterable, this._sets);
+
+ Set<String> readClasses() {
+ var s = new LinkedHashSet<String>();
+ _sets.forEach((CssClassSetImpl e) => s.addAll(e.readClasses()));
+ return s;
+ }
+
+ void writeClasses(Set<String> s) {
+ var classes = s.join(' ');
+ for (Element e in _elementIterable) {
+ e.className = classes;
+ }
+ }
+
+ /**
+ * Helper method used to modify the set of css classes on this element.
+ *
+ * f - callback with:
+ * s - a Set of all the css class name currently on this element.
+ *
+ * After f returns, the modified set is written to the
+ * className property of this element.
+ */
+ modify( f(Set<String> s)) {
+ _sets.forEach((CssClassSetImpl e) => e.modify(f));
+ }
+
+ /**
+ * Adds the class [value] to the element if it is not on it, removes it if it
+ * is.
+ *
+ * TODO(sra): It seems wrong to collect a 'changed' flag like this when the
+ * underlying toggle returns an 'is set' flag.
+ */
+ bool toggle(String value, [bool shouldAdd]) =>
+ _sets.fold(false,
+ (bool changed, CssClassSetImpl e) =>
+ e.toggle(value, shouldAdd) || changed);
+
+ /**
+ * Remove the class [value] from element, and return true on successful
+ * removal.
+ *
+ * This is the Dart equivalent of jQuery's
+ * [removeClass](http://api.jquery.com/removeClass/).
+ */
+ bool remove(Object value) => _sets.fold(false,
+ (bool changed, CssClassSetImpl e) => e.remove(value) || changed);
+}
+
+class _ElementCssClassSet extends CssClassSetImpl {
+ final Element _element;
+
+ _ElementCssClassSet(this._element);
+
+ Set<String> readClasses() {
+ var s = new LinkedHashSet<String>();
+ var classname = _element.className;
+
+ for (String name in classname.split(' ')) {
+ String trimmed = name.trim();
+ if (!trimmed.isEmpty) {
+ s.add(trimmed);
+ }
+ }
+ return s;
+ }
+
+ void writeClasses(Set<String> s) {
+ _element.className = s.join(' ');
+ }
+
+ int get length => _classListLength(_classListOf(_element));
+ bool get isEmpty => length == 0;
+ bool get isNotEmpty => length != 0;
+
+ void clear() {
+ _element.className = '';
+ }
+
+ bool contains(String value) {
+ return _contains(_element, value);
+ }
+
+ bool add(String value) {
+ return _add(_element, value);
+ }
+
+ bool remove(Object value) {
+ return value is String && _remove(_element, value);
+ }
+
+ bool toggle(String value, [bool shouldAdd]) {
+ return _toggle(_element, value, shouldAdd);
+ }
+
+ void addAll(Iterable<String> iterable) {
+ _addAll(_element, iterable);
+ }
+
+ void removeAll(Iterable<String> iterable) {
+ _removeAll(_element, iterable);
+ }
+
+ void retainAll(Iterable<String> iterable) {
+ _removeWhere(_element, iterable.toSet().contains, false);
+ }
+
+ void removeWhere(bool test(String name)) {
+ _removeWhere(_element, test, true);
+ }
+
+ void retainWhere(bool test(String name)) {
+ _removeWhere(_element, test, false);
+ }
+
+ static bool _contains(Element _element, String value) {
+ return _classListContains(_classListOf(_element), value);
+ }
+
+ static bool _add(Element _element, String value) {
+ DomTokenList list = _classListOf(_element);
+ // Compute returned result independently of action upon the set. One day we
+ // will be able to optimize it way if unused.
+ bool added = !_classListContains(list, value);
+ _classListAdd(list, value);
+ return added;
+ }
+
+ static bool _remove(Element _element, String value) {
+ DomTokenList list = _classListOf(_element);
+ bool removed = _classListContains(list, value);
+ _classListRemove(list, value);
+ return removed;
+ }
+
+ static bool _toggle(Element _element, String value, bool shouldAdd) {
+ // There is no value that can be passed as the second argument of
+ // DomTokenList.toggle that behaves the same as passing one argument.
+ // `null` is seen as false, meaning 'remove'.
+ return shouldAdd == null
+ ? _toggleDefault(_element, value)
+ : _toggleOnOff(_element, value, shouldAdd);
+ }
+
+ static bool _toggleDefault(Element _element, String value) {
+ DomTokenList list = _classListOf(_element);
+ return _classListToggle1(list, value);
+ }
+
+ static bool _toggleOnOff(Element _element, String value, bool shouldAdd) {
+ DomTokenList list = _classListOf(_element);
+ // IE's toggle does not take a second parameter. We would prefer:
+ //
+ // return _classListToggle2(list, value, shouldAdd);
+ //
+ if (shouldAdd) {
+ _classListAdd(list, value);
+ return true;
+ } else {
+ _classListRemove(list, value);
+ return false;
+ }
+ }
+
+ static void _addAll(Element _element, Iterable<String> iterable) {
+ DomTokenList list = _classListOf(_element);
+ for (String value in iterable) {
+ _classListAdd(list, value);
+ }
+ }
+
+ static void _removeAll(Element _element, Iterable<String> iterable) {
+ DomTokenList list = _classListOf(_element);
+ for (var value in iterable) {
+ _classListRemove(list, value);
+ }
+ }
+
+ static void _removeWhere(
+ Element _element, bool test(String name), bool doRemove) {
+ DomTokenList list = _classListOf(_element);
+ int i = 0;
+ while (i < _classListLength(list)) {
+ String item = list.item(i);
+ if (doRemove == test(item)) {
+ _classListRemove(list, item);
+ } else {
+ ++i;
+ }
+ }
+ }
+
+ // A collection of static methods for DomTokenList. These methods are a
+ // work-around for the lack of annotations to express the full behaviour of
+ // the DomTokenList methods.
+
+ static DomTokenList _classListOf(Element e) =>
+ JS('returns:DomTokenList;creates:DomTokenList;effects:none;depends:all;',
+ '#.classList', e);
+
+ static int _classListLength(DomTokenList list) =>
+ JS('returns:JSUInt31;effects:none;depends:all;', '#.length', list);
+
+ static bool _classListContains(DomTokenList list, String value) =>
+ JS('returns:bool;effects:none;depends:all;',
+ '#.contains(#)', list, value);
+
+ static void _classListAdd(DomTokenList list, String value) {
+ // list.add(value);
+ JS('', '#.add(#)', list, value);
+ }
+
+ static void _classListRemove(DomTokenList list, String value) {
+ // list.remove(value);
+ JS('', '#.remove(#)', list, value);
+ }
+
+ static bool _classListToggle1(DomTokenList list, String value) {
+ return JS('bool', '#.toggle(#)', list, value);
+ }
+
+ static bool _classListToggle2(
+ DomTokenList list, String value, bool shouldAdd) {
+ return JS('bool', '#.toggle(#, #)', list, value, shouldAdd);
+ }
+}
diff --git a/tools/dom/src/dartium_CssClassSet.dart b/tools/dom/src/dartium_CssClassSet.dart
new file mode 100644
index 0000000..cba9025
--- /dev/null
+++ b/tools/dom/src/dartium_CssClassSet.dart
@@ -0,0 +1,89 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of html;
+
+/**
+ * A set (union) of the CSS classes that are present in a set of elements.
+ * Implemented separately from _ElementCssClassSet for performance.
+ */
+class _MultiElementCssClassSet extends CssClassSetImpl {
+ final Iterable<Element> _elementIterable;
+ Iterable<_ElementCssClassSet> _elementCssClassSetIterable;
+
+ _MultiElementCssClassSet(this._elementIterable) {
+ _elementCssClassSetIterable = new List.from(_elementIterable).map(
+ (e) => new _ElementCssClassSet(e));
+ }
+
+ Set<String> readClasses() {
+ var s = new LinkedHashSet<String>();
+ _elementCssClassSetIterable.forEach(
+ (_ElementCssClassSet e) => s.addAll(e.readClasses()));
+ return s;
+ }
+
+ void writeClasses(Set<String> s) {
+ var classes = s.join(' ');
+ for (Element e in _elementIterable) {
+ e.className = classes;
+ }
+ }
+
+ /**
+ * Helper method used to modify the set of css classes on this element.
+ *
+ * f - callback with:
+ * s - a Set of all the css class name currently on this element.
+ *
+ * After f returns, the modified set is written to the
+ * className property of this element.
+ */
+ modify( f(Set<String> s)) {
+ _elementCssClassSetIterable.forEach((_ElementCssClassSet e) => e.modify(f));
+ }
+
+ /**
+ * Adds the class [value] to the element if it is not on it, removes it if it
+ * is.
+ */
+ bool toggle(String value, [bool shouldAdd]) =>
+ _elementCssClassSetIterable.fold(false,
+ (bool changed, _ElementCssClassSet e) =>
+ e.toggle(value, shouldAdd) || changed);
+
+ /**
+ * Remove the class [value] from element, and return true on successful
+ * removal.
+ *
+ * This is the Dart equivalent of jQuery's
+ * [removeClass](http://api.jquery.com/removeClass/).
+ */
+ bool remove(Object value) => _elementCssClassSetIterable.fold(false,
+ (bool changed, _ElementCssClassSet e) => e.remove(value) || changed);
+}
+
+class _ElementCssClassSet extends CssClassSetImpl {
+
+ final Element _element;
+
+ _ElementCssClassSet(this._element);
+
+ Set<String> readClasses() {
+ var s = new LinkedHashSet<String>();
+ var classname = _element.className;
+
+ for (String name in classname.split(' ')) {
+ String trimmed = name.trim();
+ if (!trimmed.isEmpty) {
+ s.add(trimmed);
+ }
+ }
+ return s;
+ }
+
+ void writeClasses(Set<String> s) {
+ _element.className = s.join(' ');
+ }
+}
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
index 04acea0..e12a06c 100644
--- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -52,12 +52,14 @@
import 'dart:web_sql';
import 'dart:_js_helper' show
convertDartClosureToJS, Creates, JavaScriptIndexingBehavior,
- JSName, Native, Null, Returns,
+ JSName, Native, Null, Returns, Inline, ForceInline,
findDispatchTagForInterceptorClass, setNativeSubclassDispatchRecord,
makeLeafDispatchRecord;
import 'dart:_interceptors' show
- Interceptor, JSExtendableArray, findInterceptorConstructorForType,
- findConstructorForNativeSubclassType, getNativeInterceptor,
+ Interceptor, JSExtendableArray, JSUInt31,
+ findInterceptorConstructorForType,
+ findConstructorForNativeSubclassType,
+ getNativeInterceptor,
setDispatchProperty;
import 'dart:_isolate_helper' show IsolateNatives;
import 'dart:_foreign_helper' show JS, JS_INTERCEPTOR_CONSTANT, JS_CONST;
@@ -71,6 +73,7 @@
part '$AUXILIARY_DIR/CrossFrameTypes.dart';
part '$AUXILIARY_DIR/CssClassSet.dart';
part '$AUXILIARY_DIR/CssRectangle.dart';
+part '$AUXILIARY_DIR/dart2js_CssClassSet.dart';
part '$AUXILIARY_DIR/Dimension.dart';
part '$AUXILIARY_DIR/EventListener.dart';
part '$AUXILIARY_DIR/EventStreamProvider.dart';
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index 348057d..0934721 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -67,6 +67,7 @@
part '$AUXILIARY_DIR/CanvasImageSource.dart';
part '$AUXILIARY_DIR/CrossFrameTypes.dart';
part '$AUXILIARY_DIR/CssClassSet.dart';
+part '$AUXILIARY_DIR/dartium_CssClassSet.dart';
part '$AUXILIARY_DIR/CssRectangle.dart';
part '$AUXILIARY_DIR/Dimension.dart';
part '$AUXILIARY_DIR/EventListener.dart';
diff --git a/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate b/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate
index 1b47c7d..186848e 100644
--- a/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate
+++ b/tools/dom/templates/html/impl/impl_CSSStyleDeclaration.darttemplate
@@ -11,7 +11,7 @@
part of $LIBRARYNAME;
-$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS) class $CLASSNAME $EXTENDS with
+$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME $EXTENDS with
$(CLASSNAME)Base $IMPLEMENTS {
factory $CLASSNAME() => new CssStyleDeclaration.css('');
@@ -67,14 +67,34 @@
@DomName('CSSStyleDeclaration.setProperty')
void setProperty(String propertyName, String value, [String priority]) {
- if (_supportsProperty(_camelCase(propertyName))) {
- return _setPropertyHelper(propertyName, value, priority);
- } else {
- return _setPropertyHelper(Device.cssPrefix + propertyName, value,
- priority);
- }
+ return _setPropertyHelper(_browserPropertyName(propertyName),
+ value, priority);
}
+ String _browserPropertyName(String propertyName) {
+ String name = _readCache(propertyName);
+ if (name is String) return name;
+ if (_supportsProperty(_camelCase(propertyName))) {
+ name = propertyName;
+ } else {
+ name = Device.cssPrefix + propertyName;
+ }
+ _writeCache(propertyName, name);
+ return name;
+ }
+
+$if DART2JS
+ static final _propertyCache = JS('', '{}');
+ static String _readCache(String key) =>
+ JS('String|Null', '#[#]', _propertyCache, key);
+ static void _writeCache(String key, String value) {
+ JS('void', '#[#] = #', _propertyCache, key, value);
+ }
+$else
+ static String _readCache(String key) => null;
+ static void _writeCache(String key, value) {}
+$endif
+
static String _camelCase(String hyphenated) {
$if DART2JS
var replacedMs = JS('String', r'#.replace(/^-ms-/, "ms-")', hyphenated);
@@ -92,18 +112,9 @@
$if DART2JS
void _setPropertyHelper(String propertyName, String value, [String priority]) {
- // try/catch for IE9 which throws on unsupported values.
- try {
- if (value == null) value = '';
- if (priority == null) {
- priority = '';
- }
- JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority);
- // Bug #2772, IE9 requires a poke to actually apply the value.
- if (JS('bool', '!!#.setAttribute', this)) {
- JS('void', '#.setAttribute(#, #)', this, propertyName, value);
- }
- } catch (e) {}
+ if (value == null) value = '';
+ if (priority == null) priority = '';
+ JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority);
}
/**
@@ -126,6 +137,999 @@
static bool get supportsTransitions => true;
$endif
$!MEMBERS
+$if DART2JS
+
+ /** Gets the value of "background" */
+ String get background => this._background;
+
+ /** Sets the value of "background" */
+ void set background(String value) {
+ _background = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('background')
+ String _background;
+
+ /** Gets the value of "background-attachment" */
+ String get backgroundAttachment => this._backgroundAttachment;
+
+ /** Sets the value of "background-attachment" */
+ void set backgroundAttachment(String value) {
+ _backgroundAttachment = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('backgroundAttachment')
+ String _backgroundAttachment;
+
+ /** Gets the value of "background-color" */
+ String get backgroundColor => this._backgroundColor;
+
+ /** Sets the value of "background-color" */
+ void set backgroundColor(String value) {
+ _backgroundColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('backgroundColor')
+ String _backgroundColor;
+
+ /** Gets the value of "background-image" */
+ String get backgroundImage => this._backgroundImage;
+
+ /** Sets the value of "background-image" */
+ void set backgroundImage(String value) {
+ _backgroundImage = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('backgroundImage')
+ String _backgroundImage;
+
+ /** Gets the value of "background-position" */
+ String get backgroundPosition => this._backgroundPosition;
+
+ /** Sets the value of "background-position" */
+ void set backgroundPosition(String value) {
+ _backgroundPosition = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('backgroundPosition')
+ String _backgroundPosition;
+
+ /** Gets the value of "background-repeat" */
+ String get backgroundRepeat => this._backgroundRepeat;
+
+ /** Sets the value of "background-repeat" */
+ void set backgroundRepeat(String value) {
+ _backgroundRepeat = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('backgroundRepeat')
+ String _backgroundRepeat;
+
+ /** Gets the value of "border" */
+ String get border => this._border;
+
+ /** Sets the value of "border" */
+ void set border(String value) {
+ _border = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('border')
+ String _border;
+
+ /** Gets the value of "border-bottom" */
+ String get borderBottom => this._borderBottom;
+
+ /** Sets the value of "border-bottom" */
+ void set borderBottom(String value) {
+ _borderBottom = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderBottom')
+ String _borderBottom;
+
+ /** Gets the value of "border-bottom-color" */
+ String get borderBottomColor => this._borderBottomColor;
+
+ /** Sets the value of "border-bottom-color" */
+ void set borderBottomColor(String value) {
+ _borderBottomColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderBottomColor')
+ String _borderBottomColor;
+
+ /** Gets the value of "border-bottom-style" */
+ String get borderBottomStyle => this._borderBottomStyle;
+
+ /** Sets the value of "border-bottom-style" */
+ void set borderBottomStyle(String value) {
+ _borderBottomStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderBottomStyle')
+ String _borderBottomStyle;
+
+ /** Gets the value of "border-bottom-width" */
+ String get borderBottomWidth => this._borderBottomWidth;
+
+ /** Sets the value of "border-bottom-width" */
+ void set borderBottomWidth(String value) {
+ _borderBottomWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderBottomWidth')
+ String _borderBottomWidth;
+
+ /** Gets the value of "border-collapse" */
+ String get borderCollapse => this._borderCollapse;
+
+ /** Sets the value of "border-collapse" */
+ void set borderCollapse(String value) {
+ _borderCollapse = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderCollapse')
+ String _borderCollapse;
+
+ /** Gets the value of "border-color" */
+ String get borderColor => this._borderColor;
+
+ /** Sets the value of "border-color" */
+ void set borderColor(String value) {
+ _borderColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderColor')
+ String _borderColor;
+
+ /** Gets the value of "border-left" */
+ String get borderLeft => this._borderLeft;
+
+ /** Sets the value of "border-left" */
+ void set borderLeft(String value) {
+ _borderLeft = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderLeft')
+ String _borderLeft;
+
+ /** Gets the value of "border-left-color" */
+ String get borderLeftColor => this._borderLeftColor;
+
+ /** Sets the value of "border-left-color" */
+ void set borderLeftColor(String value) {
+ _borderLeftColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderLeftColor')
+ String _borderLeftColor;
+
+ /** Gets the value of "border-left-style" */
+ String get borderLeftStyle => this._borderLeftStyle;
+
+ /** Sets the value of "border-left-style" */
+ void set borderLeftStyle(String value) {
+ _borderLeftStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderLeftStyle')
+ String _borderLeftStyle;
+
+ /** Gets the value of "border-left-width" */
+ String get borderLeftWidth => this._borderLeftWidth;
+
+ /** Sets the value of "border-left-width" */
+ void set borderLeftWidth(String value) {
+ _borderLeftWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderLeftWidth')
+ String _borderLeftWidth;
+
+ /** Gets the value of "border-right" */
+ String get borderRight => this._borderRight;
+
+ /** Sets the value of "border-right" */
+ void set borderRight(String value) {
+ _borderRight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderRight')
+ String _borderRight;
+
+ /** Gets the value of "border-right-color" */
+ String get borderRightColor => this._borderRightColor;
+
+ /** Sets the value of "border-right-color" */
+ void set borderRightColor(String value) {
+ _borderRightColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderRightColor')
+ String _borderRightColor;
+
+ /** Gets the value of "border-right-style" */
+ String get borderRightStyle => this._borderRightStyle;
+
+ /** Sets the value of "border-right-style" */
+ void set borderRightStyle(String value) {
+ _borderRightStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderRightStyle')
+ String _borderRightStyle;
+
+ /** Gets the value of "border-right-width" */
+ String get borderRightWidth => this._borderRightWidth;
+
+ /** Sets the value of "border-right-width" */
+ void set borderRightWidth(String value) {
+ _borderRightWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderRightWidth')
+ String _borderRightWidth;
+
+ /** Gets the value of "border-spacing" */
+ String get borderSpacing => this._borderSpacing;
+
+ /** Sets the value of "border-spacing" */
+ void set borderSpacing(String value) {
+ _borderSpacing = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderSpacing')
+ String _borderSpacing;
+
+ /** Gets the value of "border-style" */
+ String get borderStyle => this._borderStyle;
+
+ /** Sets the value of "border-style" */
+ void set borderStyle(String value) {
+ _borderStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderStyle')
+ String _borderStyle;
+
+ /** Gets the value of "border-top" */
+ String get borderTop => this._borderTop;
+
+ /** Sets the value of "border-top" */
+ void set borderTop(String value) {
+ _borderTop = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderTop')
+ String _borderTop;
+
+ /** Gets the value of "border-top-color" */
+ String get borderTopColor => this._borderTopColor;
+
+ /** Sets the value of "border-top-color" */
+ void set borderTopColor(String value) {
+ _borderTopColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderTopColor')
+ String _borderTopColor;
+
+ /** Gets the value of "border-top-style" */
+ String get borderTopStyle => this._borderTopStyle;
+
+ /** Sets the value of "border-top-style" */
+ void set borderTopStyle(String value) {
+ _borderTopStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderTopStyle')
+ String _borderTopStyle;
+
+ /** Gets the value of "border-top-width" */
+ String get borderTopWidth => this._borderTopWidth;
+
+ /** Sets the value of "border-top-width" */
+ void set borderTopWidth(String value) {
+ _borderTopWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderTopWidth')
+ String _borderTopWidth;
+
+ /** Gets the value of "border-width" */
+ String get borderWidth => this._borderWidth;
+
+ /** Sets the value of "border-width" */
+ void set borderWidth(String value) {
+ _borderWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('borderWidth')
+ String _borderWidth;
+
+ /** Gets the value of "bottom" */
+ String get bottom => this._bottom;
+
+ /** Sets the value of "bottom" */
+ void set bottom(String value) {
+ _bottom = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('bottom')
+ String _bottom;
+
+ /** Gets the value of "caption-side" */
+ String get captionSide => this._captionSide;
+
+ /** Sets the value of "caption-side" */
+ void set captionSide(String value) {
+ _captionSide = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('captionSide')
+ String _captionSide;
+
+ /** Gets the value of "clear" */
+ String get clear => this._clear;
+
+ /** Sets the value of "clear" */
+ void set clear(String value) {
+ _clear = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('clear')
+ String _clear;
+
+ /** Gets the value of "clip" */
+ String get clip => this._clip;
+
+ /** Sets the value of "clip" */
+ void set clip(String value) {
+ _clip = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('clip')
+ String _clip;
+
+ /** Gets the value of "color" */
+ String get color => this._color;
+
+ /** Sets the value of "color" */
+ void set color(String value) {
+ _color = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('color')
+ String _color;
+
+ /** Gets the value of "content" */
+ String get content => this._content;
+
+ /** Sets the value of "content" */
+ void set content(String value) {
+ _content = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('content')
+ String _content;
+
+ /** Gets the value of "cursor" */
+ String get cursor => this._cursor;
+
+ /** Sets the value of "cursor" */
+ void set cursor(String value) {
+ _cursor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('cursor')
+ String _cursor;
+
+ /** Gets the value of "direction" */
+ String get direction => this._direction;
+
+ /** Sets the value of "direction" */
+ void set direction(String value) {
+ _direction = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('direction')
+ String _direction;
+
+ /** Gets the value of "display" */
+ String get display => this._display;
+
+ /** Sets the value of "display" */
+ void set display(String value) {
+ _display = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('display')
+ String _display;
+
+ /** Gets the value of "empty-cells" */
+ String get emptyCells => this._emptyCells;
+
+ /** Sets the value of "empty-cells" */
+ void set emptyCells(String value) {
+ _emptyCells = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('emptyCells')
+ String _emptyCells;
+
+ /** Gets the value of "font" */
+ String get font => this._font;
+
+ /** Sets the value of "font" */
+ void set font(String value) {
+ _font = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('font')
+ String _font;
+
+ /** Gets the value of "font-family" */
+ String get fontFamily => this._fontFamily;
+
+ /** Sets the value of "font-family" */
+ void set fontFamily(String value) {
+ _fontFamily = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('fontFamily')
+ String _fontFamily;
+
+ /** Gets the value of "font-size" */
+ String get fontSize => this._fontSize;
+
+ /** Sets the value of "font-size" */
+ void set fontSize(String value) {
+ _fontSize = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('fontSize')
+ String _fontSize;
+
+ /** Gets the value of "font-style" */
+ String get fontStyle => this._fontStyle;
+
+ /** Sets the value of "font-style" */
+ void set fontStyle(String value) {
+ _fontStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('fontStyle')
+ String _fontStyle;
+
+ /** Gets the value of "font-variant" */
+ String get fontVariant => this._fontVariant;
+
+ /** Sets the value of "font-variant" */
+ void set fontVariant(String value) {
+ _fontVariant = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('fontVariant')
+ String _fontVariant;
+
+ /** Gets the value of "font-weight" */
+ String get fontWeight => this._fontWeight;
+
+ /** Sets the value of "font-weight" */
+ void set fontWeight(String value) {
+ _fontWeight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('fontWeight')
+ String _fontWeight;
+
+ /** Gets the value of "height" */
+ String get height => this._height;
+
+ /** Sets the value of "height" */
+ void set height(String value) {
+ _height = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('height')
+ String _height;
+
+ /** Gets the value of "left" */
+ String get left => this._left;
+
+ /** Sets the value of "left" */
+ void set left(String value) {
+ _left = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('left')
+ String _left;
+
+ /** Gets the value of "letter-spacing" */
+ String get letterSpacing => this._letterSpacing;
+
+ /** Sets the value of "letter-spacing" */
+ void set letterSpacing(String value) {
+ _letterSpacing = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('letterSpacing')
+ String _letterSpacing;
+
+ /** Gets the value of "line-height" */
+ String get lineHeight => this._lineHeight;
+
+ /** Sets the value of "line-height" */
+ void set lineHeight(String value) {
+ _lineHeight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('lineHeight')
+ String _lineHeight;
+
+ /** Gets the value of "list-style" */
+ String get listStyle => this._listStyle;
+
+ /** Sets the value of "list-style" */
+ void set listStyle(String value) {
+ _listStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('listStyle')
+ String _listStyle;
+
+ /** Gets the value of "list-style-image" */
+ String get listStyleImage => this._listStyleImage;
+
+ /** Sets the value of "list-style-image" */
+ void set listStyleImage(String value) {
+ _listStyleImage = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('listStyleImage')
+ String _listStyleImage;
+
+ /** Gets the value of "list-style-position" */
+ String get listStylePosition => this._listStylePosition;
+
+ /** Sets the value of "list-style-position" */
+ void set listStylePosition(String value) {
+ _listStylePosition = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('listStylePosition')
+ String _listStylePosition;
+
+ /** Gets the value of "list-style-type" */
+ String get listStyleType => this._listStyleType;
+
+ /** Sets the value of "list-style-type" */
+ void set listStyleType(String value) {
+ _listStyleType = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('listStyleType')
+ String _listStyleType;
+
+ /** Gets the value of "margin" */
+ String get margin => this._margin;
+
+ /** Sets the value of "margin" */
+ void set margin(String value) {
+ _margin = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('margin')
+ String _margin;
+
+ /** Gets the value of "margin-bottom" */
+ String get marginBottom => this._marginBottom;
+
+ /** Sets the value of "margin-bottom" */
+ void set marginBottom(String value) {
+ _marginBottom = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('marginBottom')
+ String _marginBottom;
+
+ /** Gets the value of "margin-left" */
+ String get marginLeft => this._marginLeft;
+
+ /** Sets the value of "margin-left" */
+ void set marginLeft(String value) {
+ _marginLeft = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('marginLeft')
+ String _marginLeft;
+
+ /** Gets the value of "margin-right" */
+ String get marginRight => this._marginRight;
+
+ /** Sets the value of "margin-right" */
+ void set marginRight(String value) {
+ _marginRight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('marginRight')
+ String _marginRight;
+
+ /** Gets the value of "margin-top" */
+ String get marginTop => this._marginTop;
+
+ /** Sets the value of "margin-top" */
+ void set marginTop(String value) {
+ _marginTop = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('marginTop')
+ String _marginTop;
+
+ /** Gets the value of "max-height" */
+ String get maxHeight => this._maxHeight;
+
+ /** Sets the value of "max-height" */
+ void set maxHeight(String value) {
+ _maxHeight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('maxHeight')
+ String _maxHeight;
+
+ /** Gets the value of "max-width" */
+ String get maxWidth => this._maxWidth;
+
+ /** Sets the value of "max-width" */
+ void set maxWidth(String value) {
+ _maxWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('maxWidth')
+ String _maxWidth;
+
+ /** Gets the value of "min-height" */
+ String get minHeight => this._minHeight;
+
+ /** Sets the value of "min-height" */
+ void set minHeight(String value) {
+ _minHeight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('minHeight')
+ String _minHeight;
+
+ /** Gets the value of "min-width" */
+ String get minWidth => this._minWidth;
+
+ /** Sets the value of "min-width" */
+ void set minWidth(String value) {
+ _minWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('minWidth')
+ String _minWidth;
+
+ /** Gets the value of "outline" */
+ String get outline => this._outline;
+
+ /** Sets the value of "outline" */
+ void set outline(String value) {
+ _outline = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('outline')
+ String _outline;
+
+ /** Gets the value of "outline-color" */
+ String get outlineColor => this._outlineColor;
+
+ /** Sets the value of "outline-color" */
+ void set outlineColor(String value) {
+ _outlineColor = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('outlineColor')
+ String _outlineColor;
+
+ /** Gets the value of "outline-style" */
+ String get outlineStyle => this._outlineStyle;
+
+ /** Sets the value of "outline-style" */
+ void set outlineStyle(String value) {
+ _outlineStyle = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('outlineStyle')
+ String _outlineStyle;
+
+ /** Gets the value of "outline-width" */
+ String get outlineWidth => this._outlineWidth;
+
+ /** Sets the value of "outline-width" */
+ void set outlineWidth(String value) {
+ _outlineWidth = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('outlineWidth')
+ String _outlineWidth;
+
+ /** Gets the value of "overflow" */
+ String get overflow => this._overflow;
+
+ /** Sets the value of "overflow" */
+ void set overflow(String value) {
+ _overflow = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('overflow')
+ String _overflow;
+
+ /** Gets the value of "padding" */
+ String get padding => this._padding;
+
+ /** Sets the value of "padding" */
+ void set padding(String value) {
+ _padding = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('padding')
+ String _padding;
+
+ /** Gets the value of "padding-bottom" */
+ String get paddingBottom => this._paddingBottom;
+
+ /** Sets the value of "padding-bottom" */
+ void set paddingBottom(String value) {
+ _paddingBottom = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('paddingBottom')
+ String _paddingBottom;
+
+ /** Gets the value of "padding-left" */
+ String get paddingLeft => this._paddingLeft;
+
+ /** Sets the value of "padding-left" */
+ void set paddingLeft(String value) {
+ _paddingLeft = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('paddingLeft')
+ String _paddingLeft;
+
+ /** Gets the value of "padding-right" */
+ String get paddingRight => this._paddingRight;
+
+ /** Sets the value of "padding-right" */
+ void set paddingRight(String value) {
+ _paddingRight = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('paddingRight')
+ String _paddingRight;
+
+ /** Gets the value of "padding-top" */
+ String get paddingTop => this._paddingTop;
+
+ /** Sets the value of "padding-top" */
+ void set paddingTop(String value) {
+ _paddingTop = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('paddingTop')
+ String _paddingTop;
+
+ /** Gets the value of "page-break-after" */
+ String get pageBreakAfter => this._pageBreakAfter;
+
+ /** Sets the value of "page-break-after" */
+ void set pageBreakAfter(String value) {
+ _pageBreakAfter = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('pageBreakAfter')
+ String _pageBreakAfter;
+
+ /** Gets the value of "page-break-before" */
+ String get pageBreakBefore => this._pageBreakBefore;
+
+ /** Sets the value of "page-break-before" */
+ void set pageBreakBefore(String value) {
+ _pageBreakBefore = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('pageBreakBefore')
+ String _pageBreakBefore;
+
+ /** Gets the value of "page-break-inside" */
+ String get pageBreakInside => this._pageBreakInside;
+
+ /** Sets the value of "page-break-inside" */
+ void set pageBreakInside(String value) {
+ _pageBreakInside = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('pageBreakInside')
+ String _pageBreakInside;
+
+ /** Gets the value of "position" */
+ String get position => this._position;
+
+ /** Sets the value of "position" */
+ void set position(String value) {
+ _position = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('position')
+ String _position;
+
+ /** Gets the value of "quotes" */
+ String get quotes => this._quotes;
+
+ /** Sets the value of "quotes" */
+ void set quotes(String value) {
+ _quotes = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('quotes')
+ String _quotes;
+
+ /** Gets the value of "right" */
+ String get right => this._right;
+
+ /** Sets the value of "right" */
+ void set right(String value) {
+ _right = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('right')
+ String _right;
+
+ /** Gets the value of "table-layout" */
+ String get tableLayout => this._tableLayout;
+
+ /** Sets the value of "table-layout" */
+ void set tableLayout(String value) {
+ _tableLayout = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('tableLayout')
+ String _tableLayout;
+
+ /** Gets the value of "text-align" */
+ String get textAlign => this._textAlign;
+
+ /** Sets the value of "text-align" */
+ void set textAlign(String value) {
+ _textAlign = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('textAlign')
+ String _textAlign;
+
+ /** Gets the value of "text-decoration" */
+ String get textDecoration => this._textDecoration;
+
+ /** Sets the value of "text-decoration" */
+ void set textDecoration(String value) {
+ _textDecoration = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('textDecoration')
+ String _textDecoration;
+
+ /** Gets the value of "text-indent" */
+ String get textIndent => this._textIndent;
+
+ /** Sets the value of "text-indent" */
+ void set textIndent(String value) {
+ _textIndent = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('textIndent')
+ String _textIndent;
+
+ /** Gets the value of "text-transform" */
+ String get textTransform => this._textTransform;
+
+ /** Sets the value of "text-transform" */
+ void set textTransform(String value) {
+ _textTransform = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('textTransform')
+ String _textTransform;
+
+ /** Gets the value of "top" */
+ String get top => this._top;
+
+ /** Sets the value of "top" */
+ void set top(String value) {
+ _top = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('top')
+ String _top;
+
+ /** Gets the value of "unicode-bidi" */
+ String get unicodeBidi => this._unicodeBidi;
+
+ /** Sets the value of "unicode-bidi" */
+ void set unicodeBidi(String value) {
+ _unicodeBidi = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('unicodeBidi')
+ String _unicodeBidi;
+
+ /** Gets the value of "vertical-align" */
+ String get verticalAlign => this._verticalAlign;
+
+ /** Sets the value of "vertical-align" */
+ void set verticalAlign(String value) {
+ _verticalAlign = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('verticalAlign')
+ String _verticalAlign;
+
+ /** Gets the value of "visibility" */
+ String get visibility => this._visibility;
+
+ /** Sets the value of "visibility" */
+ void set visibility(String value) {
+ _visibility = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('visibility')
+ String _visibility;
+
+ /** Gets the value of "white-space" */
+ String get whiteSpace => this._whiteSpace;
+
+ /** Sets the value of "white-space" */
+ void set whiteSpace(String value) {
+ _whiteSpace = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('whiteSpace')
+ String _whiteSpace;
+
+ /** Gets the value of "width" */
+ String get width => this._width;
+
+ /** Sets the value of "width" */
+ void set width(String value) {
+ _width = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('width')
+ String _width;
+
+ /** Gets the value of "word-spacing" */
+ String get wordSpacing => this._wordSpacing;
+
+ /** Sets the value of "word-spacing" */
+ void set wordSpacing(String value) {
+ _wordSpacing = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('wordSpacing')
+ String _wordSpacing;
+
+ /** Gets the value of "z-index" */
+ String get zIndex => this._zIndex;
+
+ /** Sets the value of "z-index" */
+ void set zIndex(String value) {
+ _zIndex = value == null ? '' : value;
+ }
+ @Returns('String')
+ @JSName('zIndex')
+ String _zIndex;
+
+$endif
}
class _CssStyleDeclarationSet extends Object with CssStyleDeclarationBase {
@@ -145,6 +1149,468 @@
_elementCssStyleDeclarationSetIterable.forEach((e) =>
e.setProperty(propertyName, value, priority));
}
+
+
+$if DART2JS
+ void _setAll(String propertyName, String value) {
+ value = value == null ? '' : value;
+ for (Element element in _elementIterable) {
+ JS('void', '#.style[#] = #', element, propertyName, value);
+ }
+ }
+
+ /** Sets the value of "background" */
+ void set background(String value) {
+ _setAll('background', value);
+ }
+
+ /** Sets the value of "background-attachment" */
+ void set backgroundAttachment(String value) {
+ _setAll('backgroundAttachment', value);
+ }
+
+ /** Sets the value of "background-color" */
+ void set backgroundColor(String value) {
+ _setAll('backgroundColor', value);
+ }
+
+ /** Sets the value of "background-image" */
+ void set backgroundImage(String value) {
+ _setAll('backgroundImage', value);
+ }
+
+ /** Sets the value of "background-position" */
+ void set backgroundPosition(String value) {
+ _setAll('backgroundPosition', value);
+ }
+
+ /** Sets the value of "background-repeat" */
+ void set backgroundRepeat(String value) {
+ _setAll('backgroundRepeat', value);
+ }
+
+ /** Sets the value of "border" */
+ void set border(String value) {
+ _setAll('border', value);
+ }
+
+ /** Sets the value of "border-bottom" */
+ void set borderBottom(String value) {
+ _setAll('borderBottom', value);
+ }
+
+ /** Sets the value of "border-bottom-color" */
+ void set borderBottomColor(String value) {
+ _setAll('borderBottomColor', value);
+ }
+
+ /** Sets the value of "border-bottom-style" */
+ void set borderBottomStyle(String value) {
+ _setAll('borderBottomStyle', value);
+ }
+
+ /** Sets the value of "border-bottom-width" */
+ void set borderBottomWidth(String value) {
+ _setAll('borderBottomWidth', value);
+ }
+
+ /** Sets the value of "border-collapse" */
+ void set borderCollapse(String value) {
+ _setAll('borderCollapse', value);
+ }
+
+ /** Sets the value of "border-color" */
+ void set borderColor(String value) {
+ _setAll('borderColor', value);
+ }
+
+ /** Sets the value of "border-left" */
+ void set borderLeft(String value) {
+ _setAll('borderLeft', value);
+ }
+
+ /** Sets the value of "border-left-color" */
+ void set borderLeftColor(String value) {
+ _setAll('borderLeftColor', value);
+ }
+
+ /** Sets the value of "border-left-style" */
+ void set borderLeftStyle(String value) {
+ _setAll('borderLeftStyle', value);
+ }
+
+ /** Sets the value of "border-left-width" */
+ void set borderLeftWidth(String value) {
+ _setAll('borderLeftWidth', value);
+ }
+
+ /** Sets the value of "border-right" */
+ void set borderRight(String value) {
+ _setAll('borderRight', value);
+ }
+
+ /** Sets the value of "border-right-color" */
+ void set borderRightColor(String value) {
+ _setAll('borderRightColor', value);
+ }
+
+ /** Sets the value of "border-right-style" */
+ void set borderRightStyle(String value) {
+ _setAll('borderRightStyle', value);
+ }
+
+ /** Sets the value of "border-right-width" */
+ void set borderRightWidth(String value) {
+ _setAll('borderRightWidth', value);
+ }
+
+ /** Sets the value of "border-spacing" */
+ void set borderSpacing(String value) {
+ _setAll('borderSpacing', value);
+ }
+
+ /** Sets the value of "border-style" */
+ void set borderStyle(String value) {
+ _setAll('borderStyle', value);
+ }
+
+ /** Sets the value of "border-top" */
+ void set borderTop(String value) {
+ _setAll('borderTop', value);
+ }
+
+ /** Sets the value of "border-top-color" */
+ void set borderTopColor(String value) {
+ _setAll('borderTopColor', value);
+ }
+
+ /** Sets the value of "border-top-style" */
+ void set borderTopStyle(String value) {
+ _setAll('borderTopStyle', value);
+ }
+
+ /** Sets the value of "border-top-width" */
+ void set borderTopWidth(String value) {
+ _setAll('borderTopWidth', value);
+ }
+
+ /** Sets the value of "border-width" */
+ void set borderWidth(String value) {
+ _setAll('borderWidth', value);
+ }
+
+ /** Sets the value of "bottom" */
+ void set bottom(String value) {
+ _setAll('bottom', value);
+ }
+
+ /** Sets the value of "caption-side" */
+ void set captionSide(String value) {
+ _setAll('captionSide', value);
+ }
+
+ /** Sets the value of "clear" */
+ void set clear(String value) {
+ _setAll('clear', value);
+ }
+
+ /** Sets the value of "clip" */
+ void set clip(String value) {
+ _setAll('clip', value);
+ }
+
+ /** Sets the value of "color" */
+ void set color(String value) {
+ _setAll('color', value);
+ }
+
+ /** Sets the value of "content" */
+ void set content(String value) {
+ _setAll('content', value);
+ }
+
+ /** Sets the value of "cursor" */
+ void set cursor(String value) {
+ _setAll('cursor', value);
+ }
+
+ /** Sets the value of "direction" */
+ void set direction(String value) {
+ _setAll('direction', value);
+ }
+
+ /** Sets the value of "display" */
+ void set display(String value) {
+ _setAll('display', value);
+ }
+
+ /** Sets the value of "empty-cells" */
+ void set emptyCells(String value) {
+ _setAll('emptyCells', value);
+ }
+
+ /** Sets the value of "font" */
+ void set font(String value) {
+ _setAll('font', value);
+ }
+
+ /** Sets the value of "font-family" */
+ void set fontFamily(String value) {
+ _setAll('fontFamily', value);
+ }
+
+ /** Sets the value of "font-size" */
+ void set fontSize(String value) {
+ _setAll('fontSize', value);
+ }
+
+ /** Sets the value of "font-style" */
+ void set fontStyle(String value) {
+ _setAll('fontStyle', value);
+ }
+
+ /** Sets the value of "font-variant" */
+ void set fontVariant(String value) {
+ _setAll('fontVariant', value);
+ }
+
+ /** Sets the value of "font-weight" */
+ void set fontWeight(String value) {
+ _setAll('fontWeight', value);
+ }
+
+ /** Sets the value of "height" */
+ void set height(String value) {
+ _setAll('height', value);
+ }
+
+ /** Sets the value of "left" */
+ void set left(String value) {
+ _setAll('left', value);
+ }
+
+ /** Sets the value of "letter-spacing" */
+ void set letterSpacing(String value) {
+ _setAll('letterSpacing', value);
+ }
+
+ /** Sets the value of "line-height" */
+ void set lineHeight(String value) {
+ _setAll('lineHeight', value);
+ }
+
+ /** Sets the value of "list-style" */
+ void set listStyle(String value) {
+ _setAll('listStyle', value);
+ }
+
+ /** Sets the value of "list-style-image" */
+ void set listStyleImage(String value) {
+ _setAll('listStyleImage', value);
+ }
+
+ /** Sets the value of "list-style-position" */
+ void set listStylePosition(String value) {
+ _setAll('listStylePosition', value);
+ }
+
+ /** Sets the value of "list-style-type" */
+ void set listStyleType(String value) {
+ _setAll('listStyleType', value);
+ }
+
+ /** Sets the value of "margin" */
+ void set margin(String value) {
+ _setAll('margin', value);
+ }
+
+ /** Sets the value of "margin-bottom" */
+ void set marginBottom(String value) {
+ _setAll('marginBottom', value);
+ }
+
+ /** Sets the value of "margin-left" */
+ void set marginLeft(String value) {
+ _setAll('marginLeft', value);
+ }
+
+ /** Sets the value of "margin-right" */
+ void set marginRight(String value) {
+ _setAll('marginRight', value);
+ }
+
+ /** Sets the value of "margin-top" */
+ void set marginTop(String value) {
+ _setAll('marginTop', value);
+ }
+
+ /** Sets the value of "max-height" */
+ void set maxHeight(String value) {
+ _setAll('maxHeight', value);
+ }
+
+ /** Sets the value of "max-width" */
+ void set maxWidth(String value) {
+ _setAll('maxWidth', value);
+ }
+
+ /** Sets the value of "min-height" */
+ void set minHeight(String value) {
+ _setAll('minHeight', value);
+ }
+
+ /** Sets the value of "min-width" */
+ void set minWidth(String value) {
+ _setAll('minWidth', value);
+ }
+
+ /** Sets the value of "outline" */
+ void set outline(String value) {
+ _setAll('outline', value);
+ }
+
+ /** Sets the value of "outline-color" */
+ void set outlineColor(String value) {
+ _setAll('outlineColor', value);
+ }
+
+ /** Sets the value of "outline-style" */
+ void set outlineStyle(String value) {
+ _setAll('outlineStyle', value);
+ }
+
+ /** Sets the value of "outline-width" */
+ void set outlineWidth(String value) {
+ _setAll('outlineWidth', value);
+ }
+
+ /** Sets the value of "overflow" */
+ void set overflow(String value) {
+ _setAll('overflow', value);
+ }
+
+ /** Sets the value of "padding" */
+ void set padding(String value) {
+ _setAll('padding', value);
+ }
+
+ /** Sets the value of "padding-bottom" */
+ void set paddingBottom(String value) {
+ _setAll('paddingBottom', value);
+ }
+
+ /** Sets the value of "padding-left" */
+ void set paddingLeft(String value) {
+ _setAll('paddingLeft', value);
+ }
+
+ /** Sets the value of "padding-right" */
+ void set paddingRight(String value) {
+ _setAll('paddingRight', value);
+ }
+
+ /** Sets the value of "padding-top" */
+ void set paddingTop(String value) {
+ _setAll('paddingTop', value);
+ }
+
+ /** Sets the value of "page-break-after" */
+ void set pageBreakAfter(String value) {
+ _setAll('pageBreakAfter', value);
+ }
+
+ /** Sets the value of "page-break-before" */
+ void set pageBreakBefore(String value) {
+ _setAll('pageBreakBefore', value);
+ }
+
+ /** Sets the value of "page-break-inside" */
+ void set pageBreakInside(String value) {
+ _setAll('pageBreakInside', value);
+ }
+
+ /** Sets the value of "position" */
+ void set position(String value) {
+ _setAll('position', value);
+ }
+
+ /** Sets the value of "quotes" */
+ void set quotes(String value) {
+ _setAll('quotes', value);
+ }
+
+ /** Sets the value of "right" */
+ void set right(String value) {
+ _setAll('right', value);
+ }
+
+ /** Sets the value of "table-layout" */
+ void set tableLayout(String value) {
+ _setAll('tableLayout', value);
+ }
+
+ /** Sets the value of "text-align" */
+ void set textAlign(String value) {
+ _setAll('textAlign', value);
+ }
+
+ /** Sets the value of "text-decoration" */
+ void set textDecoration(String value) {
+ _setAll('textDecoration', value);
+ }
+
+ /** Sets the value of "text-indent" */
+ void set textIndent(String value) {
+ _setAll('textIndent', value);
+ }
+
+ /** Sets the value of "text-transform" */
+ void set textTransform(String value) {
+ _setAll('textTransform', value);
+ }
+
+ /** Sets the value of "top" */
+ void set top(String value) {
+ _setAll('top', value);
+ }
+
+ /** Sets the value of "unicode-bidi" */
+ void set unicodeBidi(String value) {
+ _setAll('unicodeBidi', value);
+ }
+
+ /** Sets the value of "vertical-align" */
+ void set verticalAlign(String value) {
+ _setAll('verticalAlign', value);
+ }
+
+ /** Sets the value of "visibility" */
+ void set visibility(String value) {
+ _setAll('visibility', value);
+ }
+
+ /** Sets the value of "white-space" */
+ void set whiteSpace(String value) {
+ _setAll('whiteSpace', value);
+ }
+
+ /** Sets the value of "width" */
+ void set width(String value) {
+ _setAll('width', value);
+ }
+
+ /** Sets the value of "word-spacing" */
+ void set wordSpacing(String value) {
+ _setAll('wordSpacing', value);
+ }
+
+ /** Sets the value of "z-index" */
+ void set zIndex(String value) {
+ _setAll('zIndex', value);
+ }
+
+$endif
+
// Important note: CssStyleDeclarationSet does NOT implement every method
// available in CssStyleDeclaration. Some of the methods don't make so much
// sense in terms of having a resonable value to return when you're
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index a41c6a6..14d6abf 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -1387,6 +1387,38 @@
* used when an explicit accessor is not available.
*/
ElementEvents get on => new ElementEvents(this);
+
+ /**
+ * Verify if any of the attributes that we use in the sanitizer look unexpected,
+ * possibly indicating DOM clobbering attacks.
+ *
+ * Those attributes are: attributes, lastChild, children, previousNode and tagName.
+ */
+$if DART2JS
+ bool get _hasCorruptedAttributes {
+ return JS('bool', r'''
+ (function(element) {
+ if (!(element.attributes instanceof NamedNodeMap)) {
+ return true;
+ }
+ var childNodes = element.childNodes;
+ if (element.lastChild &&
+ element.lastChild !== childNodes[childNodes.length -1]) {
+ return true;
+ }
+ if (element.children) { // On Safari, children can apparently be null.
+ if (!((element.children instanceof HTMLCollection) ||
+ (element.children instanceof NodeList))) {
+ return true;
+ }
+ }
+ return false;
+ })(#)''', this);
+ }
+$else
+ // Dartium isn't affected by these attacks, because it goes directly to the C++ API.
+ bool get _hasCorruptedAttributes => false;
+$endif
$if DART2JS
@DomName('Element.offsetHeight')
diff --git a/tools/dom/templates/html/impl/impl_SVGElement.darttemplate b/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
index 1d9f06e..dd235bc 100644
--- a/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
@@ -54,13 +54,7 @@
return fragment.nodes.where((e) => e is SvgElement).single;
}
- _AttributeClassSet _cssClassSet;
- CssClassSet get classes {
- if (_cssClassSet == null) {
- _cssClassSet = new _AttributeClassSet(this);
- }
- return _cssClassSet;
- }
+ CssClassSet get classes => new _AttributeClassSet(this);
List<Element> get children => new FilteredElementList<Element>(this);
diff --git a/tools/gyp/configurations.gypi b/tools/gyp/configurations.gypi
index 6588db3..e6e19ef 100644
--- a/tools/gyp/configurations.gypi
+++ b/tools/gyp/configurations.gypi
@@ -17,6 +17,7 @@
['"<(target_arch)"=="ia32"', { 'dart_target_arch': 'IA32', }],
['"<(target_arch)"=="x64"', { 'dart_target_arch': 'X64', }],
['"<(target_arch)"=="arm"', { 'dart_target_arch': 'ARM', }],
+ ['"<(target_arch)"=="armv5te"', { 'dart_target_arch': 'ARMV5TE', }],
['"<(target_arch)"=="arm64"', { 'dart_target_arch': 'ARM64', }],
['"<(target_arch)"=="simarm"', { 'dart_target_arch': 'SIMARM', }],
['"<(target_arch)"=="simarm64"', { 'dart_target_arch': 'SIMARM64', }],
@@ -68,6 +69,13 @@
],
},
+ 'Dart_armv5te_Base': {
+ 'abstract': 1,
+ 'defines': [
+ 'TARGET_ARCH_ARM',
+ ],
+ },
+
'Dart_simarm64_Base': {
'abstract': 1,
'defines': [
@@ -246,6 +254,42 @@
],
},
+ 'DebugXARMV5TE': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_armv5te_Base', 'Dart_Debug',
+ 'Dart_Linux_Base',
+ 'Dart_Linux_xarmv5te_Base',
+ 'Dart_Linux_Debug',
+ ],
+ },
+
+ 'ReleaseXARMV5TE': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_armv5te_Base', 'Dart_Release',
+ 'Dart_Linux_Base',
+ 'Dart_Linux_xarmv5te_Base',
+ 'Dart_Linux_Release',
+ ],
+ },
+
+ 'DebugARMV5TE': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_armv5te_Base', 'Dart_Debug',
+ 'Dart_Linux_Base',
+ 'Dart_Linux_armv5te_Base',
+ 'Dart_Linux_Debug',
+ ],
+ },
+
+ 'ReleaseARMV5TE': {
+ 'inherit_from': [
+ 'Dart_Base', 'Dart_armv5te_Base', 'Dart_Release',
+ 'Dart_Linux_Base',
+ 'Dart_Linux_armv5te_Base',
+ 'Dart_Linux_Release',
+ ],
+ },
+
'DebugXARM64': {
'inherit_from': [
'Dart_Base', 'Dart_arm64_Base', 'Dart_Debug',
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index 38c3f13..2e77656 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -81,6 +81,39 @@
],
},
+ # ARMv5 cross-build
+ 'Dart_Linux_xarmv5te_Base': {
+ 'abstract': 1,
+ 'target_conditions': [
+ ['_toolset=="target"', {
+ 'cflags': [
+ '-mthumb',
+ '-mlong-calls',
+ '-march=armv5te',
+ '-mfloat-abi=soft',
+ '-Wno-psabi', # suppresses va_list warning
+ '-fno-strict-overflow',
+ ],
+ }],
+ ['_toolset=="host"', {
+ 'cflags': ['-m32', '-msse2'],
+ 'ldflags': ['-m32'],
+ }]]
+ },
+
+ # ARMv5 native build
+ 'Dart_Linux_armv5te_Base': {
+ 'abstract': 1,
+ 'cflags': [
+ '-mthumb',
+ '-mlong-calls',
+ '-march=armv5te',
+ '-mfloat-abi=soft',
+ '-Wno-psabi', # suppresses va_list warning
+ '-fno-strict-overflow',
+ ],
+ },
+
# ARM64 cross-build
'Dart_Linux_xarm64_Base': {
'abstract': 1,
diff --git a/tools/observatory_tool.py b/tools/observatory_tool.py
index 45fc36a..fab2183 100755
--- a/tools/observatory_tool.py
+++ b/tools/observatory_tool.py
@@ -30,54 +30,98 @@
result = argparse.ArgumentParser(usage=usage)
result.add_argument("--package-root", help="package root", default=None)
result.add_argument("--dart-executable", help="dart executable", default=None)
+ result.add_argument("--pub-executable", help="pub executable", default=None)
result.add_argument("--directory", help="observatory root", default=None)
result.add_argument("--command", help="[get, build, deploy]", default=None)
+ result.add_argument("--silent", help="silence all output", default=False)
return result
def ProcessOptions(options, args):
+ # Required options.
+ if (options.command == None) or (options.directory == None):
+ return False
+ # If we have a pub executable, we are running from the dart-sdk.
+ if (options.pub_executable != None):
+ return True
+ # Otherwise, we need a dart executable and a package root.
return ((options.package_root != None) and
- (options.directory != None) and
- (options.command != None) and
(options.dart_executable != None))
def ChangeDirectory(directory):
os.chdir(directory);
-def PubGet(dart_executable, pkg_root):
+def PubGet(dart_executable, pub_executable, pkg_root, silent):
# Always remove pubspec.lock before running 'pub get'.
try:
os.remove('pubspec.lock');
except OSError as e:
pass
- return subprocess.call(['python',
- RUN_PUB,
- '--package-root=' + pkg_root,
- '--dart-executable=' + dart_executable,
- 'get',
- '--offline'])
+ with open(os.devnull, 'wb') as silent_sink:
+ if (pub_executable != None):
+ return subprocess.call([pub_executable,
+ 'get',
+ '--offline'],
+ stdout=silent_sink if silent else None,
+ stderr=silent_sink if silent else None)
+ else:
+ return subprocess.call(['python',
+ RUN_PUB,
+ '--package-root=' + pkg_root,
+ '--dart-executable=' + dart_executable,
+ 'get',
+ '--offline'],
+ stdout=silent_sink if silent else None,
+ stderr=silent_sink if silent else None,)
-def PubBuild(dart_executable, pkg_root, output_dir):
- return subprocess.call(['python',
- RUN_PUB,
- '--package-root=' + pkg_root,
- '--dart-executable=' + dart_executable,
- 'build',
- '--output',
- output_dir])
+def PubBuild(dart_executable, pub_executable, pkg_root, silent, output_dir):
+ with open(os.devnull, 'wb') as silent_sink:
+ if (pub_executable != None):
+ return subprocess.call([pub_executable,
+ 'build',
+ '--output',
+ output_dir],
+ stdout=silent_sink if silent else None,
+ stderr=silent_sink if silent else None,)
+ else:
+ return subprocess.call(['python',
+ RUN_PUB,
+ '--package-root=' + pkg_root,
+ '--dart-executable=' + dart_executable,
+ 'build',
+ '--output',
+ output_dir],
+ stdout=silent_sink if silent else None,
+ stderr=silent_sink if silent else None,)
def Deploy(input_dir, output_dir):
shutil.rmtree(output_dir)
shutil.copytree(input_dir, output_dir, ignore=IGNORE_PATTERNS)
return 0
+def RewritePubSpec(input_path, output_path, search, replace):
+ with open(input_path, 'rb') as input_file:
+ input_data = input_file.read()
+ input_data = input_data.replace(search, replace)
+ with open(output_path, 'wb+') as output_file:
+ output_file.write(input_data)
+
def ExecuteCommand(options, args):
cmd = options.command
if (cmd == 'get'):
- return PubGet(options.dart_executable, options.package_root)
+ return PubGet(options.dart_executable,
+ options.pub_executable,
+ options.package_root,
+ options.silent)
elif (cmd == 'build'):
- return PubBuild(options.dart_executable, options.package_root, args[0])
+ return PubBuild(options.dart_executable,
+ options.pub_executable,
+ options.package_root,
+ options.silent,
+ args[0])
elif (cmd == 'deploy'):
Deploy('build', 'deployed')
+ elif (cmd == 'rewrite'):
+ RewritePubSpec(args[0], args[1], args[2], args[3])
else:
print >> sys.stderr, ('ERROR: command "%s" not supported') % (cmd)
return -1;
@@ -92,8 +136,12 @@
if os.getenv('DART_USE_BOOTSTRAP_BIN') != None:
dart_executable = options.dart_executable
# Calculate absolute paths before changing directory.
- options.package_root = os.path.abspath(options.package_root)
- options.dart_executable = os.path.abspath(options.dart_executable)
+ if (options.package_root != None):
+ options.package_root = os.path.abspath(options.package_root)
+ if (options.dart_executable != None):
+ options.dart_executable = os.path.abspath(options.dart_executable)
+ if (options.pub_executable != None):
+ options.pub_executable = os.path.abspath(options.pub_executable)
if len(args) == 1:
args[0] = os.path.abspath(args[0])
# Pub must be run from the project's root directory.
diff --git a/tools/testing/dart/runtime_configuration.dart b/tools/testing/dart/runtime_configuration.dart
index 1358b01..487c9e5 100644
--- a/tools/testing/dart/runtime_configuration.dart
+++ b/tools/testing/dart/runtime_configuration.dart
@@ -169,6 +169,7 @@
switch (arch) {
case 'simarm':
case 'arm':
+ case 'armv5te':
case 'simmips':
case 'mips':
case 'simarm64':
diff --git a/tools/testing/dart/test_configurations.dart b/tools/testing/dart/test_configurations.dart
index 135226e..d56514e 100644
--- a/tools/testing/dart/test_configurations.dart
+++ b/tools/testing/dart/test_configurations.dart
@@ -29,7 +29,7 @@
new Path('pkg'),
new Path('third_party/pkg_tested'),
new Path('runtime/tests/vm'),
- new Path('runtime/observatory'),
+ new Path('runtime/observatory/tests/service'),
new Path('samples'),
new Path('samples-dev'),
new Path('tests/benchmark_smoke'),
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index 4dddd24..3ee0c59 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -14,7 +14,7 @@
const List<String> defaultTestSelectors =
const ['samples', 'standalone', 'corelib', 'co19', 'language',
'isolate', 'vm', 'html', 'benchmark_smoke',
- 'utils', 'lib', 'pkg', 'analyze_library', 'vmservice',
+ 'utils', 'lib', 'pkg', 'analyze_library', 'service',
'pkg_tested'];
/**
@@ -109,7 +109,7 @@
'arch',
'The architecture to run tests for',
['-a', '--arch'],
- ['all', 'ia32', 'x64', 'arm', 'arm64', 'mips',
+ ['all', 'ia32', 'x64', 'arm', 'armv5te', 'arm64', 'mips',
'simarm', 'simarm64', 'simmips'],
'ia32'),
new _TestOptionSpecification(
diff --git a/tools/utils.py b/tools/utils.py
index 55a54bc..3c1eacb 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -48,7 +48,9 @@
# Try to guess the host architecture.
def GuessArchitecture():
os_id = platform.machine()
- if os_id.startswith('arm'):
+ if os_id.startswith('armv5te'):
+ return 'armv5te'
+ elif os_id.startswith('arm'):
return 'arm'
elif os_id.startswith('aarch64'):
return 'arm64'
@@ -220,6 +222,7 @@
'ia32': 'ia32',
'x64': 'ia32',
'arm': 'arm',
+ 'armv5te': 'arm',
'arm64': 'arm',
'mips': 'mips',
'simarm': 'ia32',
@@ -553,7 +556,11 @@
else:
arch = GuessArchitecture()
system = GuessOS()
- if arch == 'arm':
+ if arch == 'armv5te':
+ # TODO(zra): This binary does not exist, yet. Check one in once we have
+ # sufficient stability.
+ return os.path.join(dart_binary_prefix, system, 'dart-armv5te')
+ elif arch == 'arm':
return os.path.join(dart_binary_prefix, system, 'dart-arm')
elif arch == 'arm64':
return os.path.join(dart_binary_prefix, system, 'dart-arm64')